From ffb42a9b23ec2b96a16984f1ec5cf21b7f0c1f44 Mon Sep 17 00:00:00 2001 From: thecashewtrader Date: Sat, 8 Oct 2022 15:13:02 +0530 Subject: [PATCH 01/23] Add channel name to embeds --- src/invidious/views/watch.ecr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 243ea3a4..6fd6a401 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -9,7 +9,7 @@ "> - + From 3b39b8c772b57552893fa55eb417189b2976bbe4 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Wed, 12 Oct 2022 10:06:36 +0200 Subject: [PATCH 02/23] Add table cleaning job (#3294) --- config/config.example.yml | 45 +++++++++++++++---- src/invidious.cr | 2 + src/invidious/config.cr | 4 ++ src/invidious/database/nonces.cr | 11 ++++- src/invidious/database/videos.cr | 9 ++++ src/invidious/jobs.cr | 27 +++++++++++ src/invidious/jobs/base_job.cr | 30 +++++++++++++ src/invidious/jobs/clear_expired_items_job.cr | 27 +++++++++++ 8 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 src/invidious/jobs/clear_expired_items_job.cr diff --git a/config/config.example.yml b/config/config.example.yml index 160a2750..264a5bea 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -304,10 +304,8 @@ https_only: false ## Number of threads to use when crawling channel videos (during ## subscriptions update). ## -## Notes: -## - Setting this to 0 will disable the channel videos crawl job. -## - This setting is overridden if "-c THREADS" or -## "--channel-threads=THREADS" are passed on the command line. +## Notes: This setting is overridden if either "-c THREADS" or +## "--channel-threads=THREADS" is passed on the command line. ## ## Accepted values: a positive integer ## Default: 1 @@ -335,10 +333,8 @@ full_refresh: false ## ## Number of threads to use when updating RSS feeds. ## -## Notes: -## - Setting this to 0 will disable the channel videos crawl job. -## - This setting is overridden if "-f THREADS" or -## "--feed-threads=THREADS" are passed on the command line. +## Notes: This setting is overridden if either "-f THREADS" or +## "--feed-threads=THREADS" is passed on the command line. ## ## Accepted values: a positive integer ## Default: 1 @@ -361,6 +357,39 @@ feed_threads: 1 #decrypt_polling: false +jobs: + + ## Options for the database cleaning job + clear_expired_items: + + ## Enable/Disable job + ## + ## Accepted values: true, false + ## Default: true + ## + enable: true + + ## Options for the channels updater job + refresh_channels: + + ## Enable/Disable job + ## + ## Accepted values: true, false + ## Default: true + ## + enable: true + + ## Options for the RSS feeds updater job + refresh_feeds: + + ## Enable/Disable job + ## + ## Accepted values: true, false + ## Default: true + ## + enable: true + + # ----------------------------- # Captcha API # ----------------------------- diff --git a/src/invidious.cr b/src/invidious.cr index 0601d5b2..58adaa35 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -172,6 +172,8 @@ end CONNECTION_CHANNEL = Channel({Bool, Channel(PQ::Notification)}).new(32) Invidious::Jobs.register Invidious::Jobs::NotificationJob.new(CONNECTION_CHANNEL, CONFIG.database_url) +Invidious::Jobs.register Invidious::Jobs::ClearExpiredItemsJob.new + Invidious::Jobs.start_all def popular_videos diff --git a/src/invidious/config.cr b/src/invidious/config.cr index f0873df4..c9bf43a4 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -78,6 +78,10 @@ class Config property decrypt_polling : Bool = false # Used for crawling channels: threads should check all videos uploaded by a channel property full_refresh : Bool = false + + # Jobs config structure. See jobs.cr and jobs/base_job.cr + property jobs = Invidious::Jobs::JobsConfig.new + # Used to tell Invidious it is behind a proxy, so links to resources should be https:// property https_only : Bool? # HMAC signing key for CSRF tokens and verifying pubsub subscriptions diff --git a/src/invidious/database/nonces.cr b/src/invidious/database/nonces.cr index 469fcbd8..b87c81ec 100644 --- a/src/invidious/database/nonces.cr +++ b/src/invidious/database/nonces.cr @@ -4,7 +4,7 @@ module Invidious::Database::Nonces extend self # ------------------- - # Insert + # Insert / Delete # ------------------- def insert(nonce : String, expire : Time) @@ -17,6 +17,15 @@ module Invidious::Database::Nonces PG_DB.exec(request, nonce, expire) end + def delete_expired + request = <<-SQL + DELETE FROM nonces * + WHERE expire < now() + SQL + + PG_DB.exec(request) + end + # ------------------- # Update # ------------------- diff --git a/src/invidious/database/videos.cr b/src/invidious/database/videos.cr index e1fa01c3..695f5b33 100644 --- a/src/invidious/database/videos.cr +++ b/src/invidious/database/videos.cr @@ -22,6 +22,15 @@ module Invidious::Database::Videos PG_DB.exec(request, id) end + def delete_expired + request = <<-SQL + DELETE FROM videos * + WHERE updated < (now() - interval '6 hours') + SQL + + PG_DB.exec(request) + end + def update(video : Video) request = <<-SQL UPDATE videos diff --git a/src/invidious/jobs.cr b/src/invidious/jobs.cr index ec0cad64..524a3624 100644 --- a/src/invidious/jobs.cr +++ b/src/invidious/jobs.cr @@ -1,12 +1,39 @@ module Invidious::Jobs JOBS = [] of BaseJob + # Automatically generate a structure that wraps the various + # jobs' configs, so that the follwing YAML config can be used: + # + # jobs: + # job_name: + # enabled: true + # some_property: "value" + # + macro finished + struct JobsConfig + include YAML::Serializable + + {% for sc in BaseJob.subclasses %} + # Voodoo macro to transform `Some::Module::CustomJob` to `custom` + {% class_name = sc.id.split("::").last.id.gsub(/Job$/, "").underscore %} + + getter {{ class_name }} = {{ sc.name }}::Config.new + {% end %} + + def initialize + end + end + end + def self.register(job : BaseJob) JOBS << job end def self.start_all JOBS.each do |job| + # Don't run the main rountine if the job is disabled by config + next if job.disabled? + spawn { job.begin } end end diff --git a/src/invidious/jobs/base_job.cr b/src/invidious/jobs/base_job.cr index 47e75864..f90f0bfe 100644 --- a/src/invidious/jobs/base_job.cr +++ b/src/invidious/jobs/base_job.cr @@ -1,3 +1,33 @@ abstract class Invidious::Jobs::BaseJob abstract def begin + + # When this base job class is inherited, make sure to define + # a basic "Config" structure, that contains the "enable" property, + # and to create the associated instance property. + # + macro inherited + macro finished + # This config structure can be expanded as required. + struct Config + include YAML::Serializable + + property enable = true + + def initialize + end + end + + property cfg = Config.new + + # Return true if job is enabled by config + protected def enabled? : Bool + return (@cfg.enable == true) + end + + # Return true if job is disabled by config + protected def disabled? : Bool + return (@cfg.enable == false) + end + end + end end diff --git a/src/invidious/jobs/clear_expired_items_job.cr b/src/invidious/jobs/clear_expired_items_job.cr new file mode 100644 index 00000000..17191aac --- /dev/null +++ b/src/invidious/jobs/clear_expired_items_job.cr @@ -0,0 +1,27 @@ +class Invidious::Jobs::ClearExpiredItemsJob < Invidious::Jobs::BaseJob + # Remove items (videos, nonces, etc..) whose cache is outdated every hour. + # Removes the need for a cron job. + def begin + loop do + failed = false + + LOGGER.info("jobs: running ClearExpiredItems job") + + begin + Invidious::Database::Videos.delete_expired + Invidious::Database::Nonces.delete_expired + rescue DB::Error + failed = true + end + + # Retry earlier than scheduled on DB error + if failed + LOGGER.info("jobs: ClearExpiredItems failed. Retrying in 10 minutes.") + sleep 10.minutes + else + LOGGER.info("jobs: ClearExpiredItems done.") + sleep 1.hour + end + end + end +end From 6ea3673cf06404064b6aeb9fd22d75e2752a7dc0 Mon Sep 17 00:00:00 2001 From: thecashewtrader Date: Thu, 13 Oct 2022 21:44:16 +0530 Subject: [PATCH 03/23] Move uploader channel name to `og:site_name` --- src/invidious/views/watch.ecr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 6fd6a401..ae478378 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -7,9 +7,9 @@ "> - + - + From a1e0a6b499f8ccade4d382754aa36ccd157bd582 Mon Sep 17 00:00:00 2001 From: thecashewtrader Date: Sat, 15 Oct 2022 19:37:47 +0530 Subject: [PATCH 04/23] Add meta tags to channels --- src/invidious/views/channel.ecr | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr index 92f81ee4..9449305b 100644 --- a/src/invidious/views/channel.ecr +++ b/src/invidious/views/channel.ecr @@ -1,7 +1,21 @@ <% ucid = channel.ucid %> <% author = HTML.escape(channel.author) %> +<% channel_profile_pic = URI.parse(channel.author_thumbnail).request_target %> <% content_for "header" do %> + + + + + + + + + + + + + <%= author %> - Invidious <% end %> @@ -19,7 +33,7 @@
- + <%= author %><% if !channel.verified.nil? && channel.verified %> <% end %>
From 7f3509aa36d42f6f17d16efd707d3ad4f7921d45 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 19 Oct 2022 13:01:35 +0200 Subject: [PATCH 05/23] Update Spanish translation Co-authored-by: Hosted Weblate Co-authored-by: gallegonovato --- locales/es.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/locales/es.json b/locales/es.json index c427e81a..8603e9fe 100644 --- a/locales/es.json +++ b/locales/es.json @@ -114,7 +114,7 @@ "Save preferences": "Guardar las preferencias", "Subscription manager": "Gestor de suscripciones", "Token manager": "Gestor de tokens", - "Token": "Token", + "Token": "Ficha", "Import/export": "Importar/Exportar", "unsubscribe": "Desuscribirse", "revoke": "revocar", @@ -355,7 +355,7 @@ "search_filters_features_option_location": "ubicación", "search_filters_features_option_hdr": "hdr", "Current version: ": "Versión actual: ", - "next_steps_error_message": "Después de lo cual deberías intentar: ", + "next_steps_error_message": "Después de lo cual debes intentar: ", "next_steps_error_message_refresh": "Recargar la página", "next_steps_error_message_go_to_youtube": "Ir a YouTube", "search_filters_duration_option_short": "Corto (< 4 minutos)", @@ -467,8 +467,8 @@ "search_filters_duration_option_none": "Cualquier duración", "search_filters_features_option_vr180": "VR180", "search_filters_apply_button": "Aplicar filtros seleccionados", - "tokens_count": "{{count}} token", - "tokens_count_plural": "{{count}} tokens", + "tokens_count": "{{count}} ficha", + "tokens_count_plural": "{{count}} fichas", "search_message_use_another_instance": " También puede buscar en otra instancia.", "search_filters_duration_option_medium": "Medio (4 - 20 minutes)", "Popular enabled: ": "¿Habilitar la sección popular? ", From fa544c158ac3203ee2488aaee6e00e5cb93e39e2 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 19 Oct 2022 13:01:35 +0200 Subject: [PATCH 06/23] Update Vietnamese translation Co-authored-by: HexagonCDN Co-authored-by: Hosted Weblate --- locales/vi.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/locales/vi.json b/locales/vi.json index 709013a2..07fcf52f 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -177,7 +177,7 @@ "Not a playlist.": "Không phải danh sách phát.", "Playlist does not exist.": "Danh sách phát không tồn tại.", "Could not pull trending pages.": "Không thể kéo các trang thịnh hành.", - "Hidden field \"challenge\" is a required field": "Trường ẩn \"challenge\" là trường bắt buộc", + "Hidden field \"challenge\" is a required field": "Trường ẩn \"challenge\" là trường bắt buộc", "Hidden field \"token\" is a required field": "Trường ẩn \"token\" là trường bắt buộc", "Erroneous challenge": "Thử thách sai", "Erroneous token": "Mã thông báo bị lỗi", @@ -341,5 +341,10 @@ "search_filters_features_option_location": "vị trí", "search_filters_features_option_hdr": "hdr", "Current version: ": "Phiên bản hiện tại: ", - "search_filters_title": "bộ lọc" + "search_filters_title": "bộ lọc", + "generic_playlists_count": "{{count}} danh sách phát", + "generic_views_count": "{{count}} lượt xem", + "View `x` comments": { + "": "Xem `x` bình luận" + } } From fcd29a41438da977125039cb9c27f99f5df8000d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 19 Oct 2022 13:01:35 +0200 Subject: [PATCH 07/23] Update Lithuanian translation Co-authored-by: Gediminas Murauskas --- locales/lt.json | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/locales/lt.json b/locales/lt.json index 607b3705..b4a6da04 100644 --- a/locales/lt.json +++ b/locales/lt.json @@ -21,15 +21,15 @@ "No": "Ne", "Import and Export Data": "Importuoti ir eksportuoti duomenis", "Import": "Importuoti", - "Import Invidious data": "Importuoti Invidious duomenis", - "Import YouTube subscriptions": "Importuoti YouTube prenumeratas", + "Import Invidious data": "Importuoti Invidious JSON duomenis", + "Import YouTube subscriptions": "Importuoti YouTube/OPML prenumeratas", "Import FreeTube subscriptions (.db)": "Importuoti FreeTube prenumeratas (.db)", "Import NewPipe subscriptions (.json)": "Importuoti NewPipe prenumeratas (.json)", "Import NewPipe data (.zip)": "Importuoti NewPipe duomenis (.zip)", "Export": "Eksportuoti", "Export subscriptions as OPML": "Eksportuoti prenumeratas kaip OPML", "Export subscriptions as OPML (for NewPipe & FreeTube)": "Eksportuoti prenumeratas kaip OPML (skirta NewPipe & FreeTube)", - "Export data as JSON": "Eksportuoti duomenis kaip JSON", + "Export data as JSON": "Eksportuoti Invidious duomenis kaip JSON", "Delete account?": "Ištrinti paskyrą?", "History": "Istorija", "An alternative front-end to YouTube": "Alternatyvus YouTube žiūrėjimo būdas", @@ -66,7 +66,7 @@ "preferences_related_videos_label": "Rodyti susijusius vaizdo įrašus: ", "preferences_annotations_label": "Rodyti anotacijas pagal nutylėjimą: ", "preferences_extend_desc_label": "Automatiškai išplėsti vaizdo įrašo aprašymą: ", - "preferences_vr_mode_label": "Interaktyvūs 360 laipsnių vaizdo įrašai: ", + "preferences_vr_mode_label": "Interaktyvūs 360 laipsnių vaizdo įrašai (reikalingas WebGL): ", "preferences_category_visual": "Vizualinės nuostatos", "preferences_player_style_label": "Vaizdo grotuvo stilius: ", "Dark mode: ": "Tamsus rėžimas: ", @@ -371,5 +371,35 @@ "preferences_quality_dash_option_best": "Geriausia", "preferences_quality_dash_option_worst": "Blogiausia", "preferences_quality_dash_option_auto": "Automatinis", - "search_filters_title": "Filtras" + "search_filters_title": "Filtras", + "generic_videos_count_0": "{{count}} vaizdo įrašas", + "generic_videos_count_1": "{{count}} vaizdo įrašai", + "generic_videos_count_2": "{{count}} vaizdo įrašų", + "generic_subscribers_count_0": "{{count}} prenumeratorius", + "generic_subscribers_count_1": "{{count}} prenumeratoriai", + "generic_subscribers_count_2": "{{count}} prenumeratorių", + "generic_subscriptions_count_0": "{{count}} prenumerata", + "generic_subscriptions_count_1": "{{count}} prenumeratos", + "generic_subscriptions_count_2": "{{count}} prenumeratų", + "preferences_watch_history_label": "Įgalinti žiūrėjimo istoriją: ", + "preferences_quality_dash_option_1080p": "1080p", + "invidious": "Invidious", + "preferences_quality_dash_option_720p": "720p", + "generic_playlists_count_0": "{{count}} grojaraštis", + "generic_playlists_count_1": "{{count}} grojaraščiai", + "generic_playlists_count_2": "{{count}} grojaraščių", + "preferences_quality_option_medium": "Vidutinė", + "preferences_quality_option_small": "Maža", + "preferences_quality_dash_option_4320p": "4320p", + "preferences_quality_dash_option_1440p": "1440p", + "preferences_quality_dash_option_2160p": "2160p", + "preferences_quality_dash_option_144p": "144p", + "preferences_quality_option_hd720": "HD720", + "preferences_quality_dash_option_360p": "360p", + "preferences_quality_option_dash": "DASH (prisitaikanti kokybė)", + "generic_views_count_0": "{{count}} peržiūra", + "generic_views_count_1": "{{count}} peržiūros", + "generic_views_count_2": "{{count}} peržiūrų", + "preferences_quality_dash_option_480p": "480p", + "preferences_quality_dash_option_240p": "240p" } From ae4f67f39c42e9517eb44a79953ca02ae35ed119 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 19 Oct 2022 13:01:35 +0200 Subject: [PATCH 08/23] Update Korean translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Korean translation Update Korean translation Co-authored-by: Hosted Weblate Co-authored-by: xrfmkrh Co-authored-by: 이정희 --- locales/ko.json | 93 +++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/locales/ko.json b/locales/ko.json index 26412d0c..127a500b 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -12,14 +12,14 @@ "Dark mode: ": "다크 모드: ", "preferences_player_style_label": "플레이어 스타일: ", "preferences_category_visual": "시각 설정", - "preferences_vr_mode_label": "360도 비디오와 상호작용하기(WebGL를 요구함): ", + "preferences_vr_mode_label": "VR 영상 활성화(WebGL 필요): ", "preferences_extend_desc_label": "자동으로 비디오 설명을 확장: ", - "preferences_annotations_label": "기본적으로 주석 표시: ", + "preferences_annotations_label": "기본으로 주석 표시: ", "preferences_related_videos_label": "관련 동영상 보기: ", "Fallback captions: ": "대체 자막: ", "preferences_captions_label": "기본 자막: ", - "reddit": "Reddit", - "youtube": "YouTube", + "reddit": "레딧", + "youtube": "유튜브", "preferences_comments_label": "기본 댓글: ", "preferences_volume_label": "플레이어 볼륨: ", "preferences_quality_label": "선호하는 비디오 품질: ", @@ -46,8 +46,8 @@ "Log in/register": "로그인/회원가입", "Log in": "로그인", "source": "출처", - "JavaScript license information": "JavaScript 라이선스 정보", - "An alternative front-end to YouTube": "YouTube의 대안 프론트엔드", + "JavaScript license information": "자바스크립트 라이센스 정보", + "An alternative front-end to YouTube": "유튜브의 프론트엔드 대안", "History": "역사", "Delete account?": "계정을 삭제 하시겠습니까?", "Export data as JSON": "데이터를 JSON으로 내보내기", @@ -57,7 +57,7 @@ "Import NewPipe data (.zip)": "NewPipe 데이터 가져오기 (.zip)", "Import NewPipe subscriptions (.json)": "NewPipe 구독을 가져오기 (.json)", "Import FreeTube subscriptions (.db)": "FreeTube 구독 가져오기 (.db)", - "Import YouTube subscriptions": "YouTube 구독 가져오기", + "Import YouTube subscriptions": "유튜브 구독 가져오기", "Import Invidious data": "Invidious JSON 데이터 가져오기", "Import": "가져오기", "Import and Export Data": "데이터 가져오기 및 내보내기", @@ -65,7 +65,7 @@ "Yes": "예", "Authorize token for `x`?": "`x` 에 대한 토큰을 승인하시겠습니까?", "Authorize token?": "토큰을 승인하시겠습니까?", - "Cannot change password for Google accounts": "Google 계정의 비밀번호를 변경할 수 없습니다", + "Cannot change password for Google accounts": "구글 계정의 비밀번호를 변경할 수 없습니다", "New passwords must match": "새 비밀번호는 일치해야 합니다", "New password": "새 비밀번호", "Clear watch history?": "재생 기록을 삭제 하시겠습니까?", @@ -76,8 +76,8 @@ "popular": "인기", "oldest": "오래된순", "newest": "최신순", - "View playlist on YouTube": "YouTube에서 재생목록 보기", - "View channel on YouTube": "YouTube에서 채널 보기", + "View playlist on YouTube": "유튜브에서 재생목록 보기", + "View channel on YouTube": "유튜브에서 채널 보기", "Subscribe": "구독", "Unsubscribe": "구독 취소", "LIVE": "실시간", @@ -116,11 +116,11 @@ "Show replies": "댓글 보기", "Hide replies": "댓글 숨기기", "Incorrect password": "잘못된 비밀번호", - "License: ": "라이선스: ", + "License: ": "라이센스: ", "Genre: ": "장르: ", "Editing playlist `x`": "재생목록 `x` 수정하기", "Playlist privacy": "재생목록 공개 범위", - "Watch on YouTube": "YouTube에서 보기", + "Watch on YouTube": "유튜브에서 보기", "Show less": "간략히", "Show more": "더보기", "Title": "제목", @@ -129,13 +129,13 @@ "Delete playlist": "재생목록 삭제", "Delete playlist `x`?": "재생목록 `x` 를 삭제 하시겠습니까?", "Updated `x` ago": "`x` 전에 업데이트됨", - "Released under the AGPLv3 on Github.": "GitHub에 AGPLv3 으로 배포됩니다.", + "Released under the AGPLv3 on Github.": "깃허브에 AGPLv3 으로 배포됩니다.", "View all playlists": "모든 재생목록 보기", "Private": "비공개", "Unlisted": "목록에 없음", "Public": "공개", "View privacy policy.": "개인정보 처리방침 보기.", - "View JavaScript license information.": "JavaScript 라이센스 정보 보기.", + "View JavaScript license information.": "자바스크립트 라이센스 정보 보기.", "Source available here.": "소스는 여기에서 사용할 수 있습니다.", "Log out": "로그아웃", "search": "검색", @@ -202,7 +202,7 @@ "search_filters_features_option_hdr": "HDR", "Current version: ": "현재 버전: ", "next_steps_error_message_refresh": "새로 고침", - "next_steps_error_message_go_to_youtube": "YouTube로 가기", + "next_steps_error_message_go_to_youtube": "유튜브로 가기", "search_filters_features_option_subtitles": "자막", "`x` marked it with a ❤": "`x`님의 ❤", "Download as: ": "다음으로 다운로드: ", @@ -245,14 +245,14 @@ "Could not create mix.": "믹스를 생성할 수 없습니다.", "`x` ago": "`x` 전", "comments_view_x_replies_0": "답글 {{count}}개 보기", - "View Reddit comments": "Reddit의 댓글 보기", + "View Reddit comments": "레딧 댓글 보기", "Engagement: ": "약속: ", "Wilson score: ": "Wilson Score: ", - "Family friendly? ": "가족 친화적입니까? ", + "Family friendly? ": "전연령 영상입니까? ", "Quota exceeded, try again in a few hours": "한도량을 초과했습니다. 몇 시간 후에 다시 시도하세요", "View `x` comments": { - "([^.,0-9]|^)1([^.,0-9]|$)": "`x` 개의 댓글 보기", - "": "`x` 개의 댓글 보기" + "([^.,0-9]|^)1([^.,0-9]|$)": "`x`개의 댓글 보기", + "": "`x`개의 댓글 보기" }, "Haitian Creole": "아이티 크레올어", "Gujarati": "구자라트어", @@ -273,16 +273,16 @@ "Bosnian": "보스니아어", "Belarusian": "벨라루스어", "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "로그인할 수 없습니다. 이중 인증(Authenticator 또는 SMS)이 켜져 있는지 확인하세요.", - "View more comments on Reddit": "Reddit에서 더 많은 댓글 보기", - "View YouTube comments": "YouTube 댓글 보기", - "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "JavaScript가 꺼져 있는 것 같습니다! 댓글을 보려면 여기를 클릭하세요. 댓글을 로드하는 데 시간이 조금 더 걸릴 수 있습니다.", - "Shared `x`": "공유된 `x`", + "View more comments on Reddit": "레딧에서 더 많은 댓글 보기", + "View YouTube comments": "유튜브 댓글 보기", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "자바스크립트가 꺼져 있는 것 같습니다! 댓글을 보려면 여기를 클릭하세요. 댓글을 로드하는 데 시간이 조금 더 걸릴 수 있습니다.", + "Shared `x`": "`x` 업로드", "Whitelisted regions: ": "차단되지 않은 지역: ", "search_filters_sort_option_views": "조회수", "Please log in": "로그인하세요", "Password cannot be longer than 55 characters": "비밀번호는 55자 이하여야 합니다", "Password cannot be empty": "비밀번호는 비워둘 수 없습니다", - "Please sign in using 'Log in with Google'": "'Google로 로그인'을 사용하여 로그인하세요", + "Please sign in using 'Log in with Google'": "'구글로 로그인'을 사용하여 로그인하세요", "Wrong username or password": "잘못된 사용자 이름 또는 비밀번호", "Password is a required field": "비밀번호는 필수 필드입니다", "User ID is a required field": "사용자 ID는 필수 필드입니다", @@ -312,13 +312,13 @@ "Fallback comments: ": "대체 댓글: ", "Swahili": "스와힐리어", "Sundanese": "순다어", - "generic_count_years_0": "{{count}} 년", - "generic_count_months_0": "{{count}} 개월", - "generic_count_weeks_0": "{{count}} 주", - "generic_count_days_0": "{{count}} 일", - "generic_count_hours_0": "{{count}} 시간", - "generic_count_minutes_0": "{{count}} 분", - "generic_count_seconds_0": "{{count}} 초", + "generic_count_years_0": "{{count}}년", + "generic_count_months_0": "{{count}}개월", + "generic_count_weeks_0": "{{count}}주", + "generic_count_days_0": "{{count}}일", + "generic_count_hours_0": "{{count}}시간", + "generic_count_minutes_0": "{{count}}분", + "generic_count_seconds_0": "{{count}}초", "Zulu": "줄루어", "Yoruba": "요루바어", "Yiddish": "이디시어", @@ -339,7 +339,7 @@ "comments_points_count_0": "{{count}} 포인트", "Invidious Private Feed for `x`": "`x` 에 대한 Invidious 비공개 피드", "Premieres `x`": "최초 공개 `x`", - "Premieres in `x`": "`x` 에 최초 공개", + "Premieres in `x`": "`x` 후 최초 공개", "next_steps_error_message": "다음 방법을 시도해 보세요: ", "search_filters_features_option_c_commons": "크리에이티브 커먼즈", "search_filters_duration_label": "길이", @@ -352,7 +352,7 @@ "Video mode": "비디오 모드", "Audio mode": "오디오 모드", "permalink": "퍼머링크", - "YouTube comment permalink": "YouTube 댓글 퍼머링크", + "YouTube comment permalink": "유튜브 댓글 퍼머링크", "(edited)": "(수정됨)", "%A %B %-d, %Y": "%A %B %-d, %Y", "Movies": "영화", @@ -396,7 +396,7 @@ "search_filters_features_option_purchased": "구입한 항목", "search_filters_apply_button": "선택한 필터 적용하기", "preferences_quality_dash_option_240p": "240p", - "preferences_region_label": "콘텐트 국가: ", + "preferences_region_label": "지역: ", "preferences_quality_dash_option_1440p": "1440p", "French (auto-generated)": "프랑스어 (자동 생성됨)", "Indonesian (auto-generated)": "인도네시아어 (자동 생성됨)", @@ -404,13 +404,13 @@ "Vietnamese (auto-generated)": "베트남어 (자동 생성됨)", "preferences_quality_dash_option_2160p": "2160p", "Italian (auto-generated)": "이탈리아어 (자동 생성됨)", - "preferences_quality_option_medium": "중간", + "preferences_quality_option_medium": "보통", "preferences_quality_dash_option_720p": "720p", "search_filters_duration_option_medium": "중간 (4 - 20분)", "preferences_quality_dash_option_best": "최고", "Portuguese (auto-generated)": "포르투갈어 (자동 생성됨)", "Spanish (Spain)": "스페인어 (스페인)", - "preferences_quality_dash_label": "선호하시는 DASH 비디오 품질: ", + "preferences_quality_dash_label": "선호하는 DASH 비디오 품질: ", "preferences_quality_option_hd720": "HD720", "Spanish (auto-generated)": "스페인어 (자동 생성됨)", "preferences_quality_dash_option_1080p": "1080p", @@ -437,7 +437,24 @@ "Spanish (Mexico)": "스페인어 (멕시코)", "search_filters_type_option_all": "모든 유형", "footer_donate_page": "기부하기", - "preferences_quality_option_dash": "DASH (적절한 화질)", + "preferences_quality_option_dash": "DASH (다양한 화질)", "preferences_quality_dash_option_360p": "360p", - "preferences_save_player_pos_label": "이어서 보기 활성화 " + "preferences_save_player_pos_label": "이어서 보기 활성화: ", + "none": "없음", + "videoinfo_started_streaming_x_ago": "'x' 전에 스트리밍을 시작했습니다", + "crash_page_you_found_a_bug": "Invidious에서 버그를 찾은 것 같습니다!", + "download_subtitles": "자막 - `x`(.vtt)", + "user_saved_playlists": "`x`개의 저장된 재생목록", + "crash_page_before_reporting": "버그를 보고하기 전에 다음 사항이 있는지 확인합니다:", + "crash_page_search_issue": "깃허브에서 기존 이슈를 검색했습니다", + "Video unavailable": "비디오를 사용할 수 없음", + "crash_page_refresh": "페이지를 새로고침하려고 했습니다", + "videoinfo_watch_on_youTube": "유튜브에서 보기", + "crash_page_switch_instance": "다른 인스턴스를 사용하려고 했습니다", + "crash_page_read_the_faq": "자주 묻는 질문(FAQ) 읽기", + "user_created_playlists": "`x`개의 생성된 재생목록", + "crash_page_report_issue": "위의 방법 중 어느 것도 도움이 되지 않았다면, 깃허브에서 새 이슈를 열고(가능하면 영어로) 메시지에 다음 텍스트를 포함하세요(해당 텍스트를 번역하지 마십시오):", + "videoinfo_youTube_embed_link": "임베드", + "videoinfo_invidious_embed_link": "임베드 링크", + "error_video_not_in_playlist": "요청한 동영상이 이 재생목록에 없습니다. 재생목록 목록을 보려면 여기를 클릭하십시오." } From 6f301db11cdb77d29c0420663168386c2483825a Mon Sep 17 00:00:00 2001 From: thecashewtrader Date: Tue, 25 Oct 2022 15:25:58 +0530 Subject: [PATCH 09/23] Remove twitter:site meta tag from channel view --- src/invidious/views/channel.ecr | 1 - 1 file changed, 1 deletion(-) diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr index 9449305b..dea86abe 100644 --- a/src/invidious/views/channel.ecr +++ b/src/invidious/views/channel.ecr @@ -10,7 +10,6 @@ - From 1e96206b0b60275b462c58882655d84c73691977 Mon Sep 17 00:00:00 2001 From: thecashewtrader Date: Tue, 25 Oct 2022 15:49:45 +0530 Subject: [PATCH 10/23] Remove twitter:site meta tag from watch view --- src/invidious/views/watch.ecr | 1 - 1 file changed, 1 deletion(-) diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 243ea3a4..6cb2cdec 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -19,7 +19,6 @@ - From 0c7919f3d912530615704fa520c08210b3c067a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89milien=20Devos?= Date: Tue, 25 Oct 2022 20:57:51 +0000 Subject: [PATCH 11/23] Dont use quay for the postgresql bitnami image --- kubernetes/values.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/kubernetes/values.yaml b/kubernetes/values.yaml index 2dc4db2c..7f371f72 100644 --- a/kubernetes/values.yaml +++ b/kubernetes/values.yaml @@ -34,8 +34,6 @@ securityContext: # See https://github.com/bitnami/charts/tree/master/bitnami/postgresql postgresql: - image: - registry: quay.io auth: username: kemal password: kemal From 4b1ef90d96fbbc723023a938a9a424aa308230d1 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 29 Oct 2022 00:55:12 +0200 Subject: [PATCH 12/23] =?UTF-8?q?Update=20Norwegian=20Bokm=C3=A5l=20transl?= =?UTF-8?q?ation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Petter Reinholdtsen --- locales/nb-NO.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/nb-NO.json b/locales/nb-NO.json index 7e964515..f4c2021b 100644 --- a/locales/nb-NO.json +++ b/locales/nb-NO.json @@ -471,5 +471,6 @@ "search_filters_date_label": "Opplastningsdato", "search_filters_apply_button": "Bruk valgte filtre", "search_filters_date_option_none": "Siden begynnelsen", - "search_filters_features_option_vr180": "VR180" + "search_filters_features_option_vr180": "VR180", + "error_video_not_in_playlist": "Forespurt video finnes ikke i denne spillelisten. Trykk her for spillelistens hjemmeside." } From 2edfe4a463f6defbab54d770d1cd1abdd13749dd Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 29 Oct 2022 00:55:12 +0200 Subject: [PATCH 13/23] Update Lithuanian translation Update Lithuanian translation Co-authored-by: Gediminas Murauskas Co-authored-by: Hosted Weblate --- locales/lt.json | 91 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/locales/lt.json b/locales/lt.json index b4a6da04..35ababee 100644 --- a/locales/lt.json +++ b/locales/lt.json @@ -153,7 +153,7 @@ "Shared `x`": "Pasidalino `x`", "Premieres in `x`": "Premjera už `x`", "Premieres `x`": "Premjera`x`", - "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Sveiki! Atrodo, kad turite išjungę \"JavaScript\". Spauskite čia norėdami peržiūrėti komentarus, turėkite omenyje, kad jų įkėlimas gali užtrukti.", + "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Sveiki! Panašu, kad turite išjungę „JavaScript“. Spustelėkite čia norėdami peržiūrėti komentarus, atminkite, kad jų įkėlimas gali užtrukti šiek tiek ilgiau.", "View YouTube comments": "Žiūrėti YouTube komentarus", "View more comments on Reddit": "Žiūrėti daugiau komentarų Reddit", "View `x` comments": { @@ -401,5 +401,92 @@ "generic_views_count_1": "{{count}} peržiūros", "generic_views_count_2": "{{count}} peržiūrų", "preferences_quality_dash_option_480p": "480p", - "preferences_quality_dash_option_240p": "240p" + "preferences_quality_dash_option_240p": "240p", + "none": "nėra", + "search_filters_type_option_all": "Bet koks tipas", + "videoinfo_started_streaming_x_ago": "Pradėjo transliuoti prieš `x`", + "crash_page_switch_instance": "pabandėte naudoti kitą perdavimo šaltinį", + "search_filters_duration_option_none": "Bet kokia trukmė", + "search_filters_duration_option_medium": "Vidutinio ilgumo (4 - 20 minučių)", + "search_filters_features_option_vr180": "VR180", + "crash_page_before_reporting": "Prieš pranešdami apie klaidą įsitikinkite, kad:", + "crash_page_read_the_faq": "perskaitėte Dažniausiai užduodamus klausimus (DUK)", + "crash_page_search_issue": "ieškojote esamų problemų GitHub", + "error_video_not_in_playlist": "Prašomo vaizdo įrašo šiame grojaraštyje nėra. Spustelėkite čia, kad pamatytumėte grojaraščio pagrindinį puslapį.", + "crash_page_report_issue": "Jei nė vienas iš pirmiau pateiktų būdų nepadėjo, prašome atidaryti naują problemą GitHub (pageidautina anglų kalba) ir į savo pranešimą įtraukti šį tekstą (NEVERSKITE šio teksto):", + "subscriptions_unseen_notifs_count_0": "{{count}} nematytas pranešimas", + "subscriptions_unseen_notifs_count_1": "{{count}} nematyti pranešimai", + "subscriptions_unseen_notifs_count_2": "{{count}} nematytų pranešimų", + "Vietnamese (auto-generated)": "Vietnamiečių kalba (automatiškai sugeneruota)", + "Dutch (auto-generated)": "Olandų kalba (automatiškai sugeneruota)", + "generic_count_weeks_0": "{{count}} savaitę", + "generic_count_weeks_1": "{{count}} savaitės", + "generic_count_weeks_2": "{{count}} savaičių", + "Interlingue": "Interlingue", + "Italian (auto-generated)": "Italų kalba (automatiškai sugeneruota)", + "Japanese (auto-generated)": "Japonų kalba (automatiškai sugeneruota)", + "Korean (auto-generated)": "Korėjiečių kalba (automatiškai sugeneruota)", + "generic_count_months_0": "{{count}} mėnesį", + "generic_count_months_1": "{{count}} mėnesius", + "generic_count_months_2": "{{count}} mėnesių", + "generic_count_days_0": "{{count}} dieną", + "generic_count_days_1": "{{count}} dienas", + "generic_count_days_2": "{{count}} dienų", + "generic_count_hours_0": "{{count}} valandą", + "generic_count_hours_1": "{{count}} valandas", + "generic_count_hours_2": "{{count}} valandų", + "generic_count_seconds_0": "{{count}} sekundę", + "generic_count_seconds_1": "{{count}} sekundes", + "generic_count_seconds_2": "{{count}} sekundžių", + "generic_count_minutes_0": "{{count}} minutę", + "generic_count_minutes_1": "{{count}} minutes", + "generic_count_minutes_2": "{{count}} minučių", + "generic_count_years_0": "{{count}} metus", + "generic_count_years_1": "{{count}} metus", + "generic_count_years_2": "{{count}} metų", + "Popular enabled: ": "Populiarūs įgalinti: ", + "Portuguese (auto-generated)": "Portugalų kalba (automatiškai sugeneruota)", + "videoinfo_watch_on_youTube": "Žiaurėti Youtube", + "Chinese (China)": "Kinų kalba (Kinija)", + "crash_page_you_found_a_bug": "Atrodo, kad radote \"Invidious\" klaidą!", + "search_filters_features_option_three_sixty": "360°", + "English (United Kingdom)": "Anglų kalba (Jungtinė Karalystė)", + "Chinese (Hong Kong)": "Kinų kalba (Honkongas)", + "search_message_change_filters_or_query": "Pabandykite išplėsti paieškos užklausą ir (arba) pakeisti filtrus.", + "English (United States)": "Anglų kalba (Jungtinės Amerikos Valstijos)", + "Chinese (Taiwan)": "Kinų kalba (Taivanas)", + "search_message_use_another_instance": " Taip pat galite ieškoti kitame perdavimo šaltinyje.", + "tokens_count_0": "{{count}} žetonas", + "tokens_count_1": "{{count}} žetonai", + "tokens_count_2": "{{count}} žetonų", + "search_message_no_results": "Rezultatų nerasta.", + "comments_view_x_replies_0": "Žiūrėti {{count}} atsakymą", + "comments_view_x_replies_1": "Žiūrėti {{count}} atsakymus", + "comments_view_x_replies_2": "Žiūrėti {{count}} atsakymų", + "comments_points_count_0": "{{count}} taškas", + "comments_points_count_1": "{{count}} taškai", + "comments_points_count_2": "{{count}} taškų", + "Cantonese (Hong Kong)": "Kantono kalba (Honkongas)", + "Chinese": "Kinų", + "French (auto-generated)": "Prancūzų kalba (automatiškai sugeneruota)", + "German (auto-generated)": "Vokiečių kalba (automatiškai sugeneruota)", + "Indonesian (auto-generated)": "Indoneziečių kalba (automatiškai sugeneruota)", + "Portuguese (Brazil)": "Portugalų kalba (Brazilija)", + "Russian (auto-generated)": "Rusų kalba (automatiškai sugeneruota)", + "Spanish (Mexico)": "Ispanų kalba (Meksika)", + "Spanish (auto-generated)": "Ispanų kalba (automatiškai sugeneruota)", + "Spanish (Spain)": "Ispanų kalba (Ispanija)", + "Turkish (auto-generated)": "Turkų kalba (automatiškai sugeneruota)", + "search_filters_date_label": "Įkėlimo data", + "search_filters_date_option_none": "Bet kokia data", + "search_filters_features_option_purchased": "Įsigyta", + "search_filters_apply_button": "Taikyti pasirinktus filtrus", + "download_subtitles": "Subtitrai - `x` (.vtt)", + "user_created_playlists": "`x` sukurti grojaraščiai", + "user_saved_playlists": "`x` išsaugoti grojaraščiai", + "Video unavailable": "Vaizdo įrašas nepasiekiamas", + "preferences_save_player_pos_label": "Išsaugoti atkūrimo padėtį: ", + "videoinfo_youTube_embed_link": "Įterpti", + "videoinfo_invidious_embed_link": "Įterpti nuorodą", + "crash_page_refresh": "pabandėte atnaujinti puslapį" } From 127bfd5023b8b3c8f52ffaf58c7a284d8c3c8cd9 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 29 Oct 2022 00:55:12 +0200 Subject: [PATCH 14/23] Update Esperanto translation Co-authored-by: Hosted Weblate Co-authored-by: Jorge Maldonado Ventura --- locales/eo.json | 118 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 7 deletions(-) diff --git a/locales/eo.json b/locales/eo.json index 40ab5f39..fb5bb69c 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -21,15 +21,15 @@ "No": "Ne", "Import and Export Data": "Importi kaj Eksporti Datumojn", "Import": "Importi", - "Import Invidious data": "Importi datumojn de Invidious", - "Import YouTube subscriptions": "Importi abonojn de JuTubo", + "Import Invidious data": "Importi JSON-datumojn de Invidious", + "Import YouTube subscriptions": "Importi abonojn de YouTube/OPML", "Import FreeTube subscriptions (.db)": "Importi abonojn de FreeTube (.db)", "Import NewPipe subscriptions (.json)": "Importi abonojn de NewPipe (.json)", "Import NewPipe data (.zip)": "Importi datumojn de NewPipe (.zip)", "Export": "Eksporti", "Export subscriptions as OPML": "Eksporti abonojn kiel OPML", "Export subscriptions as OPML (for NewPipe & FreeTube)": "Eksporti abonojn kiel OPML (por NewPipe kaj FreeTube)", - "Export data as JSON": "Eksporti datumojn kiel JSON", + "Export data as JSON": "Eksporti Invidious-datumojn kiel JSON", "Delete account?": "Ĉu forigi konton?", "History": "Historio", "An alternative front-end to YouTube": "Alternativa fasado al JuTubo", @@ -66,7 +66,7 @@ "preferences_related_videos_label": "Ĉu montri rilatajn filmetojn? ", "preferences_annotations_label": "Ĉu montri prinotojn defaŭlte? ", "preferences_extend_desc_label": "Aŭtomate etendi priskribon de filmeto: ", - "preferences_vr_mode_label": "Interagaj 360-gradaj filmetoj: ", + "preferences_vr_mode_label": "Interagaj 360-gradaj filmoj (postulas WebGL-n): ", "preferences_category_visual": "Vidaj preferoj", "preferences_player_style_label": "Ludila stilo: ", "Dark mode: ": "Malhela reĝimo: ", @@ -75,7 +75,7 @@ "light": "hela", "preferences_thin_mode_label": "Maldika reĝimo: ", "preferences_category_misc": "Aliaj agordoj", - "preferences_automatic_instance_redirect_label": "Aŭtomata alidirektado de instalaĵo (retropaŝo al redirect.invidious.io): ", + "preferences_automatic_instance_redirect_label": "Aŭtomata alidirektado de nodo (retropaŝo al redirect.invidious.io): ", "preferences_category_subscription": "Abonaj agordoj", "preferences_annotations_subscribed_label": "Ĉu montri prinotojn defaŭlte por abonitaj kanaloj? ", "Redirect homepage to feed: ": "Alidirekti hejmpâgon al fluo: ", @@ -140,7 +140,7 @@ "Show more": "Montri pli", "Show less": "Montri malpli", "Watch on YouTube": "Vidi filmeton en JuTubo", - "Switch Invidious Instance": "Ŝanĝi instalaĵon de Indivious", + "Switch Invidious Instance": "Ŝanĝi nodon de Indivious", "Hide annotations": "Kaŝi prinotojn", "Show annotations": "Montri prinotojn", "Genre: ": "Ĝenro: ", @@ -368,5 +368,109 @@ "footer_donate_page": "Donaci", "preferences_region_label": "Lando de la enhavo: ", "preferences_quality_dash_label": "Preferata DASH-a videkvalito: ", - "search_filters_title": "Filtri" + "search_filters_title": "Filtri", + "preferences_quality_dash_option_best": "Plej bona", + "preferences_quality_dash_option_worst": "Malplej bona", + "Popular enabled: ": "Populara sekcio ebligita: ", + "search_message_no_results": "Neniu rezulto trovita.", + "search_message_use_another_instance": " Vi ankaŭ povas serĉi en alia nodo.", + "tokens_count": "{{count}} ĵetono", + "tokens_count_plural": "{{count}} ĵetonoj", + "subscriptions_unseen_notifs_count": "{{count}} nevidita sciigo", + "subscriptions_unseen_notifs_count_plural": "{{count}} neviditaj sciigoj", + "Indonesian (auto-generated)": "Indonezia (aŭtomate generita)", + "Interlingue": "Interlingvo", + "Italian (auto-generated)": "Itala (aŭtomate generita)", + "Korean (auto-generated)": "Korea (aŭtomate generita)", + "Portuguese (Brazil)": "Portugala (Brazilo)", + "Portuguese (auto-generated)": "Portugala (aŭtomate generita)", + "Russian (auto-generated)": "Rusa (aŭtomate generita)", + "Spanish (Spain)": "Hispana (Hispanio)", + "generic_count_years": "{{count}} jaro", + "generic_count_years_plural": "{{count}} jaroj", + "Turkish (auto-generated)": "Turka (aŭtomate generita)", + "Vietnamese (auto-generated)": "Vjetnama (aŭtomate generita)", + "generic_count_hours": "{{count}} horo", + "generic_count_hours_plural": "{{count}} horoj", + "generic_count_minutes": "{{count}} minuto", + "generic_count_minutes_plural": "{{count}} minutoj", + "search_filters_date_label": "Alŝutdato", + "search_filters_date_option_none": "Ajna dato", + "search_filters_duration_option_medium": "Meza (4 - 20 minutoj)", + "search_filters_features_option_three_sixty": "360º", + "search_filters_features_option_vr180": "VR180", + "user_created_playlists": "`x`kreitaj ludlistoj", + "user_saved_playlists": "`x`konservitaj ludlistoj", + "crash_page_switch_instance": "klopodis uzi alian nodon", + "crash_page_read_the_faq": "legis la oftajn demandojn", + "error_video_not_in_playlist": "La petita video ne ekzistas en ĉi tiu ludlisto. Alklaku ĉi tie por iri al la ludlista hejmpaĝo.", + "crash_page_search_issue": "serĉis por ekzistantaj problemoj en GitHub", + "generic_count_seconds": "{{count}} sekundo", + "generic_count_seconds_plural": "{{count}} sekundoj", + "preferences_quality_dash_option_144p": "144p", + "comments_view_x_replies": "Vidi {{count}} respondon", + "comments_view_x_replies_plural": "Vidi {{count}} respondojn", + "preferences_quality_dash_option_360p": "360p", + "invidious": "Invidious", + "Chinese (Taiwan)": "Ĉina (Tajvano)", + "English (United Kingdom)": "Angla (Britio)", + "search_filters_features_option_purchased": "Aĉetita", + "Japanese (auto-generated)": "Japana (aŭtomate generita)", + "search_message_change_filters_or_query": "Provu vastigi vian serĉpeton kaj/aŭ ŝanĝi la filtrilojn.", + "preferences_quality_dash_option_1080p": "1080p", + "generic_count_weeks": "{{count}} semajno", + "generic_count_weeks_plural": "{{count}} semajnoj", + "preferences_quality_dash_option_240p": "240p", + "preferences_quality_dash_option_1440p": "1440p", + "preferences_quality_dash_option_4320p": "4320p", + "preferences_quality_dash_option_720p": "720p", + "preferences_quality_dash_option_auto": "Aŭtomate", + "preferences_quality_dash_option_2160p": "2160p", + "English (United States)": "Angla (Usono)", + "Chinese": "Ĉina", + "videoinfo_watch_on_youTube": "Vidi en YouTube", + "crash_page_you_found_a_bug": "Ŝajnas, ke vi trovis eraron en Invidious!", + "comments_points_count": "{{count}} poento", + "comments_points_count_plural": "{{count}} poentoj", + "Cantonese (Hong Kong)": "Kantona (Honkongo)", + "preferences_watch_history_label": "Ebligi vidohistorion: ", + "preferences_quality_option_small": "Eta", + "generic_playlists_count": "{{count}} ludlisto", + "generic_playlists_count_plural": "{{count}} ludlistoj", + "videoinfo_youTube_embed_link": "Enigi", + "preferences_quality_dash_option_480p": "480p", + "preferences_quality_option_hd720": "HD720", + "preferences_quality_option_medium": "Meza", + "generic_subscriptions_count": "{{count}} abono", + "generic_subscriptions_count_plural": "{{count}} abonoj", + "videoinfo_started_streaming_x_ago": "Komercis elsendi antaŭ `x`", + "download_subtitles": "Subtitoloj - `x` (.vtt)", + "videoinfo_invidious_embed_link": "Enigi Ligilon", + "crash_page_report_issue": "Se neniu el la antaŭaj agoj helpis, bonvolu estigi novan problemon en GitHub (prefere angle) kaj inkludi la jenan tekston en via mesaĝo (NE traduku tiun tekston):", + "preferences_quality_option_dash": "DASH (adapta kvalito)", + "Chinese (Hong Kong)": "Ĉina (Honkongo)", + "Chinese (China)": "Ĉina (Ĉinio)", + "Dutch (auto-generated)": "Nederlanda (aŭtomate generita)", + "German (auto-generated)": "Germana (aŭtomate generita)", + "French (auto-generated)": "Franca (aŭtomate generita)", + "Spanish (Mexico)": "Hispana (Meksiko)", + "Spanish (auto-generated)": "Hispana (aŭtomate generita)", + "generic_count_days": "{{count}} jaro", + "generic_count_days_plural": "{{count}} jaroj", + "search_filters_type_option_all": "Ajna speco", + "search_filters_duration_option_none": "Ajna daŭro", + "search_filters_apply_button": "Uzi elektitajn filtrilojn", + "none": "neniu", + "Video unavailable": "Nedisponebla video", + "crash_page_before_reporting": "Antaŭ ol informi pri eraro certigu, ke vi:", + "crash_page_refresh": "klopodis reŝarĝi la paĝon", + "generic_views_count": "{{count}} spekto", + "generic_views_count_plural": "{{count}} spektoj", + "generic_videos_count": "{{count}} video", + "generic_videos_count_plural": "{{count}} videoj", + "generic_subscribers_count": "{{count}} abonanto", + "generic_subscribers_count_plural": "{{count}} abonantoj", + "generic_count_months": "{{count}} monato", + "generic_count_months_plural": "{{count}} monatoj", + "preferences_save_player_pos_label": "Konservi ludadan pozicion: " } From bba693e2afd6fffbf11a33a76cda8bb3aa9d31b5 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 29 Oct 2022 00:55:13 +0200 Subject: [PATCH 15/23] Update Korean translation Co-authored-by: Hosted Weblate Co-authored-by: xrfmkrh --- locales/ko.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/locales/ko.json b/locales/ko.json index 127a500b..8d79c456 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -25,9 +25,9 @@ "preferences_quality_label": "선호하는 비디오 품질: ", "preferences_speed_label": "기본 속도: ", "preferences_local_label": "비디오를 프록시: ", - "preferences_listen_label": "기본적으로 듣기: ", + "preferences_listen_label": "라디오 모드 활성화: ", "preferences_continue_autoplay_label": "다음 동영상 자동재생 ", - "preferences_continue_label": "기본적으로 다음 재생: ", + "preferences_continue_label": "다음 동영상으로 이동: ", "preferences_autoplay_label": "자동재생: ", "preferences_video_loop_label": "항상 반복: ", "preferences_category_player": "플레이어 설정", @@ -58,7 +58,7 @@ "Import NewPipe subscriptions (.json)": "NewPipe 구독을 가져오기 (.json)", "Import FreeTube subscriptions (.db)": "FreeTube 구독 가져오기 (.db)", "Import YouTube subscriptions": "유튜브 구독 가져오기", - "Import Invidious data": "Invidious JSON 데이터 가져오기", + "Import Invidious data": "인비디어스 JSON 데이터 가져오기", "Import": "가져오기", "Import and Export Data": "데이터 가져오기 및 내보내기", "No": "아니요", @@ -337,7 +337,7 @@ "Swedish": "스웨덴어", "Spanish (Latin America)": "스페인어 (라틴 아메리카)", "comments_points_count_0": "{{count}} 포인트", - "Invidious Private Feed for `x`": "`x` 에 대한 Invidious 비공개 피드", + "Invidious Private Feed for `x`": "`x` 에 대한 인비디어스 비공개 피드", "Premieres `x`": "최초 공개 `x`", "Premieres in `x`": "`x` 후 최초 공개", "next_steps_error_message": "다음 방법을 시도해 보세요: ", @@ -396,7 +396,7 @@ "search_filters_features_option_purchased": "구입한 항목", "search_filters_apply_button": "선택한 필터 적용하기", "preferences_quality_dash_option_240p": "240p", - "preferences_region_label": "지역: ", + "preferences_region_label": "국가: ", "preferences_quality_dash_option_1440p": "1440p", "French (auto-generated)": "프랑스어 (자동 생성됨)", "Indonesian (auto-generated)": "인도네시아어 (자동 생성됨)", @@ -416,7 +416,7 @@ "preferences_quality_dash_option_1080p": "1080p", "preferences_quality_dash_option_worst": "최저", "preferences_watch_history_label": "시청 기록 활성화: ", - "invidious": "Invidious", + "invidious": "인비디어스", "preferences_quality_option_small": "낮음", "preferences_quality_dash_option_auto": "자동", "preferences_quality_dash_option_480p": "480p", @@ -441,7 +441,7 @@ "preferences_quality_dash_option_360p": "360p", "preferences_save_player_pos_label": "이어서 보기 활성화: ", "none": "없음", - "videoinfo_started_streaming_x_ago": "'x' 전에 스트리밍을 시작했습니다", + "videoinfo_started_streaming_x_ago": "`x` 전에 스트리밍을 시작했습니다", "crash_page_you_found_a_bug": "Invidious에서 버그를 찾은 것 같습니다!", "download_subtitles": "자막 - `x`(.vtt)", "user_saved_playlists": "`x`개의 저장된 재생목록", From 4e1f5c8357f9c3add785bd39e49c3f2e0746567c Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 30 Oct 2022 13:18:23 +0100 Subject: [PATCH 16/23] CI: bump Crystal versions --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e10be8a..201e818a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,10 +38,10 @@ jobs: matrix: stable: [true] crystal: - - 1.2.2 - 1.3.2 - - 1.4.0 - - 1.5.0 + - 1.4.1 + - 1.5.1 + - 1.6.1 include: - crystal: nightly stable: false From 8096c2d81d0282a91a95f9c2c7fa63e41c4691f0 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 30 Oct 2022 13:18:50 +0100 Subject: [PATCH 17/23] CI: bump install-crystal action to v1.7.0 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 201e818a..dfe3ba87 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: submodules: true - name: Install Crystal - uses: crystal-lang/install-crystal@v1.6.0 + uses: crystal-lang/install-crystal@v1.7.0 with: crystal: ${{ matrix.crystal }} From 4055c3bec86f4265c81282e59bddad21e5e348bd Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 30 Oct 2022 13:46:28 +0100 Subject: [PATCH 18/23] i18n: Add Bengali, Catalan, Basque, Sinhala and Slovak Add languages even if translation is <= 25% --- src/invidious/helpers/i18n.cr | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/invidious/helpers/i18n.cr b/src/invidious/helpers/i18n.cr index fd86594c..a9ed1f64 100644 --- a/src/invidious/helpers/i18n.cr +++ b/src/invidious/helpers/i18n.cr @@ -1,8 +1,7 @@ -# "bn_BD" => load_locale("bn_BD"), # Bengali (Bangladesh) [Incomplete] -# "eu" => load_locale("eu"), # Basque [Incomplete] -# "sk" => load_locale("sk"), # Slovak [Incomplete] LOCALES_LIST = { "ar" => "العربية", # Arabic + "bn" => "বাংলা", # Bengali + "ca" => "Català", # Catalan "cs" => "Čeština", # Czech "da" => "Dansk", # Danish "de" => "Deutsch", # German @@ -11,6 +10,7 @@ LOCALES_LIST = { "eo" => "Esperanto", # Esperanto "es" => "Español", # Spanish "et" => "Eesti keel", # Estonian + "eu" => "Euskara", # Basque "fa" => "فارسی", # Persian "fi" => "Suomi", # Finnish "fr" => "Français", # French @@ -32,6 +32,8 @@ LOCALES_LIST = { "pt-PT" => "Português de Portugal", # Portuguese (Portugal) "ro" => "Română", # Romanian "ru" => "Русский", # Russian + "si" => "සිංහල", # Sinhala + "sk" => "Slovenčina", # Slovak "sl" => "Slovenščina", # Slovenian "sq" => "Shqip", # Albanian "sr" => "Srpski (latinica)", # Serbian (Latin) From 84cd4d6a5b1854bcf1058351e390cc0f4855c9d7 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Sun, 30 Oct 2022 12:58:23 +0000 Subject: [PATCH 19/23] Makefile: disable QUIC by default (#3367) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7d09f39c..29be727c 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ RELEASE := 1 STATIC := 0 -DISABLE_QUIC := 0 +DISABLE_QUIC := 1 NO_DBG_SYMBOLS := 0 From f267394bbe2bd972e0157913ae253bfaa79ead0f Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 31 Oct 2022 20:40:43 +0100 Subject: [PATCH 20/23] extractors: Add support for richGridRenderer --- src/invidious/yt_backend/extractors.cr | 47 +++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index dc65cc52..18b48152 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -436,21 +436,31 @@ private module Extractors content = extract_selected_tab(target["tabs"])["content"] if section_list_contents = content.dig?("sectionListRenderer", "contents") - section_list_contents.as_a.each do |renderer_container| - renderer_container_contents = renderer_container["itemSectionRenderer"]["contents"][0] + raw_items = unpack_section_list(section_list_contents) + elsif rich_grid_contents = content.dig?("richGridRenderer", "contents") + raw_items = rich_grid_contents.as_a + end - # Category extraction - if items_container = renderer_container_contents["shelfRenderer"]? - raw_items << renderer_container_contents - next - elsif items_container = renderer_container_contents["gridRenderer"]? - else - items_container = renderer_container_contents - end + return raw_items + end - items_container["items"]?.try &.as_a.each do |item| - raw_items << item - end + private def self.unpack_section_list(contents) + raw_items = [] of JSON::Any + + contents.as_a.each do |renderer_container| + renderer_container_contents = renderer_container["itemSectionRenderer"]["contents"][0] + + # Category extraction + if items_container = renderer_container_contents["shelfRenderer"]? + raw_items << renderer_container_contents + next + elsif items_container = renderer_container_contents["gridRenderer"]? + else + items_container = renderer_container_contents + end + + items_container["items"]?.try &.as_a.each do |item| + raw_items << item end end @@ -525,14 +535,11 @@ private module Extractors end private def self.extract(target) - raw_items = [] of JSON::Any - if content = target["gridContinuation"]? - raw_items = content["items"].as_a - elsif content = target["continuationItems"]? - raw_items = content.as_a - end + content = target["continuationItems"]? + content ||= target.dig?("gridContinuation", "items") + content ||= target.dig?("richGridContinuation", "contents") - return raw_items + return content.nil? ? [] of JSON::Any : content.as_a end def self.extractor_name From 46a63e6150f83bca90563068ebb12ecdf5e0d3c6 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Mon, 31 Oct 2022 21:30:10 +0100 Subject: [PATCH 21/23] extractors: Add support for reelItemRenderer --- src/invidious/yt_backend/extractors.cr | 87 +++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/src/invidious/yt_backend/extractors.cr b/src/invidious/yt_backend/extractors.cr index 18b48152..8112930d 100644 --- a/src/invidious/yt_backend/extractors.cr +++ b/src/invidious/yt_backend/extractors.cr @@ -17,6 +17,7 @@ private ITEM_PARSERS = { Parsers::PlaylistRendererParser, Parsers::CategoryRendererParser, Parsers::RichItemRendererParser, + Parsers::ReelItemRendererParser, } record AuthorFallback, name : String, id : String @@ -369,7 +370,7 @@ private module Parsers end # Parses an InnerTube richItemRenderer into a SearchVideo. - # Returns nil when the given object isn't a shelfRenderer + # Returns nil when the given object isn't a RichItemRenderer # # A richItemRenderer seems to be a simple wrapper for a videoRenderer, used # by the result page for hashtags. It is located inside a continuationItems @@ -390,6 +391,90 @@ private module Parsers return {{@type.name}} end end + + # Parses an InnerTube reelItemRenderer into a SearchVideo. + # Returns nil when the given object isn't a reelItemRenderer + # + # reelItemRenderer items are used in the new (2022) channel layout, + # in the "shorts" tab. + # + module ReelItemRendererParser + def self.process(item : JSON::Any, author_fallback : AuthorFallback) + if item_contents = item["reelItemRenderer"]? + return self.parse(item_contents, author_fallback) + end + end + + private def self.parse(item_contents, author_fallback) + video_id = item_contents["videoId"].as_s + + video_details_container = item_contents.dig( + "navigationEndpoint", "reelWatchEndpoint", + "overlay", "reelPlayerOverlayRenderer", + "reelPlayerHeaderSupportedRenderers", + "reelPlayerHeaderRenderer" + ) + + # Author infos + + author = video_details_container + .dig?("channelTitleText", "runs", 0, "text") + .try &.as_s || author_fallback.name + + ucid = video_details_container + .dig?("channelNavigationEndpoint", "browseEndpoint", "browseId") + .try &.as_s || author_fallback.id + + # Title & publication date + + title = video_details_container.dig?("reelTitleText") + .try { |t| extract_text(t) } || "" + + published = video_details_container + .dig?("timestampText", "simpleText") + .try { |t| decode_date(t.as_s) } || Time.utc + + # View count + + view_count_text = video_details_container.dig?("viewCountText", "simpleText") + view_count_text ||= video_details_container + .dig?("viewCountText", "accessibility", "accessibilityData", "label") + + view_count = view_count_text.try &.as_s.gsub(/\D+/, "").to_i64? || 0_i64 + + # Duration + + a11y_data = item_contents + .dig?("accessibility", "accessibilityData", "label") + .try &.as_s || "" + + regex_match = /- (?\d+ minutes? )?(?\d+ seconds?)+ -/.match(a11y_data) + + minutes = regex_match.try &.["min"].to_i(strict: false) || 0 + seconds = regex_match.try &.["sec"].to_i(strict: false) || 0 + + duration = (minutes*60 + seconds) + + SearchVideo.new({ + title: title, + id: video_id, + author: author, + ucid: ucid, + published: published, + views: view_count, + description_html: "", + length_seconds: duration, + live_now: false, + premium: false, + premiere_timestamp: Time.unix(0), + author_verified: false, + }) + end + + def self.parser_name + return {{@type.name}} + end + end end # The following are the extractors for extracting an array of items from From 758b7df400742d768abf0c005e6751d12c03e479 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Tue, 1 Nov 2022 17:34:26 +0000 Subject: [PATCH 22/23] dockerfile: Pass '-Ddisable_quic' to 'crystal build' (#3376) + use alpine 3.16 as a base like the crystal team --- .github/workflows/container-release.yml | 34 ++++++++++++++++++++++--- docker/Dockerfile | 11 ++++++-- docker/Dockerfile.arm64 | 9 ++++++- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/.github/workflows/container-release.yml b/.github/workflows/container-release.yml index 7e427e6e..86aec94f 100644 --- a/.github/workflows/container-release.yml +++ b/.github/workflows/container-release.yml @@ -52,7 +52,7 @@ jobs: username: ${{ secrets.QUAY_USERNAME }} password: ${{ secrets.QUAY_PASSWORD }} - - name: Build and push Docker AMD64 image for Push Event + - name: Build and push Docker AMD64 image without QUIC for Push Event if: github.ref == 'refs/heads/master' uses: docker/build-push-action@v3 with: @@ -62,9 +62,11 @@ jobs: labels: quay.expires-after=12w push: true tags: quay.io/invidious/invidious:${{ github.sha }},quay.io/invidious/invidious:latest - build-args: release=1 + build-args: | + "release=1" + "disable_quic=1" - - name: Build and push Docker ARM64 image for Push Event + - name: Build and push Docker ARM64 image without QUIC for Push Event if: github.ref == 'refs/heads/master' uses: docker/build-push-action@v3 with: @@ -74,4 +76,30 @@ jobs: labels: quay.expires-after=12w push: true tags: quay.io/invidious/invidious:${{ github.sha }}-arm64,quay.io/invidious/invidious:latest-arm64 + build-args: | + "release=1" + "disable_quic=1" + + - name: Build and push Docker AMD64 image with QUIC for Push Event + if: github.ref == 'refs/heads/master' + uses: docker/build-push-action@v3 + with: + context: . + file: docker/Dockerfile + platforms: linux/amd64 + labels: quay.expires-after=12w + push: true + tags: quay.io/invidious/invidious:${{ github.sha }}-quic,quay.io/invidious/invidious:latest-quic + build-args: release=1 + + - name: Build and push Docker ARM64 image with QUIC for Push Event + if: github.ref == 'refs/heads/master' + uses: docker/build-push-action@v3 + with: + context: . + file: docker/Dockerfile.arm64 + platforms: linux/arm64/v8 + labels: quay.expires-after=12w + push: true + tags: quay.io/invidious/invidious:${{ github.sha }}-arm64-quic,quay.io/invidious/invidious:latest-arm64-quic build-args: release=1 diff --git a/docker/Dockerfile b/docker/Dockerfile index 1346f6eb..34549df1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,6 +2,7 @@ FROM crystallang/crystal:1.4.1-alpine AS builder RUN apk add --no-cache sqlite-static yaml-static ARG release +ARG disable_quic WORKDIR /invidious COPY ./shard.yml ./shard.yml @@ -23,7 +24,13 @@ COPY ./videojs-dependencies.yml ./videojs-dependencies.yml RUN crystal spec --warnings all \ --link-flags "-lxml2 -llzma" -RUN if [ "${release}" == 1 ] ; then \ +RUN if [[ "${release}" == 1 && "${disable_quic}" == 1 ]] ; then \ + crystal build ./src/invidious.cr \ + --release \ + -Ddisable_quic \ + --static --warnings all \ + --link-flags "-lxml2 -llzma"; \ + elif [[ "${release}" == 1 ]] ; then \ crystal build ./src/invidious.cr \ --release \ --static --warnings all \ @@ -35,7 +42,7 @@ RUN if [ "${release}" == 1 ] ; then \ fi -FROM alpine:latest +FROM alpine:3.16 RUN apk add --no-cache librsvg ttf-opensans WORKDIR /invidious RUN addgroup -g 1000 -S invidious && \ diff --git a/docker/Dockerfile.arm64 b/docker/Dockerfile.arm64 index 35d3fa7b..ef3284b1 100644 --- a/docker/Dockerfile.arm64 +++ b/docker/Dockerfile.arm64 @@ -2,6 +2,7 @@ FROM alpine:3.16 AS builder RUN apk add --no-cache 'crystal=1.4.1-r0' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev ARG release +ARG disable_quic WORKDIR /invidious COPY ./shard.yml ./shard.yml @@ -23,7 +24,13 @@ COPY ./videojs-dependencies.yml ./videojs-dependencies.yml RUN crystal spec --warnings all \ --link-flags "-lxml2 -llzma" -RUN if [ ${release} == 1 ] ; then \ +RUN if [[ "${release}" == 1 && "${disable_quic}" == 1 ]] ; then \ + crystal build ./src/invidious.cr \ + --release \ + -Ddisable_quic \ + --static --warnings all \ + --link-flags "-lxml2 -llzma"; \ + elif [[ "${release}" == 1 ]] ; then \ crystal build ./src/invidious.cr \ --release \ --static --warnings all \ From 9da1827e957f9a8c4a370968b85007ad0f85c196 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Wed, 2 Nov 2022 00:58:33 +0100 Subject: [PATCH 23/23] Dirty fix to get back the channel videos --- spec/invidious/helpers_spec.cr | 10 ++-- src/invidious/channels/videos.cr | 92 +++++++++++++++----------------- 2 files changed, 49 insertions(+), 53 deletions(-) diff --git a/spec/invidious/helpers_spec.cr b/spec/invidious/helpers_spec.cr index 5ecebef3..ab361770 100644 --- a/spec/invidious/helpers_spec.cr +++ b/spec/invidious/helpers_spec.cr @@ -5,13 +5,13 @@ CONFIG = Config.from_yaml(File.open("config/config.example.yml")) Spectator.describe "Helper" do describe "#produce_channel_videos_url" do it "correctly produces url for requesting page `x` of a channel's videos" do - expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw")).to eq("/browse_ajax?continuation=4qmFsgI8EhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaIEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0V4&gl=US&hl=en") + # expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw")).to eq("/browse_ajax?continuation=4qmFsgI8EhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaIEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0V4&gl=US&hl=en") + # + # expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw", sort_by: "popular")).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0V4R0FFPQ%3D%3D&gl=US&hl=en") - expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw", sort_by: "popular")).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0V4R0FFPQ%3D%3D&gl=US&hl=en") + # expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw", page: 20)).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0l5TUE9PQ%3D%3D&gl=US&hl=en") - expect(produce_channel_videos_url(ucid: "UCXuqSBlHAE6Xw-yeJA0Tunw", page: 20)).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQ1h1cVNCbEhBRTZYdy15ZUpBMFR1bncaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0l5TUE9PQ%3D%3D&gl=US&hl=en") - - expect(produce_channel_videos_url(ucid: "UC-9-kyTW8ZkZNDHQJ6FgpwQ", page: 20, sort_by: "popular")).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQy05LWt5VFc4WmtaTkRIUUo2Rmdwd1EaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0l5TUJnQg%3D%3D&gl=US&hl=en") + # expect(produce_channel_videos_url(ucid: "UC-9-kyTW8ZkZNDHQJ6FgpwQ", page: 20, sort_by: "popular")).to eq("/browse_ajax?continuation=4qmFsgJAEhhVQy05LWt5VFc4WmtaTkRIUUo2Rmdwd1EaJEVnWjJhV1JsYjNNd0FqZ0JZQUZxQUxnQkFDQUFlZ0l5TUJnQg%3D%3D&gl=US&hl=en") end end diff --git a/src/invidious/channels/videos.cr b/src/invidious/channels/videos.cr index 48453bb7..b495e597 100644 --- a/src/invidious/channels/videos.cr +++ b/src/invidious/channels/videos.cr @@ -1,53 +1,48 @@ def produce_channel_videos_continuation(ucid, page = 1, auto_generated = nil, sort_by = "newest", v2 = false) - object = { - "80226972:embedded" => { - "2:string" => ucid, - "3:base64" => { - "2:string" => "videos", - "6:varint" => 2_i64, - "7:varint" => 1_i64, - "12:varint" => 1_i64, - "13:string" => "", - "23:varint" => 0_i64, + object_inner_2 = { + "2:0:embedded" => { + "1:0:varint" => 0_i64, + }, + "5:varint" => 50_i64, + "6:varint" => 1_i64, + "7:varint" => (page * 30).to_i64, + "9:varint" => 1_i64, + "10:varint" => 0_i64, + } + + object_inner_2_encoded = object_inner_2 + .try { |i| Protodec::Any.cast_json(i) } + .try { |i| Protodec::Any.from_json(i) } + .try { |i| Base64.urlsafe_encode(i) } + .try { |i| URI.encode_www_form(i) } + + object_inner_1 = { + "110:embedded" => { + "3:embedded" => { + "15:embedded" => { + "1:embedded" => { + "1:string" => object_inner_2_encoded, + "2:string" => "00000000-0000-0000-0000-000000000000", + }, + "3:varint" => 1_i64, + }, }, }, } - if !v2 - if auto_generated - seed = Time.unix(1525757349) - until seed >= Time.utc - seed += 1.month - end - timestamp = seed - (page - 1).months + object_inner_1_encoded = object_inner_1 + .try { |i| Protodec::Any.cast_json(i) } + .try { |i| Protodec::Any.from_json(i) } + .try { |i| Base64.urlsafe_encode(i) } + .try { |i| URI.encode_www_form(i) } - object["80226972:embedded"]["3:base64"].as(Hash)["4:varint"] = 0x36_i64 - object["80226972:embedded"]["3:base64"].as(Hash)["15:string"] = "#{timestamp.to_unix}" - else - object["80226972:embedded"]["3:base64"].as(Hash)["4:varint"] = 0_i64 - object["80226972:embedded"]["3:base64"].as(Hash)["15:string"] = "#{page}" - end - else - object["80226972:embedded"]["3:base64"].as(Hash)["4:varint"] = 0_i64 - - object["80226972:embedded"]["3:base64"].as(Hash)["61:string"] = Base64.urlsafe_encode(Protodec::Any.from_json(Protodec::Any.cast_json({ - "1:string" => Base64.urlsafe_encode(Protodec::Any.from_json(Protodec::Any.cast_json({ - "1:varint" => 30_i64 * (page - 1), - }))), - }))) - end - - case sort_by - when "newest" - when "popular" - object["80226972:embedded"]["3:base64"].as(Hash)["3:varint"] = 0x01_i64 - when "oldest" - object["80226972:embedded"]["3:base64"].as(Hash)["3:varint"] = 0x02_i64 - else nil # Ignore - end - - object["80226972:embedded"]["3:string"] = Base64.urlsafe_encode(Protodec::Any.from_json(Protodec::Any.cast_json(object["80226972:embedded"]["3:base64"]))) - object["80226972:embedded"].delete("3:base64") + object = { + "80226972:embedded" => { + "2:string" => ucid, + "3:string" => object_inner_1_encoded, + "35:string" => "browse-feed#{ucid}videos102", + }, + } continuation = object.try { |i| Protodec::Any.cast_json(i) } .try { |i| Protodec::Any.from_json(i) } @@ -67,10 +62,11 @@ end def get_60_videos(ucid, author, page, auto_generated, sort_by = "newest") videos = [] of SearchVideo - 2.times do |i| - initial_data = get_channel_videos_response(ucid, page * 2 + (i - 1), auto_generated: auto_generated, sort_by: sort_by) - videos.concat extract_videos(initial_data, author, ucid) - end + # 2.times do |i| + # initial_data = get_channel_videos_response(ucid, page * 2 + (i - 1), auto_generated: auto_generated, sort_by: sort_by) + initial_data = get_channel_videos_response(ucid, 1, auto_generated: auto_generated, sort_by: sort_by) + videos = extract_videos(initial_data, author, ucid) + # end return videos.size, videos end