Merge remote-tracking branch 'upstream/master' into side-menu

This commit is contained in:
Tommy Miland 2019-03-12 16:11:31 +01:00
commit 1b2f5a5f53
21 changed files with 271 additions and 215 deletions

View File

@ -3,7 +3,7 @@
## Invidious is an alternative front-end to YouTube ## Invidious is an alternative front-end to YouTube
- Audio-only mode (and no need to keep window open on mobile) - Audio-only mode (and no need to keep window open on mobile)
- [Open-source](https://github.com/omarroth/invidious) (AGPLv3 licensed) - [Free software](https://github.com/omarroth/invidious) (AGPLv3 licensed)
- No ads - No ads
- No need to create a Google account to save subscriptions - No need to create a Google account to save subscriptions
- Lightweight (homepage is ~4 KB compressed) - Lightweight (homepage is ~4 KB compressed)

View File

@ -9,7 +9,7 @@ a {
} }
/* All links that do not fit with the default color goes here */ /* All links that do not fit with the default color goes here */
a > .icon, a:not([data-id]) > .icon,
.pure-u-md-1-5 > .h-box > a[href^="/watch?"], .pure-u-md-1-5 > .h-box > a[href^="/watch?"],
.playlist-restricted > ol > li > a { .playlist-restricted > ol > li > a {
color: #303030; color: #303030;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -10,8 +10,9 @@
"newest": "الأجدد", "newest": "الأجدد",
"oldest": "الأقدم", "oldest": "الأقدم",
"popular": "الاكثر شعبية", "popular": "الاكثر شعبية",
"Preview page": "معاينة الصفحة", "last": "",
"Next page": "الصفحة الثانية", "Next page": "الصفحة الثانية",
"Previous page": "الصفحة السابقة",
"Clear watch history?": "مسح السجل ؟", "Clear watch history?": "مسح السجل ؟",
"Yes": "نعم", "Yes": "نعم",
"No": "لا", "No": "لا",
@ -28,7 +29,6 @@
"Export data as JSON": "استخراج البيانات كـ JSON", "Export data as JSON": "استخراج البيانات كـ JSON",
"Delete account?": "حذف الحساب ؟", "Delete account?": "حذف الحساب ؟",
"History": "السجل", "History": "السجل",
"Previous page": "الصفحة السابقة",
"An alternative front-end to YouTube": "البديل الكامل لموقع يوتيوب", "An alternative front-end to YouTube": "البديل الكامل لموقع يوتيوب",
"JavaScript license information": "معلومات ترخيص JavaScript", "JavaScript license information": "معلومات ترخيص JavaScript",
"source": "المصدر", "source": "المصدر",
@ -101,10 +101,6 @@
"Sign out": "تسجيل الخروج", "Sign out": "تسجيل الخروج",
"Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.", "Released under the AGPLv3 by Omar Roth.": "تم الإنشاء تحت AGPLv3 بواسطة عمر روث.",
"Source available here.": "الأكواد متوفرة هنا.", "Source available here.": "الأكواد متوفرة هنا.",
"Liberapay: ": "ليبرباى: ",
"Patreon: ": "باتريون: ",
"BTC: ": "بيتكوين: ",
"BCH: ": "بيتكوين كاش: ",
"View JavaScript license information.": "مشاهدة معلومات حول تراخيص الجافاسكريبت.", "View JavaScript license information.": "مشاهدة معلومات حول تراخيص الجافاسكريبت.",
"Trending": "الشائع", "Trending": "الشائع",
"Watch video on Youtube": "مشاهدة الفيديو على اليوتيوب", "Watch video on Youtube": "مشاهدة الفيديو على اليوتيوب",
@ -290,5 +286,8 @@
"Youtube permalink of the comment": "", "Youtube permalink of the comment": "",
"`x` marked it with a ❤": "", "`x` marked it with a ❤": "",
"Audio mode": "", "Audio mode": "",
"Video mode": "" "Video mode": "",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "neueste", "newest": "neueste",
"oldest": "älteste", "oldest": "älteste",
"popular": "beliebt", "popular": "beliebt",
"Preview page": "Vorschau Seite", "last": "",
"Next page": "Nächste Seite", "Next page": "Nächste Seite",
"Previous page": "Vorherige Seite",
"Clear watch history?": "Verlauf löschen?", "Clear watch history?": "Verlauf löschen?",
"Yes": "Ja", "Yes": "Ja",
"No": "Nein", "No": "Nein",
@ -28,7 +29,6 @@
"Export data as JSON": "Daten als JSON exportieren", "Export data as JSON": "Daten als JSON exportieren",
"Delete account?": "Account löschen?", "Delete account?": "Account löschen?",
"History": "Verlauf", "History": "Verlauf",
"Previous page": "Vorherige Seite",
"An alternative front-end to YouTube": "Eine alternative Oberfläche für YouTube", "An alternative front-end to YouTube": "Eine alternative Oberfläche für YouTube",
"JavaScript license information": "JavaScript Lizenzinformationen", "JavaScript license information": "JavaScript Lizenzinformationen",
"source": "Quelle", "source": "Quelle",
@ -101,10 +101,6 @@
"Sign out": "Abmelden", "Sign out": "Abmelden",
"Released under the AGPLv3 by Omar Roth.": "Veröffentlicht unter AGPLv3 von Omar Roth.", "Released under the AGPLv3 by Omar Roth.": "Veröffentlicht unter AGPLv3 von Omar Roth.",
"Source available here.": "Quellcode verfügbar hier.", "Source available here.": "Quellcode verfügbar hier.",
"Liberapay: ": "Liberapay: ",
"Patreon: ": "Patreon: ",
"BTC: ": "BTC: ",
"BCH: ": "BCH: ",
"View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.", "View JavaScript license information.": "Javascript Lizenzinformationen anzeigen.",
"Trending": "Trending", "Trending": "Trending",
"Watch video on Youtube": "Video auf YouTube ansehen", "Watch video on Youtube": "Video auf YouTube ansehen",
@ -290,5 +286,8 @@
"Youtube permalink of the comment": "", "Youtube permalink of the comment": "",
"`x` marked it with a ❤": "", "`x` marked it with a ❤": "",
"Audio mode": "", "Audio mode": "",
"Video mode": "" "Video mode": "",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "newest", "newest": "newest",
"oldest": "oldest", "oldest": "oldest",
"popular": "popular", "popular": "popular",
"Preview page": "Preview page", "last": "last",
"Next page": "Next page", "Next page": "Next page",
"Previous page": "Previous page",
"Clear watch history?": "Clear watch history?", "Clear watch history?": "Clear watch history?",
"Yes": "Yes", "Yes": "Yes",
"No": "No", "No": "No",
@ -28,7 +29,6 @@
"Export data as JSON": "Export data as JSON", "Export data as JSON": "Export data as JSON",
"Delete account?": "Delete account?", "Delete account?": "Delete account?",
"History": "History", "History": "History",
"Previous page": "Previous page",
"An alternative front-end to YouTube": "An alternative front-end to YouTube", "An alternative front-end to YouTube": "An alternative front-end to YouTube",
"JavaScript license information": "JavaScript license information", "JavaScript license information": "JavaScript license information",
"source": "source", "source": "source",
@ -284,5 +284,8 @@
"Youtube permalink of the comment": "Youtube permalink of the comment", "Youtube permalink of the comment": "Youtube permalink of the comment",
"`x` marked it with a ❤": "`x` marked it with a ❤", "`x` marked it with a ❤": "`x` marked it with a ❤",
"Audio mode": "Audio mode", "Audio mode": "Audio mode",
"Video mode": "Video mode" "Video mode": "Video mode",
"Videos": "Videos",
"Playlists": "Playlists",
"Current version: ": "Current version: "
} }

View File

@ -10,8 +10,9 @@
"newest": "berrienak", "newest": "berrienak",
"oldest": "zaharrenak", "oldest": "zaharrenak",
"popular": "ospetsuenak", "popular": "ospetsuenak",
"Preview page": "Aurrebista orria", "last": "",
"Next page": "Hurrengo orria", "Next page": "Hurrengo orria",
"Previous page": "Aurreko orria",
"Clear watch history?": "Garbitu ikusitakoen historia?", "Clear watch history?": "Garbitu ikusitakoen historia?",
"Yes": "Bai", "Yes": "Bai",
"No": "Ez", "No": "Ez",
@ -28,7 +29,6 @@
"Export data as JSON": "Datuak JSON bezala esportatu", "Export data as JSON": "Datuak JSON bezala esportatu",
"Delete account?": "Kontua ezabatu?", "Delete account?": "Kontua ezabatu?",
"History": "Historia", "History": "Historia",
"Previous page": "Aurreko orria",
"An alternative front-end to YouTube": "YouTuberako interfaze alternatibo bat", "An alternative front-end to YouTube": "YouTuberako interfaze alternatibo bat",
"JavaScript license information": "JavaScript lizentzia informazioa", "JavaScript license information": "JavaScript lizentzia informazioa",
"source": "iturburua", "source": "iturburua",
@ -284,5 +284,8 @@
"Youtube permalink of the comment": "", "Youtube permalink of the comment": "",
"`x` marked it with a ❤": "", "`x` marked it with a ❤": "",
"Audio mode": "", "Audio mode": "",
"Video mode": "" "Video mode": "",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,7 +10,9 @@
"newest": "Date d'ajout (la plus récente)", "newest": "Date d'ajout (la plus récente)",
"oldest": "Date d'ajout (la plus ancienne)", "oldest": "Date d'ajout (la plus ancienne)",
"popular": "Les plus populaires", "popular": "Les plus populaires",
"last": "",
"Next page": "Page suivante", "Next page": "Page suivante",
"Previous page": "Page précédente",
"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",
@ -27,7 +29,6 @@
"Export data as JSON": "Exporter les données au format JSON", "Export data as JSON": "Exporter les données au format JSON",
"Delete account?": "Supprimer votre compte ?", "Delete account?": "Supprimer votre compte ?",
"History": "Historique", "History": "Historique",
"Previous page": "Page précédente",
"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",
@ -283,5 +284,8 @@
"Youtube permalink of the comment": "Lien YouTube permanent vers le commentaire", "Youtube permalink of the comment": "Lien YouTube permanent vers le commentaire",
"`x` marked it with a ❤": "`x` l'a marqué d'un ❤", "`x` marked it with a ❤": "`x` l'a marqué d'un ❤",
"Audio mode": "Mode Audio", "Audio mode": "Mode Audio",
"Video mode": "Mode Vidéo" "Video mode": "Mode Vidéo",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,7 +10,9 @@
"newest": "Data di aggiunta (più recente)", "newest": "Data di aggiunta (più recente)",
"oldest": "Data di aggiunta (più vecchia)", "oldest": "Data di aggiunta (più vecchia)",
"popular": "Tendenze", "popular": "Tendenze",
"last": "",
"Next page": "Pagina successiva", "Next page": "Pagina successiva",
"Previous page": "Pagina precedente",
"Clear watch history?": "Sei sicuro di voler cancellare la cronologia dei video guardati?", "Clear watch history?": "Sei sicuro di voler cancellare la cronologia dei video guardati?",
"Yes": "Si", "Yes": "Si",
"No": "No", "No": "No",
@ -27,7 +29,6 @@
"Export data as JSON": "Esporta i dati in formato JSON", "Export data as JSON": "Esporta i dati in formato JSON",
"Delete account?": "Sei sicuro di voler cancellare l'account?", "Delete account?": "Sei sicuro di voler cancellare l'account?",
"History": "Cronologia", "History": "Cronologia",
"Previous page": "Pagina precedente",
"An alternative front-end to YouTube": "Un'interfaccia alternativa per YouTube", "An alternative front-end to YouTube": "Un'interfaccia alternativa per YouTube",
"JavaScript license information": "Info licenze JavaScript", "JavaScript license information": "Info licenze JavaScript",
"source": "sorgente", "source": "sorgente",
@ -283,5 +284,8 @@
"Youtube permalink of the comment": "Link permanente al commento di YouTube", "Youtube permalink of the comment": "Link permanente al commento di YouTube",
"`x` marked it with a ❤": "`x` l'ha contrassegnato con un ❤", "`x` marked it with a ❤": "`x` l'ha contrassegnato con un ❤",
"Audio mode": "Modalità audio", "Audio mode": "Modalità audio",
"Video mode": "Modalità video" "Video mode": "Modalità video",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "nyeste", "newest": "nyeste",
"oldest": "eldste", "oldest": "eldste",
"popular": "populært", "popular": "populært",
"Preview page": "Forhåndsvis side", "last": "",
"Next page": "Neste side", "Next page": "Neste side",
"Previous page": "Forrige side",
"Clear watch history?": "Tøm visningshistorikk?", "Clear watch history?": "Tøm visningshistorikk?",
"Yes": "Ja", "Yes": "Ja",
"No": "Nei", "No": "Nei",
@ -28,7 +29,6 @@
"Export data as JSON": "Eksporter data som JSON", "Export data as JSON": "Eksporter data som JSON",
"Delete account?": "Slett konto?", "Delete account?": "Slett konto?",
"History": "Historikk", "History": "Historikk",
"Previous page": "Forrige side",
"An alternative front-end to YouTube": "En alternativ grenseflate for YouTube", "An alternative front-end to YouTube": "En alternativ grenseflate for YouTube",
"JavaScript license information": "JavaScript-lisensinformasjon", "JavaScript license information": "JavaScript-lisensinformasjon",
"source": "kilde", "source": "kilde",
@ -87,7 +87,7 @@
"CAPTCHA enabled? ": "CAPTCHA påskrudd? ", "CAPTCHA enabled? ": "CAPTCHA påskrudd? ",
"Login enabled? ": "Innlogging påskrudd? ", "Login enabled? ": "Innlogging påskrudd? ",
"Registration enabled? ": "Registrering påskrudd? ", "Registration enabled? ": "Registrering påskrudd? ",
"Report statistics? ": "", "Report statistics? ": "Innrapporter statistikk? ",
"Save preferences": "Lagre innstillinger", "Save preferences": "Lagre innstillinger",
"Subscription manager": "Abonnementsbehandler", "Subscription manager": "Abonnementsbehandler",
"`x` subscriptions": "`x` abonnementer", "`x` subscriptions": "`x` abonnementer",
@ -284,5 +284,8 @@
"Youtube permalink of the comment": "Permanent YouTube-lenke til innholdet", "Youtube permalink of the comment": "Permanent YouTube-lenke til innholdet",
"`x` marked it with a ❤": "`x` levnet et ❤", "`x` marked it with a ❤": "`x` levnet et ❤",
"Audio mode": "Lydmodus", "Audio mode": "Lydmodus",
"Video mode": "Video-modus" "Video mode": "Video-modus",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "nieuwste", "newest": "nieuwste",
"oldest": "oudste", "oldest": "oudste",
"popular": "populair", "popular": "populair",
"Preview page": "Pagina voorvertonen", "last": "",
"Next page": "Volgende pagina", "Next page": "Volgende pagina",
"Previous page": "Vorige pagina",
"Clear watch history?": "Kijk geschiedenis wissen?", "Clear watch history?": "Kijk geschiedenis wissen?",
"Yes": "Ja", "Yes": "Ja",
"No": "Nee", "No": "Nee",
@ -28,7 +29,6 @@
"Export data as JSON": "Exporteer gegevens als JSON", "Export data as JSON": "Exporteer gegevens als JSON",
"Delete account?": "Verwijder account?", "Delete account?": "Verwijder account?",
"History": "Geschiedenis", "History": "Geschiedenis",
"Previous page": "Vorige pagina",
"An alternative front-end to YouTube": "Een alternatieve front-end voor YouTube", "An alternative front-end to YouTube": "Een alternatieve front-end voor YouTube",
"JavaScript license information": "JavaScript licentie informatie", "JavaScript license information": "JavaScript licentie informatie",
"source": "bron", "source": "bron",
@ -284,5 +284,8 @@
"Youtube permalink of the comment": "", "Youtube permalink of the comment": "",
"`x` marked it with a ❤": "", "`x` marked it with a ❤": "",
"Audio mode": "", "Audio mode": "",
"Video mode": "" "Video mode": "",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "najnowsze", "newest": "najnowsze",
"oldest": "najstarsze", "oldest": "najstarsze",
"popular": "popularne", "popular": "popularne",
"Preview page": "Podgląd strony", "last": "",
"Next page": "Następna strona", "Next page": "Następna strona",
"Previous page": "Poprzednia strona",
"Clear watch history?": "Wyczyścić historię?", "Clear watch history?": "Wyczyścić historię?",
"Yes": "Tak", "Yes": "Tak",
"No": "Nie", "No": "Nie",
@ -28,7 +29,6 @@
"Export data as JSON": "Eksportuj dane jako JSON", "Export data as JSON": "Eksportuj dane jako JSON",
"Delete account?": "Usunąć konto?", "Delete account?": "Usunąć konto?",
"History": "Historia", "History": "Historia",
"Previous page": "Poprzednia strona",
"An alternative front-end to YouTube": "Alternatywny front-end dla YouTube", "An alternative front-end to YouTube": "Alternatywny front-end dla YouTube",
"JavaScript license information": "Informacja o licencji JavaScript", "JavaScript license information": "Informacja o licencji JavaScript",
"source": "źródło", "source": "źródło",
@ -284,5 +284,8 @@
"Youtube permalink of the comment": "Odnośnik bezpośredni do komentarza na YouTube", "Youtube permalink of the comment": "Odnośnik bezpośredni do komentarza na YouTube",
"`x` marked it with a ❤": "", "`x` marked it with a ❤": "",
"Audio mode": "Tryb audio", "Audio mode": "Tryb audio",
"Video mode": "Tryb wideo" "Video mode": "Tryb wideo",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -10,8 +10,9 @@
"newest": "новые", "newest": "новые",
"oldest": "старые", "oldest": "старые",
"popular": "популярные", "popular": "популярные",
"Preview page": "Предварительный просмотр", "last": "",
"Next page": "Следующая страница", "Next page": "Следующая страница",
"Previous page": "Предыдущая страница",
"Clear watch history?": "Очистить историю просмотров?", "Clear watch history?": "Очистить историю просмотров?",
"Yes": "Да", "Yes": "Да",
"No": "Нет", "No": "Нет",
@ -28,7 +29,6 @@
"Export data as JSON": "Экспортировать данные в JSON", "Export data as JSON": "Экспортировать данные в JSON",
"Delete account?": "Удалить аккаунт?", "Delete account?": "Удалить аккаунт?",
"History": "История", "History": "История",
"Previous page": "Предыдущая страница",
"An alternative front-end to YouTube": "Альтернативный фронтенд для YouTube", "An alternative front-end to YouTube": "Альтернативный фронтенд для YouTube",
"JavaScript license information": "Лицензии JavaScript", "JavaScript license information": "Лицензии JavaScript",
"source": "источник", "source": "источник",
@ -82,14 +82,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` подписок",
@ -101,10 +101,6 @@
"Sign out": "Выйти", "Sign out": "Выйти",
"Released under the AGPLv3 by Omar Roth.": "Распространяется Omar Roth по AGPLv3.", "Released under the AGPLv3 by Omar Roth.": "Распространяется Omar Roth по AGPLv3.",
"Source available here.": "Исходный код доступен здесь.", "Source available here.": "Исходный код доступен здесь.",
"Liberapay: ": "Liberapay: ",
"Patreon: ": "Patreon: ",
"BTC: ": "BTC: ",
"BCH: ": "BCH: ",
"View JavaScript license information.": "Посмотреть лицензии JavaScript кода.", "View JavaScript license information.": "Посмотреть лицензии JavaScript кода.",
"Trending": "В тренде", "Trending": "В тренде",
"Watch video on Youtube": "Смотреть на YouTube", "Watch video on Youtube": "Смотреть на YouTube",
@ -290,5 +286,8 @@
"Youtube permalink of the comment": "Прямая ссылка на YouTube", "Youtube permalink of the comment": "Прямая ссылка на YouTube",
"`x` marked it with a ❤": "❤ от автора канала \"`x`\"", "`x` marked it with a ❤": "❤ от автора канала \"`x`\"",
"Audio mode": "Аудио режим", "Audio mode": "Аудио режим",
"Video mode": "Видео режим" "Video mode": "Видео режим",
"Videos": "",
"Playlists": "",
"Current version: ": ""
} }

View File

@ -192,6 +192,7 @@ proxies = PROXY_LIST
before_all do |env| before_all do |env|
env.response.headers["X-XSS-Protection"] = "1; mode=block;" env.response.headers["X-XSS-Protection"] = "1; mode=block;"
env.response.headers["X-Content-Type-Options"] = "nosniff" env.response.headers["X-Content-Type-Options"] = "nosniff"
preferences = DEFAULT_USER_PREFERENCES.dup
if env.request.cookies.has_key? "SID" if env.request.cookies.has_key? "SID"
headers = HTTP::Headers.new headers = HTTP::Headers.new
@ -210,9 +211,9 @@ before_all do |env|
env.set "challenge", challenge env.set "challenge", challenge
env.set "token", token env.set "token", token
locale = user.preferences.locale preferences = user.preferences
env.set "user", user env.set "user", user
env.set "preferences", user.preferences
env.set "sid", sid env.set "sid", sid
end end
else else
@ -223,9 +224,9 @@ before_all do |env|
env.set "challenge", challenge env.set "challenge", challenge
env.set "token", token env.set "token", token
locale = user.preferences.locale preferences = user.preferences
env.set "user", user env.set "user", user
env.set "preferences", user.preferences
env.set "sid", sid env.set "sid", sid
rescue ex rescue ex
end end
@ -234,14 +235,20 @@ before_all do |env|
if env.request.cookies.has_key? "PREFS" if env.request.cookies.has_key? "PREFS"
preferences = Preferences.from_json(env.request.cookies["PREFS"].value) preferences = Preferences.from_json(env.request.cookies["PREFS"].value)
locale = preferences.locale
env.set "preferences", preferences
end end
locale = env.params.query["hl"]? || locale dark_mode = env.params.query["dark_mode"]? || preferences.dark_mode.to_s
locale ||= "en-US" dark_mode = dark_mode == "true"
env.set "locale", locale
thin_mode = env.params.query["thin_mode"]? || preferences.thin_mode.to_s
thin_mode = thin_mode == "true"
locale = env.params.query["hl"]? || preferences.locale
preferences.dark_mode = dark_mode
preferences.thin_mode = thin_mode
preferences.locale = locale
env.set "preferences", preferences
current_page = env.request.path current_page = env.request.path
if env.request.query if env.request.query
@ -258,7 +265,7 @@ before_all do |env|
end end
get "/" do |env| get "/" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
if user if user
@ -285,14 +292,14 @@ get "/" do |env|
end end
get "/licenses" do |env| get "/licenses" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
rendered "licenses" rendered "licenses"
end end
# Videos # Videos
get "/watch" do |env| get "/watch" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
region = env.params.query["region"]? region = env.params.query["region"]?
if env.params.query.to_s.includes?("%20") || env.params.query.to_s.includes?("+") if env.params.query.to_s.includes?("%20") || env.params.query.to_s.includes?("+")
@ -396,6 +403,12 @@ get "/watch" do |env|
fmt_stream = video.fmt_stream(decrypt_function) fmt_stream = video.fmt_stream(decrypt_function)
adaptive_fmts = video.adaptive_fmts(decrypt_function) adaptive_fmts = video.adaptive_fmts(decrypt_function)
if params[:local]
fmt_stream.each { |fmt| fmt["url"] = URI.parse(fmt["url"]).full_path }
adaptive_fmts.each { |fmt| fmt["url"] = URI.parse(fmt["url"]).full_path }
end
video_streams = video.video_streams(adaptive_fmts) video_streams = video.video_streams(adaptive_fmts)
audio_streams = video.audio_streams(adaptive_fmts) audio_streams = video.audio_streams(adaptive_fmts)
@ -458,7 +471,7 @@ get "/watch" do |env|
end end
get "/embed/:id" do |env| get "/embed/:id" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
id = env.params.url["id"] id = env.params.url["id"]
if id.includes?("%20") || id.includes?("+") || env.params.query.to_s.includes?("%20") || env.params.query.to_s.includes?("+") if id.includes?("%20") || id.includes?("+") || env.params.query.to_s.includes?("%20") || env.params.query.to_s.includes?("+")
@ -496,6 +509,12 @@ get "/embed/:id" do |env|
fmt_stream = video.fmt_stream(decrypt_function) fmt_stream = video.fmt_stream(decrypt_function)
adaptive_fmts = video.adaptive_fmts(decrypt_function) adaptive_fmts = video.adaptive_fmts(decrypt_function)
if params[:local]
fmt_stream.each { |fmt| fmt["url"] = URI.parse(fmt["url"]).full_path }
adaptive_fmts.each { |fmt| fmt["url"] = URI.parse(fmt["url"]).full_path }
end
video_streams = video.video_streams(adaptive_fmts) video_streams = video.video_streams(adaptive_fmts)
audio_streams = video.audio_streams(adaptive_fmts) audio_streams = video.audio_streams(adaptive_fmts)
@ -546,7 +565,7 @@ end
# Playlists # Playlists
get "/playlist" do |env| get "/playlist" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
plid = env.params.query["list"]? plid = env.params.query["list"]?
if !plid if !plid
@ -577,7 +596,7 @@ get "/playlist" do |env|
end end
get "/mix" do |env| get "/mix" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
rdid = env.params.query["list"]? rdid = env.params.query["list"]?
if !rdid if !rdid
@ -600,7 +619,7 @@ end
# Search # Search
get "/opensearch.xml" do |env| get "/opensearch.xml" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/opensearchdescription+xml" env.response.content_type = "application/opensearchdescription+xml"
host = make_host_url(config, Kemal.config) host = make_host_url(config, Kemal.config)
@ -618,7 +637,7 @@ get "/opensearch.xml" do |env|
end end
get "/results" do |env| get "/results" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
query = env.params.query["search_query"]? query = env.params.query["search_query"]?
query ||= env.params.query["q"]? query ||= env.params.query["q"]?
@ -635,7 +654,7 @@ get "/results" do |env|
end end
get "/search" do |env| get "/search" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
region = env.params.query["region"]? region = env.params.query["region"]?
query = env.params.query["search_query"]? query = env.params.query["search_query"]?
@ -721,7 +740,7 @@ end
# Users # Users
get "/login" do |env| get "/login" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
if user if user
@ -767,7 +786,7 @@ end
# See https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L79 # See https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L79
post "/login" do |env| post "/login" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env, "/feed/subscriptions") referer = get_referer(env, "/feed/subscriptions")
@ -1144,7 +1163,7 @@ post "/login" do |env|
end end
get "/signout" do |env| get "/signout" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1177,22 +1196,17 @@ get "/signout" do |env|
end end
get "/preferences" do |env| get "/preferences" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env) referer = get_referer(env)
if preferences = env.get? "preferences" preferences = env.get("preferences").as(Preferences)
preferences = preferences.as(Preferences)
templated "preferences" templated "preferences"
else
preferences = DEFAULT_USER_PREFERENCES
templated "preferences"
end
end end
post "/preferences" do |env| post "/preferences" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env) referer = get_referer(env)
video_loop = env.params.body["video_loop"]?.try &.as(String) video_loop = env.params.body["video_loop"]?.try &.as(String)
@ -1335,7 +1349,7 @@ post "/preferences" do |env|
end end
get "/toggle_theme" do |env| get "/toggle_theme" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
referer = get_referer(env) referer = get_referer(env)
if user = env.get? "user" if user = env.get? "user"
@ -1344,14 +1358,9 @@ get "/toggle_theme" do |env|
preferences.dark_mode = !preferences.dark_mode preferences.dark_mode = !preferences.dark_mode
PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email) PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email)
elsif preferences = env.get? "preferences"
preferences = preferences.as(Preferences)
preferences.dark_mode = !preferences.dark_mode
env.response.cookies["PREFS"] = preferences.to_json
else else
preferences = DEFAULT_USER_PREFERENCES preferences = env.get("preferences").as(Preferences)
preferences.dark_mode = true preferences.dark_mode = !preferences.dark_mode
env.response.cookies["PREFS"] = preferences.to_json env.response.cookies["PREFS"] = preferences.to_json
end end
@ -1360,7 +1369,7 @@ get "/toggle_theme" do |env|
end end
get "/mark_watched" do |env| get "/mark_watched" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env, "/feed/subscriptions") referer = get_referer(env, "/feed/subscriptions")
@ -1390,7 +1399,7 @@ get "/mark_watched" do |env|
end end
get "/mark_unwatched" do |env| get "/mark_unwatched" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env, "/feed/history") referer = get_referer(env, "/feed/history")
@ -1422,7 +1431,7 @@ end
# /modify_notifications?receive_all_updates=false&receive_no_updates=false # /modify_notifications?receive_all_updates=false&receive_no_updates=false
# will "unding" all subscriptions. # will "unding" all subscriptions.
get "/modify_notifications" do |env| get "/modify_notifications" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1469,7 +1478,7 @@ get "/modify_notifications" do |env|
end end
get "/subscription_manager" do |env| get "/subscription_manager" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
sid = env.get? "sid" sid = env.get? "sid"
@ -1546,7 +1555,7 @@ get "/subscription_manager" do |env|
end end
get "/data_control" do |env| get "/data_control" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1561,7 +1570,7 @@ get "/data_control" do |env|
end end
post "/data_control" do |env| post "/data_control" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1660,7 +1669,7 @@ post "/data_control" do |env|
end end
get "/subscription_ajax" do |env| get "/subscription_ajax" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1741,7 +1750,7 @@ get "/subscription_ajax" do |env|
end end
get "/delete_account" do |env| get "/delete_account" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1758,7 +1767,7 @@ get "/delete_account" do |env|
end end
post "/delete_account" do |env| post "/delete_account" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1791,7 +1800,7 @@ post "/delete_account" do |env|
end end
get "/clear_watch_history" do |env| get "/clear_watch_history" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1808,7 +1817,7 @@ get "/clear_watch_history" do |env|
end end
post "/clear_watch_history" do |env| post "/clear_watch_history" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -1835,7 +1844,7 @@ end
# Feeds # Feeds
get "/feed/top" do |env| get "/feed/top" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
if config.top_enabled if config.top_enabled
templated "top" templated "top"
@ -1845,13 +1854,13 @@ get "/feed/top" do |env|
end end
get "/feed/popular" do |env| get "/feed/popular" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
templated "popular" templated "popular"
end end
get "/feed/trending" do |env| get "/feed/trending" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
trending_type = env.params.query["type"]? trending_type = env.params.query["type"]?
trending_type ||= "Default" trending_type ||= "Default"
@ -1870,7 +1879,7 @@ get "/feed/trending" do |env|
end end
get "/feed/subscriptions" do |env| get "/feed/subscriptions" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
sid = env.get? "sid" sid = env.get? "sid"
@ -1909,12 +1918,6 @@ get "/feed/subscriptions" do |env|
offset = (page - 1) * max_results offset = (page - 1) * max_results
end end
if preferences.sort == "published - reverse"
sort = ""
else
sort = "DESC"
end
notifications = PG_DB.query_one("SELECT notifications FROM users WHERE email = $1", user.email, notifications = PG_DB.query_one("SELECT notifications FROM users WHERE email = $1", user.email,
as: Array(String)) as: Array(String))
view_name = "subscriptions_#{sha256(user.email)[0..7]}" view_name = "subscriptions_#{sha256(user.email)[0..7]}"
@ -1925,7 +1928,7 @@ get "/feed/subscriptions" do |env|
args = arg_array(notifications) args = arg_array(notifications)
notifications = PG_DB.query_all("SELECT * FROM channel_videos WHERE id IN (#{args}) notifications = PG_DB.query_all("SELECT * FROM channel_videos WHERE id IN (#{args})
ORDER BY published #{sort}", notifications, as: ChannelVideo) ORDER BY published DESC", notifications, as: ChannelVideo)
videos = [] of ChannelVideo videos = [] of ChannelVideo
notifications.sort_by! { |video| video.published }.reverse! notifications.sort_by! { |video| video.published }.reverse!
@ -1953,7 +1956,7 @@ get "/feed/subscriptions" do |env|
end end
videos = PG_DB.query_all("SELECT DISTINCT ON (ucid) * FROM #{view_name} WHERE \ videos = PG_DB.query_all("SELECT DISTINCT ON (ucid) * FROM #{view_name} WHERE \
NOT id = ANY (#{values}) \ NOT id = ANY (#{values}) \
ORDER BY ucid, published #{sort}", as: ChannelVideo) ORDER BY ucid, published DESC", as: ChannelVideo)
else else
# Show latest video from each channel # Show latest video from each channel
@ -1973,12 +1976,12 @@ get "/feed/subscriptions" do |env|
end end
videos = PG_DB.query_all("SELECT * FROM #{view_name} WHERE \ videos = PG_DB.query_all("SELECT * FROM #{view_name} WHERE \
NOT id = ANY (#{values}) \ NOT id = ANY (#{values}) \
ORDER BY published #{sort} LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo) ORDER BY published DESC LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo)
else else
# Sort subscriptions as normal # Sort subscriptions as normal
videos = PG_DB.query_all("SELECT * FROM #{view_name} \ videos = PG_DB.query_all("SELECT * FROM #{view_name} \
ORDER BY published #{sort} LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo) ORDER BY published DESC LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo)
end end
end end
@ -2024,7 +2027,7 @@ get "/feed/subscriptions" do |env|
end end
get "/feed/history" do |env| get "/feed/history" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
referer = get_referer(env) referer = get_referer(env)
@ -2049,7 +2052,7 @@ get "/feed/history" do |env|
end end
get "/feed/channel/:ucid" do |env| get "/feed/channel/:ucid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/atom+xml" env.response.content_type = "application/atom+xml"
@ -2161,7 +2164,7 @@ get "/feed/channel/:ucid" do |env|
end end
get "/feed/private" do |env| get "/feed/private" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/atom+xml" env.response.content_type = "application/atom+xml"
@ -2197,12 +2200,6 @@ get "/feed/private" do |env|
sort = env.params.query["sort"]? sort = env.params.query["sort"]?
sort ||= "published" sort ||= "published"
if sort == "published - reverse"
desc = ""
else
desc = "DESC"
end
view_name = "subscriptions_#{sha256(user.email)[0..7]}" view_name = "subscriptions_#{sha256(user.email)[0..7]}"
if latest_only if latest_only
@ -2212,7 +2209,7 @@ get "/feed/private" do |env|
videos.sort_by! { |video| video.published }.reverse! videos.sort_by! { |video| video.published }.reverse!
else else
videos = PG_DB.query_all("SELECT * FROM #{view_name} \ videos = PG_DB.query_all("SELECT * FROM #{view_name} \
ORDER BY published #{desc} LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo) ORDER BY published DESC LIMIT $1 OFFSET $2", limit, offset, as: ChannelVideo)
end end
case sort case sort
@ -2282,7 +2279,7 @@ get "/feed/private" do |env|
end end
get "/feed/playlist/:plid" do |env| get "/feed/playlist/:plid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/atom+xml" env.response.content_type = "application/atom+xml"
@ -2333,7 +2330,8 @@ get "/feed/webhook/:token" do |env|
data = "#{time}" data = "#{time}"
end end
if Time.now.to_unix - time.to_i > 600 # The hub will sometimes check if we're still subscribed after delivery errors
if Time.now.to_unix - time.to_i > 432000
halt env, status_code: 400 halt env, status_code: 400
end end
@ -2387,7 +2385,7 @@ end
# YouTube appears to let users set a "brand" URL that # YouTube appears to let users set a "brand" URL that
# is different from their username, so we convert that here # is different from their username, so we convert that here
get "/c/:user" do |env| get "/c/:user" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
client = make_client(YT_URL) client = make_client(YT_URL)
user = env.params.url["user"] user = env.params.url["user"]
@ -2424,7 +2422,7 @@ get "/user/:user/videos" do |env|
end end
get "/channel/:ucid" do |env| get "/channel/:ucid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
if user if user
@ -2477,7 +2475,7 @@ get "/channel/:ucid" do |env|
end end
get "/channel/:ucid/videos" do |env| get "/channel/:ucid/videos" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
ucid = env.params.url["ucid"] ucid = env.params.url["ucid"]
params = env.request.query params = env.request.query
@ -2492,7 +2490,7 @@ get "/channel/:ucid/videos" do |env|
end end
get "/channel/:ucid/playlists" do |env| get "/channel/:ucid/playlists" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
user = env.get? "user" user = env.get? "user"
if user if user
@ -2549,7 +2547,7 @@ get "/api/v1/stats" do |env|
end end
get "/api/v1/captions/:id" do |env| get "/api/v1/captions/:id" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -2654,7 +2652,7 @@ get "/api/v1/captions/:id" do |env|
end end
get "/api/v1/comments/:id" do |env| get "/api/v1/comments/:id" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
region = env.params.query["region"]? region = env.params.query["region"]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -2721,7 +2719,7 @@ get "/api/v1/comments/:id" do |env|
end end
get "/api/v1/insights/:id" do |env| get "/api/v1/insights/:id" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
id = env.params.url["id"] id = env.params.url["id"]
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -2812,7 +2810,7 @@ get "/api/v1/insights/:id" do |env|
end end
get "/api/v1/videos/:id" do |env| get "/api/v1/videos/:id" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -2838,7 +2836,7 @@ get "/api/v1/videos/:id" do |env|
json.field "title", video.title json.field "title", video.title
json.field "videoId", video.id json.field "videoId", video.id
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
video.description, description = html_to_content(video.description) video.description, description = html_to_content(video.description)
@ -3001,7 +2999,7 @@ get "/api/v1/videos/:id" do |env|
json.field "videoId", rv["id"] json.field "videoId", rv["id"]
json.field "title", rv["title"] json.field "title", rv["title"]
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, rv["id"]) generate_thumbnails(json, rv["id"], config, Kemal.config)
end end
json.field "author", rv["author"] json.field "author", rv["author"]
json.field "lengthSeconds", rv["length_seconds"].to_i json.field "lengthSeconds", rv["length_seconds"].to_i
@ -3022,7 +3020,7 @@ get "/api/v1/videos/:id" do |env|
end end
get "/api/v1/trending" do |env| get "/api/v1/trending" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3043,7 +3041,7 @@ get "/api/v1/trending" do |env|
json.field "title", video.title json.field "title", video.title
json.field "videoId", video.id json.field "videoId", video.id
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "lengthSeconds", video.length_seconds json.field "lengthSeconds", video.length_seconds
@ -3073,7 +3071,7 @@ get "/api/v1/trending" do |env|
end end
get "/api/v1/popular" do |env| get "/api/v1/popular" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3084,7 +3082,7 @@ get "/api/v1/popular" do |env|
json.field "title", video.title json.field "title", video.title
json.field "videoId", video.id json.field "videoId", video.id
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "lengthSeconds", video.length_seconds json.field "lengthSeconds", video.length_seconds
@ -3107,7 +3105,7 @@ get "/api/v1/popular" do |env|
end end
get "/api/v1/top" do |env| get "/api/v1/top" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3123,7 +3121,7 @@ get "/api/v1/top" do |env|
json.field "title", video.title json.field "title", video.title
json.field "videoId", video.id json.field "videoId", video.id
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "lengthSeconds", video.info["length_seconds"].to_i json.field "lengthSeconds", video.info["length_seconds"].to_i
@ -3153,7 +3151,7 @@ get "/api/v1/top" do |env|
end end
get "/api/v1/channels/:ucid" do |env| get "/api/v1/channels/:ucid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3306,7 +3304,7 @@ get "/api/v1/channels/:ucid" do |env|
end end
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "description", video.description json.field "description", video.description
@ -3361,7 +3359,7 @@ end
["/api/v1/channels/:ucid/videos", "/api/v1/channels/videos/:ucid"].each do |route| ["/api/v1/channels/:ucid/videos", "/api/v1/channels/videos/:ucid"].each do |route|
get route do |env| get route do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3404,7 +3402,7 @@ end
end end
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "description", video.description json.field "description", video.description
@ -3432,7 +3430,7 @@ end
["/api/v1/channels/:ucid/latest", "/api/v1/channels/latest/:ucid"].each do |route| ["/api/v1/channels/:ucid/latest", "/api/v1/channels/latest/:ucid"].each do |route|
get route do |env| get route do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3456,7 +3454,7 @@ end
json.field "authorUrl", "/channel/#{ucid}" json.field "authorUrl", "/channel/#{ucid}"
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "description", video.description json.field "description", video.description
@ -3484,7 +3482,7 @@ end
["/api/v1/channels/:ucid/playlists", "/api/v1/channels/playlists/:ucid"].each do |route| ["/api/v1/channels/:ucid/playlists", "/api/v1/channels/playlists/:ucid"].each do |route|
get route do |env| get route do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3527,7 +3525,7 @@ end
json.field "lengthSeconds", video.length_seconds json.field "lengthSeconds", video.length_seconds
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
end end
end end
@ -3552,7 +3550,7 @@ end
end end
get "/api/v1/channels/search/:ucid" do |env| get "/api/v1/channels/search/:ucid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3580,7 +3578,7 @@ get "/api/v1/channels/search/:ucid" do |env|
json.field "authorUrl", "/channel/#{item.ucid}" json.field "authorUrl", "/channel/#{item.ucid}"
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, item.id) generate_thumbnails(json, item.id, config, Kemal.config)
end end
json.field "description", item.description json.field "description", item.description
@ -3612,7 +3610,7 @@ get "/api/v1/channels/search/:ucid" do |env|
json.field "lengthSeconds", video.length_seconds json.field "lengthSeconds", video.length_seconds
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
end end
end end
@ -3656,7 +3654,7 @@ get "/api/v1/channels/search/:ucid" do |env|
end end
get "/api/v1/search" do |env| get "/api/v1/search" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
region = env.params.query["region"]? region = env.params.query["region"]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3709,7 +3707,7 @@ get "/api/v1/search" do |env|
json.field "authorUrl", "/channel/#{item.ucid}" json.field "authorUrl", "/channel/#{item.ucid}"
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, item.id) generate_thumbnails(json, item.id, config, Kemal.config)
end end
json.field "description", item.description json.field "description", item.description
@ -3741,7 +3739,7 @@ get "/api/v1/search" do |env|
json.field "lengthSeconds", video.length_seconds json.field "lengthSeconds", video.length_seconds
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
end end
end end
@ -3785,7 +3783,7 @@ get "/api/v1/search" do |env|
end end
get "/api/v1/playlists/:plid" do |env| get "/api/v1/playlists/:plid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
plid = env.params.url["plid"] plid = env.params.url["plid"]
@ -3857,7 +3855,7 @@ get "/api/v1/playlists/:plid" do |env|
json.field "authorUrl", "/channel/#{video.ucid}" json.field "authorUrl", "/channel/#{video.ucid}"
json.field "videoThumbnails" do json.field "videoThumbnails" do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
json.field "index", video.index json.field "index", video.index
@ -3888,7 +3886,7 @@ get "/api/v1/playlists/:plid" do |env|
end end
get "/api/v1/mixes/:rdid" do |env| get "/api/v1/mixes/:rdid" do |env|
locale = LOCALES[env.get("locale").as(String)]? locale = LOCALES[env.get("preferences").as(Preferences).locale]?
env.response.content_type = "application/json" env.response.content_type = "application/json"
@ -3933,7 +3931,7 @@ get "/api/v1/mixes/:rdid" do |env|
json.field "videoThumbnails" do json.field "videoThumbnails" do
json.array do json.array do
generate_thumbnails(json, video.id) generate_thumbnails(json, video.id, config, Kemal.config)
end end
end end
@ -4220,24 +4218,39 @@ get "/videoplayback" do |env|
query_params = env.params.query query_params = env.params.query
fvip = query_params["fvip"]? || "3" fvip = query_params["fvip"]? || "3"
mn = query_params["mn"].split(",")[-1] mns = query_params["mn"].split(",")
host = "https://r#{fvip}---#{mn}.googlevideo.com"
if query_params["host"]? && !query_params["host"].empty?
host = "https://#{query_params["host"]}"
query_params.delete("host")
else
host = "https://r#{fvip}---#{mns.pop}.googlevideo.com"
end
url = "/videoplayback?#{query_params.to_s}" url = "/videoplayback?#{query_params.to_s}"
headers = env.request.headers headers = HTTP::Headers.new
headers.delete("Host") {"Accept", "Accept-Encoding", "Connection", "Range"}.each do |header|
headers.delete("Cookie") if env.request.headers[header]?
headers.delete("User-Agent") headers[header] = env.request.headers[header]
headers.delete("Referer") end
end
region = query_params["region"]? region = query_params["region"]?
response = HTTP::Client::Response.new(403) response = HTTP::Client::Response.new(403)
loop do 5.times do
begin begin
client = make_client(URI.parse(host), proxies, region) client = make_client(URI.parse(host), proxies, region)
response = client.head(url, headers) response = client.head(url, headers)
break break
rescue Socket::Addrinfo::Error
if !mns.empty?
mn = mns.pop
end
fvip = "3"
host = "https://r#{fvip}---#{mn}.googlevideo.com"
rescue ex rescue ex
end end
end end
@ -4295,11 +4308,12 @@ get "/ggpht/*" do |env|
client = make_client(URI.parse(host)) client = make_client(URI.parse(host))
url = env.request.path.lchop("/ggpht") url = env.request.path.lchop("/ggpht")
headers = env.request.headers headers = HTTP::Headers.new
headers.delete("Host") {"Range", "Accept", "Accept-Encoding"}.each do |header|
headers.delete("Cookie") if env.request.headers[header]?
headers.delete("User-Agent") headers[header] = env.request.headers[header]
headers.delete("Referer") end
end
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
@ -4344,7 +4358,7 @@ get "/vi/:id/:name" do |env|
client = make_client(URI.parse(host)) client = make_client(URI.parse(host))
if name == "maxres.jpg" if name == "maxres.jpg"
VIDEO_THUMBNAILS.each do |thumb| build_thumbnails(id, config, Kemal.config).each do |thumb|
if client.head("/vi/#{id}/#{thumb[:url]}.jpg").status_code == 200 if client.head("/vi/#{id}/#{thumb[:url]}.jpg").status_code == 200
name = thumb[:url] + ".jpg" name = thumb[:url] + ".jpg"
break break
@ -4353,11 +4367,12 @@ get "/vi/:id/:name" do |env|
end end
url = "/vi/#{id}/#{name}" url = "/vi/#{id}/#{name}"
headers = env.request.headers headers = HTTP::Headers.new
headers.delete("Host") {"Range", "Accept", "Accept-Encoding"}.each do |header|
headers.delete("Cookie") if env.request.headers[header]?
headers.delete("User-Agent") headers[header] = env.request.headers[header]
headers.delete("Referer") end
end
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

View File

@ -24,6 +24,7 @@ user: String,
registration_enabled: {type: Bool, default: true}, registration_enabled: {type: Bool, default: true},
statistics_enabled: {type: Bool, default: false}, statistics_enabled: {type: Bool, default: false},
admins: {type: Array(String), default: [] of String}, admins: {type: Array(String), default: [] of String},
external_port: {type: Int32 | Nil, default: nil},
}) })
end end
@ -74,6 +75,14 @@ class DenyFrame < Kemal::Handler
end end
end end
# Temp fix for https://github.com/crystal-lang/crystal/issues/7383
class HTTP::Client
private def handle_response(response)
# close unless response.keep_alive?
response
end
end
def rank_videos(db, n) def rank_videos(db, n)
top = [] of {Float64, String} top = [] of {Float64, String}

View File

@ -195,6 +195,7 @@ end
def make_host_url(config, kemal_config) def make_host_url(config, kemal_config)
ssl = config.https_only || kemal_config.ssl ssl = config.https_only || kemal_config.ssl
port = config.external_port || kemal_config.port
if ssl if ssl
scheme = "https://" scheme = "https://"
@ -202,7 +203,8 @@ def make_host_url(config, kemal_config)
scheme = "http://" scheme = "http://"
end end
if kemal_config.port != 80 && kemal_config.port != 443 # Add if non-standard port
if port != 80 && port != 443
port = ":#{kemal_config.port}" port = ":#{kemal_config.port}"
else else
port = "" port = ""

View File

@ -136,18 +136,6 @@ BYPASS_REGIONS = {
"TR", "TR",
} }
VIDEO_THUMBNAILS = {
{name: "maxres", host: "#{CONFIG.domain}", url: "maxres", height: 720, width: 1280},
{name: "maxresdefault", host: "i.ytimg.com", url: "maxresdefault", height: 720, width: 1280},
{name: "sddefault", host: "i.ytimg.com", url: "sddefault", height: 480, width: 640},
{name: "high", host: "i.ytimg.com", url: "hqdefault", height: 360, width: 480},
{name: "medium", host: "i.ytimg.com", url: "mqdefault", height: 180, width: 320},
{name: "default", host: "i.ytimg.com", url: "default", height: 90, width: 120},
{name: "start", host: "i.ytimg.com", url: "1", height: 90, width: 120},
{name: "middle", host: "i.ytimg.com", url: "2", height: 90, width: 120},
{name: "end", host: "i.ytimg.com", url: "3", height: 90, width: 120},
}
# See https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L380-#L476 # See https://github.com/rg3/youtube-dl/blob/master/youtube_dl/extractor/youtube.py#L380-#L476
VIDEO_FORMATS = { VIDEO_FORMATS = {
"5" => {"ext" => "flv", "width" => 400, "height" => 240, "acodec" => "mp3", "abr" => 64, "vcodec" => "h263"}, "5" => {"ext" => "flv", "width" => 400, "height" => 240, "acodec" => "mp3", "abr" => 64, "vcodec" => "h263"},
@ -329,6 +317,7 @@ class Video
end end
streams.each do |fmt| streams.each do |fmt|
fmt["url"] += "&host=" + (URI.parse(fmt["url"]).host || "")
fmt["url"] += decrypt_signature(fmt, decrypt_function) fmt["url"] += decrypt_signature(fmt, decrypt_function)
end end
@ -396,6 +385,7 @@ class Video
end end
adaptive_fmts.each do |fmt| adaptive_fmts.each do |fmt|
fmt["url"] += "&host=" + (URI.parse(fmt["url"]).host || "")
fmt["url"] += decrypt_signature(fmt, decrypt_function) fmt["url"] += decrypt_signature(fmt, decrypt_function)
end end
@ -743,11 +733,12 @@ end
def process_video_params(query, preferences) def process_video_params(query, preferences)
autoplay = query["autoplay"]?.try &.to_i? autoplay = query["autoplay"]?.try &.to_i?
continue = query["continue"]?.try &.to_i? continue = query["continue"]?.try &.to_i?
related_videos = query["related_videos"]?
listen = query["listen"]? && (query["listen"] == "true" || query["listen"] == "1").to_unsafe listen = query["listen"]? && (query["listen"] == "true" || query["listen"] == "1").to_unsafe
local = query["local"]? && (query["local"] == "true").to_unsafe
preferred_captions = query["subtitles"]?.try &.split(",").map { |a| a.downcase } preferred_captions = query["subtitles"]?.try &.split(",").map { |a| a.downcase }
quality = query["quality"]? quality = query["quality"]?
region = query["region"]? region = query["region"]?
related_videos = query["related_videos"]?
speed = query["speed"]?.try &.to_f? speed = query["speed"]?.try &.to_f?
video_loop = query["loop"]?.try &.to_i? video_loop = query["loop"]?.try &.to_i?
volume = query["volume"]?.try &.to_i? volume = query["volume"]?.try &.to_i?
@ -777,8 +768,9 @@ def process_video_params(query, preferences)
autoplay = autoplay == 1 autoplay = autoplay == 1
continue = continue == 1 continue = continue == 1
related_videos = related_videos == 1
listen = listen == 1 listen = listen == 1
local = local == 1
related_videos = related_videos == 1
video_loop = video_loop == 1 video_loop = video_loop == 1
if query["t"]? if query["t"]?
@ -811,6 +803,7 @@ def process_video_params(query, preferences)
continue: continue, continue: continue,
controls: controls, controls: controls,
listen: listen, listen: listen,
local: local,
preferred_captions: preferred_captions, preferred_captions: preferred_captions,
quality: quality, quality: quality,
raw: raw, raw: raw,
@ -826,12 +819,26 @@ def process_video_params(query, preferences)
return params return params
end end
def generate_thumbnails(json, id) def build_thumbnails(id, config, kemal_config)
return {
{name: "maxres", host: "#{make_host_url(config, kemal_config)}", url: "maxres", height: 720, width: 1280},
{name: "maxresdefault", host: "https://i.ytimg.com", url: "maxresdefault", height: 720, width: 1280},
{name: "sddefault", host: "https://i.ytimg.com", url: "sddefault", height: 480, width: 640},
{name: "high", host: "https://i.ytimg.com", url: "hqdefault", height: 360, width: 480},
{name: "medium", host: "https://i.ytimg.com", url: "mqdefault", height: 180, width: 320},
{name: "default", host: "https://i.ytimg.com", url: "default", height: 90, width: 120},
{name: "start", host: "https://i.ytimg.com", url: "1", height: 90, width: 120},
{name: "middle", host: "https://i.ytimg.com", url: "2", height: 90, width: 120},
{name: "end", host: "https://i.ytimg.com", url: "3", height: 90, width: 120},
}
end
def generate_thumbnails(json, id, config, kemal_config)
json.array do json.array do
VIDEO_THUMBNAILS.each do |thumbnail| build_thumbnails(id, config, kemal_config).each do |thumbnail|
json.object do json.object do
json.field "quality", thumbnail[:name] json.field "quality", thumbnail[:name]
json.field "url", "https://#{thumbnail[:host]}/vi/#{id}/#{thumbnail["url"]}.jpg" json.field "url", "#{thumbnail[:host]}/vi/#{id}/#{thumbnail["url"]}.jpg"
json.field "width", thumbnail[:width] json.field "width", thumbnail[:width]
json.field "height", thumbnail[:height] json.field "height", thumbnail[:height]
end end

View File

@ -22,13 +22,17 @@
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<a href="https://www.youtube.com/channel/<%= ucid %>"><%= translate(locale, "View channel on YouTube") %></a> <a href="https://www.youtube.com/channel/<%= ucid %>"><%= translate(locale, "View channel on YouTube") %></a>
<% if !auto_generated %>
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<b><%= translate(locale, "Videos") %></b> <b><%= translate(locale, "Videos") %></b>
</div> </div>
<% end %>
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<% if !auto_generated %> <% if auto_generated %>
<a href="/channel/<%= ucid %>/playlists"><%= translate(locale, "Playlists") %></a> <b><%= translate(locale, "Playlists") %></b>
<% end %> <% else %>
<a href="/channel/<%= ucid %>/playlists"><%= translate(locale, "Playlists") %></a>
<% end %>
</div> </div>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">

View File

@ -11,7 +11,7 @@
<% else %> <% else %>
<% if params[:listen] %> <% if params[:listen] %>
<% audio_streams.each_with_index do |fmt, i| %> <% audio_streams.each_with_index do |fmt, i| %>
<source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %>" type='<%= fmt["type"] %>' label="<%= fmt["bitrate"] %>k" selected="<%= i == 0 ? true : false %>"> <source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %><% if params[:local] %>&local=true<% end %>" type='<%= fmt["type"] %>' label="<%= fmt["bitrate"] %>k" selected="<%= i == 0 ? true : false %>">
<% end %> <% end %>
<% else %> <% else %>
<% if params[:quality] == "dash" %> <% if params[:quality] == "dash" %>
@ -19,20 +19,20 @@
<% end %> <% end %>
<% fmt_stream.each_with_index do |fmt, i| %> <% fmt_stream.each_with_index do |fmt, i| %>
<% if params[:quality] %> <% if params[:quality] %>
<source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %>" type='<%= fmt["type"] %>' label="<%= fmt["label"] %>" selected="<%= params[:quality] == fmt["label"].split(" - ")[0] %>"> <source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %><% if params[:local] %>&local=true<% end %>" type='<%= fmt["type"] %>' label="<%= fmt["label"] %>" selected="<%= params[:quality] == fmt["label"].split(" - ")[0] %>">
<% else %> <% else %>
<source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %>" type='<%= fmt["type"] %>' label="<%= fmt["label"] %>" selected="<%= i == 0 ? true : false %>"> <source src="/latest_version?id=<%= video.id %>&itag=<%= fmt["itag"] %><% if params[:local] %>&local=true<% end %>" type='<%= fmt["type"] %>' label="<%= fmt["label"] %>" selected="<%= i == 0 ? true : false %>">
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<% preferred_captions.each_with_index do |caption, i| %> <% preferred_captions.each_with_index do |caption, i| %>
<track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name.simpleText %>&hl=<%= env.get("locale").as(String) %>" <track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name.simpleText %>&hl=<%= env.get("preferences").as(Preferences).locale %>"
label="<%= caption.name.simpleText %>" <% if i == 0 %>default<% end %>> label="<%= caption.name.simpleText %>" <% if i == 0 %>default<% end %>>
<% end %> <% end %>
<% captions.each do |caption| %> <% captions.each do |caption| %>
<track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name.simpleText %>&hl=<%= env.get("locale").as(String) %>" <track kind="captions" src="/api/v1/captions/<%= video.id %>?label=<%= caption.name.simpleText %>&hl=<%= env.get("preferences").as(Preferences).locale %>"
label="<%= caption.name.simpleText %>"> label="<%= caption.name.simpleText %>">
<% end %> <% end %>
<% end %> <% end %>

View File

@ -255,9 +255,9 @@ function get_playlist(timeouts = 0) {
var plid = "<%= plid %>" var plid = "<%= plid %>"
if (plid.startsWith("RD")) { if (plid.startsWith("RD")) {
var plid_url = "/api/v1/mixes/<%= plid %>?continuation=<%= video.id %>&format=html&hl=<%= env.get("locale").as(String) %>"; var plid_url = "/api/v1/mixes/<%= plid %>?continuation=<%= video.id %>&format=html&hl=<%= env.get("preferences").as(Preferences).locale %>";
} else { } else {
var plid_url = "/api/v1/playlists/<%= plid %>?continuation=<%= video.id %>&format=html&hl=<%= env.get("locale").as(String) %>"; var plid_url = "/api/v1/playlists/<%= plid %>?continuation=<%= video.id %>&format=html&hl=<%= env.get("preferences").as(Preferences).locale %>";
} }
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
@ -321,7 +321,7 @@ function get_reddit_comments(timeouts = 0) {
comments.innerHTML = comments.innerHTML =
'<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>'; '<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>';
var url = "/api/v1/comments/<%= video.id %>?source=reddit&format=html&hl=<%= env.get("locale").as(String) %>"; var url = "/api/v1/comments/<%= video.id %>?source=reddit&format=html&hl=<%= env.get("preferences").as(Preferences).locale %>";
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.responseType = "json"; xhr.responseType = "json";
xhr.timeout = 20000; xhr.timeout = 20000;
@ -384,7 +384,7 @@ function get_youtube_comments(timeouts = 0) {
comments.innerHTML = comments.innerHTML =
'<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>'; '<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>';
var url = "/api/v1/comments/<%= video.id %>?format=html&hl=<%= env.get("locale").as(String) %>"; var url = "/api/v1/comments/<%= video.id %>?format=html&hl=<%= env.get("preferences").as(Preferences).locale %>";
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.responseType = "json"; xhr.responseType = "json";
xhr.timeout = 20000; xhr.timeout = 20000;
@ -442,7 +442,7 @@ function get_youtube_replies(target, load_more) {
body.innerHTML = body.innerHTML =
'<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>'; '<h3><center class="loading"><i class="icon ion-ios-refresh"></i></center></h3>';
var url = '/api/v1/comments/<%= video.id %>?format=html&hl=<%= env.get("locale").as(String) %>&continuation=' + var url = '/api/v1/comments/<%= video.id %>?format=html&hl=<%= env.get("preferences").as(Preferences).locale %>&continuation=' +
continuation; continuation;
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.responseType = 'json'; xhr.responseType = 'json';