Merge branch 'master' into api-only

This commit is contained in:
Omar Roth 2019-03-29 16:34:19 -05:00
commit 3d76898bb9
21 changed files with 483 additions and 451 deletions

View File

@ -10,7 +10,7 @@
"newest": "الأجدد",
"oldest": "الأقدم",
"popular": "الاكثر شعبية",
"last": "",
"last": "اخر الفيديوهات المعدلة",
"Next page": "الصفحة الثانية",
"Previous page": "الصفحة السابقة",
"Clear watch history?": "مسح السجل ؟",
@ -50,7 +50,7 @@
"Autoplay: ": "تشغيل تلقائى: ",
"Autoplay next video: ": "شغل الفيديو التالى تلقائى: ",
"Listen by default: ": "تشغيل النسخة السمعية تلقائى: ",
"Proxy videos? ": "",
"Proxy videos? ": "عرض الفيديوهات عن طريق الوكيل(proxy) ؟",
"Default speed: ": "السرعة الإفتراضية: ",
"Preferred video quality: ": "الجودة المفضلة للفيديوهات: ",
"Player volume: ": "صوت المشغل: ",
@ -83,14 +83,14 @@
"Manage subscriptions": "إدارة المشتركين",
"Watch history": "سجل المشاهدة",
"Delete account": "حذف الحساب",
"Administrator preferences": "",
"Default homepage: ": "",
"Feed menu: ": "",
"Top enabled? ": "",
"CAPTCHA enabled? ": "",
"Login enabled? ": "",
"Registration enabled? ": "",
"Report statistics? ": "",
"Administrator preferences": "إعدادات المدير",
"Default homepage: ": "الصفحة الرئيسية الافتراضية ",
"Feed menu: ": "قائمة التغذية",
"Top enabled? ": "تفعيل 'الأفضل' ؟ ",
"CAPTCHA enabled? ": "تفعيل الكابتشا ؟",
"Login enabled? ": "تفعيل تسجيل الدخول ؟",
"Registration enabled? ": "تفعيل التسجيل ؟",
"Report statistics? ": "إبلاغ الإحصائيات",
"Save preferences": "حفظ التفضيلات",
"Subscription manager": "مدير الإشتراكات",
"`x` subscriptions": "`x` مشتركين",
@ -103,8 +103,9 @@
"Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.",
"Source available here.": "الأكواد متوفرة هنا.",
"View JavaScript license information.": "مشاهدة معلومات حول تراخيص الجافاسكريبت.",
"View privacy policy.": "",
"View privacy policy.": "عرض سياسة الخصوصية",
"Trending": "الشائع",
"Unlisted": "غير مصنف",
"Watch video on Youtube": "مشاهدة الفيديو على اليوتيوب",
"Genre: ": "النوع: ",
"License: ": "التراخيص: ",
@ -114,6 +115,7 @@
"Whitelisted regions: ": "الدول المسموح فيها هذا الفيديو: ",
"Blacklisted regions: ": "الدول الحظور فيها هذا الفيديو: ",
"Shared `x`": "شارك منذ `x`",
"Premieres in `x`": "يعرض فى 'x'",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "اهلا! يبدو ان الجافاسكريبت معطلة. اضغط هنا لعرض التعليقات, ضع فى إعتبارك انها ستأخذ وقت اطول للعرض.",
"View YouTube comments": "عرض تعليقات اليوتيوب",
"View more comments on Reddit": "عرض المزيد من التعليقات على\\من موقع Reddit",

View File

@ -105,6 +105,7 @@
"View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.",
"View privacy policy.": "",
"Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Video auf YouTube ansehen",
"Genre: ": "Genre: ",
"License: ": "Lizenz: ",
@ -114,6 +115,7 @@
"Whitelisted regions: ": "Erlaubte Regionen: ",
"Blacklisted regions: ": "Unerlaubte Regionen: ",
"Shared `x`": "Geteilt `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Hallo! Anscheinend haben Sie JavaScript deaktiviert. Klicken Sie hier um Kommentare anzuzeigen, beachten sie dass es etwas länger dauern kann um sie zu laden.",
"View YouTube comments": "YouTube Kommentare anzeigen",
"View more comments on Reddit": "Mehr Kommentare auf Reddit anzeigen",

View File

@ -103,6 +103,7 @@
"View JavaScript license information.": "View JavaScript license information.",
"View privacy policy.": "View privacy policy.",
"Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Watch video on Youtube",
"Genre: ": "Genre: ",
"License: ": "License: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Whitelisted regions: ",
"Blacklisted regions: ": "Blacklisted regions: ",
"Shared `x`": "Shared `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.",
"View YouTube comments": "View YouTube comments",
"View more comments on Reddit": "View more comments on Reddit",

View File

@ -102,6 +102,7 @@
"Source available here.": "",
"View JavaScript license information.": "",
"View privacy policy.": "",
"Unlisted": "",
"Trending": "",
"Watch video on Youtube": "",
"Genre: ": "",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "",
"Blacklisted regions: ": "",
"Shared `x`": "",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "",
"View YouTube comments": "",
"View more comments on Reddit": "",

View File

@ -2,7 +2,7 @@
"`x` subscribers": "`x` abonnés",
"`x` videos": "`x` vidéos",
"LIVE": "EN DIRECT",
"Shared `x` ago": "Partagé il y a `x`",
"Shared `x` ago": "Ajoutée il y a `x`",
"Unsubscribe": "Se désabonner",
"Subscribe": "S'abonner",
"Login to subscribe to `x`": "Vous devez vous connecter pour vous abonner à `x`",
@ -16,7 +16,7 @@
"Clear watch history?": "Êtes-vous sûr de vouloir supprimer l'historique des vidéos regardées ?",
"Yes": "Oui",
"No": "Non",
"Import and Export Data": "Importer et Exporter les Données",
"Import and Export Data": "Importer et exporter des données",
"Import": "Importer",
"Import Invidious data": "Importer des données Invidious",
"Import YouTube subscriptions": "Importer des abonnements YouTube",
@ -32,32 +32,32 @@
"An alternative front-end to YouTube": "Un front-end alternatif à YouTube",
"JavaScript license information": "Informations sur les licences JavaScript",
"source": "source",
"Login": "Connexion",
"Login/Register": "Connexion/S'inscrire",
"Login to Google": "Se connecter à Google",
"Login": "Se connecter",
"Login/Register": "Se connecter/Créer un compte",
"Login to Google": "Se connecter avec Google",
"User ID:": "Identifiant utilisateur :",
"Password:": "Mot de passe :",
"Time (h:mm:ss):": "Heure (h:mm:ss) :",
"Text CAPTCHA": "CAPTCHA Texte",
"Image CAPTCHA": "CAPTCHA Image",
"Sign In": "S'identifier",
"Sign In": "Se connecter",
"Register": "S'inscrire",
"Email:": "E-mail :",
"Google verification code:": "Code de vérification Google :",
"Preferences": "Préférences",
"Player preferences": "Préférences du Lecteur",
"Player preferences": "Préférences du lecteur",
"Always loop: ": "Lire en boucle : ",
"Autoplay: ": "Lire Automatiquement : ",
"Autoplay: ": "Lire automatiquement : ",
"Autoplay next video: ": "Lire automatiquement la vidéo suivante : ",
"Listen by default: ": "Audio Uniquement par défaut : ",
"Proxy videos? ": "Souhaitez vous charger les vidéos à travers un proxy ?",
"Listen by default: ": "Audio uniquement : ",
"Proxy videos? ": "Charger les vidéos à travers un proxy ? ",
"Default speed: ": "Vitesse par défaut : ",
"Preferred video quality: ": "Qualité vidéo souhaitée : ",
"Player volume: ": "Volume du lecteur : ",
"Default comments: ": "Source des Commentaires : ",
"Default captions: ": "Sous-titres principal : ",
"Fallback captions: ": "Sous-titres secondaire : ",
"Show related videos? ": "Voir les vidéos liées à ce sujet ? ",
"Default comments: ": "Source des commentaires : ",
"Default captions: ": "Sous-titres par défaut : ",
"Fallback captions: ": "Fallback captions: ",
"Show related videos? ": "Voir les vidéos liées ? ",
"Visual preferences": "Préférences du site",
"Dark mode: ": "Mode Sombre : ",
"Thin mode: ": "Mode Simplifié : ",
@ -82,13 +82,13 @@
"Watch history": "Historique de visionnage",
"Delete account": "Supprimer votre compte",
"Administrator preferences": "Préferences d'Administrateur",
"Default homepage: ": "Page d'accueil par defaut :",
"Feed menu: ": "Menu des Flux :",
"Top enabled? ": "Top activé ?",
"CAPTCHA enabled? ": "CAPTCHA activé ?",
"Login enabled? ": "Connexion activé ?",
"Registration enabled? ": "Inscription activé ?",
"Report statistics? ": "Telemetrie activé ?",
"Default homepage: ": "Page d'accueil par défaut : ",
"Feed menu: ": "Menu des Flux : ",
"Top enabled? ": "Top activé ? ",
"CAPTCHA enabled? ": "CAPTCHA activé ? ",
"Login enabled? ": "Connexion activé ? ",
"Registration enabled? ": "Inscription activée ? ",
"Report statistics? ": "Télémétrie activé ? ",
"Save preferences": "Enregistrer les préférences",
"Subscription manager": "Gestionnaire d'abonnement",
"`x` subscriptions": "`x` abonnements",
@ -103,16 +103,18 @@
"View JavaScript license information.": "Voir les informations des licences JavaScript.",
"View privacy policy.": "Politique de confidentialité",
"Trending": "Tendances",
"Unlisted": "Non répertoriée",
"Watch video on Youtube": "Voir la vidéo sur Youtube",
"Genre: ": "Genre : ",
"License: ": "Licence : ",
"Family friendly? ": "Tout Public ? ",
"Wilson score: ": "Score de Wilson : ",
"Engagement: ": "Poucentage de spectateur aillant aimé Liker ou Disliker la vidéo : ",
"Engagement: ": "Poucentage de spectateur aillant aimé Like ou Dislike la vidéo : ",
"Whitelisted regions: ": "Régions en liste blanche : ",
"Blacklisted regions: ": "Régions sur liste noire : ",
"Shared `x`": "Partagée `x`",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Il semblerait que JavaScript sois désactivé. Cliquez ici pour voir les commentaires. Gardez à l'esprit que le chargement peut prendre plus de temps.",
"Shared `x`": "Ajoutée le `x`",
"Premieres in `x`": "Première dans `x`",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Il semblerait que JavaScript soit désactivé. Cliquez ici pour voir les commentaires sans. Gardez à l'esprit que le chargement peut prendre plus de temps.",
"View YouTube comments": "Voir les commentaires YouTube",
"View more comments on Reddit": "Voir plus de commentaires sur Reddit",
"View `x` comments": "Voir `x` commentaires",
@ -124,13 +126,13 @@
"Unable to login, make sure two-factor authentication (Authenticator or SMS) is enabled.": "Si vous ne parvenez pas à vous connecter, assurez-vous que l'authentification à deux facteurs (Authenticator ou SMS) est activée.",
"Invalid TFA code": "Code d'authentification à deux facteurs invalide",
"Login failed. This may be because two-factor authentication is not enabled on your account.": "La connexion a échoué. Cela peut être dû au fait que l'authentification à deux facteurs n'est pas activée sur votre compte.",
"Invalid answer": "Réponse non valide",
"Invalid answer": "Réponse invalide",
"Invalid CAPTCHA": "CAPTCHA invalide",
"CAPTCHA is a required field": "Veuillez rentrez un CAPTCHA",
"User ID is a required field": "Veuillez rentrez un Identifiant Utilisateur",
"Password is a required field": "Veuillez rentrez un Mot de passe",
"CAPTCHA is a required field": "Veuillez entrer un CAPTCHA",
"User ID is a required field": "Veuillez entrer un Identifiant Utilisateur",
"Password is a required field": "Veuillez entrer un Mot de passe",
"Invalid username or password": "Nom d'utilisateur ou mot de passe invalide",
"Please sign in using 'Sign in with Google'": "Veuillez vous connecter en utilisant \"S'identifier avec Google\"",
"Please sign in using 'Sign in with Google'": "Veuillez vous connecter en utilisant \"Se connecter avec Google\"",
"Password cannot be empty": "Le mot de passe ne peut pas être vide",
"Password cannot be longer than 55 characters": "Le mot de passe ne doit pas comporter plus de 55 caractères",
"Please sign in": "Veuillez vous connecter",
@ -268,7 +270,7 @@
"`x` hours": "`x` heures",
"`x` minutes": "`x` minutes",
"`x` seconds": "`x` secondes",
"Fallback comments: ": "Commentaires secondaires : ",
"Fallback comments: ": "Fallback comments: ",
"Popular": "Populaire",
"Top": "Top",
"About": "A Propos",
@ -289,5 +291,5 @@
"Video mode": "Mode Vidéo",
"Videos": "Vidéos",
"Playlists": "Liste de lecture",
"Current version: ": "Version actuelle :"
"Current version: ": "Version :"
}

View File

@ -103,6 +103,7 @@
"View JavaScript license information.": "Guarda le informazioni di licenza del codice JavaScript.",
"View privacy policy.": "",
"Trending": "Tendenze",
"Unlisted": "",
"Watch video on Youtube": "Guarda il video su YouTube",
"Genre: ": "Genere: ",
"License: ": "Licenza: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Regioni nella lista bianca: ",
"Blacklisted regions: ": "Regioni nella lista nera: ",
"Shared `x`": "Condiviso `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Ciao! Sembra che tu abbia disattivato JavaScript. Clicca qui per visualizzare i commenti. Considera che potrebbe volerci più tempo.",
"View YouTube comments": "Visualizza i commenti da YouTube",
"View more comments on Reddit": "Visualizza più commenti su Reddit",

View File

@ -103,6 +103,7 @@
"View JavaScript license information.": "Vis JavaScript-lisensinfo.",
"View privacy policy.": "",
"Trending": "Trendsettende",
"Unlisted": "",
"Watch video on Youtube": "Vis video på YouTube",
"Genre: ": "Sjanger: ",
"License: ": "Lisens: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Hvitlistede regioner: ",
"Blacklisted regions: ": "Svartelistede regioner: ",
"Shared `x`": "Delt `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Hei. Det ser ut til at du har JavaScript avslått. Klikk her for å vise kommentarer, ha i minnet at innlasting tar lengre tid.",
"View YouTube comments": "Vis YouTube-kommentarer",
"View more comments on Reddit": "Vis flere kommenterer på Reddit",

View File

@ -103,6 +103,7 @@
"View JavaScript license information.": "Bekijk JavaScript licentie informatie.",
"View privacy policy.": "",
"Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Bekijk video op Youtube",
"Genre: ": "Genre: ",
"License: ": "Licentie: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Toegestane regio's: ",
"Blacklisted regions: ": "Geblokkeerde regio's: ",
"Shared `x`": "`x` gedeeld",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Hoi! Het lijkt erop dat je JavaScript uit hebt staan. Klik hier om de reacties te bekijken, hou er rekening mee dat het wat langer duurt om te laden.",
"View YouTube comments": "Bekijk YouTube reacties",
"View more comments on Reddit": "Bekijk meer reacties op Reddit",

View File

@ -10,7 +10,7 @@
"newest": "najnowsze",
"oldest": "najstarsze",
"popular": "popularne",
"last": "",
"last": "ostatnie",
"Next page": "Następna strona",
"Previous page": "Poprzednia strona",
"Clear watch history?": "Wyczyścić historię?",
@ -50,7 +50,7 @@
"Autoplay: ": "Autoodtwarzanie: ",
"Autoplay next video: ": "Odtwórz następny film: ",
"Listen by default: ": "Tryb dźwiękowy: ",
"Proxy videos? ": "",
"Proxy videos? ": "Filmy przez proxy? ",
"Default speed: ": "Domyślna prędkość: ",
"Preferred video quality: ": "Preferowana jakość filmów: ",
"Player volume: ": "Głośność odtwarzacza: ",
@ -101,8 +101,9 @@
"Released under the AGPLv3 by Omar Roth.": "Wydano na licencji AGPLv3 przez Omar Roth.",
"Source available here.": "Kod źródłowy dostępny tutaj.",
"View JavaScript license information.": "Wyświetl informację o licencji JavaScript.",
"View privacy policy.": "",
"View privacy policy.": "Polityka prywatności.",
"Trending": "Na czasie",
"Unlisted": "",
"Watch video on Youtube": "Zobacz film na YouTube",
"Genre: ": "Gatunek: ",
"License: ": "Licencja: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Dostępny na obszarach: ",
"Blacklisted regions: ": "Niedostępny na obszarach: ",
"Shared `x`": "Udostępniono `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Cześć! Wygląda na to, że masz wyłączoną obsługę JavaScriptu. Kliknij tutaj, żeby zobaczyć komentarze. Pamiętaj, że wczytywanie może potrwać dłużej.",
"View YouTube comments": "Wyświetl komentarze z YouTube",
"View more comments on Reddit": "Wyświetl więcej komentarzy na Reddicie",
@ -270,7 +272,7 @@
"`x` seconds": "`x` sekund",
"Fallback comments: ": "Zastępcze komentarze: ",
"Popular": "Popularne",
"Top": "Na czasie",
"Top": "Najczęściej oglądane",
"About": "Informacje",
"Rating: ": "Ocena: ",
"Language: ": "Język: ",

View File

@ -1,295 +1,297 @@
{
"`x` subscribers": "`x` подписчиков",
"`x` videos": "`x` видео",
"LIVE": "ПРЯМОЙ ЭФИР",
"Shared `x` ago": "Опубликовано `x` назад",
"Unsubscribe": "Отписаться",
"Subscribe": "Подписаться",
"Login to subscribe to `x`": "Войти, чтобы подписаться на `x`",
"View channel on YouTube": "Канал на YouTube",
"newest": "новые",
"oldest": "старые",
"popular": "популярные",
"last": "недавно обновленные",
"Next page": "Следующая страница",
"Previous page": "Предыдущая страница",
"Clear watch history?": "Очистить историю просмотров?",
"Yes": "Да",
"No": "Нет",
"Import and Export Data": "Импорт и экспорт данных",
"Import": "Импорт",
"Import Invidious data": "Импортировать данные Invidious",
"Import YouTube subscriptions": "Импортировать YouTube подписки",
"Import FreeTube subscriptions (.db)": "Импортировать FreeTube подписки (.db)",
"Import NewPipe subscriptions (.json)": "Импортировать NewPipe подписки (.json)",
"Import NewPipe data (.zip)": "Импортировать данные NewPipe (.zip)",
"Export": "Экспорт",
"Export subscriptions as OPML": "Экспортировать подписки в OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Экспортировать подписки в OPML (для NewPipe и FreeTube)",
"Export data as JSON": "Экспортировать данные в JSON",
"Delete account?": "Удалить аккаунт?",
"History": "История",
"An alternative front-end to YouTube": "Альтернативный фронтенд для YouTube",
"JavaScript license information": "Лицензии JavaScript",
"source": "источник",
"Login": "Войти",
"Login/Register": "Войти/Регистрация",
"Login to Google": "Войти через Google",
"User ID:": "ID пользователя:",
"Password:": "Пароль:",
"Time (h:mm:ss):": "Время (ч:мм:сс):",
"Text CAPTCHA": "Текст капчи",
"Image CAPTCHA": "Изображение капчи",
"Sign In": "Войти",
"Register": "Регистрация",
"Email:": "Эл. почта:",
"Google verification code:": "Код подтверждения Google:",
"Preferences": "Настройки",
"Player preferences": "Настройки проигрывателя",
"Always loop: ": "Всегда повторять: ",
"Autoplay: ": "Автовоспроизведение: ",
"Autoplay next video: ": "Автовоспроизведение следующего видео: ",
"Listen by default: ": "Режим \"только аудио\" по-умолчанию: ",
"Proxy videos? ": "Проксировать видео? ",
"Default speed: ": "Скорость по-умолчанию: ",
"Preferred video quality: ": "Предпочтительное качество видео: ",
"Player volume: ": "Громкость воспроизведения: ",
"Default comments: ": "Источник комментариев: ",
"youtube": "YouTube",
"reddit": "Reddit",
"Default captions: ": "Субтитры по-умолчанию: ",
"Fallback captions: ": "Резервные субтитры: ",
"Show related videos? ": "Показывать похожие видео? ",
"Visual preferences": "Визуальные настройки",
"Dark mode: ": "Темная тема: ",
"Thin mode: ": "Облегченный режим: ",
"Subscription preferences": "Настройки подписок",
"Redirect homepage to feed: ": "Отображать ленту вместо главной страницы: ",
"Number of videos shown in feed: ": "Число видео в ленте: ",
"Sort videos by: ": "Сортировать видео по: ",
"published": "дате публикации",
"published - reverse": "дате - обратный порядок",
"alphabetically": "алфавиту",
"alphabetically - reverse": "алфавиту - обратный порядок",
"channel name": "имени канала",
"channel name - reverse": "имени канала - обратный порядок",
"Only show latest video from channel: ": "Отображать только последние видео с каждого канала: ",
"Only show latest unwatched video from channel: ": "Отображать только непросмотренные видео с каждого канала: ",
"Only show unwatched: ": "Отображать только непросмотренные видео: ",
"Only show notifications (if there are any): ": "Отображать только оповещения (если есть): ",
"Data preferences": "Настройки данных",
"Clear watch history": "Очистить историю просмотра",
"Import/Export data": "Импорт/Экспорт данных",
"Manage subscriptions": "Управление подписками",
"Watch history": "История просмотров",
"Delete account": "Удалить аккаунт",
"Administrator preferences": "Настройки администратора",
"Default homepage: ": "Главная страница по умолчанию: ",
"Feed menu: ": "Меню ленты: ",
"Top enabled? ": "Включить ТОП? ",
"CAPTCHA enabled? ": "Включить капчу? ",
"Login enabled? ": "Включить логин? ",
"Registration enabled? ": "Включить регистрацию? ",
"Report statistics? ": "Отображать статистику? ",
"Save preferences": "Сохранить настройки",
"Subscription manager": "Менеджер подписок",
"`x` subscriptions": "`x` подписок",
"Import/Export": "Импорт/Экспорт",
"unsubscribe": "отписаться",
"Subscriptions": "Подписки",
"`x` unseen notifications": "`x` новых оповещений",
"search": "поиск",
"Sign out": "Выйти",
"Released under the AGPLv3 by Omar Roth.": "Распространяется Omar Roth по AGPLv3.",
"Source available here.": "Исходный код доступен здесь.",
"View JavaScript license information.": "Посмотреть лицензии JavaScript кода.",
"View privacy policy.": "См. политику конфиденциальности.",
"Trending": "В тренде",
"Watch video on Youtube": "Смотреть на YouTube",
"Genre: ": "Жанр: ",
"License: ": "Лицензия: ",
"Family friendly? ": "Семейный просмотр: ",
"Wilson score: ": "Рейтинг Вильсона: ",
"Engagement: ": "Вовлеченность: ",
"Whitelisted regions: ": "Доступно для: ",
"Blacklisted regions: ": "Недоступно для: ",
"Shared `x`": "Опубликовано `x`",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Похоже, что у Вас отключен JavaScript. Нажмите сюда, чтобы увидеть комментарии (учтите, что они могут загружаться дольше).",
"View YouTube comments": "Смотреть комментарии с YouTube",
"View more comments on Reddit": "Больше комментариев на Reddit",
"View `x` comments": "Показать `x` комментариев",
"View Reddit comments": "Смотреть комментарии с Reddit",
"Hide replies": "Скрыть ответы",
"Show replies": "Показать ответы",
"Incorrect password": "Неправильный пароль",
"Quota exceeded, try again in a few hours": "Превышена квота, попробуйте снова через несколько часов",
"Unable to login, make sure two-factor authentication (Authenticator or SMS) is enabled.": "Вход не выполнен, проверьте, не включена ли двухфакторная аутентификация.",
"Invalid TFA code": "Неправильный TFA код",
"Login failed. This may be because two-factor authentication is not enabled on your account.": "Не удалось войти. Это может быть из-за того, что в вашем аккаунте не включена двухфакторная аутентификация.",
"Invalid answer": "Неверный ответ",
"Invalid CAPTCHA": "Неверная капча",
"CAPTCHA is a required field": "Необходимо ввести капчу",
"User ID is a required field": "Необходимо ввести идентификатор пользователя",
"Password is a required field": "Необходимо ввести пароль",
"Invalid username or password": "Недопустимый пароль или имя пользователя",
"Please sign in using 'Sign in with Google'": "Пожалуйста войдите через Google",
"Password cannot be empty": "Пароль не может быть пустым",
"Password cannot be longer than 55 characters": "Пароль не может быть длиннее 55 символов",
"Please sign in": "Пожалуйста, войдите",
"Invidious Private Feed for `x`": "Приватная лента Invidious для `x`",
"channel:`x`": "канал: `x`",
"Deleted or invalid channel": "Канал удален или не найден",
"This channel does not exist.": "Такой канал не существует.",
"Could not get channel info.": "Невозможно получить информацию о канале.",
"Could not fetch comments": "Невозможно получить комментарии",
"View `x` replies": "Показать `x` ответов",
"`x` ago": "`x` назад",
"Load more": "Загрузить больше",
"`x` points": "`x` очков",
"Could not create mix.": "Невозможно создать \"микс\".",
"Playlist is empty": "Плейлист пуст",
"Invalid playlist.": "Некорректный плейлист.",
"Playlist does not exist.": "Плейлист не существует.",
"Could not pull trending pages.": "Невозможно получить страницы \"в тренде\".",
"Hidden field \"challenge\" is a required field": "Необходимо заполнить скрытое поле \"challenge\"",
"Hidden field \"token\" is a required field": "Необходимо заполнить скрытое поле \"токен\"",
"Invalid challenge": "Неправильный ответ в \"challenge\"",
"Invalid token": "Неправильный токен",
"Invalid user": "Недопустимое имя пользователя",
"Token is expired, please try again": "Срок действия токена истек, попробуйте позже",
"English": "Английский",
"English (auto-generated)": "Английский (созданы автоматически)",
"Afrikaans": "Африкаанс",
"Albanian": "Албанский",
"Amharic": "Амхарский",
"Arabic": "Арабский",
"Armenian": "Армянский",
"Azerbaijani": "Азербайджанский",
"Bangla": "Бенгальский",
"Basque": "Баскский",
"Belarusian": "Белорусский",
"Bosnian": "Боснийский",
"Bulgarian": "Болгарский",
"Burmese": "Бирманский",
"Catalan": "Каталонский",
"Cebuano": "Себуанский",
"Chinese (Simplified)": "Китайский (упрощенный)",
"Chinese (Traditional)": "Китайский (традиционный)",
"Corsican": "Корсиканский",
"Croatian": "Хорватский",
"Czech": "Чешский",
"Danish": "Датский",
"Dutch": "Нидерландский",
"Esperanto": "Эсперанто",
"Estonian": "Эстонский",
"Filipino": "Филиппинский",
"Finnish": "Финский",
"French": "Французский",
"Galician": "Галисийский",
"Georgian": "Грузинский",
"German": "Немецкий",
"Greek": "Греческий",
"Gujarati": "Гуджаратский",
"Haitian Creole": "Гаит. креольский",
"Hausa": "Хауса",
"Hawaiian": "Гавайский",
"Hebrew": "Иврит",
"Hindi": "Хинди",
"Hmong": "Хмонг (мяо)",
"Hungarian": "Венгерский",
"Icelandic": "Исландский",
"Igbo": "Игбо",
"Indonesian": "Индонезийский",
"Irish": "Ирландский",
"Italian": "Итальянский",
"Japanese": "Японский",
"Javanese": "Яванский",
"Kannada": "Каннада",
"Kazakh": "Казахский",
"Khmer": "Кхмерский",
"Korean": "Корейский",
"Kurdish": "Курдский",
"Kyrgyz": "Киргизский",
"Lao": "Лаосский",
"Latin": "Латинский",
"Latvian": "Латышский",
"Lithuanian": "Литовский",
"Luxembourgish": "Люксембургский",
"Macedonian": "Македонский",
"Malagasy": "Малагасийский",
"Malay": "Малайский",
"Malayalam": "Малаялам",
"Maltese": "Мальтийский",
"Maori": "Маори",
"Marathi": "Маратхи",
"Mongolian": "Монгольская",
"Nepali": "Непальский",
"Norwegian": "Норвежский",
"Nyanja": "Ньянджа",
"Pashto": "Пушту",
"Persian": "Персидский",
"Polish": "Польский",
"Portuguese": "Португальский",
"Punjabi": "Панджаби",
"Romanian": "Румынский",
"Russian": "Русский",
"Samoan": "Самоанский",
"Scottish Gaelic": "Шотландский (гэльский)",
"Serbian": "Сербский",
"Shona": "Шона",
"Sindhi": "Синдхи",
"Sinhala": "Сингальский",
"Slovak": "Словацкий",
"Slovenian": "Словенский",
"Somali": "Сомалийский",
"Southern Sotho": "Сесото (южный сото)",
"Spanish": "Испанский",
"Spanish (Latin America)": "Испанский (Латинская Америка)",
"Sundanese": "Сунданский",
"Swahili": "Суахили",
"Swedish": "Шведский",
"Tajik": "Таджикский",
"Tamil": "Тамильский",
"Telugu": "Телугу",
"Thai": "Тайский",
"Turkish": "Турецкий",
"Ukrainian": "Украинский",
"Urdu": "Урду",
"Uzbek": "Узбекский",
"Vietnamese": "Вьетнамский",
"Welsh": "Валлийский",
"Western Frisian": "Западнофризский",
"Xhosa": "Коса",
"Yiddish": "Идиш",
"Yoruba": "Йоруба",
"Zulu": "Зулусский",
"`x` years": "`x` лет",
"`x` months": "`x` месяцев",
"`x` weeks": "`x` недель",
"`x` days": "`x` дней",
"`x` hours": "`x` часов",
"`x` minutes": "`x` минут",
"`x` seconds": "`x` секунд",
"Fallback comments: ": "Резервные комментарии: ",
"Popular": "Популярное",
"Top": "Топ",
"About": "О сайте",
"Rating: ": "Рейтинг: ",
"Language: ": "Язык: ",
"Default": "По-умолчанию",
"Music": "Музыка",
"Gaming": "Игры",
"News": "Новости",
"Movies": "Фильмы",
"Download": "Скачать",
"Download as: ": "Скачать как: ",
"%A %B %-d, %Y": "%-d %B %Y, %A",
"(edited)": "(изменено)",
"Youtube permalink of the comment": "Прямая ссылка на YouTube",
"`x` marked it with a ❤": "❤ от автора канала \"`x`\"",
"Audio mode": "Аудио режим",
"Video mode": "Видео режим",
"Videos": "Видео",
"Playlists": "Плейлисты",
"Current version: ": "Текущая версия: "
"`x` subscribers": "`x` подписчиков",
"`x` videos": "`x` видео",
"LIVE": "ПРЯМОЙ ЭФИР",
"Shared `x` ago": "Опубликовано `x` назад",
"Unsubscribe": "Отписаться",
"Subscribe": "Подписаться",
"Login to subscribe to `x`": "Войти, чтобы подписаться на `x`",
"View channel on YouTube": "Канал на YouTube",
"newest": "новые",
"oldest": "старые",
"popular": "популярные",
"last": "недавно обновленные",
"Next page": "Следующая страница",
"Previous page": "Предыдущая страница",
"Clear watch history?": "Очистить историю просмотров?",
"Yes": "Да",
"No": "Нет",
"Import and Export Data": "Импорт и экспорт данных",
"Import": "Импорт",
"Import Invidious data": "Импортировать данные Invidious",
"Import YouTube subscriptions": "Импортировать YouTube подписки",
"Import FreeTube subscriptions (.db)": "Импортировать FreeTube подписки (.db)",
"Import NewPipe subscriptions (.json)": "Импортировать NewPipe подписки (.json)",
"Import NewPipe data (.zip)": "Импортировать данные NewPipe (.zip)",
"Export": "Экспорт",
"Export subscriptions as OPML": "Экспортировать подписки в OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Экспортировать подписки в OPML (для NewPipe и FreeTube)",
"Export data as JSON": "Экспортировать данные в JSON",
"Delete account?": "Удалить аккаунт?",
"History": "История",
"An alternative front-end to YouTube": "Альтернативный фронтенд для YouTube",
"JavaScript license information": "Лицензии JavaScript",
"source": "источник",
"Login": "Войти",
"Login/Register": "Войти/Регистрация",
"Login to Google": "Войти через Google",
"User ID:": "ID пользователя:",
"Password:": "Пароль:",
"Time (h:mm:ss):": "Время (ч:мм:сс):",
"Text CAPTCHA": "Текст капчи",
"Image CAPTCHA": "Изображение капчи",
"Sign In": "Войти",
"Register": "Регистрация",
"Email:": "Эл. почта:",
"Google verification code:": "Код подтверждения Google:",
"Preferences": "Настройки",
"Player preferences": "Настройки проигрывателя",
"Always loop: ": "Всегда повторять: ",
"Autoplay: ": "Автовоспроизведение: ",
"Autoplay next video: ": "Автовоспроизведение следующего видео: ",
"Listen by default: ": "Режим \"только аудио\" по-умолчанию: ",
"Proxy videos? ": "Проксировать видео? ",
"Default speed: ": "Скорость по-умолчанию: ",
"Preferred video quality: ": "Предпочтительное качество видео: ",
"Player volume: ": "Громкость воспроизведения: ",
"Default comments: ": "Источник комментариев: ",
"youtube": "YouTube",
"reddit": "Reddit",
"Default captions: ": "Субтитры по-умолчанию: ",
"Fallback captions: ": "Резервные субтитры: ",
"Show related videos? ": "Показывать похожие видео? ",
"Visual preferences": "Визуальные настройки",
"Dark mode: ": "Темная тема: ",
"Thin mode: ": "Облегченный режим: ",
"Subscription preferences": "Настройки подписок",
"Redirect homepage to feed: ": "Отображать ленту вместо главной страницы: ",
"Number of videos shown in feed: ": "Число видео в ленте: ",
"Sort videos by: ": "Сортировать видео по: ",
"published": "дате публикации",
"published - reverse": "дате - обратный порядок",
"alphabetically": "алфавиту",
"alphabetically - reverse": "алфавиту - обратный порядок",
"channel name": "имени канала",
"channel name - reverse": "имени канала - обратный порядок",
"Only show latest video from channel: ": "Отображать только последние видео с каждого канала: ",
"Only show latest unwatched video from channel: ": "Отображать только непросмотренные видео с каждого канала: ",
"Only show unwatched: ": "Отображать только непросмотренные видео: ",
"Only show notifications (if there are any): ": "Отображать только оповещения (если есть): ",
"Data preferences": "Настройки данных",
"Clear watch history": "Очистить историю просмотра",
"Import/Export data": "Импорт/Экспорт данных",
"Manage subscriptions": "Управление подписками",
"Watch history": "История просмотров",
"Delete account": "Удалить аккаунт",
"Administrator preferences": "Настройки администратора",
"Default homepage: ": "Главная страница по умолчанию: ",
"Feed menu: ": "Меню ленты: ",
"Top enabled? ": "Включить ТОП? ",
"CAPTCHA enabled? ": "Включить капчу? ",
"Login enabled? ": "Включить логин? ",
"Registration enabled? ": "Включить регистрацию? ",
"Report statistics? ": "Отображать статистику? ",
"Save preferences": "Сохранить настройки",
"Subscription manager": "Менеджер подписок",
"`x` subscriptions": "`x` подписок",
"Import/Export": "Импорт/Экспорт",
"unsubscribe": "отписаться",
"Subscriptions": "Подписки",
"`x` unseen notifications": "`x` новых оповещений",
"search": "поиск",
"Sign out": "Выйти",
"Released under the AGPLv3 by Omar Roth.": "Распространяется Omar Roth по AGPLv3.",
"Source available here.": "Исходный код доступен здесь.",
"View JavaScript license information.": "Посмотреть лицензии JavaScript кода.",
"View privacy policy.": "См. политику конфиденциальности.",
"Trending": "В тренде",
"Unlisted": "",
"Watch video on Youtube": "Смотреть на YouTube",
"Genre: ": "Жанр: ",
"License: ": "Лицензия: ",
"Family friendly? ": "Семейный просмотр: ",
"Wilson score: ": "Рейтинг Вильсона: ",
"Engagement: ": "Вовлеченность: ",
"Whitelisted regions: ": "Доступно для: ",
"Blacklisted regions: ": "Недоступно для: ",
"Shared `x`": "Опубликовано `x`",
"Premieres in `x`": "",
"Hi! Looks like you have JavaScript disabled. Click here to view comments, keep in mind it may take a bit longer to load.": "Похоже, что у Вас отключен JavaScript. Нажмите сюда, чтобы увидеть комментарии (учтите, что они могут загружаться дольше).",
"View YouTube comments": "Смотреть комментарии с YouTube",
"View more comments on Reddit": "Больше комментариев на Reddit",
"View `x` comments": "Показать `x` комментариев",
"View Reddit comments": "Смотреть комментарии с Reddit",
"Hide replies": "Скрыть ответы",
"Show replies": "Показать ответы",
"Incorrect password": "Неправильный пароль",
"Quota exceeded, try again in a few hours": "Превышена квота, попробуйте снова через несколько часов",
"Unable to login, make sure two-factor authentication (Authenticator or SMS) is enabled.": "Вход не выполнен, проверьте, не включена ли двухфакторная аутентификация.",
"Invalid TFA code": "Неправильный TFA код",
"Login failed. This may be because two-factor authentication is not enabled on your account.": "Не удалось войти. Это может быть из-за того, что в вашем аккаунте не включена двухфакторная аутентификация.",
"Invalid answer": "Неверный ответ",
"Invalid CAPTCHA": "Неверная капча",
"CAPTCHA is a required field": "Необходимо ввести капчу",
"User ID is a required field": "Необходимо ввести идентификатор пользователя",
"Password is a required field": "Необходимо ввести пароль",
"Invalid username or password": "Недопустимый пароль или имя пользователя",
"Please sign in using 'Sign in with Google'": "Пожалуйста войдите через Google",
"Password cannot be empty": "Пароль не может быть пустым",
"Password cannot be longer than 55 characters": "Пароль не может быть длиннее 55 символов",
"Please sign in": "Пожалуйста, войдите",
"Invidious Private Feed for `x`": "Приватная лента Invidious для `x`",
"channel:`x`": "канал: `x`",
"Deleted or invalid channel": "Канал удален или не найден",
"This channel does not exist.": "Такой канал не существует.",
"Could not get channel info.": "Невозможно получить информацию о канале.",
"Could not fetch comments": "Невозможно получить комментарии",
"View `x` replies": "Показать `x` ответов",
"`x` ago": "`x` назад",
"Load more": "Загрузить больше",
"`x` points": "`x` очков",
"Could not create mix.": "Невозможно создать \"микс\".",
"Playlist is empty": "Плейлист пуст",
"Invalid playlist.": "Некорректный плейлист.",
"Playlist does not exist.": "Плейлист не существует.",
"Could not pull trending pages.": "Невозможно получить страницы \"в тренде\".",
"Hidden field \"challenge\" is a required field": "Необходимо заполнить скрытое поле \"challenge\"",
"Hidden field \"token\" is a required field": "Необходимо заполнить скрытое поле \"токен\"",
"Invalid challenge": "Неправильный ответ в \"challenge\"",
"Invalid token": "Неправильный токен",
"Invalid user": "Недопустимое имя пользователя",
"Token is expired, please try again": "Срок действия токена истек, попробуйте позже",
"English": "Английский",
"English (auto-generated)": "Английский (созданы автоматически)",
"Afrikaans": "Африкаанс",
"Albanian": "Албанский",
"Amharic": "Амхарский",
"Arabic": "Арабский",
"Armenian": "Армянский",
"Azerbaijani": "Азербайджанский",
"Bangla": "Бенгальский",
"Basque": "Баскский",
"Belarusian": "Белорусский",
"Bosnian": "Боснийский",
"Bulgarian": "Болгарский",
"Burmese": "Бирманский",
"Catalan": "Каталонский",
"Cebuano": "Себуанский",
"Chinese (Simplified)": "Китайский (упрощенный)",
"Chinese (Traditional)": "Китайский (традиционный)",
"Corsican": "Корсиканский",
"Croatian": "Хорватский",
"Czech": "Чешский",
"Danish": "Датский",
"Dutch": "Нидерландский",
"Esperanto": "Эсперанто",
"Estonian": "Эстонский",
"Filipino": "Филиппинский",
"Finnish": "Финский",
"French": "Французский",
"Galician": "Галисийский",
"Georgian": "Грузинский",
"German": "Немецкий",
"Greek": "Греческий",
"Gujarati": "Гуджаратский",
"Haitian Creole": "Гаит. креольский",
"Hausa": "Хауса",
"Hawaiian": "Гавайский",
"Hebrew": "Иврит",
"Hindi": "Хинди",
"Hmong": "Хмонг (мяо)",
"Hungarian": "Венгерский",
"Icelandic": "Исландский",
"Igbo": "Игбо",
"Indonesian": "Индонезийский",
"Irish": "Ирландский",
"Italian": "Итальянский",
"Japanese": "Японский",
"Javanese": "Яванский",
"Kannada": "Каннада",
"Kazakh": "Казахский",
"Khmer": "Кхмерский",
"Korean": "Корейский",
"Kurdish": "Курдский",
"Kyrgyz": "Киргизский",
"Lao": "Лаосский",
"Latin": "Латинский",
"Latvian": "Латышский",
"Lithuanian": "Литовский",
"Luxembourgish": "Люксембургский",
"Macedonian": "Македонский",
"Malagasy": "Малагасийский",
"Malay": "Малайский",
"Malayalam": "Малаялам",
"Maltese": "Мальтийский",
"Maori": "Маори",
"Marathi": "Маратхи",
"Mongolian": "Монгольская",
"Nepali": "Непальский",
"Norwegian": "Норвежский",
"Nyanja": "Ньянджа",
"Pashto": "Пушту",
"Persian": "Персидский",
"Polish": "Польский",
"Portuguese": "Португальский",
"Punjabi": "Панджаби",
"Romanian": "Румынский",
"Russian": "Русский",
"Samoan": "Самоанский",
"Scottish Gaelic": "Шотландский (гэльский)",
"Serbian": "Сербский",
"Shona": "Шона",
"Sindhi": "Синдхи",
"Sinhala": "Сингальский",
"Slovak": "Словацкий",
"Slovenian": "Словенский",
"Somali": "Сомалийский",
"Southern Sotho": "Сесото (южный сото)",
"Spanish": "Испанский",
"Spanish (Latin America)": "Испанский (Латинская Америка)",
"Sundanese": "Сунданский",
"Swahili": "Суахили",
"Swedish": "Шведский",
"Tajik": "Таджикский",
"Tamil": "Тамильский",
"Telugu": "Телугу",
"Thai": "Тайский",
"Turkish": "Турецкий",
"Ukrainian": "Украинский",
"Urdu": "Урду",
"Uzbek": "Узбекский",
"Vietnamese": "Вьетнамский",
"Welsh": "Валлийский",
"Western Frisian": "Западнофризский",
"Xhosa": "Коса",
"Yiddish": "Идиш",
"Yoruba": "Йоруба",
"Zulu": "Зулусский",
"`x` years": "`x` лет",
"`x` months": "`x` месяцев",
"`x` weeks": "`x` недель",
"`x` days": "`x` дней",
"`x` hours": "`x` часов",
"`x` minutes": "`x` минут",
"`x` seconds": "`x` секунд",
"Fallback comments: ": "Резервные комментарии: ",
"Popular": "Популярное",
"Top": "Топ",
"About": "О сайте",
"Rating: ": "Рейтинг: ",
"Language: ": "Язык: ",
"Default": "По-умолчанию",
"Music": "Музыка",
"Gaming": "Игры",
"News": "Новости",
"Movies": "Фильмы",
"Download": "Скачать",
"Download as: ": "Скачать как: ",
"%A %B %-d, %Y": "%-d %B %Y, %A",
"(edited)": "(изменено)",
"Youtube permalink of the comment": "Прямая ссылка на YouTube",
"`x` marked it with a ❤": "❤ от автора канала \"`x`\"",
"Audio mode": "Аудио режим",
"Video mode": "Видео режим",
"Videos": "Видео",
"Playlists": "Плейлисты",
"Current version: ": "Текущая версия: "
}

View File

@ -242,6 +242,9 @@ get "/api/v1/comments/:id" do |env|
source = env.params.query["source"]?
source ||= "youtube"
thin_mode = env.params.query["thin_mode"]?
thin_mode = thin_mode == "true"
format = env.params.query["format"]?
format ||= "json"
@ -249,7 +252,7 @@ get "/api/v1/comments/:id" do |env|
if source == "youtube"
begin
comments = fetch_youtube_comments(id, continuation, proxies, format, locale, region)
comments = fetch_youtube_comments(id, continuation, proxies, format, locale, thin_mode, region)
rescue ex
error_message = {"error" => ex.message}.to_json
env.response.status_code = 500
@ -1688,6 +1691,11 @@ get "/videoplayback" do |env|
fvip = query_params["fvip"]? || "3"
mns = query_params["mn"].split(",")
if query_params["region"]?
region = query_params["region"]
query_params.delete("region")
end
if query_params["host"]? && !query_params["host"].empty?
host = "https://#{query_params["host"]}"
query_params.delete("host")
@ -1704,8 +1712,6 @@ get "/videoplayback" do |env|
end
end
region = query_params["region"]?
response = HTTP::Client::Response.new(403)
5.times do
begin
@ -1725,9 +1731,12 @@ get "/videoplayback" do |env|
if response.headers["Location"]?
url = URI.parse(response.headers["Location"])
host = url.host
env.response.headers["Access-Control-Allow-Origin"] = "*"
url = url.full_path
url += "&host=#{host}"
if region
url += "&region=#{region}"
end
@ -1744,15 +1753,30 @@ get "/videoplayback" do |env|
client.get(url, headers) do |response|
env.response.status_code = response.status_code
if title = env.params.query["title"]?
# https://blog.fastmail.com/2011/06/24/download-non-english-filenames/
env.response.headers["Content-Disposition"] = "attachment; filename=\"#{URI.escape(title)}\"; filename*=UTF-8''#{URI.escape(title)}"
end
response.headers.each do |key, value|
env.response.headers[key] = value
end
if response.headers["Location"]?
url = URI.parse(response.headers["Location"])
host = url.host
env.response.headers["Access-Control-Allow-Origin"] = "*"
url = url.full_path
url += "&host=#{host}"
if region
url += "&region=#{region}"
end
next env.redirect url
end
if title = query_params["title"]?
# https://blog.fastmail.com/2011/06/24/download-non-english-filenames/
env.response.headers["Content-Disposition"] = "attachment; filename=\"#{URI.escape(title)}\"; filename*=UTF-8''#{URI.escape(title)}"
end
env.response.headers["Access-Control-Allow-Origin"] = "*"
begin

View File

@ -1,4 +1,4 @@
class InvidiousChannel
struct InvidiousChannel
add_mapping({
id: String,
author: String,
@ -8,7 +8,7 @@ class InvidiousChannel
})
end
class ChannelVideo
struct ChannelVideo
add_mapping({
id: String,
title: String,

View File

@ -29,7 +29,7 @@ class RedditComment
})
end
class RedditLink
struct RedditLink
JSON.mapping({
author: String,
score: Int32,
@ -41,7 +41,7 @@ class RedditLink
})
end
class RedditMore
struct RedditMore
JSON.mapping({
children: Array(String),
count: Int32,
@ -56,7 +56,7 @@ class RedditListing
})
end
def fetch_youtube_comments(id, continuation, proxies, format, locale, region)
def fetch_youtube_comments(id, continuation, proxies, format, locale, thin_mode, region)
video = fetch_video(id, proxies, region: region)
session_token = video.info["session_token"]?
@ -232,7 +232,7 @@ def fetch_youtube_comments(id, continuation, proxies, format, locale, region)
if format == "html"
comments = JSON.parse(comments)
content_html = template_youtube_comments(comments, locale)
content_html = template_youtube_comments(comments, locale, thin_mode)
comments = JSON.build do |json|
json.object do
@ -278,7 +278,7 @@ def fetch_reddit_comments(id)
return comments, thread
end
def template_youtube_comments(comments, locale)
def template_youtube_comments(comments, locale, thin_mode)
html = ""
root = comments["comments"].as_a
@ -297,7 +297,11 @@ def template_youtube_comments(comments, locale)
END_HTML
end
author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).full_path}"
if !thin_mode
author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).full_path}"
else
author_thumbnail = ""
end
html += <<-END_HTML
<div class="pure-g">
@ -318,7 +322,12 @@ def template_youtube_comments(comments, locale)
END_HTML
if child["creatorHeart"]?
creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).full_path}"
if !thin_mode
creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).full_path}"
else
creator_thumbnail = ""
end
html += <<-END_HTML
<span class="creator-heart-container" title="#{translate(locale, "`x` marked it with a ❤", child["creatorHeart"]["creatorName"].as_s)}">
<div class="creator-heart">

View File

@ -1,4 +1,4 @@
class Config
struct Config
YAML.mapping({
channel_threads: Int32, # Number of threads to use for crawling videos from channels (for updating subscriptions)
feed_threads: Int32, # Number of threads to use for updating feeds

View File

@ -9,6 +9,17 @@ macro add_mapping(mapping)
DB.mapping({{mapping}})
end
macro json_mapping(mapping)
def initialize({{*mapping.keys.map { |id| "@#{id}".id }}})
end
def to_a
return [{{*mapping.keys.map { |id| "@#{id}".id }}}]
end
JSON.mapping({{mapping}})
end
macro templated(filename, template = "template")
render "src/invidious/views/#{{{filename}}}.ecr", "src/invidious/views/#{{{template}}}.ecr"
end

View File

@ -106,7 +106,7 @@ def subscribe_to_feeds(db, logger, key, config)
if config.use_pubsub_feeds
spawn do
loop do
db.query_all("SELECT id FROM channels WHERE CURRENT_TIMESTAMP - subscribed > '4 days'") do |rs|
db.query_all("SELECT id FROM channels WHERE CURRENT_TIMESTAMP - subscribed > '4 days' OR subscribed IS NULL") do |rs|
rs.each do
ucid = rs.read(String)
response = subscribe_pubsub(ucid, key, config)

View File

@ -1,4 +1,4 @@
class MixVideo
struct MixVideo
add_mapping({
title: String,
id: String,
@ -10,7 +10,7 @@ class MixVideo
})
end
class Mix
struct Mix
add_mapping({
title: String,
id: String,

View File

@ -1,4 +1,4 @@
class PlaylistVideo
struct PlaylistVideo
add_mapping({
title: String,
id: String,
@ -12,7 +12,7 @@ class PlaylistVideo
})
end
class Playlist
struct Playlist
add_mapping({
title: String,
id: String,

View File

@ -1,4 +1,4 @@
class SearchVideo
struct SearchVideo
add_mapping({
title: String,
id: String,
@ -16,7 +16,7 @@ class SearchVideo
})
end
class SearchPlaylistVideo
struct SearchPlaylistVideo
add_mapping({
title: String,
id: String,
@ -24,7 +24,7 @@ class SearchPlaylistVideo
})
end
class SearchPlaylist
struct SearchPlaylist
add_mapping({
title: String,
id: String,
@ -36,7 +36,7 @@ class SearchPlaylist
})
end
class SearchChannel
struct SearchChannel
add_mapping({
author: String,
ucid: String,

View File

@ -1,12 +1,12 @@
require "crypto/bcrypt/password"
class User
struct User
module PreferencesConverter
def self.from_rs(rs)
begin
Preferences.from_json(rs.read(String))
rescue ex
DEFAULT_USER_PREFERENCES
Preferences.from_json("{}")
end
end
end
@ -18,7 +18,6 @@ class User
email: String,
preferences: {
type: Preferences,
default: DEFAULT_USER_PREFERENCES,
converter: PreferencesConverter,
},
password: String?,
@ -27,30 +26,30 @@ class User
})
end
DEFAULT_USER_PREFERENCES = Preferences.from_json({
"video_loop" => false,
"autoplay" => false,
"continue" => false,
"local" => false,
"listen" => false,
"speed" => 1.0,
"quality" => "hd720",
"volume" => 100,
"comments" => ["youtube", ""],
"captions" => ["", "", ""],
"related_videos" => true,
"redirect_feed" => false,
"locale" => "en-US",
"dark_mode" => false,
"thin_mode" => false,
"max_results" => 40,
"sort" => "published",
"latest_only" => false,
"unseen_only" => false,
"notifications_only" => false,
}.to_json)
DEFAULT_USER_PREFERENCES = Preferences.new(
video_loop: false,
autoplay: false,
continue: false,
local: false,
listen: false,
speed: 1.0_f32,
quality: "hd720",
volume: 100,
comments: ["youtube", ""],
captions: ["", "", ""],
related_videos: true,
redirect_feed: false,
locale: "en-US",
dark_mode: false,
thin_mode: false,
max_results: 40,
sort: "published",
latest_only: false,
unseen_only: false,
notifications_only: false,
)
class Preferences
struct Preferences
module StringToArray
def self.to_json(value : Array(String), json : JSON::Builder)
json.array do
@ -74,58 +73,27 @@ class Preferences
end
end
JSON.mapping({
video_loop: Bool,
autoplay: Bool,
continue: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.continue,
},
local: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.local,
},
listen: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.listen,
},
speed: Float32,
quality: String,
volume: Int32,
comments: {
type: Array(String),
default: DEFAULT_USER_PREFERENCES.comments,
converter: StringToArray,
},
captions: {
type: Array(String),
default: DEFAULT_USER_PREFERENCES.captions,
},
redirect_feed: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.redirect_feed,
},
related_videos: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.related_videos,
},
dark_mode: Bool,
thin_mode: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.thin_mode,
},
max_results: Int32,
sort: String,
latest_only: Bool,
unseen_only: Bool,
notifications_only: {
type: Bool,
default: DEFAULT_USER_PREFERENCES.notifications_only,
},
locale: {
type: String,
default: DEFAULT_USER_PREFERENCES.locale,
},
json_mapping({
video_loop: {type: Bool, default: DEFAULT_USER_PREFERENCES.video_loop},
autoplay: {type: Bool, default: DEFAULT_USER_PREFERENCES.autoplay},
continue: {type: Bool, default: DEFAULT_USER_PREFERENCES.continue},
local: {type: Bool, default: DEFAULT_USER_PREFERENCES.local},
listen: {type: Bool, default: DEFAULT_USER_PREFERENCES.listen},
speed: {type: Float32, default: DEFAULT_USER_PREFERENCES.speed},
quality: {type: String, default: DEFAULT_USER_PREFERENCES.quality},
volume: {type: Int32, default: DEFAULT_USER_PREFERENCES.volume},
comments: {type: Array(String), default: DEFAULT_USER_PREFERENCES.comments, converter: StringToArray},
captions: {type: Array(String), default: DEFAULT_USER_PREFERENCES.captions, converter: StringToArray},
redirect_feed: {type: Bool, default: DEFAULT_USER_PREFERENCES.redirect_feed},
related_videos: {type: Bool, default: DEFAULT_USER_PREFERENCES.related_videos},
dark_mode: {type: Bool, default: DEFAULT_USER_PREFERENCES.dark_mode},
thin_mode: {type: Bool, default: DEFAULT_USER_PREFERENCES.thin_mode},
max_results: {type: Int32, default: DEFAULT_USER_PREFERENCES.max_results},
sort: {type: String, default: DEFAULT_USER_PREFERENCES.sort},
latest_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.latest_only},
unseen_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.unseen_only},
notifications_only: {type: Bool, default: DEFAULT_USER_PREFERENCES.notifications_only},
locale: {type: String, default: DEFAULT_USER_PREFERENCES.locale},
})
end

View File

@ -241,7 +241,7 @@ VIDEO_FORMATS = {
"251" => {"ext" => "webm", "format" => "DASH audio", "acodec" => "opus", "abr" => 160},
}
class Video
struct Video
property player_json : JSON::Any?
module HTTPParamConverter
@ -251,7 +251,7 @@ class Video
end
def allow_ratings
allow_ratings = player_response["videoDetails"].try &.["allowRatings"]?.try &.as_bool
allow_ratings = player_response["videoDetails"]?.try &.["allowRatings"]?.try &.as_bool
if allow_ratings.nil?
return true
@ -271,7 +271,7 @@ class Video
end
def is_listed
is_listed = player_response["videoDetails"].try &.["isCrawlable"]?.try &.as_bool
is_listed = player_response["videoDetails"]?.try &.["isCrawlable"]?.try &.as_bool
if is_listed.nil?
return true
@ -281,7 +281,7 @@ class Video
end
def is_upcoming
is_upcoming = player_response["videoDetails"].try &.["isUpcoming"]?.try &.as_bool
is_upcoming = player_response["videoDetails"]?.try &.["isUpcoming"]?.try &.as_bool
if is_upcoming.nil?
return false
@ -297,7 +297,7 @@ class Video
.try &.["liveStreamabilityRenderer"]?
.try &.["offlineSlate"]?
.try &.["liveStreamOfflineSlateRenderer"]?
.try &.["scheduledStartTime"].as_s.to_i64
.try &.["scheduledStartTime"]?.try &.as_s.to_i64
end
if premiere_timestamp
@ -549,7 +549,7 @@ class Video
})
end
class Caption
struct Caption
JSON.mapping(
name: CaptionName,
baseUrl: String,
@ -557,7 +557,7 @@ class Caption
)
end
class CaptionName
struct CaptionName
JSON.mapping(
simpleText: String,
)