diff options
43 files changed, 916 insertions, 728 deletions
diff --git a/locales/ar.json b/locales/ar.json index 57062e89..5d8b230f 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -15,13 +15,13 @@ "New password": "كلمة مرور جديدة", "New passwords must match": "يَجبُ أن تكون كلمتا المرور متطابقتين", "Authorize token?": "رمز التفويض؟", - "Authorize token for `x`?": "السماح بالرمز المميز ل 'x'؟", + "Authorize token for `x`?": "السماح بالرمز المميز ل `x`؟", "Yes": "نعم", "No": "لا", "Import and Export Data": "اِستيراد البيانات وتصديرها", "Import": "استيراد", "Import Invidious data": "استيراد بيانات JSON Invidious", - "Import YouTube subscriptions": "استيراد اشتراكات YouTube/OPML", + "Import YouTube subscriptions": "استيراد الاشتراكات YouTube بتنسيق CSV أو OPML", "Import FreeTube subscriptions (.db)": "استيراد اشتراكات فريتيوب (.db)", "Import NewPipe subscriptions (.json)": "استيراد اشتراكات نيو بايب (.json)", "Import NewPipe data (.zip)": "استيراد بيانات نيو بايب (.zip)", @@ -170,7 +170,7 @@ "Password cannot be empty": "لا يمكن أن تكون كلمة السر فارغة", "Password cannot be longer than 55 characters": "يجب أن لا تتعدى كلمة السر 55 حرفًا", "Please log in": "الرجاء تسجيل الدخول", - "Invidious Private Feed for `x`": "تغذية Invidious خاصة ل 'x'", + "Invidious Private Feed for `x`": "تغذية Invidious خاصة ل `x`", "channel:`x`": "قناة:`x`", "Deleted or invalid channel": "قناة ممسوحة او غير صالحة", "This channel does not exist.": "هذه القناة غير موجودة.", @@ -382,11 +382,11 @@ "videoinfo_watch_on_youTube": "مشاهدة على يوتيوب", "videoinfo_youTube_embed_link": "مضمن", "videoinfo_invidious_embed_link": "رابط مضمن", - "user_created_playlists": "'x' إنشاء قوائم التشغيل", - "user_saved_playlists": "قوائم التشغيل المحفوظة 'x'", + "user_created_playlists": "`x` إنشاء قوائم التشغيل", + "user_saved_playlists": "قوائم التشغيل المحفوظة `x`", "Video unavailable": "الفيديو غير متوفر", "search_filters_features_option_three_sixty": "360°", - "download_subtitles": "ترجمات - 'x' (.vtt)", + "download_subtitles": "ترجمات - `x` (.vtt)", "invidious": "الخيالي", "preferences_save_player_pos_label": "حفظ موضع التشغيل: ", "crash_page_you_found_a_bug": "يبدو أنك قد وجدت خطأً برمجيًّا في Invidious!", @@ -556,5 +556,13 @@ "generic_channels_count_4": "{{count}} قنوات", "generic_channels_count_5": "{{count}} قناة", "Import YouTube watch history (.json)": "استيراد سجل مشاهدة YouTube بصيغة (.json)", - "toggle_theme": "تبديل الموضوع" + "toggle_theme": "تبديل الموضوع", + "Add to playlist": "أضف إلى قائمة التشغيل", + "Add to playlist: ": "أضف إلى قائمة التشغيل: ", + "Answer": "الرد", + "Search for videos": "ابحث عن مقاطع الفيديو", + "The Popular feed has been disabled by the administrator.": "تم تعطيل الخلاصة الشائعة من قبل المسؤول.", + "carousel_slide": "الشريحة {{current}} من {{total}}", + "carousel_skip": "تخطي الكاروسيل", + "carousel_go_to": "انتقل إلى الشريحة `x`" } diff --git a/locales/bn.json b/locales/bn.json index 9d1c7b24..501a1ca3 100644 --- a/locales/bn.json +++ b/locales/bn.json @@ -90,5 +90,7 @@ "preferences_quality_option_medium": "মধ্যম", "preferences_quality_option_small": "ছোট", "preferences_quality_dash_option_1080p": "১০৮০পি", - "preferences_quality_dash_option_720p": "৭২০পি" + "preferences_quality_dash_option_720p": "৭২০পি", + "Add to playlist": "প্লেলিস্টে যোগ করুন", + "Add to playlist: ": "প্লেলিস্টে যোগ করুন: " } diff --git a/locales/cs.json b/locales/cs.json index 4aa20f28..1350f146 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -21,7 +21,7 @@ "Import and Export Data": "Import a export dat", "Import": "Importovat", "Import Invidious data": "Importovat JSON údaje Invidious", - "Import YouTube subscriptions": "Importovat odběry z YouTube/OPML", + "Import YouTube subscriptions": "Importovat odběry z YouTube CSV nebo OPML", "Import FreeTube subscriptions (.db)": "Importovat odběry z FreeTube (.db)", "Import NewPipe subscriptions (.json)": "Importovat odběry z NewPipe (.json)", "Import NewPipe data (.zip)": "Importovat údeje z NewPipe (.zip)", @@ -505,5 +505,13 @@ "generic_channels_count_1": "{{count}} kanály", "generic_channels_count_2": "{{count}} kanálů", "Import YouTube watch history (.json)": "Importovat historii sledování z YouTube (.json)", - "toggle_theme": "Přepnout motiv" + "toggle_theme": "Přepnout motiv", + "Add to playlist": "Přidat do playlistu", + "Add to playlist: ": "Přidat do playlistu: ", + "Answer": "Odpověď", + "Search for videos": "Hledat videa", + "The Popular feed has been disabled by the administrator.": "Kategorie Populární byla zakázána administrátorem.", + "carousel_slide": "Snímek {{current}} z {{total}}", + "carousel_skip": "Přeskočit galerii", + "carousel_go_to": "Přejít na snímek `x`" } diff --git a/locales/da.json b/locales/da.json index 019f1c51..9cbb446a 100644 --- a/locales/da.json +++ b/locales/da.json @@ -165,12 +165,12 @@ "Password cannot be empty": "Adgangskoden må ikke være tom", "Password cannot be longer than 55 characters": "Adgangskoden må ikke være længere end 55 tegn", "Please log in": "Venligst log ind", - "channel:`x`": "kanal: 'x'", + "channel:`x`": "kanal: `x`", "Deleted or invalid channel": "Slettet eller invalid kanal", "This channel does not exist.": "Denne kanal eksisterer ikke.", "Could not get channel info.": "Kunne ikke hente kanal info.", "Could not fetch comments": "Kunne ikke hente kommentarer", - "`x` ago": "'x' siden", + "`x` ago": "`x` siden", "Load more": "Hent flere", "Could not create mix.": "Kunne ikke skabe blanding.", "Empty playlist": "Tom playliste", diff --git a/locales/de.json b/locales/de.json index 756aff76..46327f57 100644 --- a/locales/de.json +++ b/locales/de.json @@ -487,5 +487,11 @@ "channel_tab_releases_label": "Veröffentlichungen", "generic_channels_count": "{{count}} Kanal", "generic_channels_count_plural": "{{count}} Kanäle", - "Import YouTube watch history (.json)": "YouTube Wiedergabeverlauf importieren (.json)" + "Import YouTube watch history (.json)": "YouTube Wiedergabeverlauf importieren (.json)", + "Answer": "Antwort", + "The Popular feed has been disabled by the administrator.": "Der Angesagt-Feed wurde vom Administrator deaktiviert.", + "Add to playlist": "Einer Wiedergabeliste hinzufügen", + "Search for videos": "Nach Videos suchen", + "toggle_theme": "Thema wechseln", + "Add to playlist: ": "Einer Wiedergabeliste hinzufügen: " } diff --git a/locales/en-US.json b/locales/en-US.json index 10887612..3987f796 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -43,7 +43,7 @@ "Import and Export Data": "Import and Export Data", "Import": "Import", "Import Invidious data": "Import Invidious JSON data", - "Import YouTube subscriptions": "Import YouTube/OPML subscriptions", + "Import YouTube subscriptions": "Import YouTube CSV or OPML subscriptions", "Import YouTube playlist (.csv)": "Import YouTube playlist (.csv)", "Import YouTube watch history (.json)": "Import YouTube watch history (.json)", "Import FreeTube subscriptions (.db)": "Import FreeTube subscriptions (.db)", diff --git a/locales/es.json b/locales/es.json index 7a41710e..1d082e60 100644 --- a/locales/es.json +++ b/locales/es.json @@ -21,7 +21,7 @@ "Import and Export Data": "Importación y exportación de datos", "Import": "Importar", "Import Invidious data": "Importar datos JSON de Invidious", - "Import YouTube subscriptions": "Importar suscripciones de YouTube/OPML", + "Import YouTube subscriptions": "Importar suscripciones CSV u OPML de YouTube", "Import FreeTube subscriptions (.db)": "Importar suscripciones de FreeTube (.db)", "Import NewPipe subscriptions (.json)": "Importar suscripciones de NewPipe (.json)", "Import NewPipe data (.zip)": "Importar datos de NewPipe (.zip)", @@ -133,7 +133,7 @@ "Create playlist": "Crear lista de reproducción", "Title": "Título", "Playlist privacy": "Privacidad de la lista de reproducción", - "Editing playlist `x`": "Editando la lista de reproducción 'x'", + "Editing playlist `x`": "Editando la lista de reproducción `x`", "Show more": "Mostrar más", "Show less": "Mostrar menos", "Watch on YouTube": "Ver en YouTube", @@ -505,5 +505,13 @@ "generic_channels_count_1": "{{count}} canales", "generic_channels_count_2": "{{count}} canales", "Import YouTube watch history (.json)": "Importar el historial de las visualizaciones de YouTube (.json)", - "toggle_theme": "Alternar tema" + "toggle_theme": "Alternar tema", + "Add to playlist: ": "Añadir a la lista de reproducción: ", + "Add to playlist": "Añadir a la lista de reproducción", + "Answer": "Respuesta", + "Search for videos": "Buscar por vídeos", + "The Popular feed has been disabled by the administrator.": "El feed Popular ha sido desactivado por el administrador.", + "carousel_slide": "Diapositiva {{current}} de {{total}}", + "carousel_skip": "Saltar el carrusel", + "carousel_go_to": "Ir a la diapositiva `x`" } diff --git a/locales/eu.json b/locales/eu.json index 8b365270..fbca537b 100644 --- a/locales/eu.json +++ b/locales/eu.json @@ -161,13 +161,13 @@ "Source available here.": "Iturburua hemen eskura.", "View JavaScript license information.": "JavaScriptaren lizentzi adierazpena ikusi.", "Blacklisted regions: ": "zerrenda beltzaren zonaldeak: ", - "Premieres `x`": "'x' estrenaldiak", + "Premieres `x`": "`x` estrenaldiak", "Wrong answer": "Erantzun ez zuzena", "Password is a required field": "Pasahitza beharrezkoa da", "Wrong username or password": "Pasahitza edo ezizena gaizki", "Password cannot be longer than 55 characters": "Pasahitza 55 karaktere baino luzeagoa ezin da izan", "This channel does not exist.": "Kanal hau ez dago.", - "`x` ago": "duela 'x'", + "`x` ago": "duela `x`", "Czech": "Txekiera", "preferences_region_label": "Herrialdeko edukiera: ", "preferences_sort_label": "Bideoak ordenatu: ", @@ -207,24 +207,24 @@ "Public": "Orokorra", "Unlisted": "Ez zerrendatua", "Subscription manager": "Harpidetzen kudeatzailea", - "Updated `x` ago": "Duela 'x' eguneratua", + "Updated `x` ago": "Duela `x` eguneratua", "Hide replies": "Erantzunak izkutatu", "preferences_thin_mode_label": "Urri eran: ", "Show replies": "Erantzunak erakutsi", "Watch on YouTube": "YouTuben ikusi", - "Premieres in `x`": "'x'eko estrenaldiak", - "Delete playlist `x`?": "'x' zerrenda ezabatu nahi?", + "Premieres in `x`": "`x`eko estrenaldiak", + "Delete playlist `x`?": "`x` zerrenda ezabatu nahi?", "Token is expired, please try again": "Token kadukatua, saiatu berriro", "CAPTCHA enabled: ": "CAPTCHA gaitu: ", "Released under the AGPLv3 on Github.": "GitHubeko AGPLv3pean argitaratuta.", - "channel:`x`": "Kanal: 'x'", + "channel:`x`": "Kanal: `x`", "Georgian": "Georgiera", "Incorrect password": "Pasahitza gaizki", "Playlist does not exist.": "Zerrenda ez da existitzen.", "preferences_category_misc": "Askotariko lehentasunak", "View `x` comments": { - "([^.,0-9]|^)1([^.,0-9]|$)": "'x' iruzkina ikusi", - "": "'x' iruzkinak ikusi" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x` iruzkina ikusi", + "": "`x` iruzkinak ikusi" }, "Report statistics: ": "Estatistikak adierazi: ", "preferences_max_results_label": "Jotzeko bideo zerrendaren luzera: ", @@ -237,7 +237,7 @@ "Hidden field \"challenge\" is a required field": "\"challenge\" eremu ezkutua beharrezkoa da", "German": "Alemaniarra", "View YouTube comments": "YouTubeko iruzkinak ikusi", - "`x` is live": "'x' bizirik darrai", + "`x` is live": "`x` bizirik darrai", "Password cannot be empty": "Pasahitza ezin da hutsik utzi", "preferences_video_loop_label": "Beti begiztatu: ", "Only show latest unwatched video from channel: ": "kanalaren azken bideo ezikusia erakutsi soilik ", @@ -261,9 +261,9 @@ "Hide annotations": "Oharrak izkutatu", "Title": "Titulua", "channel name": "Kanalaren izena", - "Authorize token for `x`?": "Baimendu tokena 'x'tzako?", + "Authorize token for `x`?": "Baimendu tokena `x`tzako?", "Private": "Pribatua", - "Editing playlist `x`": "'x' zerrenda editatu", + "Editing playlist `x`": "`x` zerrenda editatu", "Could not pull trending pages.": "Ezin ekarri orri arrakastatsuak.", "crash_page_read_the_faq": "Bide <a href=\"`x`\"> (FAQ) ohiko galderak</a>" } diff --git a/locales/hi.json b/locales/hi.json index a7e0639a..0a1c09dd 100644 --- a/locales/hi.json +++ b/locales/hi.json @@ -62,7 +62,7 @@ "Import and Export Data": "डेटा को आयात और निर्यात करें", "Import": "आयात करें", "Import Invidious data": "Invidious JSON डेटा आयात करें", - "Import YouTube subscriptions": "YouTube/OPML सदस्यताएँ आयात करें", + "Import YouTube subscriptions": "YouTube CSV या OPML सदस्यताएँ आयात करें", "Import FreeTube subscriptions (.db)": "FreeTube सदस्यताएँ आयात करें (.db)", "Import NewPipe subscriptions (.json)": "NewPipe सदस्यताएँ आयात करें (.json)", "Import NewPipe data (.zip)": "NewPipe डेटा आयात करें (.zip)", @@ -487,5 +487,14 @@ "Download is disabled": "डाउनलोड करना अक्षम है", "generic_channels_count": "{{count}} चैनल", "generic_channels_count_plural": "{{count}} चैनल", - "Import YouTube watch history (.json)": "YouTube पर देखने का इतिहास आयात करें (.json)" + "Import YouTube watch history (.json)": "YouTube पर देखने का इतिहास आयात करें (.json)", + "Add to playlist": "प्लेलिस्ट में जोड़ें", + "Answer": "जवाब", + "The Popular feed has been disabled by the administrator.": "लोकप्रिय फ़ीड व्यवस्थापक द्वारा अक्षम कर दिया गया है।", + "toggle_theme": "थीम टॉगल करें", + "carousel_slide": "{{total}} में से स्लाइड {{current}}", + "carousel_skip": "कैरोसेल छोड़ें", + "Add to playlist: ": "प्लेलिस्ट में जोड़ें: ", + "Search for videos": "वीडियो खोजें", + "carousel_go_to": "स्लाइड `x` पर जाएँ" } diff --git a/locales/hr.json b/locales/hr.json index 2d86144f..91425248 100644 --- a/locales/hr.json +++ b/locales/hr.json @@ -21,7 +21,7 @@ "Import and Export Data": "Uvezi i izvezi podatke", "Import": "Uvezi", "Import Invidious data": "Uvezi Invidious JSON podatke", - "Import YouTube subscriptions": "Uvezi YouTube/OPML pretplate", + "Import YouTube subscriptions": "Uvezi YouTube CSV ili OPML pretplate", "Import FreeTube subscriptions (.db)": "Uvezi FreeTube pretplate (.db)", "Import NewPipe subscriptions (.json)": "Uvezi NewPipe pretplate (.json)", "Import NewPipe data (.zip)": "Uvezi NewPipe podatke (.zip)", @@ -504,5 +504,14 @@ "generic_channels_count_0": "{{count}} kanal", "generic_channels_count_1": "{{count}} kanala", "generic_channels_count_2": "{{count}} kanala", - "Import YouTube watch history (.json)": "Uvezi YouTube povijest gledanja (.json)" + "Import YouTube watch history (.json)": "Uvezi YouTube povijest gledanja (.json)", + "Add to playlist": "Dodaj u zbirku", + "Add to playlist: ": "Dodaj u zbirku: ", + "Answer": "Odgovor", + "Search for videos": "Traži videa", + "The Popular feed has been disabled by the administrator.": "Popularni feed je administrator deaktivirao.", + "toggle_theme": "Uklj./Isklj. temu", + "carousel_slide": "Kadar {{current}} od {{total}}", + "carousel_go_to": "Idi na kadar `x`", + "carousel_skip": "Preskoči vrtuljak" } diff --git a/locales/ia.json b/locales/ia.json index 19b6b0c0..2c8cb2b0 100644 --- a/locales/ia.json +++ b/locales/ia.json @@ -37,5 +37,9 @@ "E-mail": "E-mail", "Delete account?": "Deler conto?", "preferences_volume_label": "Volumine del reproductor: ", - "preferences_sort_label": "Ordinar le videos per: " + "preferences_sort_label": "Ordinar le videos per: ", + "Next page": "Pagina sequente", + "Previous page": "Pagina previe", + "Yes": "Si", + "Import": "Importar" } diff --git a/locales/it.json b/locales/it.json index 7b6bb5d9..79aa6c16 100644 --- a/locales/it.json +++ b/locales/it.json @@ -504,5 +504,14 @@ "generic_channels_count_0": "{{count}} canale", "generic_channels_count_1": "{{count}} canali", "generic_channels_count_2": "{{count}} canali", - "Import YouTube watch history (.json)": "Importa la cronologia delle visualizzazioni di YouTube (.json)" + "Import YouTube watch history (.json)": "Importa la cronologia delle visualizzazioni di YouTube (.json)", + "Answer": "Risposta", + "toggle_theme": "Cambia Tema", + "Add to playlist": "Aggiungi alla playlist", + "Add to playlist: ": "Aggiungi alla playlist ", + "Search for videos": "Cerca dei video", + "The Popular feed has been disabled by the administrator.": "La sezione dei contenuti popolari è stata disabilitata dall'amministratore.", + "carousel_slide": "Fotogramma {{current}} di {{total}}", + "carousel_skip": "Salta la galleria", + "carousel_go_to": "Vai al fotogramma `x`" } diff --git a/locales/ja.json b/locales/ja.json index 2e3437bc..d430b2a4 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -470,5 +470,14 @@ "generic_button_rss": "RSS", "playlist_button_add_items": "動画を追加", "generic_channels_count_0": "{{count}}個のチャンネル", - "Import YouTube watch history (.json)": "YouTube 視聴履歴をインポート (.json)" + "Import YouTube watch history (.json)": "YouTube 視聴履歴をインポート (.json)", + "Add to playlist": "再生リストに追加", + "Add to playlist: ": "再生リストに追加: ", + "Answer": "回答", + "Search for videos": "動画を検索", + "The Popular feed has been disabled by the administrator.": "人気の動画のページは管理者によって無効にされています。", + "carousel_go_to": "スライド`x`を表示", + "carousel_slide": "スライド{{current}} / 全{{total}}個中", + "carousel_skip": "画像のスライド表示をスキップ", + "toggle_theme": "テーマの切り替え" } diff --git a/locales/ko.json b/locales/ko.json index c0257ee5..7611e8e7 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -460,7 +460,7 @@ "Music in this video": "동영상 속 음악", "Artist: ": "아티스트: ", "Download is disabled": "다운로드가 비활성화 되어있음", - "Import YouTube playlist (.csv)": "유튜브 플레이리스트 가져오기 (.csv)", + "Import YouTube playlist (.csv)": "유튜브 재생목록 가져오기 (.csv)", "playlist_button_add_items": "동영상 추가", "channel_tab_podcasts_label": "팟캐스트", "generic_button_delete": "삭제", @@ -468,7 +468,16 @@ "generic_button_save": "저장", "generic_button_cancel": "취소", "generic_button_rss": "RSS", - "channel_tab_releases_label": "출시", + "channel_tab_releases_label": "발매", "generic_channels_count_0": "{{count}} 채널", - "Import YouTube watch history (.json)": "유튜브 시청 기록 가져오기 (.json)" + "Import YouTube watch history (.json)": "유튜브 시청 기록 가져오기 (.json)", + "Add to playlist": "재생목록에 추가", + "Add to playlist: ": "재생목록에 추가: ", + "Answer": "답", + "The Popular feed has been disabled by the administrator.": "관리자가 인기 피드를 비활성화했습니다.", + "carousel_skip": "캐러셀 건너뛰기", + "carousel_go_to": "`x` 슬라이드로 이동", + "Search for videos": "비디오 검색", + "toggle_theme": "테마 전환", + "carousel_slide": "{{total}}의 슬라이드 {{current}}" } diff --git a/locales/lmo.json b/locales/lmo.json new file mode 100644 index 00000000..9d2fe2a8 --- /dev/null +++ b/locales/lmo.json @@ -0,0 +1,232 @@ +{ + "Add to playlist": "Giont a la playlist", + "generic_button_edit": "Modifega", + "generic_button_save": "Salva", + "LIVE": "EN DÌRETT", + "Shared `x` ago": "Compartiss `x` fa", + "View channel on YouTube": "Varda el canal sul YouTube", + "newest": "plù nöeuf", + "oldest": "plù végh", + "Search for videos": "Càuta dei video", + "The Popular feed has been disabled by the administrator.": "la seziùn Pupular la è stada disabilidada par l'amministratòr.", + "generic_channels_count": "{{count}} canal", + "generic_channels_count_plural": "{{count}} canai", + "popular": "pupular", + "generic_views_count": "{{count}} visualisazión", + "generic_views_count_plural": "{{count}} visualisazióni", + "generic_videos_count": "{{count}} video", + "generic_videos_count_plural": "{{count}} video", + "generic_playlists_count": "{{count}} playlist", + "generic_playlists_count_plural": "{{count}} playlist", + "generic_subscriptions_count": "{{count}} inscrizion", + "generic_subscriptions_count_plural": "{{count}} inscrizioni", + "generic_button_cancel": "Cançéla", + "generic_button_delete": "Scassa via", + "Unsubscribe": "Disinscriviti", + "Next page": "Pagina siguènt", + "Previous page": "Pagina indrèe", + "Clear watch history?": "Cançélar la istoria dei video vardàa?", + "New password": "Nöeva password", + "Import and Export Data": "Importazion ed esportazion dei dat", + "Import": "Importa", + "Import Invidious data": "Importa i dat de l'Invidious en el formàt JSON", + "Import YouTube subscriptions": "Importa le inscrizioni dal YouTube/OPML", + "Import YouTube playlist (.csv)": "Importa le playlist dal YouTube (.csv)", + "Import YouTube watch history (.json)": "Importa la istoria de visualizazzion dal YouTube (.json)", + "Import FreeTube subscriptions (.db)": "Importa le inscrizioni dal FreeTube (.db)", + "Import NewPipe data (.zip)": "importa i dat del NewPipe (.zip)", + "Export": "Esporta", + "Export subscriptions as OPML": "Esporta inscrizioni com OPML", + "Export data as JSON": "Esporta i dat de l'Invidious com JSON", + "Delete account?": "Eliminà 'l profil?", + "History": "Istoria", + "An alternative front-end to YouTube": "Una interfacia alternatif al YouTube", + "JavaScript license information": "Informaziòn su la licensa JavaScript", + "source": "font", + "Log in": "Và dent", + "Text CAPTCHA": "Tèst del CAPTCHA", + "Image CAPTCHA": "Imàgen del CAPTCHA", + "Sign In": "Ven denter", + "Register": "Registres", + "E-mail": "E-mail", + "Preferences": "Priferenze", + "preferences_category_player": "Priferenze del riprodutòr", + "preferences_quality_option_dash": "DASH (qualità adatif)", + "preferences_quality_option_hd720": "HD720", + "preferences_quality_option_medium": "Media", + "preferences_quality_option_small": "Picinina", + "preferences_quality_dash_option_auto": "Auto", + "preferences_quality_dash_option_best": "Meglior", + "preferences_quality_dash_option_worst": "Peggior", + "preferences_quality_dash_option_4320p": "4320p", + "preferences_quality_dash_option_2160p": "2160p", + "preferences_quality_dash_option_1440p": "1440p", + "preferences_quality_dash_option_1080p": "1080p", + "preferences_quality_dash_option_720p": "720p", + "preferences_quality_dash_option_480p": "480p", + "preferences_quality_dash_option_360p": "360p", + "preferences_quality_dash_option_240p": "240p", + "preferences_quality_dash_option_144p": "144p", + "reddit": "Reddit", + "invidious": "Invidious", + "light": "ciar", + "dark": "scur", + "preferences_category_misc": "Priferenze varie", + "preferences_category_subscription": "Priferenze de le inscrizioni", + "published": "data de publicazion", + "published - reverse": "data de publicazion - invertì", + "alphabetically": "orden alfabetegh", + "channel name": "nòm del canal", + "channel name - reverse": "nòm del canal - invertì", + "Enable web notifications": "Empisa le notifeghe da la red", + "`x` uploaded a video": "`x` la ghàa cargà un video", + "`x` is live": "`x` l'è 'n dirétt adés", + "preferences_category_data": "Priferenze dei dat", + "Import/export data": "Importa/esporta i dat", + "Change password": "Cambia la parola ciav", + "Manage subscriptions": "Organisa le inscrizioni", + "Manage tokens": "Organisa i tokens", + "Watch history": "Istoria dei video vardà", + "Delete account": "Cançéla 'l profil", + "Save preferences": "Salva priferenze", + "Subscription manager": "Manegia le inscrizioni", + "Token": "Token", + "tokens_count": "{{count}} token", + "tokens_count_plural": "{{count}} token", + "Import/export": "Importa/esporta", + "unsubscribe": "disinscriviti", + "subscriptions_unseen_notifs_count": "{{count}} notifega mia visualisada", + "subscriptions_unseen_notifs_count_plural": "{{count}} notifeghe mia visualisade", + "Log out": "Sortiss", + "Released under the AGPLv3 on Github.": "Publicà en el GitHub suta licenza AGPLv3.", + "Source available here.": "Codegh de la font disponivel chì.", + "View privacy policy.": "Varda la pulitega de la privacy.", + "Trending": "De moda", + "Public": "Publico", + "Unlisted": "Non en lista", + "Private": "Privàt", + "View all playlists": "Varda tute le playlist", + "Updated `x` ago": "Giurnà `x` fa", + "Delete playlist `x`?": "Cançéla la playlist `x`?", + "Delete playlist": "Cançéla playlist", + "Create playlist": "Crea playlist", + "Title": "Titel", + "Playlist privacy": "Privacy de la playlist", + "Editing playlist `x`": "Modifega playlist `x`", + "playlist_button_add_items": "Gionta video", + "Show more": "Varda plù", + "Show less": "Varda mèn", + "Watch on YouTube": "Varda sul YouTube", + "Switch Invidious Instance": "Cambia la instanza del Invidious", + "search_message_no_results": "Non è stat truvà nigun resultat.", + "Cebuano": "Cebuano", + "Chinese (Traditional)": "Cines (Tradizional)", + "Corsican": "Còrso", + "Croatian": "Cruat", + "Georgian": "Georgian", + "Gujarati": "Gujarati", + "Hawaiian": "Hawaiian", + "Kurdish": "Curd", + "Latin": "Latin", + "Latvian": "Letton", + "Lithuanian": "Lituan", + "Malay": "Males", + "Maltese": "Maltes", + "Mongolian": "móngol", + "Persian": "Persian", + "Polish": "Polacch", + "Portuguese": "Portoghes", + "Romanian": "Romen", + "Scottish Gaelic": "Gaelich Scusses", + "Spanish (Latin America)": "Spagnöl (America do Sùd)", + "Thai": "Thai", + "Western Frisian": "Frisian do ponente", + "Basque": "Basco", + "Chinese (Simplified)": "Cines (Semplificà)", + "Haitian Creole": "Creolo de Haiti", + "Galician": "Galiçian", + "Hebrew": "Ebraich", + "Korean": "Corean", + "View playlist on YouTube": "Varda la playlist sul YouTube", + "Southern Sotho": "Sotho do Sùd", + "generic_button_rss": "RSS", + "Welsh": "Galés", + "Answer": "Resposta", + "New passwords must match": "Le nöeve password la deven esere uguai", + "Authorize token?": "Autorisà 'l token?", + "Authorize token for `x`?": "Autorisà 'l token par `x`?", + "Yes": "Sì", + "No": "No", + "Export subscriptions as OPML (for NewPipe & FreeTube)": "Esporta inscrizioni com OPML (par 'l NewPipe e 'l FreeTube)", + "Log in/register": "Va dent/Registres", + "User ID": "ID utent", + "Password": "Parola ciav", + "Time (h:mm:ss):": "Temp (h:mm:ss):", + "Import NewPipe subscriptions (.json)": "importa le inscrizioni dal NewPipe (.json)", + "youtube": "YouTube", + "alphabetically - reverse": "orden alfabetegh - invertì", + "preferences_category_visual": "Priferenze grafeghe", + "Clear watch history": "Scompartiss la istoria dei video vardà", + "preferences_category_admin": "Priferenze de l'amministratòr", + "Token manager": "Manegia i token", + "Subscriptions": "Inscrizioni", + "search": "cerca", + "View JavaScript license information.": "Varda le informazion su la licenza JavaScript.", + "search_message_change_filters_or_query": "Ti pödi pruà a slargà la reçerca e/or a cangià i filter.", + "generic_subscribers_count": "{{count}} inscritt", + "generic_subscribers_count_plural": "{{count}} inscriti", + "Subscribe": "Inscriviti", + "last": "ùltim", + "Add to playlist: ": "Giont a la playlist: ", + "preferences_autoplay_label": "Reproduzion automatega: ", + "preferences_continue_label": "Reproduzion seguént preimpostà: ", + "preferences_continue_autoplay_label": "Fa partì en automatico el video seguént: ", + "preferences_listen_label": "Modalità de sól audio preimpostà: ", + "preferences_local_label": "Proxy par i video: ", + "preferences_watch_history_label": "Ativà la istoria de reproduzion: ", + "preferences_speed_label": "Velocità preimpostà: ", + "preferences_volume_label": "Volume del reprodutòr: ", + "preferences_region_label": "Nazion del contenut: ", + "Dark mode: ": "Tema scur ", + "preferences_dark_mode_label": "Tema: ", + "preferences_thin_mode_label": "Modalità legera: ", + "preferences_automatic_instance_redirect_label": "Reindirizazzion automatega de la instansa (rivèrt a redirect.invidious.io): ", + "Hide annotations": "Piaca le notazioni", + "Show annotations": "Mostra le notazioni", + "Family friendly? ": "Adàt a tüti? ", + "Whitelisted regions: ": "Regioni en lista bianca: ", + "Blacklisted regions: ": "Regioni en lista negher ", + "Artist: ": "Artista: ", + "Song: ": "Cansòn ", + "Album: ": "Album: ", + "View YouTube comments": "Varda i comment dal YouTube", + "Password cannot be empty": "La parola ciav la no po miga esser voeut", + "channel:`x`": "Canal:`x`", + "Bangla": "Bengales", + "Hausa": "Hausa", + "Hindi": "Hindi", + "Hmong": "Hmong", + "Igbo": "Igbo", + "Javanese": "Javanese", + "Kannada": "Kannada", + "Kazakh": "Kazach", + "Khmer": "Khmer", + "Kyrgyz": "Kirghiz", + "Lao": "Lao", + "Luxembourgish": "Lussemburghes", + "Macedonian": "Macedon", + "Malagasy": "Malagascio", + "Malayalam": "Malayalam", + "Maori": "Maori", + "Marathi": "Marati", + "Nepali": "Nepales", + "Nyanja": "Nyanja", + "Pashto": "Pashtu", + "Punjabi": "Punjabi", + "Samoan": "Samoan", + "Standard YouTube license": "licensa predefinida de Youtube", + "License: ": "Licensa: ", + "Music in this video": "Musica en sto video", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Ué! Sembra che ti la g'hà desabilitàa el JavaScript. Schisa chì para vardà i comment, ma cunsidera che peul vörse 'n po plu de temp a cargà.", + "preferences_video_loop_label": "Reproduci sèmper: " +} diff --git a/locales/nl.json b/locales/nl.json index a30bc5b5..d495a2d1 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -487,5 +487,14 @@ "generic_button_delete": "Verwijderen", "Import YouTube playlist (.csv)": "YouTube-afspeellijst importeren (.csv)", "Standard YouTube license": "Standaard YouTube-licentie", - "Import YouTube watch history (.json)": "YouTube-kijkgeschiedenis importeren (.json)" + "Import YouTube watch history (.json)": "YouTube-kijkgeschiedenis importeren (.json)", + "Add to playlist": "Aan afspeellijst toevoegen", + "The Popular feed has been disabled by the administrator.": "De Populaire feed werd uitgeschakeld door een beheerder.", + "carousel_slide": "Dia {{current}} van {{total}}", + "carousel_go_to": "Naar dia `x` gaan", + "Add to playlist: ": "Aan afspeellijst toevoegen: ", + "Answer": "Antwoorden", + "Search for videos": "Naar video's zoeken", + "carousel_skip": "Carousel overslaan", + "toggle_theme": "Thema omschakelen" } diff --git a/locales/pl.json b/locales/pl.json index 0d18e90a..f24e9766 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -21,13 +21,13 @@ "Import and Export Data": "Import i eksport danych", "Import": "Import", "Import Invidious data": "Importuj dane JSON Invidious", - "Import YouTube subscriptions": "Importuj subskrybcje z YouTube/OPML", - "Import FreeTube subscriptions (.db)": "Importuj subskrybcje z FreeTube (.db)", - "Import NewPipe subscriptions (.json)": "Importuj subskrybcje z NewPipe (.json)", + "Import YouTube subscriptions": "Importuj subskrypcje YouTube w formacie CSV lub OPML", + "Import FreeTube subscriptions (.db)": "Importuj subskrypcje FreeTube (.db)", + "Import NewPipe subscriptions (.json)": "Importuj subskrypcje NewPipe (.json)", "Import NewPipe data (.zip)": "Importuj dane NewPipe (.zip)", "Export": "Eksport", - "Export subscriptions as OPML": "Eksportuj subskrybcje jako OPML", - "Export subscriptions as OPML (for NewPipe & FreeTube)": "Eksportuj subskrybcje jako OPML (dla NewPipe i FreeTube)", + "Export subscriptions as OPML": "Eksportuj subskrypcje jako OPML", + "Export subscriptions as OPML (for NewPipe & FreeTube)": "Eksportuj subskrypcje jako OPML (dla NewPipe i FreeTube)", "Export data as JSON": "Eksportuj dane Invidious jako JSON", "Delete account?": "Usunąć konto?", "History": "Historia", @@ -73,7 +73,7 @@ "preferences_thin_mode_label": "Tryb minimalny: ", "preferences_category_misc": "Różne preferencje", "preferences_automatic_instance_redirect_label": "Automatycznie przekierowanie instancji (powrót do redirect.invidious.io): ", - "preferences_category_subscription": "Preferencje subskrybcji", + "preferences_category_subscription": "Preferencje subskrypcji", "preferences_annotations_subscribed_label": "Domyślnie wyświetlaj adnotacje dla subskrybowanych kanałów: ", "Redirect homepage to feed: ": "Przekieruj stronę główną do subskrybcji: ", "preferences_max_results_label": "Liczba filmów widoczna na stronie subskrybcji: ", @@ -95,7 +95,7 @@ "Clear watch history": "Wyczyść historię", "Import/export data": "Import/Eksport danych", "Change password": "Zmień hasło", - "Manage subscriptions": "Organizuj subskrybcje", + "Manage subscriptions": "Organizuj subskrypcje", "Manage tokens": "Zarządzaj tokenami", "Watch history": "Historia", "Delete account": "Usuń konto", @@ -115,7 +115,7 @@ "Import/export": "Import/Eksport", "unsubscribe": "odsubskrybuj", "revoke": "cofnij", - "Subscriptions": "Subskrybcje", + "Subscriptions": "Subskrypcje", "search": "szukaj", "Log out": "Wyloguj", "Source available here.": "Kod źródłowy dostępny tutaj.", @@ -505,5 +505,13 @@ "generic_channels_count_1": "{{count}} kanały", "generic_channels_count_2": "{{count}} kanałów", "Import YouTube watch history (.json)": "Importuj historię oglądania z YouTube (.json)", - "toggle_theme": "Przełącz motyw" + "toggle_theme": "Przełącz motyw", + "The Popular feed has been disabled by the administrator.": "Kanał Popularne został wyłączony przez administratora.", + "Answer": "Odpowiedź", + "Search for videos": "Wyszukaj filmy", + "Add to playlist": "Dodaj do playlisty", + "Add to playlist: ": "Dodaj do playlisty: ", + "carousel_slide": "Slajd {{current}} z {{total}}", + "carousel_skip": "Pomiń karuzelę", + "carousel_go_to": "Przejdź do slajdu `x`" } diff --git a/locales/pt-BR.json b/locales/pt-BR.json index af14eb29..1637b5d8 100644 --- a/locales/pt-BR.json +++ b/locales/pt-BR.json @@ -1,27 +1,27 @@ { "LIVE": "AO VIVO", - "Shared `x` ago": "Compartilhado `x` atrás", + "Shared `x` ago": "Publicado há `x`", "Unsubscribe": "Cancelar inscrição", "Subscribe": "Inscrever-se", "View channel on YouTube": "Ver canal no YouTube", - "View playlist on YouTube": "Ver lista de reprodução no YouTube", + "View playlist on YouTube": "Ver playlist no YouTube", "newest": "mais recentes", "oldest": "mais antigos", "popular": "populares", - "last": "último", + "last": "últimos", "Next page": "Próxima página", "Previous page": "Página anterior", - "Clear watch history?": "Limpar histórico de reprodução?", + "Clear watch history?": "Limpar histórico de exibição?", "New password": "Nova senha", - "New passwords must match": "Nova senha deve ser igual", - "Authorize token?": "Autorizar o token?", - "Authorize token for `x`?": "Autorizar o token para `x`?", + "New passwords must match": "As senhas devem ser iguais", + "Authorize token?": "Autorizar token?", + "Authorize token for `x`?": "Autorizar token para `x`?", "Yes": "Sim", "No": "Não", - "Import and Export Data": "Importar e Exportar Dados", + "Import and Export Data": "Importar/exportar dados", "Import": "Importar", - "Import Invidious data": "Importar dados em JSON do Invidious", - "Import YouTube subscriptions": "Importar inscrições do YouTube/OPML", + "Import Invidious data": "Importar dados JSON do Invidious", + "Import YouTube subscriptions": "Importar inscrições no formato CSV ou OPML do YouTube", "Import FreeTube subscriptions (.db)": "Importar inscrições do FreeTube (.db)", "Import NewPipe subscriptions (.json)": "Importar inscrições do NewPipe (.json)", "Import NewPipe data (.zip)": "Importar dados do NewPipe (.zip)", @@ -32,49 +32,49 @@ "Delete account?": "Excluir conta?", "History": "Histórico", "An alternative front-end to YouTube": "Uma interface alternativa para o YouTube", - "JavaScript license information": "Informação de licença do JavaScript", - "source": "código-fonte", - "Log in": "Entrar", - "Log in/register": "Entrar/Registrar", + "JavaScript license information": "Informações sobre a licença do JavaScript", + "source": "fonte", + "Log in": "Fazer login", + "Log in/register": "Fazer login/criar conta", "User ID": "Usuário", "Password": "Senha", "Time (h:mm:ss):": "Hora (h:mm:ss):", - "Text CAPTCHA": "CAPTCHA em texto", - "Image CAPTCHA": "CAPTCHA em imagem", + "Text CAPTCHA": "Mudar para um desafio de texto", + "Image CAPTCHA": "Mudar para um desafio visual", "Sign In": "Entrar", - "Register": "Registrar", + "Register": "Criar conta", "E-mail": "E-mail", "Preferences": "Preferências", - "preferences_category_player": "Preferências do reprodutor", + "preferences_category_player": "Preferências de reprodução", "preferences_video_loop_label": "Repetir sempre: ", "preferences_autoplay_label": "Reprodução automática: ", - "preferences_continue_label": "Sempre reproduzir próximo: ", + "preferences_continue_label": "Reproduzir a seguir, por padrão: ", "preferences_continue_autoplay_label": "Reproduzir próximo vídeo automaticamente: ", "preferences_listen_label": "Apenas áudio por padrão: ", "preferences_local_label": "Usar proxy nos vídeos: ", "preferences_speed_label": "Velocidade padrão: ", "preferences_quality_label": "Qualidade de vídeo preferida: ", "preferences_volume_label": "Volume de reprodução: ", - "preferences_comments_label": "Preferência de comentários: ", + "preferences_comments_label": "Comentários padrão: ", "youtube": "YouTube", "reddit": "Reddit", - "preferences_captions_label": "Preferência de legendas: ", + "preferences_captions_label": "Legendas padrão: ", "Fallback captions: ": "Legendas alternativas: ", "preferences_related_videos_label": "Mostrar vídeos relacionados: ", "preferences_annotations_label": "Sempre mostrar anotações: ", - "preferences_extend_desc_label": "Estenda automaticamente a descrição do vídeo: ", + "preferences_extend_desc_label": "Expandir automaticamente a descrição do vídeo: ", "preferences_vr_mode_label": "Vídeos interativos de 360 graus (requer WebGL): ", "preferences_category_visual": "Preferências visuais", - "preferences_player_style_label": "Estilo do tocador: ", + "preferences_player_style_label": "Estilo de reprodução: ", "Dark mode: ": "Modo escuro: ", "preferences_dark_mode_label": "Tema: ", "dark": "escuro", "light": "claro", "preferences_thin_mode_label": "Modo compacto: ", "preferences_category_misc": "Preferências diversas", - "preferences_automatic_instance_redirect_label": "Redirecionamento de instância automática (fallback para redirect.invidious.io): ", + "preferences_automatic_instance_redirect_label": "Redirecionamento automático de instâncias (alternativa para redirect.invidious.io): ", "preferences_category_subscription": "Preferências de inscrições", - "preferences_annotations_subscribed_label": "Sempre mostrar anotações dos vídeos de canais inscritos: ", + "preferences_annotations_subscribed_label": "Mostrar anotações por padrão para canais inscritos? ", "Redirect homepage to feed: ": "Redirecionar página inicial para o feed: ", "preferences_max_results_label": "Número de vídeos no feed: ", "preferences_sort_label": "Ordenar vídeos por: ", @@ -84,30 +84,30 @@ "alphabetically - reverse": "alfabética - ordem inversa", "channel name": "nome do canal", "channel name - reverse": "nome do canal - ordem inversa", - "Only show latest video from channel: ": "Mostrar apenas o vídeo mais recente do canal: ", - "Only show latest unwatched video from channel: ": "Mostrar apenas o vídeo mais recente não visualizado do canal: ", - "preferences_unseen_only_label": "Mostrar apenas vídeos não visualizados: ", - "preferences_notifications_only_label": "Mostrar apenas notificações (se existentes): ", - "Enable web notifications": "Ativar notificações pela web", - "`x` uploaded a video": "`x` publicou um novo vídeo", + "Only show latest video from channel: ": "Mostrar apenas vídeos mais recentes do canal: ", + "Only show latest unwatched video from channel: ": "Mostrar apenas vídeos mais recentes não assistido do canal: ", + "preferences_unseen_only_label": "Mostrar apenas vídeos não assistido: ", + "preferences_notifications_only_label": "Mostrar apenas notificações (se houver): ", + "Enable web notifications": "Ativar notificações da Web", + "`x` uploaded a video": "`x` publicou um vídeo", "`x` is live": "`x` está ao vivo", "preferences_category_data": "Preferências de dados", - "Clear watch history": "Limpar histórico de reprodução", - "Import/export data": "Importar/Exportar dados", + "Clear watch history": "Limpar histórico de exibição", + "Import/export data": "Importar/exportar dados", "Change password": "Alterar senha", "Manage subscriptions": "Gerenciar inscrições", "Manage tokens": "Gerenciar tokens", - "Watch history": "Histórico de reprodução", - "Delete account": "Apagar sua conta", + "Watch history": "Histórico de exibição", + "Delete account": "Excluir conta", "preferences_category_admin": "Preferências de administrador", - "preferences_default_home_label": "Página de início padrão: ", - "preferences_feed_menu_label": "Menu do feed: ", - "preferences_show_nick_label": "Mostrar o nickname no topo: ", - "Top enabled: ": "Habilitar destaques: ", - "CAPTCHA enabled: ": "Habilitar CAPTCHA: ", - "Login enabled: ": "Habilitar login: ", - "Registration enabled: ": "Habilitar registro: ", - "Report statistics: ": "Habilitar estatísticas: ", + "preferences_default_home_label": "Página inicial padrão: ", + "preferences_feed_menu_label": "Guias de feed preferidos: ", + "preferences_show_nick_label": "Mostrar nome de usuário na parte superior: ", + "Top enabled: ": "Destaques ativados: ", + "CAPTCHA enabled: ": "CAPTCHA ativado: ", + "Login enabled: ": "Fazer login ativado: ", + "Registration enabled: ": "Criar conta ativado: ", + "Report statistics: ": "Relatório de estatísticas: ", "Save preferences": "Salvar preferências", "Subscription manager": "Gerenciador de inscrições", "Token manager": "Gerenciador de tokens", @@ -115,24 +115,24 @@ "tokens_count_0": "{{count}} token", "tokens_count_1": "{{count}} tokens", "tokens_count_2": "{{count}} tokens", - "Import/export": "Importar/Exportar", + "Import/export": "Importar/exportar", "unsubscribe": "cancelar inscrição", "revoke": "revogar", "Subscriptions": "Inscrições", - "search": "Pesquisar", + "search": "pesquisar", "Log out": "Sair", "Released under the AGPLv3 on Github.": "Lançado sob a AGPLv3 no GitHub.", "Source available here.": "Código-fonte disponível aqui.", - "View JavaScript license information.": "Ver informações da licença do JavaScript.", - "View privacy policy.": "Ver a política de privacidade.", - "Trending": "Tendências", + "View JavaScript license information.": "Informações de licença JavaScript.", + "View privacy policy.": "Política de privacidade.", + "Trending": "Em alta", "Public": "Público", "Unlisted": "Não listado", "Private": "Privado", - "View all playlists": "Mostrar todas listas de reprodução", + "View all playlists": "Ver todas as playlists", "Updated `x` ago": "Atualizado `x` atrás", - "Delete playlist `x`?": "Apagar a playlist `x`?", - "Delete playlist": "Apagar playlist", + "Delete playlist `x`?": "Excluir playlist `x`?", + "Delete playlist": "Excluir playlist", "Create playlist": "Criar playlist", "Title": "Título", "Playlist privacy": "Privacidade da playlist", @@ -140,24 +140,24 @@ "Show more": "Mostrar mais", "Show less": "Mostrar menos", "Watch on YouTube": "Assistir no YouTube", - "Switch Invidious Instance": "Mudar a instância do Invidious", + "Switch Invidious Instance": "Alterar instância Invidious", "Hide annotations": "Ocultar anotações", "Show annotations": "Mostrar anotações", "Genre: ": "Gênero: ", "License: ": "Licença: ", "Family friendly? ": "Filtrar conteúdo impróprio: ", "Wilson score: ": "Pontuação de Wilson: ", - "Engagement: ": "Empenho: ", + "Engagement: ": "Engajamento: ", "Whitelisted regions: ": "Regiões permitidas: ", "Blacklisted regions: ": "Regiões bloqueadas: ", - "Shared `x`": "Compartilhado `x`", + "Shared `x`": "Publicado em `x`", "Premieres in `x`": "Estreia em `x`", "Premieres `x`": "Estreia `x`", - "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Oi! Parece que seu JavaScript está desativado. Clique aqui para ver os comentários, entretanto eles podem levar um pouco mais de tempo para carregar.", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Olá! Parece que você está com o JavaScript desativado. Clique aqui para ver os comentários, mas lembre-se de que eles podem demorar um pouco mais para carregar.", "View YouTube comments": "Ver comentários no YouTube", "View more comments on Reddit": "Ver mais comentários no Reddit", "View `x` comments": { - "([^.,0-9]|^)1([^.,0-9]|$)": "Ver `x` comentários", + "([^.,0-9]|^)1([^.,0-9]|$)": "Ver `x` comentário", "": "Ver `x` comentários" }, "View Reddit comments": "Ver comentários no Reddit", @@ -166,7 +166,7 @@ "Incorrect password": "Senha incorreta", "Wrong answer": "Resposta incorreta", "Erroneous CAPTCHA": "CAPTCHA inválido", - "CAPTCHA is a required field": "O CAPTCHA é um campo obrigatório", + "CAPTCHA is a required field": "CAPTCHA é um campo obrigatório", "User ID is a required field": "O nome de usuário é um campo obrigatório", "Password is a required field": "A senha é um campo obrigatório", "Wrong username or password": "Nome de usuário ou senha inválidos", @@ -175,17 +175,17 @@ "Please log in": "Por favor, inicie sua sessão", "Invidious Private Feed for `x`": "Feed Privado do Invidious para `x`", "channel:`x`": "canal: `x`", - "Deleted or invalid channel": "Este canal foi apagado ou é inválido", + "Deleted or invalid channel": "Canal excluído ou inválido", "This channel does not exist.": "Este canal não existe.", "Could not get channel info.": "Não foi possível obter as informações do canal.", "Could not fetch comments": "Não foi possível obter os comentários", "`x` ago": "`x` atrás", "Load more": "Carregar mais", "Could not create mix.": "Não foi possível criar o mix.", - "Empty playlist": "Lista de reprodução vazia", - "Not a playlist.": "Não é uma lista de reprodução.", - "Playlist does not exist.": "A lista de reprodução não existe.", - "Could not pull trending pages.": "Não foi possível obter as páginas dos vídeos em alta.", + "Empty playlist": "Playlist vazia", + "Not a playlist.": "Não é uma playlist.", + "Playlist does not exist.": "A playlist não existe.", + "Could not pull trending pages.": "Não foi possível obter as páginas de vídeos em alta.", "Hidden field \"challenge\" is a required field": "O campo oculto \"desafio\" é obrigatório", "Hidden field \"token\" is a required field": "O campo oculto \"token\" é obrigatório", "Erroneous challenge": "Desafio inválido", @@ -319,87 +319,87 @@ "generic_count_seconds_0": "{{count}} segundo", "generic_count_seconds_1": "{{count}} segundos", "generic_count_seconds_2": "{{count}} segundos", - "Fallback comments: ": "Comentários alternativos: ", + "Fallback comments: ": "Alternativa para comentários: ", "Popular": "Populares", - "Search": "Procurar", - "Top": "No topo", + "Search": "Pesquisar", + "Top": "Destaques", "About": "Sobre", "Rating: ": "Avaliação: ", "preferences_locale_label": "Idioma: ", - "View as playlist": "Ver como lista de reprodução", + "View as playlist": "Ver como playlist", "Default": "Padrão", "Music": "Músicas", "Gaming": "Jogos", "News": "Notícias", "Movies": "Filmes", - "Download": "Baixar", + "Download": "Download", "Download as: ": "Baixar como: ", "%A %B %-d, %Y": "%A %-d %B %Y", "(edited)": "(editado)", "YouTube comment permalink": "Link permanente do comentário no YouTube", "permalink": "Link permanente", - "`x` marked it with a ❤": "`x` foi marcado como ❤", + "`x` marked it with a ❤": "`x` foi marcado com um ❤", "Audio mode": "Modo de áudio", "Video mode": "Modo de vídeo", "channel_tab_videos_label": "Vídeos", - "Playlists": "Listas de reprodução", + "Playlists": "Playlists", "channel_tab_community_label": "Comunidade", - "search_filters_sort_option_relevance": "relevância", - "search_filters_sort_option_rating": "avaliação", - "search_filters_sort_option_date": "data", - "search_filters_sort_option_views": "visualizações", - "search_filters_type_label": "content_type", - "search_filters_duration_label": "duração", - "search_filters_features_label": "recursos", - "search_filters_sort_label": "ordenar", - "search_filters_date_option_hour": "hora", - "search_filters_date_option_today": "hoje", - "search_filters_date_option_week": "semana", - "search_filters_date_option_month": "mês", - "search_filters_date_option_year": "ano", - "search_filters_type_option_video": "vídeo", + "search_filters_sort_option_relevance": "Relevância", + "search_filters_sort_option_rating": "Avaliação", + "search_filters_sort_option_date": "Data de publicação", + "search_filters_sort_option_views": "Visualizações", + "search_filters_type_label": "Tipo", + "search_filters_duration_label": "Duração", + "search_filters_features_label": "Características", + "search_filters_sort_label": "Ordenar por", + "search_filters_date_option_hour": "Últimas horas", + "search_filters_date_option_today": "Hoje", + "search_filters_date_option_week": "Esta semana", + "search_filters_date_option_month": "Este mês", + "search_filters_date_option_year": "Este ano", + "search_filters_type_option_video": "Vídeo", "search_filters_type_option_channel": "Canal", - "search_filters_type_option_playlist": "playlist", - "search_filters_type_option_movie": "filme", - "search_filters_type_option_show": "show", - "search_filters_features_option_hd": "hd", - "search_filters_features_option_subtitles": "legendas", - "search_filters_features_option_c_commons": "creative_commons", - "search_filters_features_option_three_d": "3d", - "search_filters_features_option_live": "ao vivo", - "search_filters_features_option_four_k": "4k", - "search_filters_features_option_location": "localização", - "search_filters_features_option_hdr": "hdr", + "search_filters_type_option_playlist": "Playlist", + "search_filters_type_option_movie": "Filme", + "search_filters_type_option_show": "Séries", + "search_filters_features_option_hd": "HD", + "search_filters_features_option_subtitles": "Legendas", + "search_filters_features_option_c_commons": "Creative Commons", + "search_filters_features_option_three_d": "3D", + "search_filters_features_option_live": "AO VIVO", + "search_filters_features_option_four_k": "4K", + "search_filters_features_option_location": "Localização", + "search_filters_features_option_hdr": "HDR", "Current version: ": "Versão atual: ", "next_steps_error_message": "Depois disso, você deve tentar: ", - "next_steps_error_message_refresh": "Atualizar", + "next_steps_error_message_refresh": "Recarregar", "next_steps_error_message_go_to_youtube": "Ir para o YouTube", - "footer_donate_page": "Doe", - "adminprefs_modified_source_code_url_label": "URL para repositório de código fonte modificado", + "footer_donate_page": "Doar", + "adminprefs_modified_source_code_url_label": "URL para o repositório do código-fonte modificado", "search_filters_duration_option_long": "Longo (> 20 minutos)", "search_filters_duration_option_short": "Curto (< 4 minutos)", "footer_documentation": "Documentação", - "footer_source_code": "Código fonte", - "footer_original_source_code": "Código fonte original", + "footer_source_code": "Código-fonte", + "footer_original_source_code": "Código-fonte original", "footer_modfied_source_code": "Código-fonte modificado", - "preferences_quality_dash_label": "Qualidade de vídeo do painel preferida: ", + "preferences_quality_dash_label": "Qualidade de vídeo DASH preferida: ", "preferences_region_label": "País do conteúdo: ", "preferences_quality_dash_option_4320p": "4320p", "generic_videos_count_0": "{{count}} vídeo", "generic_videos_count_1": "{{count}} vídeos", "generic_videos_count_2": "{{count}} vídeos", - "generic_playlists_count_0": "{{count}} lista de reprodução", - "generic_playlists_count_1": "{{count}} listas de reprodução", - "generic_playlists_count_2": "{{count}} listas de reprodução", + "generic_playlists_count_0": "{{count}} playlist", + "generic_playlists_count_1": "{{count}} playlists", + "generic_playlists_count_2": "{{count}} playlists", "generic_subscribers_count_0": "{{count}} inscrito", "generic_subscribers_count_1": "{{count}} inscritos", "generic_subscribers_count_2": "{{count}} inscritos", "generic_subscriptions_count_0": "{{count}} inscrição", "generic_subscriptions_count_1": "{{count}} inscrições", "generic_subscriptions_count_2": "{{count}} inscrições", - "subscriptions_unseen_notifs_count_0": "{{count}} notificação não vista", - "subscriptions_unseen_notifs_count_1": "{{count}} notificações não vistas", - "subscriptions_unseen_notifs_count_2": "{{count}} notificações não vistas", + "subscriptions_unseen_notifs_count_0": "{{count}} notificação não visualizada", + "subscriptions_unseen_notifs_count_1": "{{count}} notificações não visualizadas", + "subscriptions_unseen_notifs_count_2": "{{count}} notificações não visualizadas", "comments_view_x_replies_0": "Ver {{count}} resposta", "comments_view_x_replies_1": "Ver {{count}} respostas", "comments_view_x_replies_2": "Ver {{count}} respostas", @@ -407,14 +407,14 @@ "comments_points_count_1": "{{count}} pontos", "comments_points_count_2": "{{count}} pontos", "crash_page_you_found_a_bug": "Parece que você encontrou um erro no Invidious!", - "crash_page_before_reporting": "Antes de reportar um erro, verifique se você:", - "preferences_save_player_pos_label": "Salvar a posição de reprodução: ", + "crash_page_before_reporting": "Antes de informar um erro, verifique se você:", + "preferences_save_player_pos_label": "Salvar posição de reprodução: ", "search_filters_features_option_purchased": "Comprado", "crash_page_refresh": "tentou <a href=\"`x`\">recarregar a página</a>", "crash_page_switch_instance": "tentou <a href=\"`x`\">usar outra instância</a>", "crash_page_search_issue": "procurou por um <a href=\"`x`\">erro existente no GitHub</a>", "crash_page_report_issue": "Se nenhuma opção acima ajudou, por favor <a href=\"`x`\">abra um novo problema no Github</a> (preferencialmente em inglês) e inclua o seguinte texto (NÃO traduza):", - "crash_page_read_the_faq": "leia as <a href=\"`x`\">Perguntas frequentes (FAQ)</a>", + "crash_page_read_the_faq": "leu as <a href=\"`x`\">Perguntas frequentes (FAQ)</a>", "generic_views_count_0": "{{count}} visualização", "generic_views_count_1": "{{count}} visualizações", "generic_views_count_2": "{{count}} visualizações", @@ -422,8 +422,8 @@ "preferences_quality_option_hd720": "HD720", "preferences_quality_option_small": "Pequeno", "preferences_quality_dash_option_auto": "Auto", - "preferences_quality_dash_option_best": "Melhor", - "preferences_quality_dash_option_worst": "Pior", + "preferences_quality_dash_option_best": "Melhor qualidade", + "preferences_quality_dash_option_worst": "Pior qualidade", "preferences_quality_dash_option_2160p": "2160p", "preferences_quality_dash_option_1440p": "1440p", "preferences_quality_dash_option_1080p": "1080p", @@ -435,17 +435,17 @@ "invidious": "Invidious", "preferences_quality_option_medium": "Médio", "search_filters_features_option_three_sixty": "360°", - "none": "none", + "none": "nenhum", "videoinfo_watch_on_youTube": "Assistir no YouTube", - "videoinfo_youTube_embed_link": "Embutir", - "videoinfo_invidious_embed_link": "Link Embutido", + "videoinfo_youTube_embed_link": "Embed", + "videoinfo_invidious_embed_link": "Embed link", "download_subtitles": "Legendas - `x` (.vtt)", - "user_created_playlists": "`x` listas de reprodução criadas", - "user_saved_playlists": "`x` listas de reprodução salvas", + "user_created_playlists": "`x` playlists criadas", + "user_saved_playlists": "`x` playlists salvas", "Video unavailable": "Vídeo indisponível", "videoinfo_started_streaming_x_ago": "Iniciou a transmissão a `x`", "search_filters_title": "Filtro", - "preferences_watch_history_label": "Ative o histórico de exibição: ", + "preferences_watch_history_label": "Ativar histórico de exibição: ", "search_message_no_results": "Nenhum resultado encontrado.", "search_message_change_filters_or_query": "Tente ampliar sua consulta de pesquisa e/ou alterar os filtros.", "English (United Kingdom)": "Inglês (Reino Unido)", @@ -465,7 +465,7 @@ "Portuguese (Brazil)": "Português (Brasil)", "Russian (auto-generated)": "Russo (gerado automaticamente)", "Vietnamese (auto-generated)": "Vietnamita (gerado automaticamente)", - "search_filters_date_label": "Data de upload", + "search_filters_date_label": "Data de publicação", "search_filters_date_option_none": "Qualquer data", "Dutch (auto-generated)": "Holandês (gerado automaticamente)", "French (auto-generated)": "Francês (gerado automaticamente)", @@ -479,21 +479,21 @@ "Turkish (auto-generated)": "Turco (gerado automaticamente)", "search_filters_duration_option_medium": "Médio (4 - 20 minutos)", "search_filters_features_option_vr180": "VR180", - "Popular enabled: ": "Popular habilitado: ", + "Popular enabled: ": "Página \"Populares\" ativada: ", "error_video_not_in_playlist": "O vídeo solicitado não existe nesta playlist. <a href=\"`x`\">Clique aqui para acessar a página inicial da playlist.</a>", "channel_tab_channels_label": "Canais", - "channel_tab_playlists_label": "Listas de reprodução", - "channel_tab_shorts_label": "Curtos", - "channel_tab_streams_label": "Ao Vivo", + "channel_tab_playlists_label": "Playlists", + "channel_tab_shorts_label": "Shorts", + "channel_tab_streams_label": "Transmissão ao vivo", "Music in this video": "Música neste vídeo", "Artist: ": "Artista: ", "Album: ": "Álbum: ", "Standard YouTube license": "Licença padrão do YouTube", "Song: ": "Música: ", - "Channel Sponsor": "Patrocinador do Canal", - "Download is disabled": "Download está desabilitado", - "Import YouTube playlist (.csv)": "Importar lista de reprodução do YouTube (.csv)", - "generic_button_delete": "Apagar", + "Channel Sponsor": "Patrocinador do canal", + "Download is disabled": "Download indisponível", + "Import YouTube playlist (.csv)": "Importar playlist do YouTube (.csv)", + "generic_button_delete": "Excluir", "generic_button_save": "Salvar", "generic_button_edit": "Editar", "playlist_button_add_items": "Adicionar vídeos", @@ -504,6 +504,14 @@ "generic_channels_count_0": "{{count}} canal", "generic_channels_count_1": "{{count}} canais", "generic_channels_count_2": "{{count}} canais", - "Import YouTube watch history (.json)": "Importar histórico de reprodução do YouTube (.json)", - "toggle_theme": "Alternar Tema" + "Import YouTube watch history (.json)": "Importar histórico de exibição do YouTube (.json)", + "toggle_theme": "Alternar tema", + "Add to playlist": "Adicionar à playlist", + "Add to playlist: ": "Adicionar à playlist: ", + "Search for videos": "Pesquisar vídeos", + "The Popular feed has been disabled by the administrator.": "O feed \"Populares\" foi desativado pelo administrador.", + "Answer": "Resposta", + "carousel_slide": "Slide {{current}} de {{total}}", + "carousel_skip": "Ignorar carrossel", + "carousel_go_to": "Ir ao slide `x`" } diff --git a/locales/pt-PT.json b/locales/pt-PT.json index 3834c9e2..f83a80a9 100644 --- a/locales/pt-PT.json +++ b/locales/pt-PT.json @@ -130,12 +130,12 @@ "Private": "Privado", "View all playlists": "Ver todas as listas de reprodução", "Updated `x` ago": "Atualizado `x` atrás", - "Delete playlist `x`?": "Eliminar a lista de reprodução 'x'?", + "Delete playlist `x`?": "Eliminar a lista de reprodução `x`?", "Delete playlist": "Eliminar lista de reprodução", "Create playlist": "Criar lista de reprodução", "Title": "Título", "Playlist privacy": "Privacidade da lista de reprodução", - "Editing playlist `x`": "A editar lista de reprodução 'x'", + "Editing playlist `x`": "A editar lista de reprodução `x`", "Show more": "Mostrar mais", "Show less": "Mostrar menos", "Watch on YouTube": "Ver no YouTube", @@ -150,8 +150,8 @@ "Whitelisted regions: ": "Regiões permitidas: ", "Blacklisted regions: ": "Regiões bloqueadas: ", "Shared `x`": "Partilhado `x`", - "Premieres in `x`": "Estreias em 'x'", - "Premieres `x`": "Estreias 'x'", + "Premieres in `x`": "Estreias em `x`", + "Premieres `x`": "Estreias `x`", "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Olá! Parece que o JavaScript está desativado. Clique aqui para ver os comentários, entretanto eles podem levar mais tempo para carregar.", "View YouTube comments": "Ver comentários do YouTube", "View more comments on Reddit": "Ver mais comentários no Reddit", @@ -173,7 +173,7 @@ "Password cannot be longer than 55 characters": "A palavra-chave não pode ser superior a 55 caracteres", "Please log in": "Por favor, inicie sessão", "Invidious Private Feed for `x`": "Feed Privado do Invidious para `x`", - "channel:`x`": "canal:'x'", + "channel:`x`": "canal:`x`", "Deleted or invalid channel": "Canal eliminado ou inválido", "This channel does not exist.": "Este canal não existe.", "Could not get channel info.": "Não foi possível obter as informações do canal.", diff --git a/locales/pt.json b/locales/pt.json index c1d8b5b4..463dbf3a 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -1,25 +1,25 @@ { - "search_filters_type_option_show": "Série", + "search_filters_type_option_show": "Séries", "search_filters_sort_option_views": "Visualizações", "search_filters_sort_option_date": "Data de carregamento", "search_filters_sort_option_rating": "Avaliação", "search_filters_sort_option_relevance": "Relevância", - "Switch Invidious Instance": "Mudar a instância do Invidious", + "Switch Invidious Instance": "Alterar instância Invidious", "Show less": "Mostrar menos", "Show more": "Mostrar mais", - "Released under the AGPLv3 on Github.": "Lançado sob a AGPLv3 no GitHub.", + "Released under the AGPLv3 on Github.": "Disponibilizada sob a AGPLv3 no GitHub.", "preferences_show_nick_label": "Mostrar nome de utilizador em cima: ", "preferences_automatic_instance_redirect_label": "Redirecionamento de instância automática (solução de último recurso para redirect.invidious.io): ", "preferences_category_misc": "Preferências diversas", - "preferences_vr_mode_label": "Vídeos interativos de 360 graus (necessita de WebGL): ", - "preferences_extend_desc_label": "Estender automaticamente a descrição do vídeo: ", + "preferences_vr_mode_label": "Vídeos interativos de 360 graus (requer WebGL): ", + "preferences_extend_desc_label": "Expandir automaticamente a descrição do vídeo: ", "next_steps_error_message_go_to_youtube": "Ir para o YouTube", "next_steps_error_message": "Pode tentar as seguintes opções: ", - "next_steps_error_message_refresh": "Atualizar", + "next_steps_error_message_refresh": "Recarregar", "search_filters_features_option_hdr": "HDR", "search_filters_features_option_location": "Localização", "search_filters_features_option_four_k": "4K", - "search_filters_features_option_live": "Ao Vivo", + "search_filters_features_option_live": "Direto", "search_filters_features_option_three_d": "3D", "search_filters_features_option_c_commons": "Creative Commons", "search_filters_features_option_subtitles": "Legendas", @@ -37,11 +37,11 @@ "search_filters_features_label": "Funcionalidades", "search_filters_duration_label": "Duração", "search_filters_type_label": "Tipo", - "permalink": "hiperligação permanente", - "YouTube comment permalink": "Hiperligação permanente do comentário no YouTube", + "permalink": "ligação permanente", + "YouTube comment permalink": "Ligação permanente do comentário no YouTube", "Download as: ": "Descarregar como: ", "Download": "Descarregar", - "Default": "Predefinido", + "Default": "Padrão", "Top": "Destaques", "Search": "Pesquisar", "generic_count_years_0": "{{count}} ano", @@ -67,21 +67,21 @@ "generic_count_seconds_2": "{{count}} segundos", "Chinese (Traditional)": "Chinês (tradicional)", "Chinese (Simplified)": "Chinês (simplificado)", - "Could not pull trending pages.": "Não foi possível obter as páginas de tendências.", - "Could not create mix.": "Não foi possível criar a mistura.", + "Could not pull trending pages.": "Não foi possível obter a página de tendências.", + "Could not create mix.": "Não foi possível criar o mix.", "Deleted or invalid channel": "Canal eliminado ou inválido", - "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Olá! Parece que o JavaScript está desativado. Clique aqui para ver os comentários, entretanto eles podem levar mais tempo para carregar.", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Olá! Parece que o JavaScript está desativado. Clique aqui para ver os comentários, mas tenha e conta que podem levar mais tempo para carregar.", "Delete playlist": "Eliminar lista de reprodução", - "Delete playlist `x`?": "Eliminar a lista de reprodução 'x'?", + "Delete playlist `x`?": "Eliminar lista de reprodução `x`?", "search": "pesquisar", "unsubscribe": "anular subscrição", - "Import/export": "Importar / exportar", + "Import/export": "Importar/exportar", "Save preferences": "Guardar preferências", "Top enabled: ": "Destaques ativados: ", "Delete account": "Eliminar conta", - "Import/export data": "Importar / exportar dados", + "Import/export data": "Importar/exportar dados", "preferences_annotations_label": "Mostrar anotações sempre: ", - "preferences_continue_label": "Reproduzir sempre o próximo: ", + "preferences_continue_label": "Reproduzir sempre o seguinte: ", "Sign In": "Entrar", "Log in/register": "Iniciar sessão/registar", "Delete account?": "Eliminar conta?", @@ -93,7 +93,7 @@ "Danish": "Dinamarquês", "Czech": "Checo", "Croatian": "Croata", - "Corsican": "Corso", + "Corsican": "Córsego", "Cebuano": "Cebuano", "Catalan": "Catalão", "Burmese": "Birmanês", @@ -107,10 +107,10 @@ "Arabic": "Árabe", "Amharic": "Amárico", "Albanian": "Albanês", - "Afrikaans": "Africano", + "Afrikaans": "Africânder", "English (auto-generated)": "Inglês (auto-gerado)", "English": "Inglês", - "Token is expired, please try again": "Token expirou, tente novamente", + "Token is expired, please try again": "Token caducado, tente novamente", "No such user": "Utilizador inválido", "Erroneous token": "Token inválido", "Erroneous challenge": "Desafio inválido", @@ -124,29 +124,29 @@ "Could not fetch comments": "Não foi possível obter os comentários", "Could not get channel info.": "Não foi possível obter as informações do canal.", "This channel does not exist.": "Este canal não existe.", - "channel:`x`": "canal:'x'", + "channel:`x`": "canal:`x`", "Invidious Private Feed for `x`": "Feed Privado do Invidious para `x`", "Please log in": "Por favor, inicie sessão", - "Password cannot be longer than 55 characters": "A palavra-chave não pode ser superior a 55 caracteres", - "Password cannot be empty": "A palavra-chave não pode estar vazia", - "Wrong username or password": "Nome de utilizador ou palavra-chave incorreto", - "Password is a required field": "Palavra-chave é um campo obrigatório", + "Password cannot be longer than 55 characters": "A palavra-passe não pode ter mais do que 55 caracteres", + "Password cannot be empty": "A palavra-passe não pode estar vazia", + "Wrong username or password": "Nome de utilizador ou palavra-passe incorreta", + "Password is a required field": "Palavra-passe é um campo obrigatório", "User ID is a required field": "O nome de utilizador é um campo obrigatório", "CAPTCHA is a required field": "CAPTCHA é um campo obrigatório", "Erroneous CAPTCHA": "CAPTCHA inválido", "Wrong answer": "Resposta errada", - "Incorrect password": "Palavra-chave incorreta", + "Incorrect password": "Palavra-passe incorreta", "Show replies": "Mostrar respostas", "Hide replies": "Ocultar respostas", "View Reddit comments": "Ver comentários do Reddit", "View `x` comments": { "": "Ver `x` comentários", - "([^.,0-9]|^)1([^.,0-9]|$)": "Ver `x` comentários" + "([^.,0-9]|^)1([^.,0-9]|$)": "Ver `x` comentário" }, "View more comments on Reddit": "Ver mais comentários no Reddit", "View YouTube comments": "Ver comentários do YouTube", - "Premieres `x`": "Estreias 'x'", - "Premieres in `x`": "Estreias em 'x'", + "Premieres `x`": "Estreia `x`", + "Premieres in `x`": "Estreia a `x`", "Shared `x`": "Partilhado `x`", "Blacklisted regions: ": "Regiões bloqueadas: ", "Whitelisted regions: ": "Regiões permitidas: ", @@ -158,44 +158,44 @@ "Show annotations": "Mostrar anotações", "Hide annotations": "Ocultar anotações", "Watch on YouTube": "Ver no YouTube", - "Editing playlist `x`": "A editar lista de reprodução 'x'", + "Editing playlist `x`": "A editar lista de reprodução `x`", "Playlist privacy": "Privacidade da lista de reprodução", "Title": "Título", "Create playlist": "Criar lista de reprodução", - "Updated `x` ago": "Atualizado `x` atrás", + "Updated `x` ago": "Atualizado há `x`", "View all playlists": "Ver todas as listas de reprodução", "Private": "Privado", "Unlisted": "Não listado", "Public": "Público", "Trending": "Tendências", - "View privacy policy.": "Ver a política de privacidade.", - "View JavaScript license information.": "Ver informações da licença do JavaScript.", + "View privacy policy.": "Ver política de privacidade.", + "View JavaScript license information.": "Ver informações da licença JavaScript.", "Source available here.": "Código-fonte disponível aqui.", "Log out": "Terminar sessão", "Subscriptions": "Subscrições", "revoke": "revogar", - "tokens_count_0": "{{count}} Token", - "tokens_count_1": "{{count}} Tokens", - "tokens_count_2": "{{count}} Tokens", + "tokens_count_0": "{{count}} token", + "tokens_count_1": "{{count}} tokens", + "tokens_count_2": "{{count}} tokens", "Token": "Token", - "Token manager": "Gerir tokens", - "Subscription manager": "Gerir subscrições", + "Token manager": "Gestor de tokens", + "Subscription manager": "Gestor de subscrições", "Report statistics: ": "Relatório de estatísticas: ", "Registration enabled: ": "Registar ativado: ", "Login enabled: ": "Iniciar sessão ativado: ", "CAPTCHA enabled: ": "CAPTCHA ativado: ", "preferences_feed_menu_label": "Menu de subscrições: ", - "preferences_default_home_label": "Página inicial predefinida: ", + "preferences_default_home_label": "Página inicial padrão: ", "preferences_category_admin": "Preferências de administrador", "Watch history": "Histórico de reprodução", "Manage tokens": "Gerir tokens", - "Manage subscriptions": "Gerir as subscrições", - "Change password": "Alterar palavra-chave", + "Manage subscriptions": "Gerir subscrições", + "Change password": "Alterar palavra-passe", "Clear watch history": "Limpar histórico de reprodução", "preferences_category_data": "Preferências de dados", "`x` is live": "`x` está em direto", - "`x` uploaded a video": "`x` publicou um novo vídeo", - "Enable web notifications": "Ativar notificações pela web", + "`x` uploaded a video": "`x` publicou um vídeo", + "Enable web notifications": "Ativar notificações web", "preferences_notifications_only_label": "Mostrar apenas notificações (se existirem): ", "preferences_unseen_only_label": "Mostrar apenas vídeos não visualizados: ", "Only show latest unwatched video from channel: ": "Mostrar apenas vídeos mais recentes não visualizados do canal: ", @@ -207,9 +207,9 @@ "published - reverse": "publicado - inverso", "published": "publicado", "preferences_sort_label": "Ordenar vídeos por: ", - "preferences_max_results_label": "Quantidade de vídeos nas subscrições: ", + "preferences_max_results_label": "Número de vídeos nas subscrições: ", "Redirect homepage to feed: ": "Redirecionar página inicial para subscrições: ", - "preferences_annotations_subscribed_label": "Mostrar sempre anotações aos canais subscritos: ", + "preferences_annotations_subscribed_label": "Mostrar sempre anotações nos canais subscritos: ", "preferences_category_subscription": "Preferências de subscrições", "preferences_thin_mode_label": "Modo compacto: ", "light": "claro", @@ -220,11 +220,11 @@ "preferences_category_visual": "Preferências visuais", "preferences_related_videos_label": "Mostrar vídeos relacionados: ", "Fallback captions: ": "Legendas alternativas: ", - "preferences_captions_label": "Legendas predefinidas: ", + "preferences_captions_label": "Legendas padrão: ", "reddit": "Reddit", "youtube": "YouTube", - "preferences_comments_label": "Preferência dos comentários: ", - "preferences_volume_label": "Volume da reprodução: ", + "preferences_comments_label": "Comentários padrão: ", + "preferences_volume_label": "Volume de reprodução: ", "preferences_quality_label": "Qualidade de vídeo preferida: ", "preferences_speed_label": "Velocidade preferida: ", "preferences_local_label": "Usar proxy nos vídeos: ", @@ -239,11 +239,11 @@ "Image CAPTCHA": "Imagem CAPTCHA", "Text CAPTCHA": "Texto CAPTCHA", "Time (h:mm:ss):": "Tempo (h:mm:ss):", - "Password": "Palavra-chave", + "Password": "Palavra-passe", "User ID": "Utilizador", "Log in": "Iniciar sessão", - "source": "código-fonte", - "JavaScript license information": "Informação de licença do JavaScript", + "source": "fonte", + "JavaScript license information": "Informação da licença JavaScript", "An alternative front-end to YouTube": "Uma interface alternativa ao YouTube", "History": "Histórico", "Export data as JSON": "Exportar dados Invidious como JSON", @@ -253,18 +253,18 @@ "Import NewPipe data (.zip)": "Importar dados do NewPipe (.zip)", "Import NewPipe subscriptions (.json)": "Importar subscrições do NewPipe (.json)", "Import FreeTube subscriptions (.db)": "Importar subscrições do FreeTube (.db)", - "Import YouTube subscriptions": "Importar subscrições do YouTube/OPML", + "Import YouTube subscriptions": "Importar subscrições via YouTube/OPML", "Import Invidious data": "Importar dados JSON do Invidious", "Import": "Importar", "No": "Não", "Yes": "Sim", - "Authorize token for `x`?": "Autorizar token para `x`?", - "Authorize token?": "Autorizar token?", - "New passwords must match": "As novas palavra-chaves devem corresponder", - "New password": "Nova palavra-chave", + "Authorize token for `x`?": "Autorizar 'token' para `x`?", + "Authorize token?": "Autorizar 'token'?", + "New passwords must match": "As novas palavras-passe devem ser iguais", + "New password": "Nova palavra-passe", "Clear watch history?": "Limpar histórico de reprodução?", "Previous page": "Página anterior", - "Next page": "Próxima página", + "Next page": "Página seguinte", "last": "últimos", "Current version: ": "Versão atual: ", "channel_tab_community_label": "Comunidade", @@ -272,19 +272,19 @@ "channel_tab_videos_label": "Vídeos", "Video mode": "Modo de vídeo", "Audio mode": "Modo de áudio", - "`x` marked it with a ❤": "`x` foi marcado como ❤", + "`x` marked it with a ❤": "`x` foi marcado com um ❤", "(edited)": "(editado)", "%A %B %-d, %Y": "%A %B %-d, %Y", "Movies": "Filmes", "News": "Notícias", "Gaming": "Jogos", - "Music": "Música", + "Music": "Músicas", "View as playlist": "Ver como lista de reprodução", "preferences_locale_label": "Idioma: ", "Rating: ": "Avaliação: ", - "About": "Sobre", + "About": "Acerca", "Popular": "Popular", - "Fallback comments: ": "Comentários alternativos: ", + "Fallback comments: ": "Alternativa para comentários: ", "Zulu": "Zulu", "Yoruba": "Ioruba", "Yiddish": "Iídiche", @@ -329,7 +329,7 @@ "Marathi": "Marathi", "Maori": "Maori", "Maltese": "Maltês", - "Malayalam": "Malaiala", + "Malayalam": "Malaialaio", "Malay": "Malaio", "Malagasy": "Malgaxe", "Macedonian": "Macedónio", @@ -365,15 +365,15 @@ "Galician": "Galego", "French": "Francês", "Finnish": "Finlandês", - "popular": "popular", - "oldest": "mais antigos", - "newest": "mais recentes", + "popular": "populares", + "oldest": "antigos", + "newest": "recentes", "View playlist on YouTube": "Ver lista de reprodução no YouTube", "View channel on YouTube": "Ver canal no YouTube", "Subscribe": "Subscrever", "Unsubscribe": "Anular subscrição", "Shared `x` ago": "Partilhado `x` atrás", - "LIVE": "AO VIVO", + "LIVE": "Direto", "search_filters_duration_option_short": "Curto (< 4 minutos)", "search_filters_duration_option_long": "Longo (> 20 minutos)", "footer_source_code": "Código-fonte", @@ -386,7 +386,7 @@ "preferences_quality_dash_label": "Qualidade de vídeo DASH preferida: ", "preferences_quality_option_small": "Baixa", "preferences_quality_option_hd720": "HD720", - "preferences_quality_dash_option_auto": "Automático", + "preferences_quality_dash_option_auto": "Automática", "preferences_quality_dash_option_best": "Melhor", "preferences_quality_dash_option_4320p": "4320p", "preferences_quality_dash_option_2160p": "2160p", @@ -397,7 +397,7 @@ "preferences_quality_dash_option_144p": "144p", "search_filters_features_option_purchased": "Comprado", "search_filters_features_option_three_sixty": "360°", - "videoinfo_invidious_embed_link": "Incorporar hiperligação", + "videoinfo_invidious_embed_link": "Incorporar ligação", "Video unavailable": "Vídeo não disponível", "invidious": "Invidious", "preferences_quality_option_medium": "Média", @@ -408,7 +408,7 @@ "preferences_quality_dash_option_worst": "Pior", "none": "nenhum", "videoinfo_youTube_embed_link": "Incorporar", - "preferences_save_player_pos_label": "Guardar a posição de reprodução atual do vídeo: ", + "preferences_save_player_pos_label": "Guardar posição de reprodução: ", "download_subtitles": "Legendas - `x` (.vtt)", "generic_views_count_0": "{{count}} visualização", "generic_views_count_1": "{{count}} visualizações", @@ -427,12 +427,12 @@ "comments_view_x_replies_0": "Ver {{count}} resposta", "comments_view_x_replies_1": "Ver {{count}} respostas", "comments_view_x_replies_2": "Ver {{count}} respostas", - "generic_subscribers_count_0": "{{count}} inscrito", - "generic_subscribers_count_1": "{{count}} inscritos", - "generic_subscribers_count_2": "{{count}} inscritos", - "generic_subscriptions_count_0": "{{count}} inscrição", - "generic_subscriptions_count_1": "{{count}} inscrições", - "generic_subscriptions_count_2": "{{count}} inscrições", + "generic_subscribers_count_0": "{{count}} subscritor", + "generic_subscribers_count_1": "{{count}} subscritores", + "generic_subscribers_count_2": "{{count}} subscritores", + "generic_subscriptions_count_0": "{{count}} subscrição", + "generic_subscriptions_count_1": "{{count}} subscrições", + "generic_subscriptions_count_2": "{{count}} subscrições", "comments_points_count_0": "{{count}} ponto", "comments_points_count_1": "{{count}} pontos", "comments_points_count_2": "{{count}} pontos", @@ -440,7 +440,7 @@ "crash_page_before_reporting": "Antes de reportar um erro, verifique se:", "crash_page_refresh": "tentou <a href=\"`x`\">recarregar a página</a>", "crash_page_switch_instance": "tentou <a href=\"`x`\">usar outra instância</a>", - "crash_page_read_the_faq": "leia as <a href=\"`x`\">Perguntas frequentes (FAQ)</a>", + "crash_page_read_the_faq": "leu as <a href=\"`x`\">Perguntas frequentes (FAQ)</a>", "crash_page_search_issue": "procurou se <a href=\"`x`\">o erro já foi reportado no GitHub</a>", "crash_page_report_issue": "Se nenhuma opção acima ajudou, por favor <a href=\"`x`\">abra um novo problema no Github</a> (preferencialmente em inglês) e inclua o seguinte texto (NÃO o traduza):", "user_created_playlists": "`x` listas de reprodução criadas", @@ -484,7 +484,7 @@ "channel_tab_playlists_label": "Listas de reprodução", "channel_tab_channels_label": "Canais", "channel_tab_shorts_label": "Curtos", - "channel_tab_streams_label": "Diretos", + "channel_tab_streams_label": "Emissões em direto", "Music in this video": "Música neste vídeo", "Artist: ": "Artista: ", "Album: ": "Álbum: ", @@ -493,17 +493,25 @@ "Standard YouTube license": "Licença padrão do YouTube", "Download is disabled": "A descarga está desativada", "Import YouTube playlist (.csv)": "Importar lista de reprodução do YouTube (.csv)", - "generic_button_delete": "Deletar", + "generic_button_delete": "Eliminar", "generic_button_edit": "Editar", "generic_button_rss": "RSS", "channel_tab_podcasts_label": "Podcasts", "channel_tab_releases_label": "Lançamentos", - "generic_button_save": "Salvar", + "generic_button_save": "Guardar", "generic_button_cancel": "Cancelar", "playlist_button_add_items": "Adicionar vídeos", "generic_channels_count_0": "{{count}} canal", "generic_channels_count_1": "{{count}} canais", "generic_channels_count_2": "{{count}} canais", "Import YouTube watch history (.json)": "Importar histórico de reprodução do YouTube (.json)", - "toggle_theme": "Trocar tema" + "toggle_theme": "Trocar tema", + "Add to playlist": "Adicionar à lista de reprodução", + "Add to playlist: ": "Adicionar à lista de reprodução: ", + "Answer": "Resposta", + "Search for videos": "Procurar vídeos", + "carousel_slide": "Diapositivo {{current}} de{{total}}", + "carousel_skip": "Ignorar carrossel", + "carousel_go_to": "Ir para o diapositivo`x`", + "The Popular feed has been disabled by the administrator.": "O feed Popular foi desativado por um administrador." } diff --git a/locales/ro.json b/locales/ro.json index 85bf746f..ccbeef63 100644 --- a/locales/ro.json +++ b/locales/ro.json @@ -478,5 +478,6 @@ "search_filters_type_option_all": "orice tip", "preferences_quality_dash_option_240p": "240p", "preferences_quality_dash_option_144p": "144p", - "Show less": "Afișați mai puțin" + "Show less": "Afișați mai puțin", + "Add to playlist": "Adaugă la playlist" } diff --git a/locales/sr.json b/locales/sr.json index b4a98da6..4b24e7c0 100644 --- a/locales/sr.json +++ b/locales/sr.json @@ -21,7 +21,7 @@ "Import and Export Data": "Uvoz i izvoz podataka", "Import": "Uvezi", "Import Invidious data": "Uvezi Invidious JSON podatke", - "Import YouTube subscriptions": "Uvezi YouTube/OPML praćenja", + "Import YouTube subscriptions": "Uvezi YouTube CSV ili OPML praćenja", "Import FreeTube subscriptions (.db)": "Uvezi FreeTube praćenja (.db)", "Import NewPipe subscriptions (.json)": "Uvezi NewPipe praćenja (.json)", "Import NewPipe data (.zip)": "Uvezi NewPipe podatke (.zip)", @@ -504,5 +504,14 @@ "generic_views_count_0": "{{count}} pregled", "generic_views_count_1": "{{count}} pregleda", "generic_views_count_2": "{{count}} pregleda", - "Import YouTube watch history (.json)": "Uvezi YouTube istoriju gledanja (.json)" + "Import YouTube watch history (.json)": "Uvezi YouTube istoriju gledanja (.json)", + "The Popular feed has been disabled by the administrator.": "Administrator je onemogućio fid „Popularno“.", + "Add to playlist: ": "Dodajte na plejlistu: ", + "Add to playlist": "Dodaj na plejlistu", + "carousel_slide": "Slajd {{current}} od {{total}}", + "carousel_go_to": "Idi na slajd `x`", + "Answer": "Odgovor", + "Search for videos": "Pretražite video snimke", + "carousel_skip": "Preskoči karusel", + "toggle_theme": "Подеси тему" } diff --git a/locales/sr_Cyrl.json b/locales/sr_Cyrl.json index 52ac4116..57c6de9c 100644 --- a/locales/sr_Cyrl.json +++ b/locales/sr_Cyrl.json @@ -21,7 +21,7 @@ "Import and Export Data": "Увоз и извоз података", "Import": "Увези", "Import Invidious data": "Увези Invidious JSON податке", - "Import YouTube subscriptions": "Увези YouTube/OPML праћења", + "Import YouTube subscriptions": "Увези YouTube CSV или OPML праћења", "Import FreeTube subscriptions (.db)": "Увези FreeTube праћења (.db)", "Import NewPipe subscriptions (.json)": "Увези NewPipe праћења (.json)", "Import NewPipe data (.zip)": "Увези NewPipe податке (.zip)", @@ -505,5 +505,13 @@ "generic_views_count_1": "{{count}} прегледа", "generic_views_count_2": "{{count}} прегледа", "Import YouTube watch history (.json)": "Увези YouTube историју гледањa (.json)", - "toggle_theme": "Укључи тему" + "toggle_theme": "Укључи тему", + "Add to playlist": "Додај на плејлисту", + "Answer": "Одговор", + "Search for videos": "Претражите видео снимке", + "carousel_go_to": "Иди на слајд `x`", + "Add to playlist: ": "Додајте на плејлисту: ", + "carousel_skip": "Прескочи карусел", + "The Popular feed has been disabled by the administrator.": "Администратор је онемогућио фид „Популарно“.", + "carousel_slide": "Слајд {{current}} од {{total}}" } diff --git a/locales/sv-SE.json b/locales/sv-SE.json index db3486df..76edc341 100644 --- a/locales/sv-SE.json +++ b/locales/sv-SE.json @@ -488,5 +488,13 @@ "crash_page_you_found_a_bug": "Det verkar som att du har hittat en bugg i Invidious!", "generic_views_count": "{{count}} visning", "generic_views_count_plural": "{{count}} visningar", - "toggle_theme": "Växla tema" + "toggle_theme": "Växla tema", + "Add to playlist": "Lägg till i spellista", + "Add to playlist: ": "Lägg till i spellista: ", + "Answer": "Svara", + "Search for videos": "Sök efter videor", + "The Popular feed has been disabled by the administrator.": "Det populära flödet har inaktiverats av administratören.", + "carousel_slide": "Bildspel {{current}} av {{total}}", + "carousel_skip": "Hoppa över karusellen", + "carousel_go_to": "Gå till bildspel `x`" } diff --git a/locales/tk.json b/locales/tk.json new file mode 100644 index 00000000..798ea6ce --- /dev/null +++ b/locales/tk.json @@ -0,0 +1,7 @@ +{ + "Add to playlist": "Aýdym sanawyna goş", + "Add to playlist: ": "Pleýliste goş: ", + "Answer": "Jogap", + "Search for videos": "Wideo gözläň", + "The Popular feed has been disabled by the administrator.": "Trende bolan administrator tarapyndan ýapyldy." +} diff --git a/locales/tr.json b/locales/tr.json index d25cfd65..3b7bf3a4 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -21,7 +21,7 @@ "Import and Export Data": "Verileri İçe ve Dışa Aktar", "Import": "İçe Aktar", "Import Invidious data": "Invidious JSON Verilerini İçe Aktar", - "Import YouTube subscriptions": "YouTube/OPML Aboneliklerini İçe Aktar", + "Import YouTube subscriptions": "YouTube CSV veya OPML Aboneliklerini İçe Aktar", "Import FreeTube subscriptions (.db)": "FreeTube Aboneliklerini İçe Aktar (.db)", "Import NewPipe subscriptions (.json)": "NewPipe Aboneliklerini İçe Aktar (.json)", "Import NewPipe data (.zip)": "NewPipe Verilerini İçe Aktar (.zip)", @@ -488,5 +488,13 @@ "generic_channels_count": "{{count}} kanal", "generic_channels_count_plural": "{{count}} kanal", "Import YouTube watch history (.json)": "YouTube İzleme Geçmişini İçe Aktar (.json)", - "toggle_theme": "Temayı Değiştir" + "toggle_theme": "Temayı Değiştir", + "Add to playlist": "Oynatma listesine ekle", + "Add to playlist: ": "Oynatma listesine ekle: ", + "Answer": "Yanıt", + "Search for videos": "Video ara", + "carousel_slide": "Sunum {{current}} / {{total}}", + "carousel_skip": "Kayar menüyü atla", + "carousel_go_to": "`x` sunumuna git", + "The Popular feed has been disabled by the administrator.": "Popüler akışı yönetici tarafından devre dışı bırakıldı." } diff --git a/locales/uk.json b/locales/uk.json index f9640bba..223772d9 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -127,7 +127,7 @@ "Create playlist": "Створити список відтворення", "Title": "Заголовок", "Playlist privacy": "Конфіденційність списку відтворення", - "Editing playlist `x`": "Редагування списку відтворення \"x\"", + "Editing playlist `x`": "Редагування списку відтворення `x`", "Watch on YouTube": "Дивитися на YouTube", "Hide annotations": "Приховати анотації", "Show annotations": "Показати анотації", @@ -505,5 +505,13 @@ "generic_channels_count_1": "{{count}} канали", "generic_channels_count_2": "{{count}} каналів", "Import YouTube watch history (.json)": "Імпортувати історію переглядів YouTube (.json)", - "toggle_theme": "Перемкнути тему" + "toggle_theme": "Перемкнути тему", + "Add to playlist": "Додати до списку відтворення", + "Add to playlist: ": "Додати до списку відтворення: ", + "Answer": "Відповідь", + "Search for videos": "Шукати відео", + "The Popular feed has been disabled by the administrator.": "Стрічка Популярні вимкнена адміністратором.", + "carousel_slide": "Слайд {{current}} з {{total}}", + "carousel_skip": "Пропустити карусель", + "carousel_go_to": "Перейти до слайда `x`" } diff --git a/locales/vi.json b/locales/vi.json index 4f8dc30d..229f8fa9 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -33,12 +33,12 @@ "Export data as JSON": "Xuất dữ liệu Invidious dưới dạng JSON", "Delete account?": "Xóa tài khoản?", "History": "Lịch sử", - "An alternative front-end to YouTube": "Một front-end thay thế cho YouTube", + "An alternative front-end to YouTube": "Giao diện thay thế cho YouTube", "JavaScript license information": "Thông tin giấy phép JavaScript", "source": "nguồn", "Log in": "Đăng nhập", "Log in/register": "Đăng nhập / đăng ký", - "User ID": "ID người dùng", + "User ID": "Mã nhận dạng người dùng", "Password": "Mật khẩu", "Time (h:mm:ss):": "Thời gian (h:mm:ss):", "Text CAPTCHA": "CAPTCHA dạng chữ", @@ -46,16 +46,16 @@ "Sign In": "Đăng nhập", "Register": "Đăng ký", "E-mail": "E-mail", - "Preferences": "Sở thích", + "Preferences": "Cài đặt", "preferences_category_player": "Tùy chọn trình phát video", "preferences_video_loop_label": "Luôn lặp lại: ", "preferences_autoplay_label": "Tự động phát: ", "preferences_continue_label": "Phát kế tiếp theo mặc định: ", "preferences_continue_autoplay_label": "Tự động phát video tiếp theo: ", "preferences_listen_label": "Nghe theo mặc định: ", - "preferences_local_label": "Video proxy: ", + "preferences_local_label": "Máy chủ sử lý video: ", "preferences_speed_label": "Tốc độ mặc định: ", - "preferences_quality_label": "Chất lượng video ưa thích: ", + "preferences_quality_label": "Chất lượng video: ", "preferences_volume_label": "Âm lượng video: ", "preferences_comments_label": "Nhận xét mặc định: ", "youtube": "YouTube", @@ -341,13 +341,13 @@ "([^.,0-9]|^)1([^.,0-9]|$)": "Hiển thị `x`bình luận" }, "Song: ": "Ca khúc: ", - "Premieres in `x`": "Trình chiếu lần đầu vào `x`", - "preferences_quality_dash_option_worst": "Thấp nhất", + "Premieres in `x`": "Trình chiếu ở `x`", + "preferences_quality_dash_option_worst": "Tệ nhất", "preferences_watch_history_label": "Bật lịch sử video đã xem ", "preferences_quality_option_hd720": "HD720", "unsubscribe": "hủy đăng kí", "revoke": "gỡ bỏ", - "preferences_quality_dash_label": "Chất lượng video DASH ưa thích ", + "preferences_quality_dash_label": "Chất lượng video DASH ", "preferences_quality_dash_option_auto": "Tự động", "Subscriptions": "Thuê bao", "View YouTube comments": "Hiển thị bình luận từ YouTube", @@ -470,5 +470,14 @@ "search_filters_duration_option_medium": "Trung bình (4 - 20 phút)", "generic_count_seconds_0": "{{count}} giây", "search_filters_date_label": "Ngày tải lên", - "crash_page_you_found_a_bug": "Có vẻ như bạn đã tìm ra lỗi trong Indivious!" + "crash_page_you_found_a_bug": "Có vẻ như bạn đã tìm ra lỗi trong Indivious!", + "Add to playlist": "Thêm vào danh sách phát", + "Add to playlist: ": "Thêm vào danh sách phát: ", + "Answer": "Trả lời", + "toggle_theme": "Bật/tắt diện mạo", + "carousel_slide": "Trang {{current}} trên tổng {{total}} trang", + "carousel_skip": "Bỏ qua Carousel", + "carousel_go_to": "Đi tới trang `x`", + "Search for videos": "Tìm kiếm video", + "The Popular feed has been disabled by the administrator.": "Bảng tin phổ biến đã bị tắt bởi ban quản lý." } diff --git a/locales/zh-CN.json b/locales/zh-CN.json index faa67e6c..756645f4 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -26,7 +26,7 @@ "Import and Export Data": "导入与导出数据", "Import": "导入", "Import Invidious data": "导入 Invidious JSON 数据", - "Import YouTube subscriptions": "导入 YouTube/OPML 订阅", + "Import YouTube subscriptions": "导入 YouTube CSV 或 OPML 订阅", "Import FreeTube subscriptions (.db)": "导入 FreeTube 订阅 (.db)", "Import NewPipe subscriptions (.json)": "导入 NewPipe 订阅 (.json)", "Import NewPipe data (.zip)": "导入 NewPipe 数据 (.zip)", @@ -471,5 +471,13 @@ "generic_button_rss": "RSS", "channel_tab_releases_label": "公告", "generic_channels_count_0": "{{count}} 个频道", - "toggle_theme": "切换主题" + "toggle_theme": "切换主题", + "Add to playlist": "添加到播放列表", + "Add to playlist: ": "添加到播放列表: ", + "Answer": "响应", + "Search for videos": "搜索视频", + "The Popular feed has been disabled by the administrator.": "“流行”源已被管理员禁用。", + "carousel_slide": "当前为第 {{current}} 张图,共 {{total}} 张图", + "carousel_skip": "跳过图集", + "carousel_go_to": "转到图 `x`" } diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 1520c269..2584db9c 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -26,7 +26,7 @@ "Import and Export Data": "匯入與匯出資料", "Import": "匯入", "Import Invidious data": "匯入 Invidious JSON 資料", - "Import YouTube subscriptions": "匯入 YouTube/OPML 訂閱", + "Import YouTube subscriptions": "匯入 YouTube CSV 或 OPML 訂閱", "Import FreeTube subscriptions (.db)": "匯入 FreeTube 訂閱 (.db)", "Import NewPipe subscriptions (.json)": "匯入 NewPipe 訂閱 (.json)", "Import NewPipe data (.zip)": "匯入 NewPipe 資料 (.zip)", @@ -471,5 +471,13 @@ "channel_tab_podcasts_label": "Podcast", "channel_tab_releases_label": "發布", "generic_channels_count_0": "{{count}} 個頻道", - "toggle_theme": "切換佈景主題" + "toggle_theme": "切換佈景主題", + "Add to playlist": "新增至播放清單", + "Add to playlist: ": "新增至播放清單: ", + "Answer": "答案", + "Search for videos": "搜尋影片", + "carousel_slide": "第 {{current}} 張投影片,共 {{total}} 張", + "carousel_skip": "略過輪播", + "carousel_go_to": "跳到投影片 `x`", + "The Popular feed has been disabled by the administrator.": "熱門 feed 已被管理員停用。" } diff --git a/src/invidious/channels/about.cr b/src/invidious/channels/about.cr index 8b60a728..b5a27667 100644 --- a/src/invidious/channels/about.cr +++ b/src/invidious/channels/about.cr @@ -14,6 +14,7 @@ record AboutChannel, is_family_friendly : Bool, allowed_regions : Array(String), tabs : Array(String), + tags : Array(String), verified : Bool def get_about_info(ucid, locale) : AboutChannel @@ -43,6 +44,8 @@ def get_about_info(ucid, locale) : AboutChannel auto_generated = true end + tags = [] of String + if auto_generated author = initdata["header"]["interactiveTabbedHeaderRenderer"]["title"]["simpleText"].as_s author_url = initdata["microformat"]["microformatDataRenderer"]["urlCanonical"].as_s @@ -52,7 +55,13 @@ def get_about_info(ucid, locale) : AboutChannel banners = initdata["header"]["interactiveTabbedHeaderRenderer"]?.try &.["banner"]?.try &.["thumbnails"]? banner = banners.try &.[-1]?.try &.["url"].as_s? - description_node = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"] + description_base_node = initdata["header"]["interactiveTabbedHeaderRenderer"]["description"] + # some channels have the description in a simpleText + # ex: https://www.youtube.com/channel/UCQvWX73GQygcwXOTSf_VDVg/ + description_node = description_base_node.dig?("simpleText") || description_base_node + + tags = initdata.dig?("header", "interactiveTabbedHeaderRenderer", "badges") + .try &.as_a.map(&.["metadataBadgeRenderer"]["label"].as_s) || [] of String else author = initdata["metadata"]["channelMetadataRenderer"]["title"].as_s author_url = initdata["metadata"]["channelMetadataRenderer"]["channelUrl"].as_s @@ -70,6 +79,7 @@ def get_about_info(ucid, locale) : AboutChannel # end description_node = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]? + tags = initdata.dig?("microformat", "microformatDataRenderer", "tags").try &.as_a.map(&.as_s) || [] of String end is_family_friendly = initdata["microformat"]["microformatDataRenderer"]["familySafe"].as_bool @@ -131,7 +141,8 @@ def get_about_info(ucid, locale) : AboutChannel # ["description"]["simpleText"] and ["primaryLinks"][0]["title"]["simpleText"] auto_generated = ( (channel_about_meta["primaryLinks"]?.try &.size) == 1 && \ - extract_text(channel_about_meta.dig?("primaryLinks", 0, "title")) == "Auto-generated by YouTube" + extract_text(channel_about_meta.dig?("primaryLinks", 0, "title")) == "Auto-generated by YouTube" || + channel_about_meta.dig?("links", 0, "channelExternalLinkViewModel", "title", "content").try &.as_s == "Auto-generated by YouTube" ) end end @@ -155,6 +166,7 @@ def get_about_info(ucid, locale) : AboutChannel is_family_friendly: is_family_friendly, allowed_regions: allowed_regions, tabs: tab_names, + tags: tags, verified: author_verified || false, ) end diff --git a/src/invidious/comments/content.cr b/src/invidious/comments/content.cr index c8cdc2df..beefd9ad 100644 --- a/src/invidious/comments/content.cr +++ b/src/invidious/comments/content.cr @@ -64,15 +64,15 @@ def content_to_comment_html(content, video_id : String? = "") # check for custom emojis if run["emoji"]? if run["emoji"]["isCustomEmoji"]?.try &.as_bool - if emojiImage = run.dig?("emoji", "image") - emojiAlt = emojiImage.dig?("accessibility", "accessibilityData", "label").try &.as_s || text - emojiThumb = emojiImage["thumbnails"][0] + if emoji_image = run.dig?("emoji", "image") + emoji_alt = emoji_image.dig?("accessibility", "accessibilityData", "label").try &.as_s || text + emoji_thumb = emoji_image["thumbnails"][0] text = String.build do |str| - str << %(<img alt=") << emojiAlt << "\" " - str << %(src="/ggpht) << URI.parse(emojiThumb["url"].as_s).request_target << "\" " - str << %(title=") << emojiAlt << "\" " - str << %(width=") << emojiThumb["width"] << "\" " - str << %(height=") << emojiThumb["height"] << "\" " + str << %(<img alt=") << emoji_alt << "\" " + str << %(src="/ggpht) << URI.parse(emoji_thumb["url"].as_s).request_target << "\" " + str << %(title=") << emoji_alt << "\" " + str << %(width=") << emoji_thumb["width"] << "\" " + str << %(height=") << emoji_thumb["height"] << "\" " str << %(class="channel-emoji" />) end else diff --git a/src/invidious/comments/youtube.cr b/src/invidious/comments/youtube.cr index 185d8e43..0716fcde 100644 --- a/src/invidious/comments/youtube.cr +++ b/src/invidious/comments/youtube.cr @@ -57,7 +57,7 @@ module Invidious::Comments return initial_data end - def parse_youtube(id, response, format, locale, thin_mode, sort_by = "top", isPost = false) + def parse_youtube(id, response, format, locale, thin_mode, sort_by = "top", is_post = false) contents = nil if on_response_received_endpoints = response["onResponseReceivedEndpoints"]? @@ -104,6 +104,8 @@ module Invidious::Comments end end + mutations = response.dig?("frameworkUpdates", "entityBatchUpdate", "mutations").try &.as_a || [] of JSON::Any + response = JSON.build do |json| json.object do if header @@ -113,7 +115,7 @@ module Invidious::Comments json.field "commentCount", comment_count end - if isPost + if is_post json.field "postId", id else json.field "videoId", id @@ -131,73 +133,138 @@ module Invidious::Comments node_replies = node["replies"]["commentRepliesRenderer"] end - if node["comment"]? - node_comment = node["comment"]["commentRenderer"] - else - node_comment = node["commentRenderer"] - end + if cvm = node["commentViewModel"]? + # two commentViewModels for inital request + # one commentViewModel when getting a replies to a comment + cvm = cvm["commentViewModel"] if cvm["commentViewModel"]? + + comment_key = cvm["commentKey"] + toolbar_key = cvm["toolbarStateKey"] + comment_mutation = mutations.find { |i| i.dig?("payload", "commentEntityPayload", "key") == comment_key } + toolbar_mutation = mutations.find { |i| i.dig?("entityKey") == toolbar_key } + + if !comment_mutation.nil? && !toolbar_mutation.nil? + # todo parse styleRuns, commandRuns and attachmentRuns for comments + html_content = parse_description(comment_mutation.dig("payload", "commentEntityPayload", "properties", "content"), id) + comment_author = comment_mutation.dig("payload", "commentEntityPayload", "author") + json.field "authorId", comment_author["channelId"].as_s + json.field "authorUrl", "/channel/#{comment_author["channelId"].as_s}" + json.field "author", comment_author["displayName"].as_s + json.field "verified", comment_author["isVerified"].as_bool + json.field "authorThumbnails" do + json.array do + comment_mutation.dig?("payload", "commentEntityPayload", "avatar", "image", "sources").try &.as_a.each do |thumbnail| + json.object do + json.field "url", thumbnail["url"] + json.field "width", thumbnail["width"] + json.field "height", thumbnail["height"] + end + end + end + end - content_html = node_comment["contentText"]?.try { |t| parse_content(t, id) } || "" - author = node_comment["authorText"]?.try &.["simpleText"]? || "" + json.field "authorIsChannelOwner", comment_author["isCreator"].as_bool + json.field "isSponsor", (comment_author["sponsorBadgeUrl"]? != nil) - json.field "verified", (node_comment["authorCommentBadge"]? != nil) + if sponsor_badge_url = comment_author["sponsorBadgeUrl"]? + # Sponsor icon thumbnails always have one object and there's only ever the url property in it + json.field "sponsorIconUrl", sponsor_badge_url + end - json.field "author", author - json.field "authorThumbnails" do - json.array do - node_comment["authorThumbnail"]["thumbnails"].as_a.each do |thumbnail| - json.object do - json.field "url", thumbnail["url"] - json.field "width", thumbnail["width"] - json.field "height", thumbnail["height"] + comment_toolbar = comment_mutation.dig("payload", "commentEntityPayload", "toolbar") + json.field "likeCount", short_text_to_number(comment_toolbar["likeCountNotliked"].as_s) + reply_count = short_text_to_number(comment_toolbar["replyCount"]?.try &.as_s || "0") + + if heart_state = toolbar_mutation.dig?("payload", "engagementToolbarStateEntityPayload", "heartState") + if heart_state.as_s == "TOOLBAR_HEART_STATE_HEARTED" + json.field "creatorHeart" do + json.object do + json.field "creatorThumbnail", comment_toolbar["creatorThumbnailUrl"].as_s + json.field "creatorName", comment_toolbar["heartActiveTooltip"].as_s.sub("❤ by ", "") + end + end end end + + published_text = comment_mutation.dig?("payload", "commentEntityPayload", "properties", "publishedTime").try &.as_s end - end - if node_comment["authorEndpoint"]? - json.field "authorId", node_comment["authorEndpoint"]["browseEndpoint"]["browseId"] - json.field "authorUrl", node_comment["authorEndpoint"]["browseEndpoint"]["canonicalBaseUrl"] + json.field "isPinned", (cvm.dig?("pinnedText") != nil) + json.field "commentId", cvm["commentId"] else - json.field "authorId", "" - json.field "authorUrl", "" - end + if node["comment"]? + node_comment = node["comment"]["commentRenderer"] + else + node_comment = node["commentRenderer"] + end + json.field "commentId", node_comment["commentId"] + html_content = node_comment["contentText"]?.try { |t| parse_content(t, id) } + + json.field "verified", (node_comment["authorCommentBadge"]? != nil) + + json.field "author", node_comment["authorText"]?.try &.["simpleText"]? || "" + json.field "authorThumbnails" do + json.array do + node_comment["authorThumbnail"]["thumbnails"].as_a.each do |thumbnail| + json.object do + json.field "url", thumbnail["url"] + json.field "width", thumbnail["width"] + json.field "height", thumbnail["height"] + end + end + end + end + + if comment_action_buttons_renderer = node_comment.dig?("actionButtons", "commentActionButtonsRenderer") + json.field "likeCount", comment_action_buttons_renderer["likeButton"]["toggleButtonRenderer"]["accessibilityData"]["accessibilityData"]["label"].as_s.scan(/\d/).map(&.[0]).join.to_i + if comment_action_buttons_renderer["creatorHeart"]? + heart_data = comment_action_buttons_renderer["creatorHeart"]["creatorHeartRenderer"]["creatorThumbnail"] + json.field "creatorHeart" do + json.object do + json.field "creatorThumbnail", heart_data["thumbnails"][-1]["url"] + json.field "creatorName", heart_data["accessibility"]["accessibilityData"]["label"] + end + end + end + end - published_text = node_comment["publishedTimeText"]["runs"][0]["text"].as_s - published = decode_date(published_text.rchop(" (edited)")) + if node_comment["authorEndpoint"]? + json.field "authorId", node_comment["authorEndpoint"]["browseEndpoint"]["browseId"] + json.field "authorUrl", node_comment["authorEndpoint"]["browseEndpoint"]["canonicalBaseUrl"] + else + json.field "authorId", "" + json.field "authorUrl", "" + end - if published_text.includes?(" (edited)") - json.field "isEdited", true - else - json.field "isEdited", false - end + json.field "authorIsChannelOwner", node_comment["authorIsChannelOwner"] + json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) + published_text = node_comment["publishedTimeText"]["runs"][0]["text"].as_s - json.field "content", html_to_content(content_html) - json.field "contentHtml", content_html + json.field "isSponsor", (node_comment["sponsorCommentBadge"]? != nil) + if node_comment["sponsorCommentBadge"]? + # Sponsor icon thumbnails always have one object and there's only ever the url property in it + json.field "sponsorIconUrl", node_comment.dig("sponsorCommentBadge", "sponsorCommentBadgeRenderer", "customBadge", "thumbnails", 0, "url").to_s + end - json.field "isPinned", (node_comment["pinnedCommentBadge"]? != nil) - json.field "isSponsor", (node_comment["sponsorCommentBadge"]? != nil) - if node_comment["sponsorCommentBadge"]? - # Sponsor icon thumbnails always have one object and there's only ever the url property in it - json.field "sponsorIconUrl", node_comment.dig("sponsorCommentBadge", "sponsorCommentBadgeRenderer", "customBadge", "thumbnails", 0, "url").to_s + reply_count = node_comment["replyCount"]? end - json.field "published", published.to_unix - json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) - comment_action_buttons_renderer = node_comment["actionButtons"]["commentActionButtonsRenderer"] - - json.field "likeCount", comment_action_buttons_renderer["likeButton"]["toggleButtonRenderer"]["accessibilityData"]["accessibilityData"]["label"].as_s.scan(/\d/).map(&.[0]).join.to_i - json.field "commentId", node_comment["commentId"] - json.field "authorIsChannelOwner", node_comment["authorIsChannelOwner"] + content_html = html_content || "" + json.field "content", html_to_content(content_html) + json.field "contentHtml", content_html - if comment_action_buttons_renderer["creatorHeart"]? - hearth_data = comment_action_buttons_renderer["creatorHeart"]["creatorHeartRenderer"]["creatorThumbnail"] - json.field "creatorHeart" do - json.object do - json.field "creatorThumbnail", hearth_data["thumbnails"][-1]["url"] - json.field "creatorName", hearth_data["accessibility"]["accessibilityData"]["label"] - end + if published_text != nil + published_text = published_text.to_s + if published_text.includes?(" (edited)") + json.field "isEdited", true + published = decode_date(published_text.rchop(" (edited)")) + else + json.field "isEdited", false + published = decode_date(published_text) end + + json.field "published", published.to_unix + json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) end if node_replies && !response["commentRepliesContinuation"]? @@ -210,7 +277,7 @@ module Invidious::Comments json.field "replies" do json.object do - json.field "replyCount", node_comment["replyCount"]? || 1 + json.field "replyCount", reply_count || 1 json.field "continuation", continuation end end @@ -236,7 +303,6 @@ module Invidious::Comments if format == "html" response = JSON.parse(response) content_html = Frontend::Comments.template_youtube(response, locale, thin_mode) - response = JSON.build do |json| json.object do json.field "contentHtml", content_html diff --git a/src/invidious/jsonify/api_v1/video_json.cr b/src/invidious/jsonify/api_v1/video_json.cr index 1651559a..0dced80b 100644 --- a/src/invidious/jsonify/api_v1/video_json.cr +++ b/src/invidious/jsonify/api_v1/video_json.cr @@ -62,6 +62,7 @@ module Invidious::JSONify::APIv1 json.field "rating", 0_i64 json.field "isListed", video.is_listed json.field "liveNow", video.live_now + json.field "isPostLiveDvr", video.post_live_dvr json.field "isUpcoming", video.is_upcoming if video.premiere_timestamp @@ -160,6 +161,8 @@ module Invidious::JSONify::APIv1 json.field "type", fmt["mimeType"] json.field "quality", fmt["quality"] + json.field "bitrate", fmt["bitrate"].as_i.to_s if fmt["bitrate"]? + fmt_info = Invidious::Videos::Formats.itag_to_metadata?(fmt["itag"]) if fmt_info fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.as_i || 30 @@ -227,6 +230,7 @@ module Invidious::JSONify::APIv1 json.field "author", rv["author"] json.field "authorUrl", "/channel/#{rv["ucid"]?}" json.field "authorId", rv["ucid"]? + json.field "authorVerified", rv["author_verified"] == "true" if rv["author_thumbnail"]? json.field "authorThumbnails" do json.array do diff --git a/src/invidious/routes/api/manifest.cr b/src/invidious/routes/api/manifest.cr index 662d1002..d89e752c 100644 --- a/src/invidious/routes/api/manifest.cr +++ b/src/invidious/routes/api/manifest.cr @@ -21,7 +21,13 @@ module Invidious::Routes::API::Manifest end if dashmpd = video.dash_manifest_url - manifest = YT_POOL.client &.get(URI.parse(dashmpd).request_target).body + response = YT_POOL.client &.get(URI.parse(dashmpd).request_target) + + if response.status_code != 200 + haltf env, status_code: response.status_code + end + + manifest = response.body manifest = manifest.gsub(/<BaseURL>[^<]+<\/BaseURL>/) do |baseurl| url = baseurl.lchop("<BaseURL>") diff --git a/src/invidious/routes/api/v1/channels.cr b/src/invidious/routes/api/v1/channels.cr index 67018660..7faf200a 100644 --- a/src/invidious/routes/api/v1/channels.cr +++ b/src/invidious/routes/api/v1/channels.cr @@ -90,6 +90,7 @@ module Invidious::Routes::API::V1::Channels json.field "allowedRegions", channel.allowed_regions json.field "tabs", channel.tabs + json.field "tags", channel.tags json.field "authorVerified", channel.verified json.field "latestVideos" do @@ -393,7 +394,7 @@ module Invidious::Routes::API::V1::Channels else comments = YoutubeAPI.browse(continuation: continuation) end - return Comments.parse_youtube(id, comments, format, locale, thin_mode, isPost: true) + return Comments.parse_youtube(id, comments, format, locale, thin_mode, is_post: true) end def self.channels(env) diff --git a/src/invidious/routes/channels.cr b/src/invidious/routes/channels.cr index d4d8b1c1..fea49bbe 100644 --- a/src/invidious/routes/channels.cr +++ b/src/invidious/routes/channels.cr @@ -231,7 +231,7 @@ module Invidious::Routes::Channels if nojs comments = Comments.fetch_community_post_comments(ucid, id) - comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, isPost: true))["contentHtml"] + comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, is_post: true))["contentHtml"] end templated "post" end diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index a8f02056..c218b4ef 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -82,6 +82,10 @@ struct Video return (self.video_type == VideoType::Livestream) end + def post_live_dvr + return info["isPostLiveDvr"].as_bool + end + def premiere_timestamp : Time? info .dig?("microformat", "playerMicroformatRenderer", "liveBroadcastDetails", "startTimestamp") @@ -394,17 +398,6 @@ def fetch_video(id, region) .dig?("microformat", "playerMicroformatRenderer", "availableCountries") .try &.as_a.map &.as_s || [] of String - # Check for region-blocks - if info["reason"]?.try &.as_s.includes?("your country") - bypass_regions = PROXY_LIST.keys & allowed_regions - if !bypass_regions.empty? - region = bypass_regions[rand(bypass_regions.size)] - region_info = extract_video_info(video_id: id, proxy_region: region) - region_info["region"] = JSON::Any.new(region) if region - info = region_info if !region_info["reason"]? - end - end - if reason = info["reason"]? if reason == "Video unavailable" raise NotFoundException.new(reason.as_s || "") diff --git a/src/invidious/videos/description.cr b/src/invidious/videos/description.cr index 542cb416..c7191dec 100644 --- a/src/invidious/videos/description.cr +++ b/src/invidious/videos/description.cr @@ -7,7 +7,19 @@ private def copy_string(str : String::Builder, iter : Iterator, count : Int) : I cp = iter.next break if cp.is_a?(Iterator::Stop) - str << cp.chr + if cp == 0x26 # Ampersand (&) + str << "&" + elsif cp == 0x27 # Single quote (') + str << "'" + elsif cp == 0x22 # Double quote (") + str << """ + elsif cp == 0x3C # Less-than (<) + str << "<" + elsif cp == 0x3E # Greater than (>) + str << ">" + else + str << cp.chr + end # A codepoint from the SMP counts twice copied += 1 if cp > 0xFFFF diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 75fe4a36..e3816d79 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -50,9 +50,9 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)? } end -def extract_video_info(video_id : String, proxy_region : String? = nil) +def extract_video_info(video_id : String) # Init client config for the API - client_config = YoutubeAPI::ClientConfig.new(proxy_region: proxy_region) + client_config = YoutubeAPI::ClientConfig.new # Fetch data from the player endpoint player_response = YoutubeAPI.player(video_id: video_id, params: "", client_config: client_config) @@ -216,6 +216,9 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any live_now = microformat.dig?("liveBroadcastDetails", "isLiveNow") .try &.as_bool || false + post_live_dvr = video_details.dig?("isPostLiveDvr") + .try &.as_bool || false + # Extra video infos allowed_regions = microformat["availableCountries"]? @@ -267,7 +270,18 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any .try &.dig?("videoActions", "menuRenderer", "topLevelButtons") if toplevel_buttons - likes_button = toplevel_buttons.try &.as_a + # New Format as of december 2023 + likes_button = toplevel_buttons.dig?(0, + "segmentedLikeDislikeButtonViewModel", + "likeButtonViewModel", + "likeButtonViewModel", + "toggleButtonViewModel", + "toggleButtonViewModel", + "defaultButtonViewModel", + "buttonViewModel" + ) + + likes_button ||= toplevel_buttons.try &.as_a .find(&.dig?("toggleButtonRenderer", "defaultIcon", "iconType").=== "LIKE") .try &.["toggleButtonRenderer"] @@ -280,9 +294,10 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any ) if likes_button + likes_txt = likes_button.dig?("accessibilityText") # Note: The like count from `toggledText` is off by one, as it would # represent the new like count in the event where the user clicks on "like". - likes_txt = (likes_button["defaultText"]? || likes_button["toggledText"]?) + likes_txt ||= (likes_button["defaultText"]? || likes_button["toggledText"]?) .try &.dig?("accessibility", "accessibilityData", "label") likes = likes_txt.as_s.gsub(/\D/, "").to_i64? if likes_txt @@ -405,6 +420,7 @@ def parse_video_info(video_id : String, player_response : Hash(String, JSON::Any "isListed" => JSON::Any.new(is_listed || false), "isUpcoming" => JSON::Any.new(is_upcoming || false), "keywords" => JSON::Any.new(keywords.map { |v| JSON::Any.new(v) }), + "isPostLiveDvr" => JSON::Any.new(post_live_dvr), # Related videos "relatedVideos" => JSON::Any.new(related), # Description diff --git a/src/invidious/yt_backend/connection_pool.cr b/src/invidious/yt_backend/connection_pool.cr index 81cfb272..d3dbcc0e 100644 --- a/src/invidious/yt_backend/connection_pool.cr +++ b/src/invidious/yt_backend/connection_pool.cr @@ -24,25 +24,20 @@ struct YoutubeConnectionPool @pool = build_pool() end - def client(region = nil, &block) - if region - conn = make_client(url, region, force_resolve = true) + def client(&block) + conn = pool.checkout + begin response = yield conn - else - conn = pool.checkout - begin - response = yield conn - rescue ex - conn.close - conn = HTTP::Client.new(url) + rescue ex + conn.close + conn = HTTP::Client.new(url) - conn.family = CONFIG.force_resolve - conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC - conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com" - response = yield conn - ensure - pool.release(conn) - end + conn.family = CONFIG.force_resolve + conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC + conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com" + response = yield conn + ensure + pool.release(conn) end response @@ -60,9 +55,9 @@ struct YoutubeConnectionPool end def make_client(url : URI, region = nil, force_resolve : Bool = false) - client = HTTPClient.new(url, OpenSSL::SSL::Context::Client.insecure) + client = HTTP::Client.new(url) - # Some services do not support IPv6. + # Force the usage of a specific configured IP Family if force_resolve client.family = CONFIG.force_resolve end @@ -71,17 +66,6 @@ def make_client(url : URI, region = nil, force_resolve : Bool = false) client.read_timeout = 10.seconds client.connect_timeout = 10.seconds - if region - PROXY_LIST[region]?.try &.sample(40).each do |proxy| - begin - proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) - client.set_proxy(proxy) - break - rescue ex - end - end - end - return client end diff --git a/src/invidious/yt_backend/proxy.cr b/src/invidious/yt_backend/proxy.cr deleted file mode 100644 index 2d0fd4ba..00000000 --- a/src/invidious/yt_backend/proxy.cr +++ /dev/null @@ -1,316 +0,0 @@ -# See https://github.com/crystal-lang/crystal/issues/2963 -class HTTPProxy - getter proxy_host : String - getter proxy_port : Int32 - getter options : Hash(Symbol, String) - getter tls : OpenSSL::SSL::Context::Client? - - def initialize(@proxy_host, @proxy_port = 80, @options = {} of Symbol => String) - end - - def open(host, port, tls = nil, connection_options = {} of Symbol => Float64 | Nil) - dns_timeout = connection_options.fetch(:dns_timeout, nil) - connect_timeout = connection_options.fetch(:connect_timeout, nil) - read_timeout = connection_options.fetch(:read_timeout, nil) - - socket = TCPSocket.new @proxy_host, @proxy_port, dns_timeout, connect_timeout - socket.read_timeout = read_timeout if read_timeout - socket.sync = true - - socket << "CONNECT #{host}:#{port} HTTP/1.1\r\n" - - if options[:user]? - credentials = Base64.strict_encode("#{options[:user]}:#{options[:password]}") - credentials = "#{credentials}\n".gsub(/\s/, "") - socket << "Proxy-Authorization: Basic #{credentials}\r\n" - end - - socket << "\r\n" - - resp = parse_response(socket) - - if resp[:code]? == 200 - {% if !flag?(:without_openssl) %} - if tls - tls_socket = OpenSSL::SSL::Socket::Client.new(socket, context: tls, sync_close: true, hostname: host) - socket = tls_socket - end - {% end %} - - return socket - else - socket.close - raise IO::Error.new(resp.inspect) - end - end - - private def parse_response(socket) - resp = {} of Symbol => Int32 | String | Hash(String, String) - - begin - version, code, reason = socket.gets.as(String).chomp.split(/ /, 3) - - headers = {} of String => String - - while (line = socket.gets.as(String)) && (line.chomp != "") - name, value = line.split(/:/, 2) - headers[name.strip] = value.strip - end - - resp[:version] = version - resp[:code] = code.to_i - resp[:reason] = reason - resp[:headers] = headers - rescue - end - - return resp - end -end - -class HTTPClient < HTTP::Client - def set_proxy(proxy : HTTPProxy) - begin - @io = proxy.open(host: @host, port: @port, tls: @tls, connection_options: proxy_connection_options) - rescue IO::Error - @io = nil - end - end - - def unset_proxy - @io = nil - end - - def proxy_connection_options - opts = {} of Symbol => Float64 | Nil - - opts[:dns_timeout] = @dns_timeout - opts[:connect_timeout] = @connect_timeout - opts[:read_timeout] = @read_timeout - - return opts - end -end - -def get_proxies(country_code = "US") - # return get_spys_proxies(country_code) - return get_nova_proxies(country_code) -end - -def filter_proxies(proxies) - proxies.select! do |proxy| - begin - client = HTTPClient.new(YT_URL) - client.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com" - client.read_timeout = 10.seconds - client.connect_timeout = 10.seconds - - proxy = HTTPProxy.new(proxy_host: proxy[:ip], proxy_port: proxy[:port]) - client.set_proxy(proxy) - - status_ok = client.head("/").status_code == 200 - client.close - status_ok - rescue ex - false - end - end - - return proxies -end - -def get_nova_proxies(country_code = "US") - country_code = country_code.downcase - client = HTTP::Client.new(URI.parse("https://www.proxynova.com")) - client.read_timeout = 10.seconds - client.connect_timeout = 10.seconds - - headers = HTTP::Headers.new - headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36" - headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" - headers["Accept-Language"] = "Accept-Language: en-US,en;q=0.9" - headers["Host"] = "www.proxynova.com" - headers["Origin"] = "https://www.proxynova.com" - headers["Referer"] = "https://www.proxynova.com/proxy-server-list/country-#{country_code}/" - - response = client.get("/proxy-server-list/country-#{country_code}/", headers) - client.close - document = XML.parse_html(response.body) - - proxies = [] of {ip: String, port: Int32, score: Float64} - document.xpath_nodes(%q(//tr[@data-proxy-id])).each do |node| - ip = node.xpath_node(%q(.//td/abbr/script)).not_nil!.content - ip = ip.match(/document\.write\('(?<sub1>[^']+)'.substr\(8\) \+ '(?<sub2>[^']+)'/).not_nil! - ip = "#{ip["sub1"][8..-1]}#{ip["sub2"]}" - port = node.xpath_node(%q(.//td[2])).not_nil!.content.strip.to_i - - anchor = node.xpath_node(%q(.//td[4]/div)).not_nil! - speed = anchor["data-value"].to_f - latency = anchor["title"].to_f - uptime = node.xpath_node(%q(.//td[5]/span)).not_nil!.content.rchop("%").to_f - - # TODO: Tweak me - score = (uptime*4 + speed*2 + latency)/7 - proxies << {ip: ip, port: port, score: score} - end - - # proxies = proxies.sort_by { |proxy| proxy[:score] }.reverse - return proxies -end - -def get_spys_proxies(country_code = "US") - client = HTTP::Client.new(URI.parse("http://spys.one")) - client.read_timeout = 10.seconds - client.connect_timeout = 10.seconds - - headers = HTTP::Headers.new - headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36" - headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" - headers["Accept-Language"] = "Accept-Language: en-US,en;q=0.9" - headers["Host"] = "spys.one" - headers["Origin"] = "http://spys.one" - headers["Referer"] = "http://spys.one/free-proxy-list/#{country_code}/" - headers["Content-Type"] = "application/x-www-form-urlencoded" - body = { - "xpp" => "5", - "xf1" => "0", - "xf2" => "0", - "xf4" => "0", - "xf5" => "1", - } - - response = client.post("/free-proxy-list/#{country_code}/", headers, form: body) - client.close - 20.times do - if response.status_code == 200 - break - end - response = client.post("/free-proxy-list/#{country_code}/", headers, form: body) - end - - response = XML.parse_html(response.body) - - mapping = response.xpath_node(%q(.//body/script)).not_nil!.content - mapping = mapping.match(/\}\('(?<p>[^']+)',\d+,\d+,'(?<x>[^']+)'/).not_nil! - p = mapping["p"].not_nil! - x = mapping["x"].not_nil! - mapping = decrypt_port(p, x) - - proxies = [] of {ip: String, port: Int32, score: Float64} - response = response.xpath_node(%q(//tr/td/table)).not_nil! - response.xpath_nodes(%q(.//tr)).each do |node| - if !node["onmouseover"]? - next - end - - ip = node.xpath_node(%q(.//td[1]/font[2])).to_s.match(/<font class="spy14">(?<address>[^<]+)</).not_nil!["address"] - encrypted_port = node.xpath_node(%q(.//td[1]/font[2]/script)).not_nil!.content - encrypted_port = encrypted_port.match(/<\\\/font>"\+(?<encrypted_port>[\d\D]+)\)$/).not_nil!["encrypted_port"] - - port = "" - encrypted_port.split("+").each do |number| - number = number.delete("()") - left_side, right_side = number.split("^") - result = mapping[left_side] ^ mapping[right_side] - port = "#{port}#{result}" - end - port = port.to_i - - latency = node.xpath_node(%q(.//td[6])).not_nil!.content.to_f - speed = node.xpath_node(%q(.//td[7]/font/table)).not_nil!["width"].to_f - uptime = node.xpath_node(%q(.//td[8]/font/acronym)).not_nil! - - # Skip proxies that are down - if uptime["title"].ends_with? "?" - next - end - - if md = uptime.content.match(/^\d+/) - uptime = md[0].to_f - else - next - end - - score = (uptime*4 + speed*2 + latency)/7 - - proxies << {ip: ip, port: port, score: score} - end - - proxies = proxies.sort_by!(&.[:score]).reverse! - return proxies -end - -def decrypt_port(p, x) - x = x.split("^") - s = {} of String => String - - 60.times do |i| - if x[i]?.try &.empty? - s[y_func(i)] = y_func(i) - else - s[y_func(i)] = x[i] - end - end - - x = s - p = p.gsub(/\b\w+\b/, x) - - p = p.split(";") - p = p.map(&.split("=")) - - mapping = {} of String => Int32 - p.each do |item| - if item == [""] - next - end - - key = item[0] - value = item[1] - value = value.split("^") - - if value.size == 1 - value = value[0].to_i - else - left_side = value[0].to_i? - left_side ||= mapping[value[0]] - right_side = value[1].to_i? - right_side ||= mapping[value[1]] - - value = left_side ^ right_side - end - - mapping[key] = value - end - - return mapping -end - -def y_func(c) - return (c < 60 ? "" : y_func((c/60).to_i)) + ((c = c % 60) > 35 ? ((c.to_u8 + 29).unsafe_chr) : c.to_s(36)) -end - -PROXY_LIST = { - "GB" => [{ip: "147.135.206.233", port: 3128}, {ip: "167.114.180.102", port: 8080}, {ip: "176.35.250.108", port: 8080}, {ip: "5.148.128.44", port: 80}, {ip: "62.7.85.234", port: 8080}, {ip: "88.150.135.10", port: 36624}], - "DE" => [{ip: "138.201.223.250", port: 31288}, {ip: "138.68.73.59", port: 32574}, {ip: "159.69.211.173", port: 3128}, {ip: "173.249.43.105", port: 3128}, {ip: "212.202.244.90", port: 8080}, {ip: "5.56.18.35", port: 38827}], - "FR" => [{ip: "137.74.254.242", port: 3128}, {ip: "151.80.143.155", port: 53281}, {ip: "178.33.150.97", port: 3128}, {ip: "37.187.2.31", port: 3128}, {ip: "5.135.164.72", port: 3128}, {ip: "5.39.91.73", port: 3128}, {ip: "51.38.162.2", port: 32231}, {ip: "51.38.217.121", port: 808}, {ip: "51.75.109.81", port: 3128}, {ip: "51.75.109.82", port: 3128}, {ip: "51.75.109.83", port: 3128}, {ip: "51.75.109.84", port: 3128}, {ip: "51.75.109.86", port: 3128}, {ip: "51.75.109.88", port: 3128}, {ip: "51.75.109.90", port: 3128}, {ip: "62.210.167.3", port: 3128}, {ip: "90.63.218.232", port: 8080}, {ip: "91.134.165.198", port: 9999}], - "IN" => [{ip: "1.186.151.206", port: 36253}, {ip: "1.186.63.130", port: 39142}, {ip: "103.105.40.1", port: 16538}, {ip: "103.105.40.153", port: 16538}, {ip: "103.106.148.203", port: 60227}, {ip: "103.106.148.207", port: 51451}, {ip: "103.12.246.12", port: 8080}, {ip: "103.14.235.109", port: 8080}, {ip: "103.14.235.26", port: 8080}, {ip: "103.198.172.4", port: 50820}, {ip: "103.205.112.1", port: 23500}, {ip: "103.209.64.19", port: 6666}, {ip: "103.211.76.5", port: 8080}, {ip: "103.216.82.19", port: 6666}, {ip: "103.216.82.190", port: 6666}, {ip: "103.216.82.209", port: 54806}, {ip: "103.216.82.214", port: 6666}, {ip: "103.216.82.37", port: 6666}, {ip: "103.216.82.44", port: 8080}, {ip: "103.216.82.50", port: 53281}, {ip: "103.22.173.230", port: 8080}, {ip: "103.224.38.2", port: 83}, {ip: "103.226.142.90", port: 41386}, {ip: "103.236.114.38", port: 49638}, {ip: "103.240.161.107", port: 6666}, {ip: "103.240.161.108", port: 6666}, {ip: "103.240.161.109", port: 6666}, {ip: "103.240.161.59", port: 48809}, {ip: "103.245.198.101", port: 8080}, {ip: "103.250.148.82", port: 6666}, {ip: "103.251.58.51", port: 61489}, {ip: "103.253.169.115", port: 32731}, {ip: "103.253.211.182", port: 8080}, {ip: "103.253.211.182", port: 80}, {ip: "103.255.234.169", port: 39847}, {ip: "103.42.161.118", port: 8080}, {ip: "103.42.162.30", port: 8080}, {ip: "103.42.162.50", port: 8080}, {ip: "103.42.162.58", port: 8080}, {ip: "103.46.233.12", port: 83}, {ip: "103.46.233.13", port: 83}, {ip: "103.46.233.16", port: 83}, {ip: "103.46.233.17", port: 83}, {ip: "103.46.233.21", port: 83}, {ip: "103.46.233.23", port: 83}, {ip: "103.46.233.29", port: 81}, {ip: "103.46.233.29", port: 83}, {ip: "103.46.233.50", port: 83}, {ip: "103.47.153.87", port: 8080}, {ip: "103.47.66.2", port: 39804}, {ip: "103.49.53.1", port: 81}, {ip: "103.52.220.1", port: 49068}, {ip: "103.56.228.166", port: 53281}, {ip: "103.56.30.128", port: 8080}, {ip: "103.65.193.17", port: 50862}, {ip: "103.65.195.1", port: 33960}, {ip: "103.69.220.14", port: 3128}, {ip: "103.70.128.84", port: 8080}, {ip: "103.70.128.86", port: 8080}, {ip: "103.70.131.74", port: 8080}, {ip: "103.70.146.250", port: 59563}, {ip: "103.72.216.194", port: 38345}, {ip: "103.75.161.38", port: 21776}, {ip: "103.76.253.155", port: 3128}, {ip: "103.87.104.137", port: 8080}, {ip: "110.235.198.3", port: 57660}, {ip: "114.69.229.161", port: 8080}, {ip: "117.196.231.201", port: 37769}, {ip: "117.211.166.214", port: 3128}, {ip: "117.240.175.51", port: 3128}, {ip: "117.240.210.155", port: 53281}, {ip: "117.240.59.115", port: 36127}, {ip: "117.242.154.73", port: 33889}, {ip: "117.244.15.243", port: 3128}, {ip: "119.235.54.3", port: 8080}, {ip: "120.138.117.102", port: 59308}, {ip: "123.108.200.185", port: 83}, {ip: "123.108.200.217", port: 82}, {ip: "123.176.43.218", port: 40524}, {ip: "125.21.43.82", port: 8080}, {ip: "125.62.192.225", port: 82}, {ip: "125.62.192.33", port: 84}, {ip: "125.62.194.1", port: 83}, {ip: "125.62.213.134", port: 82}, {ip: "125.62.213.18", port: 83}, {ip: "125.62.213.201", port: 84}, {ip: "125.62.213.242", port: 83}, {ip: "125.62.214.185", port: 84}, {ip: "139.5.26.27", port: 53281}, {ip: "14.102.67.101", port: 30337}, {ip: "14.142.122.134", port: 8080}, {ip: "150.129.114.194", port: 6666}, {ip: "150.129.151.62", port: 6666}, {ip: "150.129.171.115", port: 6666}, {ip: "150.129.201.30", port: 6666}, {ip: "157.119.207.38", port: 53281}, {ip: "175.100.185.151", port: 53281}, {ip: "182.18.177.114", port: 56173}, {ip: "182.73.194.170", port: 8080}, {ip: "182.74.85.230", port: 51214}, {ip: "183.82.116.56", port: 8080}, {ip: "183.82.32.56", port: 49551}, {ip: "183.87.14.229", port: 53281}, {ip: "183.87.14.250", port: 44915}, {ip: "202.134.160.168", port: 8080}, {ip: "202.134.166.1", port: 8080}, {ip: "202.134.180.50", port: 8080}, {ip: "202.62.84.210", port: 53281}, {ip: "203.192.193.225", port: 8080}, {ip: "203.192.195.14", port: 31062}, {ip: "203.192.217.11", port: 8080}, {ip: "223.196.83.182", port: 53281}, {ip: "27.116.20.169", port: 36630}, {ip: "27.116.20.209", port: 36630}, {ip: "27.116.51.21", port: 36033}, {ip: "43.224.8.114", port: 50333}, {ip: "43.224.8.116", port: 6666}, {ip: "43.224.8.124", port: 6666}, {ip: "43.224.8.86", port: 6666}, {ip: "43.225.20.73", port: 8080}, {ip: "43.225.23.26", port: 8080}, {ip: "43.230.196.98", port: 36569}, {ip: "43.240.5.225", port: 31777}, {ip: "43.241.28.248", port: 8080}, {ip: "43.242.209.201", port: 8080}, {ip: "43.246.139.82", port: 8080}, {ip: "43.248.73.86", port: 53281}, {ip: "43.251.170.145", port: 54059}, {ip: "45.112.57.230", port: 61222}, {ip: "45.115.171.30", port: 47949}, {ip: "45.121.29.254", port: 54858}, {ip: "45.123.26.146", port: 53281}, {ip: "45.125.61.193", port: 32804}, {ip: "45.125.61.209", port: 32804}, {ip: "45.127.121.194", port: 53281}, {ip: "45.250.226.14", port: 3128}, {ip: "45.250.226.38", port: 8080}, {ip: "45.250.226.47", port: 8080}, {ip: "45.250.226.55", port: 8080}, {ip: "49.249.251.86", port: 53281}], - "CN" => [{ip: "182.61.170.45", port: 3128}], - "RU" => [{ip: "109.106.139.225", port: 45689}, {ip: "109.161.48.228", port: 53281}, {ip: "109.167.224.198", port: 51919}, {ip: "109.172.57.250", port: 23500}, {ip: "109.194.2.126", port: 61822}, {ip: "109.195.150.128", port: 37564}, {ip: "109.201.96.171", port: 31773}, {ip: "109.201.97.204", port: 41258}, {ip: "109.201.97.235", port: 39125}, {ip: "109.206.140.74", port: 45991}, {ip: "109.206.148.31", port: 30797}, {ip: "109.69.75.5", port: 46347}, {ip: "109.71.181.170", port: 53983}, {ip: "109.74.132.190", port: 42663}, {ip: "109.74.143.45", port: 36529}, {ip: "109.75.140.158", port: 59916}, {ip: "109.95.84.114", port: 52125}, {ip: "130.255.12.24", port: 31004}, {ip: "134.19.147.72", port: 44812}, {ip: "134.90.181.7", port: 54353}, {ip: "145.255.6.171", port: 31252}, {ip: "146.120.227.3", port: 8080}, {ip: "149.255.112.194", port: 48968}, {ip: "158.46.127.222", port: 52574}, {ip: "158.46.43.144", port: 39120}, {ip: "158.58.130.185", port: 50016}, {ip: "158.58.132.12", port: 56962}, {ip: "158.58.133.106", port: 41258}, {ip: "158.58.133.13", port: 21213}, {ip: "176.101.0.47", port: 34471}, {ip: "176.101.89.226", port: 33470}, {ip: "176.106.12.65", port: 30120}, {ip: "176.107.80.110", port: 58901}, {ip: "176.110.121.9", port: 46322}, {ip: "176.110.121.90", port: 21776}, {ip: "176.111.97.18", port: 8080}, {ip: "176.112.106.230", port: 33996}, {ip: "176.112.110.40", port: 61142}, {ip: "176.113.116.70", port: 55589}, {ip: "176.113.27.192", port: 47337}, {ip: "176.115.197.118", port: 8080}, {ip: "176.117.255.182", port: 53100}, {ip: "176.120.200.69", port: 44331}, {ip: "176.124.123.93", port: 41258}, {ip: "176.192.124.98", port: 60787}, {ip: "176.192.5.238", port: 61227}, {ip: "176.192.8.206", port: 39422}, {ip: "176.193.15.94", port: 8080}, {ip: "176.196.195.170", port: 48129}, {ip: "176.196.198.154", port: 35252}, {ip: "176.196.238.234", port: 44648}, {ip: "176.196.239.46", port: 35656}, {ip: "176.196.246.6", port: 53281}, {ip: "176.196.84.138", port: 51336}, {ip: "176.197.145.246", port: 32649}, {ip: "176.197.99.142", port: 47278}, {ip: "176.215.1.108", port: 60339}, {ip: "176.215.170.147", port: 35604}, {ip: "176.56.23.14", port: 35340}, {ip: "176.62.185.54", port: 53883}, {ip: "176.74.13.110", port: 8080}, {ip: "178.130.29.226", port: 53295}, {ip: "178.170.254.178", port: 46788}, {ip: "178.213.13.136", port: 53281}, {ip: "178.218.104.8", port: 49707}, {ip: "178.219.183.163", port: 8080}, {ip: "178.237.180.34", port: 57307}, {ip: "178.57.101.212", port: 38020}, {ip: "178.57.101.235", port: 31309}, {ip: "178.64.190.133", port: 46688}, {ip: "178.75.1.111", port: 50411}, {ip: "178.75.27.131", port: 41879}, {ip: "185.13.35.178", port: 40654}, {ip: "185.15.189.67", port: 30215}, {ip: "185.175.119.137", port: 41258}, {ip: "185.18.111.194", port: 41258}, {ip: "185.19.176.237", port: 53281}, {ip: "185.190.40.115", port: 31747}, {ip: "185.216.195.134", port: 61287}, {ip: "185.22.172.94", port: 10010}, {ip: "185.22.172.94", port: 1448}, {ip: "185.22.174.65", port: 10010}, {ip: "185.22.174.65", port: 1448}, {ip: "185.23.64.100", port: 3130}, {ip: "185.23.82.39", port: 59248}, {ip: "185.233.94.105", port: 59288}, {ip: "185.233.94.146", port: 57736}, {ip: "185.3.68.54", port: 53500}, {ip: "185.32.120.177", port: 60724}, {ip: "185.34.20.164", port: 53700}, {ip: "185.34.23.43", port: 63238}, {ip: "185.51.60.141", port: 39935}, {ip: "185.61.92.228", port: 33060}, {ip: "185.61.93.67", port: 49107}, {ip: "185.7.233.66", port: 53504}, {ip: "185.72.225.10", port: 56285}, {ip: "185.75.5.158", port: 60819}, {ip: "185.9.86.186", port: 39345}, {ip: "188.133.136.10", port: 47113}, {ip: "188.168.75.254", port: 56899}, {ip: "188.170.41.6", port: 60332}, {ip: "188.187.189.142", port: 38264}, {ip: "188.234.151.103", port: 8080}, {ip: "188.235.11.88", port: 57143}, {ip: "188.235.137.196", port: 23500}, {ip: "188.244.175.2", port: 8080}, {ip: "188.255.82.136", port: 53281}, {ip: "188.43.4.117", port: 60577}, {ip: "188.68.95.166", port: 41258}, {ip: "188.92.242.180", port: 52048}, {ip: "188.93.242.213", port: 49774}, {ip: "192.162.193.243", port: 36910}, {ip: "192.162.214.11", port: 41258}, {ip: "193.106.170.133", port: 38591}, {ip: "193.232.113.244", port: 40412}, {ip: "193.232.234.130", port: 61932}, {ip: "193.242.177.105", port: 53281}, {ip: "193.242.178.50", port: 52376}, {ip: "193.242.178.90", port: 8080}, {ip: "193.33.101.152", port: 34611}, {ip: "194.114.128.149", port: 61213}, {ip: "194.135.15.146", port: 59328}, {ip: "194.135.216.178", port: 56805}, {ip: "194.135.75.74", port: 41258}, {ip: "194.146.201.67", port: 53281}, {ip: "194.186.18.46", port: 56408}, {ip: "194.186.20.62", port: 21231}, {ip: "194.190.171.214", port: 43960}, {ip: "194.9.27.82", port: 42720}, {ip: "195.133.232.58", port: 41733}, {ip: "195.14.114.116", port: 59530}, {ip: "195.14.114.24", port: 56897}, {ip: "195.158.250.97", port: 41582}, {ip: "195.16.48.142", port: 36083}, {ip: "195.191.183.169", port: 47238}, {ip: "195.206.45.112", port: 53281}, {ip: "195.208.172.70", port: 8080}, {ip: "195.209.141.67", port: 31927}, {ip: "195.209.176.2", port: 8080}, {ip: "195.210.144.166", port: 30088}, {ip: "195.211.160.88", port: 44464}, {ip: "195.218.144.182", port: 31705}, {ip: "195.46.168.147", port: 8080}, {ip: "195.9.188.78", port: 53281}, {ip: "195.9.209.10", port: 35242}, {ip: "195.9.223.246", port: 52098}, {ip: "195.9.237.66", port: 8080}, {ip: "195.9.91.66", port: 33199}, {ip: "195.91.132.20", port: 19600}, {ip: "195.98.183.82", port: 30953}, {ip: "212.104.82.246", port: 36495}, {ip: "212.119.229.18", port: 33852}, {ip: "212.13.97.122", port: 30466}, {ip: "212.19.21.19", port: 53264}, {ip: "212.19.5.157", port: 58442}, {ip: "212.19.8.223", port: 30281}, {ip: "212.19.8.239", port: 55602}, {ip: "212.192.202.207", port: 4550}, {ip: "212.22.80.224", port: 34822}, {ip: "212.26.247.178", port: 38418}, {ip: "212.33.228.161", port: 37971}, {ip: "212.33.243.83", port: 38605}, {ip: "212.34.53.126", port: 44369}, {ip: "212.5.107.81", port: 56481}, {ip: "212.7.230.7", port: 51405}, {ip: "212.77.138.161", port: 41258}, {ip: "213.108.221.201", port: 32800}, {ip: "213.109.7.135", port: 59918}, {ip: "213.128.9.204", port: 35549}, {ip: "213.134.196.12", port: 38723}, {ip: "213.168.37.86", port: 8080}, {ip: "213.187.118.184", port: 53281}, {ip: "213.21.23.98", port: 53281}, {ip: "213.210.67.166", port: 53281}, {ip: "213.234.0.242", port: 56503}, {ip: "213.247.192.131", port: 41258}, {ip: "213.251.226.208", port: 56900}, {ip: "213.33.155.80", port: 44387}, {ip: "213.33.199.194", port: 36411}, {ip: "213.33.224.82", port: 8080}, {ip: "213.59.153.19", port: 53281}, {ip: "217.10.45.103", port: 8080}, {ip: "217.107.197.39", port: 33628}, {ip: "217.116.60.66", port: 21231}, {ip: "217.195.87.58", port: 41258}, {ip: "217.197.239.54", port: 34463}, {ip: "217.74.161.42", port: 34175}, {ip: "217.8.84.76", port: 46378}, {ip: "31.131.67.14", port: 8080}, {ip: "31.132.127.142", port: 35432}, {ip: "31.132.218.252", port: 32423}, {ip: "31.173.17.118", port: 51317}, {ip: "31.193.124.70", port: 53281}, {ip: "31.210.211.147", port: 8080}, {ip: "31.220.183.217", port: 53281}, {ip: "31.29.212.82", port: 35066}, {ip: "31.42.254.24", port: 30912}, {ip: "31.47.189.14", port: 38473}, {ip: "37.113.129.98", port: 41665}, {ip: "37.192.103.164", port: 34835}, {ip: "37.192.194.50", port: 50165}, {ip: "37.192.99.151", port: 51417}, {ip: "37.205.83.91", port: 35888}, {ip: "37.233.85.155", port: 53281}, {ip: "37.235.167.66", port: 53281}, {ip: "37.235.65.2", port: 47816}, {ip: "37.235.67.178", port: 34450}, {ip: "37.9.134.133", port: 41262}, {ip: "46.150.174.90", port: 53281}, {ip: "46.151.156.198", port: 56013}, {ip: "46.16.226.10", port: 8080}, {ip: "46.163.131.55", port: 48306}, {ip: "46.173.191.51", port: 53281}, {ip: "46.174.222.61", port: 34977}, {ip: "46.180.96.79", port: 42319}, {ip: "46.181.151.79", port: 39386}, {ip: "46.21.74.130", port: 8080}, {ip: "46.227.162.98", port: 51558}, {ip: "46.229.187.169", port: 53281}, {ip: "46.229.67.198", port: 47437}, {ip: "46.243.179.221", port: 41598}, {ip: "46.254.217.54", port: 53281}, {ip: "46.32.68.188", port: 39707}, {ip: "46.39.224.112", port: 36765}, {ip: "46.63.162.171", port: 8080}, {ip: "46.73.33.253", port: 8080}, {ip: "5.128.32.12", port: 51959}, {ip: "5.129.155.3", port: 51390}, {ip: "5.129.16.27", port: 48935}, {ip: "5.141.81.65", port: 61853}, {ip: "5.16.15.234", port: 8080}, {ip: "5.167.51.235", port: 8080}, {ip: "5.167.96.238", port: 3128}, {ip: "5.19.165.235", port: 30793}, {ip: "5.35.93.157", port: 31773}, {ip: "5.59.137.90", port: 8888}, {ip: "5.8.207.160", port: 57192}, {ip: "62.122.97.66", port: 59143}, {ip: "62.148.151.253", port: 53570}, {ip: "62.152.85.158", port: 31156}, {ip: "62.165.54.153", port: 55522}, {ip: "62.173.140.14", port: 8080}, {ip: "62.173.155.206", port: 41258}, {ip: "62.182.206.19", port: 37715}, {ip: "62.213.14.166", port: 8080}, {ip: "62.76.123.224", port: 8080}, {ip: "77.221.220.133", port: 44331}, {ip: "77.232.153.248", port: 60950}, {ip: "77.233.10.37", port: 54210}, {ip: "77.244.27.109", port: 47554}, {ip: "77.37.142.203", port: 53281}, {ip: "77.39.29.29", port: 49243}, {ip: "77.75.6.34", port: 8080}, {ip: "77.87.102.7", port: 42601}, {ip: "77.94.121.212", port: 36896}, {ip: "77.94.121.51", port: 45293}, {ip: "78.110.154.177", port: 59888}, {ip: "78.140.201.226", port: 8090}, {ip: "78.153.4.122", port: 9001}, {ip: "78.156.225.170", port: 41258}, {ip: "78.156.243.146", port: 59730}, {ip: "78.29.14.201", port: 39001}, {ip: "78.81.24.112", port: 8080}, {ip: "78.85.36.203", port: 8080}, {ip: "79.104.219.125", port: 3128}, {ip: "79.104.55.134", port: 8080}, {ip: "79.137.181.170", port: 8080}, {ip: "79.173.124.194", port: 47832}, {ip: "79.173.124.207", port: 53281}, {ip: "79.174.186.168", port: 45710}, {ip: "79.175.51.13", port: 54853}, {ip: "79.175.57.77", port: 55477}, {ip: "80.234.107.118", port: 56952}, {ip: "80.237.6.1", port: 34880}, {ip: "80.243.14.182", port: 49320}, {ip: "80.251.48.215", port: 45157}, {ip: "80.254.121.66", port: 41055}, {ip: "80.254.125.236", port: 80}, {ip: "80.72.121.185", port: 52379}, {ip: "80.89.133.210", port: 3128}, {ip: "80.91.17.113", port: 41258}, {ip: "81.162.61.166", port: 40392}, {ip: "81.163.57.121", port: 41258}, {ip: "81.163.57.46", port: 41258}, {ip: "81.163.62.136", port: 41258}, {ip: "81.23.112.98", port: 55269}, {ip: "81.23.118.106", port: 60427}, {ip: "81.23.177.245", port: 8080}, {ip: "81.24.126.166", port: 8080}, {ip: "81.30.216.147", port: 41258}, {ip: "81.95.131.10", port: 44292}, {ip: "82.114.125.22", port: 8080}, {ip: "82.151.208.20", port: 8080}, {ip: "83.221.216.110", port: 47326}, {ip: "83.246.139.24", port: 8080}, {ip: "83.97.108.8", port: 41258}, {ip: "84.22.154.76", port: 8080}, {ip: "84.52.110.36", port: 38674}, {ip: "84.52.74.194", port: 8080}, {ip: "84.52.77.227", port: 41806}, {ip: "84.52.79.166", port: 43548}, {ip: "84.52.84.157", port: 44331}, {ip: "84.52.88.125", port: 32666}, {ip: "85.113.48.148", port: 8080}, {ip: "85.113.49.220", port: 8080}, {ip: "85.12.193.210", port: 58470}, {ip: "85.15.179.5", port: 8080}, {ip: "85.173.244.102", port: 53281}, {ip: "85.174.227.52", port: 59280}, {ip: "85.192.184.133", port: 8080}, {ip: "85.192.184.133", port: 80}, {ip: "85.21.240.193", port: 55820}, {ip: "85.21.63.219", port: 53281}, {ip: "85.235.190.18", port: 42494}, {ip: "85.237.56.193", port: 8080}, {ip: "85.91.119.6", port: 8080}, {ip: "86.102.116.30", port: 8080}, {ip: "86.110.30.146", port: 38109}, {ip: "87.117.3.129", port: 3128}, {ip: "87.225.108.195", port: 8080}, {ip: "87.228.103.111", port: 8080}, {ip: "87.228.103.43", port: 8080}, {ip: "87.229.143.10", port: 48872}, {ip: "87.249.205.103", port: 8080}, {ip: "87.249.21.193", port: 43079}, {ip: "87.255.13.217", port: 8080}, {ip: "88.147.159.167", port: 53281}, {ip: "88.200.225.32", port: 38583}, {ip: "88.204.59.177", port: 32666}, {ip: "88.84.209.69", port: 30819}, {ip: "88.87.72.72", port: 8080}, {ip: "88.87.79.20", port: 8080}, {ip: "88.87.91.163", port: 48513}, {ip: "88.87.93.20", port: 33277}, {ip: "89.109.12.82", port: 47972}, {ip: "89.109.21.43", port: 9090}, {ip: "89.109.239.183", port: 41041}, {ip: "89.109.54.137", port: 36469}, {ip: "89.17.37.218", port: 52957}, {ip: "89.189.130.103", port: 32626}, {ip: "89.189.159.214", port: 42530}, {ip: "89.189.174.121", port: 52636}, {ip: "89.23.18.29", port: 53281}, {ip: "89.249.251.21", port: 3128}, {ip: "89.250.149.114", port: 60981}, {ip: "89.250.17.209", port: 8080}, {ip: "89.250.19.173", port: 8080}, {ip: "90.150.87.172", port: 81}, {ip: "90.154.125.173", port: 33078}, {ip: "90.188.38.81", port: 60585}, {ip: "90.189.151.183", port: 32601}, {ip: "91.103.208.114", port: 57063}, {ip: "91.122.100.222", port: 44331}, {ip: "91.122.207.229", port: 8080}, {ip: "91.144.139.93", port: 3128}, {ip: "91.144.142.19", port: 44617}, {ip: "91.146.16.54", port: 57902}, {ip: "91.190.116.194", port: 38783}, {ip: "91.190.80.100", port: 31659}, {ip: "91.190.85.97", port: 34286}, {ip: "91.203.36.188", port: 8080}, {ip: "91.205.131.102", port: 8080}, {ip: "91.205.146.25", port: 37501}, {ip: "91.210.94.212", port: 52635}, {ip: "91.213.23.110", port: 8080}, {ip: "91.215.22.51", port: 53305}, {ip: "91.217.42.3", port: 8080}, {ip: "91.217.42.4", port: 8080}, {ip: "91.220.135.146", port: 41258}, {ip: "91.222.167.213", port: 38057}, {ip: "91.226.140.71", port: 33199}, {ip: "91.235.7.216", port: 59067}, {ip: "92.124.195.22", port: 3128}, {ip: "92.126.193.180", port: 8080}, {ip: "92.241.110.223", port: 53281}, {ip: "92.252.240.1", port: 53281}, {ip: "92.255.164.187", port: 3128}, {ip: "92.255.195.57", port: 53281}, {ip: "92.255.229.146", port: 55785}, {ip: "92.255.5.2", port: 41012}, {ip: "92.38.32.36", port: 56113}, {ip: "92.39.138.98", port: 31150}, {ip: "92.51.16.155", port: 46202}, {ip: "92.55.59.63", port: 33030}, {ip: "93.170.112.200", port: 47995}, {ip: "93.183.86.185", port: 53281}, {ip: "93.188.45.157", port: 8080}, {ip: "93.81.246.5", port: 53281}, {ip: "93.91.112.247", port: 41258}, {ip: "94.127.217.66", port: 40115}, {ip: "94.154.85.214", port: 8080}, {ip: "94.180.106.94", port: 32767}, {ip: "94.180.249.187", port: 38051}, {ip: "94.230.243.6", port: 8080}, {ip: "94.232.57.231", port: 51064}, {ip: "94.24.244.170", port: 48936}, {ip: "94.242.55.108", port: 10010}, {ip: "94.242.55.108", port: 1448}, {ip: "94.242.57.136", port: 10010}, {ip: "94.242.57.136", port: 1448}, {ip: "94.242.58.108", port: 10010}, {ip: "94.242.58.108", port: 1448}, {ip: "94.242.58.14", port: 10010}, {ip: "94.242.58.14", port: 1448}, {ip: "94.242.58.142", port: 10010}, {ip: "94.242.58.142", port: 1448}, {ip: "94.242.59.245", port: 10010}, {ip: "94.242.59.245", port: 1448}, {ip: "94.247.241.70", port: 53640}, {ip: "94.247.62.165", port: 33176}, {ip: "94.253.13.228", port: 54935}, {ip: "94.253.14.187", port: 55045}, {ip: "94.28.94.154", port: 46966}, {ip: "94.73.217.125", port: 40858}, {ip: "95.140.19.9", port: 8080}, {ip: "95.140.20.94", port: 33994}, {ip: "95.154.137.66", port: 41258}, {ip: "95.154.159.119", port: 44242}, {ip: "95.154.82.254", port: 52484}, {ip: "95.161.157.227", port: 43170}, {ip: "95.161.182.146", port: 33877}, {ip: "95.161.189.26", port: 61522}, {ip: "95.165.163.146", port: 8888}, {ip: "95.165.172.90", port: 60496}, {ip: "95.165.182.18", port: 38950}, {ip: "95.165.203.222", port: 33805}, {ip: "95.165.244.122", port: 58162}, {ip: "95.167.123.54", port: 58664}, {ip: "95.167.241.242", port: 49636}, {ip: "95.171.1.92", port: 35956}, {ip: "95.172.52.230", port: 35989}, {ip: "95.181.35.30", port: 40804}, {ip: "95.181.56.178", port: 39144}, {ip: "95.181.75.228", port: 53281}, {ip: "95.188.74.194", port: 57122}, {ip: "95.189.112.214", port: 35508}, {ip: "95.31.10.247", port: 30711}, {ip: "95.31.197.77", port: 41651}, {ip: "95.31.2.199", port: 33632}, {ip: "95.71.125.50", port: 49882}, {ip: "95.73.62.13", port: 32185}, {ip: "95.79.36.55", port: 44861}, {ip: "95.79.55.196", port: 53281}, {ip: "95.79.99.148", port: 3128}, {ip: "95.80.65.39", port: 43555}, {ip: "95.80.93.44", port: 41258}, {ip: "95.80.98.41", port: 8080}, {ip: "95.83.156.250", port: 58438}, {ip: "95.84.128.25", port: 33765}, {ip: "95.84.154.73", port: 57423}], - "CA" => [{ip: "144.217.161.149", port: 8080}, {ip: "24.37.9.6", port: 54154}, {ip: "54.39.138.144", port: 3128}, {ip: "54.39.138.145", port: 3128}, {ip: "54.39.138.151", port: 3128}, {ip: "54.39.138.152", port: 3128}, {ip: "54.39.138.153", port: 3128}, {ip: "54.39.138.154", port: 3128}, {ip: "54.39.138.155", port: 3128}, {ip: "54.39.138.156", port: 3128}, {ip: "54.39.138.157", port: 3128}, {ip: "54.39.53.104", port: 3128}, {ip: "66.70.167.113", port: 3128}, {ip: "66.70.167.116", port: 3128}, {ip: "66.70.167.117", port: 3128}, {ip: "66.70.167.119", port: 3128}, {ip: "66.70.167.120", port: 3128}, {ip: "66.70.167.125", port: 3128}, {ip: "66.70.188.148", port: 3128}, {ip: "70.35.213.229", port: 36127}, {ip: "70.65.233.174", port: 8080}, {ip: "72.139.24.66", port: 38861}, {ip: "74.15.191.160", port: 41564}], - "JP" => [{ip: "47.91.20.67", port: 8080}, {ip: "61.118.35.94", port: 55725}], - "IT" => [{ip: "109.70.201.97", port: 53517}, {ip: "176.31.82.212", port: 8080}, {ip: "185.132.228.118", port: 55583}, {ip: "185.49.58.88", port: 56006}, {ip: "185.94.89.179", port: 41258}, {ip: "213.203.134.10", port: 41258}, {ip: "217.61.172.12", port: 41369}, {ip: "46.232.143.126", port: 41258}, {ip: "46.232.143.253", port: 41258}, {ip: "93.67.154.125", port: 8080}, {ip: "93.67.154.125", port: 80}, {ip: "95.169.95.242", port: 53803}], - "TH" => [{ip: "1.10.184.166", port: 57330}, {ip: "1.10.186.100", port: 55011}, {ip: "1.10.186.209", port: 32431}, {ip: "1.10.186.245", port: 34360}, {ip: "1.10.186.93", port: 53711}, {ip: "1.10.187.118", port: 62000}, {ip: "1.10.187.34", port: 51635}, {ip: "1.10.187.43", port: 38715}, {ip: "1.10.188.181", port: 51093}, {ip: "1.10.188.83", port: 31940}, {ip: "1.10.188.95", port: 30593}, {ip: "1.10.189.58", port: 48564}, {ip: "1.179.157.237", port: 46178}, {ip: "1.179.164.213", port: 8080}, {ip: "1.179.198.37", port: 8080}, {ip: "1.20.100.99", port: 53794}, {ip: "1.20.101.221", port: 55707}, {ip: "1.20.101.254", port: 35394}, {ip: "1.20.101.80", port: 36234}, {ip: "1.20.102.133", port: 40296}, {ip: "1.20.103.13", port: 40544}, {ip: "1.20.103.56", port: 55422}, {ip: "1.20.96.234", port: 53142}, {ip: "1.20.97.54", port: 60122}, {ip: "1.20.99.63", port: 32123}, {ip: "101.108.92.20", port: 8080}, {ip: "101.109.143.71", port: 36127}, {ip: "101.51.141.110", port: 42860}, {ip: "101.51.141.60", port: 60417}, {ip: "103.246.17.237", port: 3128}, {ip: "110.164.73.131", port: 8080}, {ip: "110.164.87.80", port: 35844}, {ip: "110.77.134.106", port: 8080}, {ip: "113.53.29.92", port: 47297}, {ip: "113.53.83.192", port: 32780}, {ip: "113.53.83.195", port: 35686}, {ip: "113.53.91.214", port: 8080}, {ip: "115.87.27.0", port: 53276}, {ip: "118.172.211.3", port: 58535}, {ip: "118.172.211.40", port: 30430}, {ip: "118.174.196.174", port: 23500}, {ip: "118.174.196.203", port: 23500}, {ip: "118.174.220.107", port: 41222}, {ip: "118.174.220.110", port: 39025}, {ip: "118.174.220.115", port: 41011}, {ip: "118.174.220.118", port: 59556}, {ip: "118.174.220.136", port: 55041}, {ip: "118.174.220.163", port: 31561}, {ip: "118.174.220.168", port: 47455}, {ip: "118.174.220.231", port: 40924}, {ip: "118.174.220.238", port: 46326}, {ip: "118.174.234.13", port: 53084}, {ip: "118.174.234.26", port: 41926}, {ip: "118.174.234.32", port: 57403}, {ip: "118.174.234.59", port: 59149}, {ip: "118.174.234.68", port: 42626}, {ip: "118.174.234.83", port: 38006}, {ip: "118.175.207.104", port: 38959}, {ip: "118.175.244.111", port: 8080}, {ip: "118.175.93.207", port: 50738}, {ip: "122.154.38.53", port: 8080}, {ip: "122.154.59.6", port: 8080}, {ip: "122.154.72.102", port: 8080}, {ip: "122.155.222.98", port: 3128}, {ip: "124.121.22.121", port: 61699}, {ip: "125.24.156.16", port: 44321}, {ip: "125.25.165.105", port: 33850}, {ip: "125.25.165.111", port: 40808}, {ip: "125.25.165.42", port: 47221}, {ip: "125.25.201.14", port: 30100}, {ip: "125.26.99.135", port: 55637}, {ip: "125.26.99.141", port: 38537}, {ip: "125.26.99.148", port: 31818}, {ip: "134.236.247.137", port: 8080}, {ip: "159.192.98.224", port: 3128}, {ip: "171.100.2.154", port: 8080}, {ip: "171.100.9.126", port: 49163}, {ip: "180.180.156.116", port: 48431}, {ip: "180.180.156.46", port: 48507}, {ip: "180.180.156.87", port: 36628}, {ip: "180.180.218.204", port: 51565}, {ip: "180.180.8.34", port: 8080}, {ip: "182.52.238.125", port: 58861}, {ip: "182.52.74.73", port: 36286}, {ip: "182.52.74.76", port: 34084}, {ip: "182.52.74.77", port: 34825}, {ip: "182.52.74.78", port: 48708}, {ip: "182.52.90.45", port: 53799}, {ip: "182.53.206.155", port: 34307}, {ip: "182.53.206.43", port: 45330}, {ip: "182.53.206.49", port: 54228}, {ip: "183.88.212.141", port: 8080}, {ip: "183.88.212.184", port: 8080}, {ip: "183.88.213.85", port: 8080}, {ip: "183.88.214.47", port: 8080}, {ip: "184.82.128.211", port: 8080}, {ip: "202.183.201.13", port: 8081}, {ip: "202.29.20.151", port: 43083}, {ip: "203.150.172.151", port: 8080}, {ip: "27.131.157.94", port: 8080}, {ip: "27.145.100.22", port: 8080}, {ip: "27.145.100.243", port: 8080}, {ip: "49.231.196.114", port: 53281}, {ip: "58.97.72.83", port: 8080}, {ip: "61.19.145.66", port: 8080}], - "ES" => [{ip: "185.198.184.14", port: 48122}, {ip: "185.26.226.241", port: 36012}, {ip: "194.224.188.82", port: 3128}, {ip: "195.235.68.61", port: 3128}, {ip: "195.53.237.122", port: 3128}, {ip: "195.53.86.82", port: 3128}, {ip: "213.96.245.47", port: 8080}, {ip: "217.125.71.214", port: 33950}, {ip: "62.14.178.72", port: 53281}, {ip: "80.35.254.42", port: 53281}, {ip: "81.33.4.214", port: 61711}, {ip: "83.175.238.170", port: 53281}, {ip: "85.217.137.77", port: 3128}, {ip: "90.170.205.178", port: 33680}, {ip: "93.156.177.91", port: 53281}, {ip: "95.60.152.139", port: 37995}], - "AE" => [{ip: "178.32.5.90", port: 36159}], - "KR" => [{ip: "112.217.219.179", port: 3128}, {ip: "114.141.229.2", port: 58115}, {ip: "121.139.218.165", port: 31409}, {ip: "122.49.112.2", port: 38592}, {ip: "61.42.18.132", port: 53281}], - "BR" => [{ip: "128.201.97.157", port: 53281}, {ip: "128.201.97.158", port: 53281}, {ip: "131.0.246.157", port: 35252}, {ip: "131.161.26.90", port: 8080}, {ip: "131.72.143.100", port: 41396}, {ip: "138.0.24.66", port: 53281}, {ip: "138.121.130.50", port: 50600}, {ip: "138.121.155.127", port: 61932}, {ip: "138.121.32.133", port: 23492}, {ip: "138.185.176.63", port: 53281}, {ip: "138.204.233.190", port: 53281}, {ip: "138.204.233.242", port: 53281}, {ip: "138.219.71.74", port: 52688}, {ip: "138.36.107.24", port: 41184}, {ip: "138.94.115.166", port: 8080}, {ip: "143.0.188.161", port: 53281}, {ip: "143.202.218.135", port: 8080}, {ip: "143.208.2.42", port: 53281}, {ip: "143.208.79.223", port: 8080}, {ip: "143.255.52.102", port: 40687}, {ip: "143.255.52.116", port: 57856}, {ip: "143.255.52.117", port: 37279}, {ip: "144.217.22.128", port: 8080}, {ip: "168.0.8.225", port: 8080}, {ip: "168.0.8.55", port: 8080}, {ip: "168.121.139.54", port: 40056}, {ip: "168.181.168.23", port: 53281}, {ip: "168.181.170.198", port: 31935}, {ip: "168.232.198.25", port: 32009}, {ip: "168.232.198.35", port: 42267}, {ip: "168.232.207.145", port: 46342}, {ip: "170.0.104.107", port: 60337}, {ip: "170.0.112.2", port: 50359}, {ip: "170.0.112.229", port: 50359}, {ip: "170.238.118.107", port: 34314}, {ip: "170.239.144.9", port: 3128}, {ip: "170.247.29.138", port: 8080}, {ip: "170.81.237.36", port: 37124}, {ip: "170.84.51.74", port: 53281}, {ip: "170.84.60.222", port: 42981}, {ip: "177.10.202.67", port: 8080}, {ip: "177.101.60.86", port: 80}, {ip: "177.103.231.211", port: 55091}, {ip: "177.12.80.50", port: 50556}, {ip: "177.131.13.9", port: 20183}, {ip: "177.135.178.115", port: 42510}, {ip: "177.135.248.75", port: 20183}, {ip: "177.184.206.238", port: 39508}, {ip: "177.185.148.46", port: 58623}, {ip: "177.200.83.238", port: 8080}, {ip: "177.21.24.146", port: 666}, {ip: "177.220.188.120", port: 47556}, {ip: "177.220.188.213", port: 8080}, {ip: "177.222.229.243", port: 23500}, {ip: "177.234.161.42", port: 8080}, {ip: "177.36.11.241", port: 3128}, {ip: "177.36.12.193", port: 23500}, {ip: "177.37.199.175", port: 49608}, {ip: "177.39.187.70", port: 37315}, {ip: "177.44.175.199", port: 8080}, {ip: "177.46.148.126", port: 3128}, {ip: "177.46.148.142", port: 3128}, {ip: "177.47.194.98", port: 21231}, {ip: "177.5.98.58", port: 20183}, {ip: "177.52.55.19", port: 60901}, {ip: "177.54.200.66", port: 57526}, {ip: "177.55.255.74", port: 37147}, {ip: "177.67.217.94", port: 53281}, {ip: "177.73.248.6", port: 54381}, {ip: "177.73.4.234", port: 23500}, {ip: "177.75.143.211", port: 35955}, {ip: "177.75.161.206", port: 3128}, {ip: "177.75.86.49", port: 20183}, {ip: "177.8.216.106", port: 8080}, {ip: "177.8.216.114", port: 8080}, {ip: "177.8.37.247", port: 56052}, {ip: "177.84.216.17", port: 50569}, {ip: "177.85.200.254", port: 53095}, {ip: "177.87.169.1", port: 53281}, {ip: "179.107.97.178", port: 3128}, {ip: "179.109.144.25", port: 8080}, {ip: "179.109.193.137", port: 53281}, {ip: "179.189.125.206", port: 8080}, {ip: "179.97.30.46", port: 53100}, {ip: "186.192.195.220", port: 38983}, {ip: "186.193.11.226", port: 48999}, {ip: "186.193.26.106", port: 3128}, {ip: "186.208.220.248", port: 3128}, {ip: "186.209.243.142", port: 3128}, {ip: "186.209.243.233", port: 3128}, {ip: "186.211.106.227", port: 34334}, {ip: "186.211.160.178", port: 36756}, {ip: "186.215.133.170", port: 20183}, {ip: "186.216.81.21", port: 31773}, {ip: "186.219.214.13", port: 32708}, {ip: "186.224.94.6", port: 48957}, {ip: "186.225.97.246", port: 43082}, {ip: "186.226.171.163", port: 48698}, {ip: "186.226.179.2", port: 56089}, {ip: "186.226.234.67", port: 33834}, {ip: "186.228.147.58", port: 20183}, {ip: "186.233.97.163", port: 8888}, {ip: "186.248.170.82", port: 53281}, {ip: "186.249.213.101", port: 53482}, {ip: "186.249.213.65", port: 52018}, {ip: "186.250.213.225", port: 60774}, {ip: "186.250.96.70", port: 8080}, {ip: "186.250.96.77", port: 8080}, {ip: "187.1.43.246", port: 53396}, {ip: "187.108.36.250", port: 20183}, {ip: "187.108.38.10", port: 20183}, {ip: "187.109.36.251", port: 20183}, {ip: "187.109.40.9", port: 20183}, {ip: "187.109.56.101", port: 20183}, {ip: "187.111.90.89", port: 53281}, {ip: "187.115.10.50", port: 20183}, {ip: "187.19.62.7", port: 59010}, {ip: "187.33.79.61", port: 33469}, {ip: "187.35.158.150", port: 38872}, {ip: "187.44.1.167", port: 8080}, {ip: "187.45.127.87", port: 20183}, {ip: "187.45.156.109", port: 8080}, {ip: "187.5.218.215", port: 20183}, {ip: "187.58.65.225", port: 3128}, {ip: "187.63.111.37", port: 3128}, {ip: "187.72.166.10", port: 8080}, {ip: "187.73.68.14", port: 53281}, {ip: "187.84.177.6", port: 45903}, {ip: "187.84.191.170", port: 43936}, {ip: "187.87.204.210", port: 45597}, {ip: "187.87.39.247", port: 31793}, {ip: "189.1.16.162", port: 23500}, {ip: "189.113.124.162", port: 8080}, {ip: "189.124.195.185", port: 37318}, {ip: "189.3.196.18", port: 61595}, {ip: "189.37.33.59", port: 35532}, {ip: "189.7.49.66", port: 42700}, {ip: "189.90.194.35", port: 30843}, {ip: "189.90.248.75", port: 8080}, {ip: "189.91.231.43", port: 3128}, {ip: "191.239.243.156", port: 3128}, {ip: "191.240.154.246", port: 23500}, {ip: "191.240.156.154", port: 36127}, {ip: "191.240.99.142", port: 9090}, {ip: "191.241.226.230", port: 53281}, {ip: "191.241.228.74", port: 20183}, {ip: "191.241.228.78", port: 20183}, {ip: "191.241.33.238", port: 39188}, {ip: "191.241.36.170", port: 8080}, {ip: "191.241.36.218", port: 3128}, {ip: "191.242.182.132", port: 8081}, {ip: "191.243.221.130", port: 3128}, {ip: "191.255.207.231", port: 20183}, {ip: "191.36.192.196", port: 3128}, {ip: "191.36.244.230", port: 51377}, {ip: "191.5.0.79", port: 53281}, {ip: "191.6.228.6", port: 53281}, {ip: "191.7.193.18", port: 38133}, {ip: "191.7.20.134", port: 3128}, {ip: "192.140.91.173", port: 20183}, {ip: "200.150.86.138", port: 44677}, {ip: "200.155.36.185", port: 3128}, {ip: "200.155.36.188", port: 3128}, {ip: "200.155.39.41", port: 3128}, {ip: "200.174.158.26", port: 34112}, {ip: "200.187.177.105", port: 20183}, {ip: "200.187.87.138", port: 20183}, {ip: "200.192.252.201", port: 8080}, {ip: "200.192.255.102", port: 8080}, {ip: "200.203.144.2", port: 50262}, {ip: "200.229.238.42", port: 20183}, {ip: "200.233.134.85", port: 43172}, {ip: "200.233.136.177", port: 20183}, {ip: "200.241.44.3", port: 20183}, {ip: "200.255.122.170", port: 8080}, {ip: "200.255.122.174", port: 8080}, {ip: "201.12.21.57", port: 8080}, {ip: "201.131.224.21", port: 56200}, {ip: "201.182.223.16", port: 37492}, {ip: "201.20.89.126", port: 8080}, {ip: "201.22.95.10", port: 8080}, {ip: "201.57.167.34", port: 8080}, {ip: "201.59.200.246", port: 80}, {ip: "201.6.167.178", port: 3128}, {ip: "201.90.36.194", port: 3128}, {ip: "45.226.20.6", port: 8080}, {ip: "45.234.139.129", port: 20183}, {ip: "45.234.200.18", port: 53281}, {ip: "45.235.87.4", port: 51996}, {ip: "45.6.136.38", port: 53281}, {ip: "45.6.80.131", port: 52080}, {ip: "45.6.93.10", port: 8080}, {ip: "45.71.108.162", port: 53281}], - "PK" => [{ip: "103.18.243.154", port: 8080}, {ip: "110.36.218.126", port: 36651}, {ip: "110.36.234.210", port: 8080}, {ip: "110.39.162.74", port: 53281}, {ip: "110.39.174.58", port: 8080}, {ip: "111.68.108.34", port: 8080}, {ip: "125.209.116.182", port: 31653}, {ip: "125.209.78.21", port: 8080}, {ip: "125.209.82.78", port: 35087}, {ip: "180.92.156.150", port: 8080}, {ip: "202.142.158.114", port: 8080}, {ip: "202.147.173.10", port: 8080}, {ip: "202.147.173.10", port: 80}, {ip: "202.69.38.82", port: 8080}, {ip: "203.128.16.126", port: 59538}, {ip: "203.128.16.154", port: 33002}, {ip: "27.255.4.170", port: 8080}], - "ID" => [{ip: "101.128.68.113", port: 8080}, {ip: "101.255.116.113", port: 53281}, {ip: "101.255.120.170", port: 6969}, {ip: "101.255.121.74", port: 8080}, {ip: "101.255.124.242", port: 8080}, {ip: "101.255.124.242", port: 80}, {ip: "101.255.56.138", port: 53560}, {ip: "103.10.171.132", port: 41043}, {ip: "103.10.81.172", port: 80}, {ip: "103.108.158.3", port: 48196}, {ip: "103.111.219.159", port: 53281}, {ip: "103.111.54.26", port: 49781}, {ip: "103.111.54.74", port: 8080}, {ip: "103.19.110.177", port: 8080}, {ip: "103.2.146.66", port: 49089}, {ip: "103.206.168.177", port: 53281}, {ip: "103.206.253.58", port: 49573}, {ip: "103.21.92.254", port: 33929}, {ip: "103.226.49.83", port: 23500}, {ip: "103.227.147.142", port: 37581}, {ip: "103.23.101.58", port: 8080}, {ip: "103.24.107.2", port: 8181}, {ip: "103.245.19.222", port: 53281}, {ip: "103.247.122.38", port: 8080}, {ip: "103.247.218.166", port: 3128}, {ip: "103.248.219.26", port: 53634}, {ip: "103.253.2.165", port: 33543}, {ip: "103.253.2.168", port: 51229}, {ip: "103.253.2.174", port: 30827}, {ip: "103.28.114.134", port: 8080}, {ip: "103.28.220.73", port: 53281}, {ip: "103.30.246.47", port: 3128}, {ip: "103.31.45.169", port: 57655}, {ip: "103.41.122.14", port: 53281}, {ip: "103.75.101.97", port: 8080}, {ip: "103.76.17.151", port: 23500}, {ip: "103.76.50.181", port: 8080}, {ip: "103.76.50.181", port: 80}, {ip: "103.76.50.182", port: 8080}, {ip: "103.78.74.170", port: 3128}, {ip: "103.78.80.194", port: 33442}, {ip: "103.8.122.5", port: 53297}, {ip: "103.80.236.107", port: 53281}, {ip: "103.80.238.203", port: 53281}, {ip: "103.86.140.74", port: 59538}, {ip: "103.94.122.254", port: 8080}, {ip: "103.94.125.244", port: 41508}, {ip: "103.94.169.19", port: 8080}, {ip: "103.94.7.254", port: 53281}, {ip: "106.0.51.50", port: 17385}, {ip: "110.93.13.202", port: 34881}, {ip: "112.78.37.6", port: 54791}, {ip: "114.199.110.58", port: 55898}, {ip: "114.199.112.170", port: 23500}, {ip: "114.199.123.194", port: 8080}, {ip: "114.57.33.162", port: 46935}, {ip: "114.57.33.214", port: 8080}, {ip: "114.6.197.254", port: 8080}, {ip: "114.7.15.146", port: 8080}, {ip: "114.7.162.254", port: 53281}, {ip: "115.124.75.226", port: 53990}, {ip: "115.124.75.228", port: 3128}, {ip: "117.102.78.42", port: 8080}, {ip: "117.102.93.251", port: 8080}, {ip: "117.102.94.186", port: 8080}, {ip: "117.102.94.186", port: 80}, {ip: "117.103.2.249", port: 58276}, {ip: "117.54.13.174", port: 34190}, {ip: "117.74.124.129", port: 8088}, {ip: "118.97.100.83", port: 35220}, {ip: "118.97.191.162", port: 80}, {ip: "118.97.191.203", port: 8080}, {ip: "118.97.36.18", port: 8080}, {ip: "118.97.73.85", port: 53281}, {ip: "118.99.105.226", port: 8080}, {ip: "119.252.168.53", port: 53281}, {ip: "122.248.45.35", port: 53281}, {ip: "122.50.6.186", port: 8080}, {ip: "122.50.6.186", port: 80}, {ip: "123.231.226.114", port: 47562}, {ip: "123.255.202.83", port: 32523}, {ip: "124.158.164.195", port: 8080}, {ip: "124.81.99.30", port: 3128}, {ip: "137.59.162.10", port: 3128}, {ip: "139.0.29.20", port: 59532}, {ip: "139.255.123.194", port: 4550}, {ip: "139.255.16.171", port: 31773}, {ip: "139.255.17.2", port: 47421}, {ip: "139.255.19.162", port: 42371}, {ip: "139.255.7.81", port: 53281}, {ip: "139.255.91.115", port: 8080}, {ip: "139.255.92.26", port: 53281}, {ip: "158.140.181.140", port: 54041}, {ip: "160.202.40.20", port: 55655}, {ip: "175.103.42.147", port: 8080}, {ip: "180.178.98.198", port: 8080}, {ip: "180.250.101.146", port: 8080}, {ip: "182.23.107.212", port: 3128}, {ip: "182.23.2.101", port: 49833}, {ip: "182.23.7.226", port: 8080}, {ip: "182.253.209.203", port: 3128}, {ip: "183.91.66.210", port: 80}, {ip: "202.137.10.179", port: 57338}, {ip: "202.137.25.53", port: 3128}, {ip: "202.137.25.8", port: 8080}, {ip: "202.138.242.76", port: 4550}, {ip: "202.138.249.202", port: 43108}, {ip: "202.148.2.254", port: 8000}, {ip: "202.162.201.94", port: 53281}, {ip: "202.165.47.26", port: 8080}, {ip: "202.43.167.130", port: 8080}, {ip: "202.51.126.10", port: 53281}, {ip: "202.59.171.164", port: 58567}, {ip: "202.93.128.98", port: 3128}, {ip: "203.142.72.114", port: 808}, {ip: "203.153.117.65", port: 54144}, {ip: "203.189.89.1", port: 53281}, {ip: "203.77.239.18", port: 37002}, {ip: "203.99.123.25", port: 61502}, {ip: "220.247.168.163", port: 53281}, {ip: "220.247.173.154", port: 53281}, {ip: "220.247.174.206", port: 53445}, {ip: "222.124.131.211", port: 47343}, {ip: "222.124.173.146", port: 53281}, {ip: "222.124.2.131", port: 8080}, {ip: "222.124.2.186", port: 8080}, {ip: "222.124.215.187", port: 38913}, {ip: "222.124.221.179", port: 53281}, {ip: "223.25.101.242", port: 59504}, {ip: "223.25.97.62", port: 8080}, {ip: "223.25.99.38", port: 80}, {ip: "27.111.44.202", port: 80}, {ip: "27.111.47.3", port: 51144}, {ip: "36.37.124.234", port: 36179}, {ip: "36.37.124.235", port: 36179}, {ip: "36.37.81.135", port: 8080}, {ip: "36.37.89.98", port: 32323}, {ip: "36.66.217.179", port: 8080}, {ip: "36.66.98.6", port: 53281}, {ip: "36.67.143.183", port: 48746}, {ip: "36.67.206.187", port: 8080}, {ip: "36.67.32.87", port: 8080}, {ip: "36.67.93.220", port: 3128}, {ip: "36.67.93.220", port: 80}, {ip: "36.89.10.51", port: 34115}, {ip: "36.89.119.149", port: 8080}, {ip: "36.89.157.23", port: 37728}, {ip: "36.89.181.155", port: 60165}, {ip: "36.89.188.11", port: 39507}, {ip: "36.89.194.113", port: 37811}, {ip: "36.89.226.254", port: 8081}, {ip: "36.89.232.138", port: 23500}, {ip: "36.89.39.10", port: 3128}, {ip: "36.89.65.253", port: 60997}, {ip: "43.243.141.114", port: 8080}, {ip: "43.245.184.202", port: 41102}, {ip: "43.245.184.238", port: 80}, {ip: "66.96.233.225", port: 35053}, {ip: "66.96.237.253", port: 8080}], - "BD" => [{ip: "103.103.88.91", port: 8080}, {ip: "103.106.119.154", port: 8080}, {ip: "103.106.236.1", port: 8080}, {ip: "103.106.236.41", port: 8080}, {ip: "103.108.144.139", port: 53281}, {ip: "103.109.57.218", port: 8080}, {ip: "103.109.58.242", port: 8080}, {ip: "103.112.129.106", port: 31094}, {ip: "103.112.129.82", port: 53281}, {ip: "103.114.10.177", port: 8080}, {ip: "103.114.10.250", port: 8080}, {ip: "103.15.245.26", port: 8080}, {ip: "103.195.204.73", port: 21776}, {ip: "103.197.49.106", port: 49688}, {ip: "103.198.168.29", port: 21776}, {ip: "103.214.200.6", port: 59008}, {ip: "103.218.25.161", port: 8080}, {ip: "103.218.25.41", port: 8080}, {ip: "103.218.26.204", port: 8080}, {ip: "103.218.27.221", port: 8080}, {ip: "103.231.229.90", port: 53281}, {ip: "103.239.252.233", port: 8080}, {ip: "103.239.252.50", port: 8080}, {ip: "103.239.253.193", port: 8080}, {ip: "103.250.68.193", port: 51370}, {ip: "103.5.232.146", port: 8080}, {ip: "103.73.224.53", port: 23500}, {ip: "103.9.134.73", port: 65301}, {ip: "113.11.47.242", port: 40071}, {ip: "113.11.5.67", port: 40071}, {ip: "114.31.5.34", port: 52606}, {ip: "115.127.51.226", port: 42764}, {ip: "115.127.64.62", port: 39611}, {ip: "115.127.91.106", port: 8080}, {ip: "119.40.85.198", port: 36899}, {ip: "123.200.29.110", port: 23500}, {ip: "123.49.51.42", port: 55124}, {ip: "163.47.36.90", port: 3128}, {ip: "180.211.134.158", port: 23500}, {ip: "180.211.193.74", port: 40536}, {ip: "180.92.238.226", port: 53451}, {ip: "182.160.104.213", port: 8080}, {ip: "202.191.126.58", port: 23500}, {ip: "202.4.126.170", port: 8080}, {ip: "202.5.37.241", port: 33623}, {ip: "202.5.57.5", port: 61729}, {ip: "202.79.17.65", port: 60122}, {ip: "203.188.248.52", port: 23500}, {ip: "27.147.146.78", port: 52220}, {ip: "27.147.164.10", port: 52344}, {ip: "27.147.212.38", port: 53281}, {ip: "27.147.217.154", port: 43252}, {ip: "27.147.219.102", port: 49464}, {ip: "43.239.74.137", port: 8080}, {ip: "43.240.103.252", port: 8080}, {ip: "45.125.223.57", port: 8080}, {ip: "45.125.223.81", port: 8080}, {ip: "45.251.228.122", port: 41418}, {ip: "45.64.132.137", port: 8080}, {ip: "45.64.132.137", port: 80}, {ip: "61.247.186.137", port: 8080}], - "MX" => [{ip: "148.217.94.54", port: 3128}, {ip: "177.244.28.77", port: 53281}, {ip: "187.141.73.147", port: 53281}, {ip: "187.185.15.35", port: 53281}, {ip: "187.188.46.172", port: 53455}, {ip: "187.216.83.185", port: 8080}, {ip: "187.216.90.46", port: 53281}, {ip: "187.243.253.182", port: 33796}, {ip: "189.195.132.86", port: 43286}, {ip: "189.204.158.161", port: 8080}, {ip: "200.79.180.115", port: 8080}, {ip: "201.140.113.90", port: 37193}, {ip: "201.144.14.229", port: 53281}, {ip: "201.163.73.93", port: 53281}], - "PH" => [{ip: "103.86.187.242", port: 23500}, {ip: "122.54.101.69", port: 8080}, {ip: "122.54.65.150", port: 8080}, {ip: "125.5.20.134", port: 53281}, {ip: "146.88.77.51", port: 8080}, {ip: "182.18.200.92", port: 8080}, {ip: "219.90.87.91", port: 53281}, {ip: "58.69.12.210", port: 8080}], - "EG" => [{ip: "41.65.0.167", port: 8080}], - "VN" => [{ip: "1.55.240.156", port: 53281}, {ip: "101.99.23.136", port: 3128}, {ip: "103.15.51.160", port: 8080}, {ip: "113.161.128.169", port: 60427}, {ip: "113.161.161.143", port: 57967}, {ip: "113.161.173.10", port: 3128}, {ip: "113.161.35.108", port: 30028}, {ip: "113.164.79.177", port: 46281}, {ip: "113.190.235.50", port: 34619}, {ip: "115.78.160.247", port: 8080}, {ip: "117.2.155.29", port: 47228}, {ip: "117.2.17.26", port: 53281}, {ip: "117.2.22.41", port: 41973}, {ip: "117.4.145.16", port: 51487}, {ip: "118.69.219.185", port: 55184}, {ip: "118.69.61.212", port: 53281}, {ip: "118.70.116.227", port: 61651}, {ip: "118.70.219.124", port: 53281}, {ip: "221.121.12.238", port: 36077}, {ip: "27.2.7.59", port: 52148}], - "CD" => [{ip: "41.79.233.45", port: 8080}], - "TR" => [{ip: "151.80.65.175", port: 3128}, {ip: "176.235.186.242", port: 37043}, {ip: "178.250.92.18", port: 8080}, {ip: "185.203.170.92", port: 8080}, {ip: "185.203.170.94", port: 8080}, {ip: "185.203.170.95", port: 8080}, {ip: "185.51.36.152", port: 41258}, {ip: "195.137.223.50", port: 41336}, {ip: "195.155.98.70", port: 52598}, {ip: "212.156.146.22", port: 40080}, {ip: "213.14.31.122", port: 44621}, {ip: "31.145.137.139", port: 31871}, {ip: "31.145.138.129", port: 31871}, {ip: "31.145.138.146", port: 34159}, {ip: "31.145.187.172", port: 30636}, {ip: "78.188.4.124", port: 34514}, {ip: "88.248.23.216", port: 36426}, {ip: "93.182.72.36", port: 8080}, {ip: "95.0.194.241", port: 9090}], -} diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr index 9e0631f6..8235898f 100644 --- a/src/invidious/yt_backend/youtube_api.cr +++ b/src/invidious/yt_backend/youtube_api.cr @@ -188,10 +188,6 @@ module YoutubeAPI # conf_2 = ClientConfig.new(client_type: ClientType::Android) # YoutubeAPI::player(video_id: "dQw4w9WgXcQ", client_config: conf_2) # - # # Proxy request through russian proxies - # conf_3 = ClientConfig.new(proxy_region: "RU") - # YoutubeAPI::next({video_id: "dQw4w9WgXcQ"}, client_config: conf_3) - # ``` # struct ClientConfig # Type of client to emulate. @@ -202,16 +198,11 @@ module YoutubeAPI # (this is passed as the `gl` parameter). property region : String | Nil - # ISO code of country where the proxy is located. - # Used in case of geo-restricted videos. - property proxy_region : String | Nil - # Initialization function def initialize( *, @client_type = ClientType::Web, - @region = "US", - @proxy_region = nil + @region = "US" ) end @@ -271,9 +262,8 @@ module YoutubeAPI # Convert to string, for logging purposes def to_s return { - client_type: self.name, - region: @region, - proxy_region: @proxy_region, + client_type: self.name, + region: @region, }.to_s end end @@ -620,7 +610,7 @@ module YoutubeAPI LOGGER.trace("YoutubeAPI: POST data: #{data}") # Send the POST request - body = YT_POOL.client(client_config.proxy_region) do |client| + body = YT_POOL.client() do |client| client.post(url, headers: headers, body: data.to_json) do |response| self._decompress(response.body_io, response.headers["Content-Encoding"]?) end |
