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": "الأجدد", "newest": "الأجدد",
"oldest": "الأقدم", "oldest": "الأقدم",
"popular": "الاكثر شعبية", "popular": "الاكثر شعبية",
"last": "", "last": "اخر الفيديوهات المعدلة",
"Next page": "الصفحة الثانية", "Next page": "الصفحة الثانية",
"Previous page": "الصفحة السابقة", "Previous page": "الصفحة السابقة",
"Clear watch history?": "مسح السجل ؟", "Clear watch history?": "مسح السجل ؟",
@ -50,7 +50,7 @@
"Autoplay: ": "تشغيل تلقائى: ", "Autoplay: ": "تشغيل تلقائى: ",
"Autoplay next video: ": "شغل الفيديو التالى تلقائى: ", "Autoplay next video: ": "شغل الفيديو التالى تلقائى: ",
"Listen by default: ": "تشغيل النسخة السمعية تلقائى: ", "Listen by default: ": "تشغيل النسخة السمعية تلقائى: ",
"Proxy videos? ": "", "Proxy videos? ": "عرض الفيديوهات عن طريق الوكيل(proxy) ؟",
"Default speed: ": "السرعة الإفتراضية: ", "Default speed: ": "السرعة الإفتراضية: ",
"Preferred video quality: ": "الجودة المفضلة للفيديوهات: ", "Preferred video quality: ": "الجودة المفضلة للفيديوهات: ",
"Player volume: ": "صوت المشغل: ", "Player volume: ": "صوت المشغل: ",
@ -83,14 +83,14 @@
"Manage subscriptions": "إدارة المشتركين", "Manage subscriptions": "إدارة المشتركين",
"Watch history": "سجل المشاهدة", "Watch history": "سجل المشاهدة",
"Delete account": "حذف الحساب", "Delete account": "حذف الحساب",
"Administrator preferences": "", "Administrator preferences": "إعدادات المدير",
"Default homepage: ": "", "Default homepage: ": "الصفحة الرئيسية الافتراضية ",
"Feed menu: ": "", "Feed menu: ": "قائمة التغذية",
"Top enabled? ": "", "Top enabled? ": "تفعيل 'الأفضل' ؟ ",
"CAPTCHA enabled? ": "", "CAPTCHA enabled? ": "تفعيل الكابتشا ؟",
"Login enabled? ": "", "Login enabled? ": "تفعيل تسجيل الدخول ؟",
"Registration enabled? ": "", "Registration enabled? ": "تفعيل التسجيل ؟",
"Report statistics? ": "", "Report statistics? ": "إبلاغ الإحصائيات",
"Save preferences": "حفظ التفضيلات", "Save preferences": "حفظ التفضيلات",
"Subscription manager": "مدير الإشتراكات", "Subscription manager": "مدير الإشتراكات",
"`x` subscriptions": "`x` مشتركين", "`x` subscriptions": "`x` مشتركين",
@ -103,8 +103,9 @@
"Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.", "Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.",
"Source available here.": "الأكواد متوفرة هنا.", "Source available here.": "الأكواد متوفرة هنا.",
"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: ": "التراخيص: ",
@ -114,6 +115,7 @@
"Whitelisted regions: ": "الدول المسموح فيها هذا الفيديو: ", "Whitelisted regions: ": "الدول المسموح فيها هذا الفيديو: ",
"Blacklisted regions: ": "الدول الحظور فيها هذا الفيديو: ", "Blacklisted regions: ": "الدول الحظور فيها هذا الفيديو: ",
"Shared `x`": "شارك منذ `x`", "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.": "اهلا! يبدو ان الجافاسكريبت معطلة. اضغط هنا لعرض التعليقات, ضع فى إعتبارك انها ستأخذ وقت اطول للعرض.", "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": "عرض المزيد من التعليقات على\\من موقع Reddit", "View more comments on Reddit": "عرض المزيد من التعليقات على\\من موقع Reddit",

View File

@ -105,6 +105,7 @@
"View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.", "View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.",
"View privacy policy.": "", "View privacy policy.": "",
"Trending": "Trending", "Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Video auf YouTube ansehen", "Watch video on Youtube": "Video auf YouTube ansehen",
"Genre: ": "Genre: ", "Genre: ": "Genre: ",
"License: ": "Lizenz: ", "License: ": "Lizenz: ",
@ -114,6 +115,7 @@
"Whitelisted regions: ": "Erlaubte Regionen: ", "Whitelisted regions: ": "Erlaubte Regionen: ",
"Blacklisted regions: ": "Unerlaubte Regionen: ", "Blacklisted regions: ": "Unerlaubte Regionen: ",
"Shared `x`": "Geteilt `x`", "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.", "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 YouTube comments": "YouTube Kommentare anzeigen",
"View more comments on Reddit": "Mehr Kommentare auf Reddit 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 JavaScript license information.": "View JavaScript license information.",
"View privacy policy.": "View privacy policy.", "View privacy policy.": "View privacy policy.",
"Trending": "Trending", "Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Watch video on Youtube", "Watch video on Youtube": "Watch video on Youtube",
"Genre: ": "Genre: ", "Genre: ": "Genre: ",
"License: ": "License: ", "License: ": "License: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Whitelisted regions: ", "Whitelisted regions: ": "Whitelisted regions: ",
"Blacklisted regions: ": "Blacklisted regions: ", "Blacklisted regions: ": "Blacklisted regions: ",
"Shared `x`": "Shared `x`", "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.", "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 YouTube comments": "View YouTube comments",
"View more comments on Reddit": "View more comments on Reddit", "View more comments on Reddit": "View more comments on Reddit",

View File

@ -102,6 +102,7 @@
"Source available here.": "", "Source available here.": "",
"View JavaScript license information.": "", "View JavaScript license information.": "",
"View privacy policy.": "", "View privacy policy.": "",
"Unlisted": "",
"Trending": "", "Trending": "",
"Watch video on Youtube": "", "Watch video on Youtube": "",
"Genre: ": "", "Genre: ": "",
@ -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

@ -2,7 +2,7 @@
"`x` subscribers": "`x` abonnés", "`x` subscribers": "`x` abonnés",
"`x` videos": "`x` vidéos", "`x` videos": "`x` vidéos",
"LIVE": "EN DIRECT", "LIVE": "EN DIRECT",
"Shared `x` ago": "Partagé il y a `x`", "Shared `x` ago": "Ajoutée il y a `x`",
"Unsubscribe": "Se désabonner", "Unsubscribe": "Se désabonner",
"Subscribe": "S'abonner", "Subscribe": "S'abonner",
"Login to subscribe to `x`": "Vous devez vous connecter pour vous abonner à `x`", "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 ?", "Clear watch history?": "Êtes-vous sûr de vouloir supprimer l'historique des vidéos regardées ?",
"Yes": "Oui", "Yes": "Oui",
"No": "Non", "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": "Importer",
"Import Invidious data": "Importer des données Invidious", "Import Invidious data": "Importer des données Invidious",
"Import YouTube subscriptions": "Importer des abonnements YouTube", "Import YouTube subscriptions": "Importer des abonnements YouTube",
@ -32,32 +32,32 @@
"An alternative front-end to YouTube": "Un front-end alternatif à YouTube", "An alternative front-end to YouTube": "Un front-end alternatif à YouTube",
"JavaScript license information": "Informations sur les licences JavaScript", "JavaScript license information": "Informations sur les licences JavaScript",
"source": "source", "source": "source",
"Login": "Connexion", "Login": "Se connecter",
"Login/Register": "Connexion/S'inscrire", "Login/Register": "Se connecter/Créer un compte",
"Login to Google": "Se connecter à Google", "Login to Google": "Se connecter avec Google",
"User ID:": "Identifiant utilisateur :", "User ID:": "Identifiant utilisateur :",
"Password:": "Mot de passe :", "Password:": "Mot de passe :",
"Time (h:mm:ss):": "Heure (h:mm:ss) :", "Time (h:mm:ss):": "Heure (h:mm:ss) :",
"Text CAPTCHA": "CAPTCHA Texte", "Text CAPTCHA": "CAPTCHA Texte",
"Image CAPTCHA": "CAPTCHA Image", "Image CAPTCHA": "CAPTCHA Image",
"Sign In": "S'identifier", "Sign In": "Se connecter",
"Register": "S'inscrire", "Register": "S'inscrire",
"Email:": "E-mail :", "Email:": "E-mail :",
"Google verification code:": "Code de vérification Google :", "Google verification code:": "Code de vérification Google :",
"Preferences": "Préférences", "Preferences": "Préférences",
"Player preferences": "Préférences du Lecteur", "Player preferences": "Préférences du lecteur",
"Always loop: ": "Lire en boucle : ", "Always loop: ": "Lire en boucle : ",
"Autoplay: ": "Lire Automatiquement : ", "Autoplay: ": "Lire automatiquement : ",
"Autoplay next video: ": "Lire automatiquement la vidéo suivante : ", "Autoplay next video: ": "Lire automatiquement la vidéo suivante : ",
"Listen by default: ": "Audio Uniquement par défaut : ", "Listen by default: ": "Audio uniquement : ",
"Proxy videos? ": "Souhaitez vous charger les vidéos à travers un proxy ?", "Proxy videos? ": "Charger les vidéos à travers un proxy ? ",
"Default speed: ": "Vitesse par défaut : ", "Default speed: ": "Vitesse par défaut : ",
"Preferred video quality: ": "Qualité vidéo souhaitée : ", "Preferred video quality: ": "Qualité vidéo souhaitée : ",
"Player volume: ": "Volume du lecteur : ", "Player volume: ": "Volume du lecteur : ",
"Default comments: ": "Source des Commentaires : ", "Default comments: ": "Source des commentaires : ",
"Default captions: ": "Sous-titres principal : ", "Default captions: ": "Sous-titres par défaut : ",
"Fallback captions: ": "Sous-titres secondaire : ", "Fallback captions: ": "Fallback captions: ",
"Show related videos? ": "Voir les vidéos liées à ce sujet ? ", "Show related videos? ": "Voir les vidéos liées ? ",
"Visual preferences": "Préférences du site", "Visual preferences": "Préférences du site",
"Dark mode: ": "Mode Sombre : ", "Dark mode: ": "Mode Sombre : ",
"Thin mode: ": "Mode Simplifié : ", "Thin mode: ": "Mode Simplifié : ",
@ -82,13 +82,13 @@
"Watch history": "Historique de visionnage", "Watch history": "Historique de visionnage",
"Delete account": "Supprimer votre compte", "Delete account": "Supprimer votre compte",
"Administrator preferences": "Préferences d'Administrateur", "Administrator preferences": "Préferences d'Administrateur",
"Default homepage: ": "Page d'accueil par defaut :", "Default homepage: ": "Page d'accueil par défaut : ",
"Feed menu: ": "Menu des Flux : ", "Feed menu: ": "Menu des Flux : ",
"Top enabled? ": "Top activé ? ", "Top enabled? ": "Top activé ? ",
"CAPTCHA enabled? ": "CAPTCHA activé ? ", "CAPTCHA enabled? ": "CAPTCHA activé ? ",
"Login enabled? ": "Connexion activé ? ", "Login enabled? ": "Connexion activé ? ",
"Registration enabled? ": "Inscription activé ?", "Registration enabled? ": "Inscription activée ? ",
"Report statistics? ": "Telemetrie activé ?", "Report statistics? ": "Télémétrie activé ? ",
"Save preferences": "Enregistrer les préférences", "Save preferences": "Enregistrer les préférences",
"Subscription manager": "Gestionnaire d'abonnement", "Subscription manager": "Gestionnaire d'abonnement",
"`x` subscriptions": "`x` abonnements", "`x` subscriptions": "`x` abonnements",
@ -103,16 +103,18 @@
"View JavaScript license information.": "Voir les informations des licences JavaScript.", "View JavaScript license information.": "Voir les informations des licences JavaScript.",
"View privacy policy.": "Politique de confidentialité", "View privacy policy.": "Politique de confidentialité",
"Trending": "Tendances", "Trending": "Tendances",
"Unlisted": "Non répertoriée",
"Watch video on Youtube": "Voir la vidéo sur Youtube", "Watch video on Youtube": "Voir la vidéo sur Youtube",
"Genre: ": "Genre : ", "Genre: ": "Genre : ",
"License: ": "Licence : ", "License: ": "Licence : ",
"Family friendly? ": "Tout Public ? ", "Family friendly? ": "Tout Public ? ",
"Wilson score: ": "Score de Wilson : ", "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 : ", "Whitelisted regions: ": "Régions en liste blanche : ",
"Blacklisted regions: ": "Régions sur liste noire : ", "Blacklisted regions: ": "Régions sur liste noire : ",
"Shared `x`": "Partagée `x`", "Shared `x`": "Ajoutée le `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.", "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 YouTube comments": "Voir les commentaires YouTube",
"View more comments on Reddit": "Voir plus de commentaires sur Reddit", "View more comments on Reddit": "Voir plus de commentaires sur Reddit",
"View `x` comments": "Voir `x` commentaires", "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.", "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", "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.", "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", "Invalid CAPTCHA": "CAPTCHA invalide",
"CAPTCHA is a required field": "Veuillez rentrez un CAPTCHA", "CAPTCHA is a required field": "Veuillez entrer un CAPTCHA",
"User ID is a required field": "Veuillez rentrez un Identifiant Utilisateur", "User ID is a required field": "Veuillez entrer un Identifiant Utilisateur",
"Password is a required field": "Veuillez rentrez un Mot de passe", "Password is a required field": "Veuillez entrer un Mot de passe",
"Invalid username or password": "Nom d'utilisateur ou mot de passe invalide", "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 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", "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", "Please sign in": "Veuillez vous connecter",
@ -268,7 +270,7 @@
"`x` hours": "`x` heures", "`x` hours": "`x` heures",
"`x` minutes": "`x` minutes", "`x` minutes": "`x` minutes",
"`x` seconds": "`x` secondes", "`x` seconds": "`x` secondes",
"Fallback comments: ": "Commentaires secondaires : ", "Fallback comments: ": "Fallback comments: ",
"Popular": "Populaire", "Popular": "Populaire",
"Top": "Top", "Top": "Top",
"About": "A Propos", "About": "A Propos",
@ -289,5 +291,5 @@
"Video mode": "Mode Vidéo", "Video mode": "Mode Vidéo",
"Videos": "Vidéos", "Videos": "Vidéos",
"Playlists": "Liste de lecture", "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 JavaScript license information.": "Guarda le informazioni di licenza del codice JavaScript.",
"View privacy policy.": "", "View privacy policy.": "",
"Trending": "Tendenze", "Trending": "Tendenze",
"Unlisted": "",
"Watch video on Youtube": "Guarda il video su YouTube", "Watch video on Youtube": "Guarda il video su YouTube",
"Genre: ": "Genere: ", "Genre: ": "Genere: ",
"License: ": "Licenza: ", "License: ": "Licenza: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Regioni nella lista bianca: ", "Whitelisted regions: ": "Regioni nella lista bianca: ",
"Blacklisted regions: ": "Regioni nella lista nera: ", "Blacklisted regions: ": "Regioni nella lista nera: ",
"Shared `x`": "Condiviso `x`", "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.", "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 YouTube comments": "Visualizza i commenti da YouTube",
"View more comments on Reddit": "Visualizza più commenti su Reddit", "View more comments on Reddit": "Visualizza più commenti su Reddit",

View File

@ -103,6 +103,7 @@
"View JavaScript license information.": "Vis JavaScript-lisensinfo.", "View JavaScript license information.": "Vis JavaScript-lisensinfo.",
"View privacy policy.": "", "View privacy policy.": "",
"Trending": "Trendsettende", "Trending": "Trendsettende",
"Unlisted": "",
"Watch video on Youtube": "Vis video på YouTube", "Watch video on Youtube": "Vis video på YouTube",
"Genre: ": "Sjanger: ", "Genre: ": "Sjanger: ",
"License: ": "Lisens: ", "License: ": "Lisens: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Hvitlistede regioner: ", "Whitelisted regions: ": "Hvitlistede regioner: ",
"Blacklisted regions: ": "Svartelistede regioner: ", "Blacklisted regions: ": "Svartelistede regioner: ",
"Shared `x`": "Delt `x`", "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.", "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 YouTube comments": "Vis YouTube-kommentarer",
"View more comments on Reddit": "Vis flere kommenterer på Reddit", "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 JavaScript license information.": "Bekijk JavaScript licentie informatie.",
"View privacy policy.": "", "View privacy policy.": "",
"Trending": "Trending", "Trending": "Trending",
"Unlisted": "",
"Watch video on Youtube": "Bekijk video op Youtube", "Watch video on Youtube": "Bekijk video op Youtube",
"Genre: ": "Genre: ", "Genre: ": "Genre: ",
"License: ": "Licentie: ", "License: ": "Licentie: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Toegestane regio's: ", "Whitelisted regions: ": "Toegestane regio's: ",
"Blacklisted regions: ": "Geblokkeerde regio's: ", "Blacklisted regions: ": "Geblokkeerde regio's: ",
"Shared `x`": "`x` gedeeld", "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.", "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 YouTube comments": "Bekijk YouTube reacties",
"View more comments on Reddit": "Bekijk meer reacties op Reddit", "View more comments on Reddit": "Bekijk meer reacties op Reddit",

View File

@ -10,7 +10,7 @@
"newest": "najnowsze", "newest": "najnowsze",
"oldest": "najstarsze", "oldest": "najstarsze",
"popular": "popularne", "popular": "popularne",
"last": "", "last": "ostatnie",
"Next page": "Następna strona", "Next page": "Następna strona",
"Previous page": "Poprzednia strona", "Previous page": "Poprzednia strona",
"Clear watch history?": "Wyczyścić historię?", "Clear watch history?": "Wyczyścić historię?",
@ -50,7 +50,7 @@
"Autoplay: ": "Autoodtwarzanie: ", "Autoplay: ": "Autoodtwarzanie: ",
"Autoplay next video: ": "Odtwórz następny film: ", "Autoplay next video: ": "Odtwórz następny film: ",
"Listen by default: ": "Tryb dźwiękowy: ", "Listen by default: ": "Tryb dźwiękowy: ",
"Proxy videos? ": "", "Proxy videos? ": "Filmy przez proxy? ",
"Default speed: ": "Domyślna prędkość: ", "Default speed: ": "Domyślna prędkość: ",
"Preferred video quality: ": "Preferowana jakość filmów: ", "Preferred video quality: ": "Preferowana jakość filmów: ",
"Player volume: ": "Głośność odtwarzacza: ", "Player volume: ": "Głośność odtwarzacza: ",
@ -101,8 +101,9 @@
"Released under the AGPLv3 by Omar Roth.": "Wydano na licencji AGPLv3 przez Omar Roth.", "Released under the AGPLv3 by Omar Roth.": "Wydano na licencji AGPLv3 przez Omar Roth.",
"Source available here.": "Kod źródłowy dostępny tutaj.", "Source available here.": "Kod źródłowy dostępny tutaj.",
"View JavaScript license information.": "Wyświetl informację o licencji JavaScript.", "View JavaScript license information.": "Wyświetl informację o licencji JavaScript.",
"View privacy policy.": "", "View privacy policy.": "Polityka prywatności.",
"Trending": "Na czasie", "Trending": "Na czasie",
"Unlisted": "",
"Watch video on Youtube": "Zobacz film na YouTube", "Watch video on Youtube": "Zobacz film na YouTube",
"Genre: ": "Gatunek: ", "Genre: ": "Gatunek: ",
"License: ": "Licencja: ", "License: ": "Licencja: ",
@ -112,6 +113,7 @@
"Whitelisted regions: ": "Dostępny na obszarach: ", "Whitelisted regions: ": "Dostępny na obszarach: ",
"Blacklisted regions: ": "Niedostępny na obszarach: ", "Blacklisted regions: ": "Niedostępny na obszarach: ",
"Shared `x`": "Udostępniono `x`", "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.", "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 YouTube comments": "Wyświetl komentarze z YouTube",
"View more comments on Reddit": "Wyświetl więcej komentarzy na Reddicie", "View more comments on Reddit": "Wyświetl więcej komentarzy na Reddicie",
@ -270,7 +272,7 @@
"`x` seconds": "`x` sekund", "`x` seconds": "`x` sekund",
"Fallback comments: ": "Zastępcze komentarze: ", "Fallback comments: ": "Zastępcze komentarze: ",
"Popular": "Popularne", "Popular": "Popularne",
"Top": "Na czasie", "Top": "Najczęściej oglądane",
"About": "Informacje", "About": "Informacje",
"Rating: ": "Ocena: ", "Rating: ": "Ocena: ",
"Language: ": "Język: ", "Language: ": "Język: ",

View File

@ -105,6 +105,7 @@
"View JavaScript license information.": "Посмотреть лицензии JavaScript кода.", "View JavaScript license information.": "Посмотреть лицензии JavaScript кода.",
"View privacy policy.": "См. политику конфиденциальности.", "View privacy policy.": "См. политику конфиденциальности.",
"Trending": "В тренде", "Trending": "В тренде",
"Unlisted": "",
"Watch video on Youtube": "Смотреть на YouTube", "Watch video on Youtube": "Смотреть на YouTube",
"Genre: ": "Жанр: ", "Genre: ": "Жанр: ",
"License: ": "Лицензия: ", "License: ": "Лицензия: ",
@ -114,6 +115,7 @@
"Whitelisted regions: ": "Доступно для: ", "Whitelisted regions: ": "Доступно для: ",
"Blacklisted regions: ": "Недоступно для: ", "Blacklisted regions: ": "Недоступно для: ",
"Shared `x`": "Опубликовано `x`", "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. Нажмите сюда, чтобы увидеть комментарии (учтите, что они могут загружаться дольше).", "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 YouTube comments": "Смотреть комментарии с YouTube",
"View more comments on Reddit": "Больше комментариев на Reddit", "View more comments on Reddit": "Больше комментариев на Reddit",

View File

@ -242,6 +242,9 @@ get "/api/v1/comments/:id" do |env|
source = env.params.query["source"]? source = env.params.query["source"]?
source ||= "youtube" source ||= "youtube"
thin_mode = env.params.query["thin_mode"]?
thin_mode = thin_mode == "true"
format = env.params.query["format"]? format = env.params.query["format"]?
format ||= "json" format ||= "json"
@ -249,7 +252,7 @@ get "/api/v1/comments/:id" do |env|
if source == "youtube" if source == "youtube"
begin 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 rescue ex
error_message = {"error" => ex.message}.to_json error_message = {"error" => ex.message}.to_json
env.response.status_code = 500 env.response.status_code = 500
@ -1688,6 +1691,11 @@ get "/videoplayback" do |env|
fvip = query_params["fvip"]? || "3" fvip = query_params["fvip"]? || "3"
mns = query_params["mn"].split(",") 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? if query_params["host"]? && !query_params["host"].empty?
host = "https://#{query_params["host"]}" host = "https://#{query_params["host"]}"
query_params.delete("host") query_params.delete("host")
@ -1704,8 +1712,6 @@ get "/videoplayback" do |env|
end end
end end
region = query_params["region"]?
response = HTTP::Client::Response.new(403) response = HTTP::Client::Response.new(403)
5.times do 5.times do
begin begin
@ -1725,9 +1731,12 @@ get "/videoplayback" do |env|
if response.headers["Location"]? if response.headers["Location"]?
url = URI.parse(response.headers["Location"]) url = URI.parse(response.headers["Location"])
host = url.host
env.response.headers["Access-Control-Allow-Origin"] = "*" env.response.headers["Access-Control-Allow-Origin"] = "*"
url = url.full_path url = url.full_path
url += "&host=#{host}"
if region if region
url += "&region=#{region}" url += "&region=#{region}"
end end
@ -1744,15 +1753,30 @@ get "/videoplayback" do |env|
client.get(url, headers) do |response| client.get(url, headers) do |response|
env.response.status_code = response.status_code 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| response.headers.each do |key, value|
env.response.headers[key] = value env.response.headers[key] = value
end 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"] = "*" env.response.headers["Access-Control-Allow-Origin"] = "*"
begin begin

View File

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

View File

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

View File

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

View File

@ -9,6 +9,17 @@ macro add_mapping(mapping)
DB.mapping({{mapping}}) DB.mapping({{mapping}})
end 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") macro templated(filename, template = "template")
render "src/invidious/views/#{{{filename}}}.ecr", "src/invidious/views/#{{{template}}}.ecr" render "src/invidious/views/#{{{filename}}}.ecr", "src/invidious/views/#{{{template}}}.ecr"
end end

View File

@ -106,7 +106,7 @@ def subscribe_to_feeds(db, logger, key, config)
if config.use_pubsub_feeds if config.use_pubsub_feeds
spawn do spawn do
loop 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 rs.each do
ucid = rs.read(String) ucid = rs.read(String)
response = subscribe_pubsub(ucid, key, config) response = subscribe_pubsub(ucid, key, config)

View File

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

View File

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

View File

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

View File

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

View File

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