diff options
| -rw-r--r-- | .github/workflows/ci.yml | 3 | ||||
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | assets/css/player.css | 4 | ||||
| -rw-r--r-- | docker/Dockerfile.arm64 | 2 | ||||
| -rw-r--r-- | locales/ar.json | 10 | ||||
| -rw-r--r-- | locales/en-US.json | 2 | ||||
| -rw-r--r-- | locales/eo.json | 8 | ||||
| -rw-r--r-- | locales/es.json | 10 | ||||
| -rw-r--r-- | locales/ja.json | 16 | ||||
| -rw-r--r-- | locales/ko.json | 10 | ||||
| -rw-r--r-- | locales/lt.json | 8 | ||||
| -rw-r--r-- | locales/pt.json | 8 | ||||
| -rw-r--r-- | locales/tr.json | 8 | ||||
| -rw-r--r-- | locales/zh-CN.json | 8 | ||||
| -rw-r--r-- | locales/zh-TW.json | 8 | ||||
| -rw-r--r-- | src/invidious.cr | 195 | ||||
| -rw-r--r-- | src/invidious/helpers/extractors.cr | 14 | ||||
| -rw-r--r-- | src/invidious/routes/images.cr | 191 | ||||
| -rw-r--r-- | src/invidious/views/template.ecr | 4 |
19 files changed, 295 insertions, 216 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bb4c491..b99ecf18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,7 @@ jobs: crystal: - 1.0.0 - 1.1.1 + - 1.2.0 include: - crystal: nightly stable: false @@ -48,7 +49,7 @@ jobs: - uses: actions/checkout@v2 - name: Install Crystal - uses: oprypin/install-crystal@v1.2.4 + uses: crystal-lang/install-crystal@v1.5.3 with: crystal: ${{ matrix.crystal }} @@ -3,7 +3,7 @@ <h1>Invidious</h1> <a href="https://www.gnu.org/licenses/agpl-3.0.en.html"> - <img alt="License: AGPLv3+" src="https://shields.io/badge/License-AGPL%20v3+-blue.svg"> + <img alt="License: AGPLv3" src="https://shields.io/badge/License-AGPL%20v3-blue.svg"> </a> <a href="https://github.com/iv-org/invidious/actions"> <img alt="Build Status" src="https://github.com/iv-org/invidious/workflows/Invidious%20CI/badge.svg"> diff --git a/assets/css/player.css b/assets/css/player.css index 656fb48c..120fd2f8 100644 --- a/assets/css/player.css +++ b/assets/css/player.css @@ -218,6 +218,10 @@ video.video-js { #player-container { position: relative; + padding-left: 0; + padding-right: 0; + margin-left: 1em; + margin-right: 1em; padding-bottom: 82vh; height: 0; } diff --git a/docker/Dockerfile.arm64 b/docker/Dockerfile.arm64 index 063ba6d2..193ed09d 100644 --- a/docker/Dockerfile.arm64 +++ b/docker/Dockerfile.arm64 @@ -1,5 +1,5 @@ FROM alpine:edge AS builder -RUN apk add --no-cache 'crystal=1.1.1-r0' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev +RUN apk add --no-cache 'crystal=1.1.1-r1' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev ARG release diff --git a/locales/ar.json b/locales/ar.json index 4f7f1e2c..457c648b 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -382,7 +382,7 @@ "News": "الأخبار", "Movies": "الأفلام", "Download": "نزّل", - "Download as: ": "نزله كـ:. ", + "Download as: ": "نزله ك:. ", "%A %B %-d, %Y": "%A %-d %B %Y", "(edited)": "(تم تعديلة)", "YouTube comment permalink": "رابط التعليق على اليوتيوب", @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "تحديث", "next_steps_error_message_go_to_youtube": "انتقل إلى يوتيوب", "short": "قصير (< 4 دقائق)", - "long": "طويل (> 20 دقيقة)" + "long": "طويل (> 20 دقيقة)", + "footer_source_code": "شفرة المصدر", + "footer_original_source_code": "شفرة المصدر الأصلية", + "footer_modfied_source_code": "شفرة المصدر المعدلة", + "adminprefs_modified_source_code_url_label": "URL إلى مستودع التعليمات البرمجية المصدرية المعدلة", + "footer_documentation": "التوثيق", + "footer_donate": "تبرّع: " } diff --git a/locales/en-US.json b/locales/en-US.json index 1fa1983d..8d213c7a 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -426,7 +426,7 @@ "next_steps_error_message": "After which you should try to: ", "next_steps_error_message_refresh": "Refresh", "next_steps_error_message_go_to_youtube": "Go to YouTube", - "footer_donate": "Donate: ", + "footer_donate_page": "Donate", "footer_documentation": "Documentation", "footer_source_code": "Source code", "footer_original_source_code": "Original source code", diff --git a/locales/eo.json b/locales/eo.json index a00da6aa..5c1d3b52 100644 --- a/locales/eo.json +++ b/locales/eo.json @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "Reŝargi", "next_steps_error_message_go_to_youtube": "Iri al JuTubo", "long": "Longa (> 20 minutos)", - "short": "Mallonga (< 4 minutos)" + "short": "Mallonga (< 4 minutos)", + "footer_donate": "Doni: ", + "footer_documentation": "Dokumentaro", + "footer_source_code": "Fontkodo", + "adminprefs_modified_source_code_url_label": "URL al modifita deponejo de fontkodo", + "footer_modfied_source_code": "Modifita Fontkodo", + "footer_original_source_code": "Originala fontkodo" } diff --git a/locales/es.json b/locales/es.json index 3cbe9be4..7255a8bc 100644 --- a/locales/es.json +++ b/locales/es.json @@ -424,6 +424,12 @@ "next_steps_error_message": "Después de lo cual deberías intentar: ", "next_steps_error_message_refresh": "Recargar", "next_steps_error_message_go_to_youtube": "Ir a YouTube", - "short": "Corto (< minutos)", - "long": "Largo (> minutos)" + "short": "Corto (< 4 minutos)", + "long": "Largo (> 20 minutos)", + "footer_documentation": "Documentación", + "footer_original_source_code": "Código fuente original", + "adminprefs_modified_source_code_url_label": "URL al repositorio de código fuente modificado", + "footer_source_code": "Código fuente", + "footer_donate": "Donar: ", + "footer_modfied_source_code": "Código fuente modificado" } diff --git a/locales/ja.json b/locales/ja.json index c4f78f96..4c2e692d 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -78,7 +78,7 @@ "Show related videos: ": "関連動画を表示: ", "Show annotations by default: ": "デフォルトでアノテーションを表示: ", "Automatically extend video description: ": "動画の説明文を自動的に拡張: ", - "Interactive 360 degree videos: ": "インタラクティブ360°動画: ", + "Interactive 360 degree videos: ": "対話的な360°動画: ", "Visual preferences": "外観設定", "Player style: ": "プレイヤースタイル: ", "Dark mode: ": "ダークモード: ", @@ -137,7 +137,7 @@ }, "Import/export": "インポート/エクスポート", "unsubscribe": "登録解除", - "revoke": "revoke", + "revoke": "取り消す", "Subscriptions": "登録チャンネル", "`x` unseen notifications": { "([^.,0-9]|^)1([^.,0-9]|$)": "`x` 個の未読通知", @@ -145,7 +145,7 @@ }, "search": "検索", "Log out": "ログアウト", - "Released under the AGPLv3 on Github.": "Github 上で AGPLv3 の下で公開されています", + "Released under the AGPLv3 on Github.": "Github 上で AGPLv3 の元で公開されています", "Source available here.": "ソースはここで閲覧可能です。", "View JavaScript license information.": "JavaScript ライセンス情報", "View privacy policy.": "プライバシーポリシー", @@ -423,5 +423,13 @@ "Current version: ": "現在のバージョン: ", "next_steps_error_message": "下記のものを試して下さい: ", "next_steps_error_message_refresh": "再読込", - "next_steps_error_message_go_to_youtube": "YouTubeへ" + "next_steps_error_message_go_to_youtube": "YouTubeへ", + "short": "4 分未満", + "footer_donate": "寄金: ", + "footer_documentation": "文書", + "footer_source_code": "ソースコード", + "footer_original_source_code": "ソースコード(元)", + "footer_modfied_source_code": "ソースコード(編集)", + "adminprefs_modified_source_code_url_label": "編集したソースコードのレポジトリーURL", + "long": "20 分以上" } diff --git a/locales/ko.json b/locales/ko.json index 16d4797e..27fdc683 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -423,5 +423,13 @@ "today": "오늘", "hour": "지난 1시간", "sort": "정렬기준", - "features": "기능별" + "features": "기능별", + "short": "4분 미만", + "long": "20분 초과", + "footer_donate": "후원: ", + "footer_documentation": "문서", + "footer_source_code": "소스 코드", + "footer_original_source_code": "원본 소스 코드", + "footer_modfied_source_code": "수정된 소스 코드", + "adminprefs_modified_source_code_url_label": "수정된 소스 코드 저장소의 URL" } diff --git a/locales/lt.json b/locales/lt.json index 4b2fa5aa..c1842e54 100644 --- a/locales/lt.json +++ b/locales/lt.json @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "Atnaujinti", "next_steps_error_message_go_to_youtube": "Eiti į YouTube", "short": "Trumpas (< 4 minučių)", - "long": "Ilgas (> 20 minučių)" + "long": "Ilgas (> 20 minučių)", + "footer_documentation": "Dokumentacija", + "footer_source_code": "Pirminis kodas", + "footer_donate": "Paaukoti: ", + "footer_original_source_code": "Pradinis pirminis kodas", + "adminprefs_modified_source_code_url_label": "URL į pakeisto pirminio kodo repozitoriją", + "footer_modfied_source_code": "Pakeistas pirminis kodas" } diff --git a/locales/pt.json b/locales/pt.json index 66de7d10..918ab4c0 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -425,5 +425,11 @@ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` subscritores" }, "short": "Curto (< 4 minutos)", - "long": "Longo (> 20 minutos)" + "long": "Longo (> 20 minutos)", + "footer_source_code": "Código-fonte", + "footer_original_source_code": "Código-fonte original", + "adminprefs_modified_source_code_url_label": "URL do repositório do código-fonte alterado", + "footer_donate": "Fazer um donativo: ", + "footer_documentation": "Documentação", + "footer_modfied_source_code": "Código-fonte alterado" } diff --git a/locales/tr.json b/locales/tr.json index 8432e8a9..26c6abdd 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "Yenile", "next_steps_error_message_go_to_youtube": "YouTube'a git", "short": "Kısa (4 dakikadan az)", - "long": "Uzun (20 dakikadan fazla)" + "long": "Uzun (20 dakikadan fazla)", + "footer_donate": "Bağış yap: ", + "footer_documentation": "Belgelendirme", + "footer_source_code": "Kaynak kodları", + "footer_original_source_code": "Orijinal kaynak kodları", + "footer_modfied_source_code": "Değiştirilmiş kaynak kodları", + "adminprefs_modified_source_code_url_label": "Değiştirilmiş kaynak kodları deposunun URL'si" } diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 1033e77e..918b7c68 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "刷新", "next_steps_error_message_go_to_youtube": "转到 YouTube", "short": "短(少于4分钟)", - "long": "长(多于 20 分钟)" + "long": "长(多于 20 分钟)", + "footer_donate": "捐赠: ", + "footer_documentation": "文档", + "footer_source_code": "源代码", + "footer_modfied_source_code": "修改的源代码", + "adminprefs_modified_source_code_url_label": "更改的源代码仓库网址", + "footer_original_source_code": "原始源代码" } diff --git a/locales/zh-TW.json b/locales/zh-TW.json index 403221c4..51de7090 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -425,5 +425,11 @@ "next_steps_error_message_refresh": "重新整理", "next_steps_error_message_go_to_youtube": "到 YouTube", "short": "短(小於4分鐘)", - "long": "長(多於20分鐘)" + "long": "長(多於20分鐘)", + "footer_donate": "抖內: ", + "footer_documentation": "文件", + "footer_source_code": "原始碼", + "footer_original_source_code": "原本的原始碼", + "footer_modfied_source_code": "修改後的原始碼", + "adminprefs_modified_source_code_url_label": "修改後的原始碼倉庫 URL" } diff --git a/src/invidious.cr b/src/invidious.cr index 73abe6b0..18ec0b97 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -389,6 +389,13 @@ end Invidious::Routing.post "/feed/webhook/:token", Invidious::Routes::Feeds, :push_notifications_post {% end %} +Invidious::Routing.get "/ggpht/*", Invidious::Routes::Images, :ggpht +Invidious::Routing.options "/sb/:authority/:id/:storyboard/:index", Invidious::Routes::Images, :options_storyboard +Invidious::Routing.get "/sb/:authority/:id/:storyboard/:index", Invidious::Routes::Images, :get_storyboard +Invidious::Routing.get "/s_p/:id/:name", Invidious::Routes::Images, :s_p_image +Invidious::Routing.get "/yts/img/:name", Invidious::Routes::Images, :yts_image +Invidious::Routing.get "/vi/:id/:name", Invidious::Routes::Images, :thumbnails + # API routes (macro) define_v1_api_routes() @@ -1273,194 +1280,6 @@ post "/api/v1/auth/notifications" do |env| create_notification_stream(env, topics, connection_channel) end -get "/ggpht/*" do |env| - url = env.request.path.lchop("/ggpht") - - headers = HTTP::Headers{":authority" => "yt3.ggpht.com"} - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end - - begin - YT_POOL.client &.get(url, headers) do |response| - env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - - env.response.headers["Access-Control-Allow-Origin"] = "*" - - if response.status_code >= 300 - env.response.headers.delete("Transfer-Encoding") - break - end - - proxy_file(response, env) - end - rescue ex - end -end - -options "/sb/:authority/:id/:storyboard/:index" do |env| - env.response.headers["Access-Control-Allow-Origin"] = "*" - env.response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" - env.response.headers["Access-Control-Allow-Headers"] = "Content-Type, Range" -end - -get "/sb/:authority/:id/:storyboard/:index" do |env| - authority = env.params.url["authority"] - id = env.params.url["id"] - storyboard = env.params.url["storyboard"] - index = env.params.url["index"] - - url = "/sb/#{id}/#{storyboard}/#{index}?#{env.params.query}" - - headers = HTTP::Headers.new - - headers[":authority"] = "#{authority}.ytimg.com" - - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end - - begin - YT_POOL.client &.get(url, headers) do |response| - env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - - env.response.headers["Connection"] = "close" - env.response.headers["Access-Control-Allow-Origin"] = "*" - - if response.status_code >= 300 - env.response.headers.delete("Transfer-Encoding") - break - end - - proxy_file(response, env) - end - rescue ex - end -end - -get "/s_p/:id/:name" do |env| - id = env.params.url["id"] - name = env.params.url["name"] - - url = env.request.resource - - headers = HTTP::Headers{":authority" => "i9.ytimg.com"} - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end - - begin - YT_POOL.client &.get(url, headers) do |response| - env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - - env.response.headers["Access-Control-Allow-Origin"] = "*" - - if response.status_code >= 300 && response.status_code != 404 - env.response.headers.delete("Transfer-Encoding") - break - end - - proxy_file(response, env) - end - rescue ex - end -end - -get "/yts/img/:name" do |env| - headers = HTTP::Headers.new - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end - - begin - YT_POOL.client &.get(env.request.resource, headers) do |response| - env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - - env.response.headers["Access-Control-Allow-Origin"] = "*" - - if response.status_code >= 300 && response.status_code != 404 - env.response.headers.delete("Transfer-Encoding") - break - end - - proxy_file(response, env) - end - rescue ex - end -end - -get "/vi/:id/:name" do |env| - id = env.params.url["id"] - name = env.params.url["name"] - - headers = HTTP::Headers{":authority" => "i.ytimg.com"} - - if name == "maxres.jpg" - build_thumbnails(id).each do |thumb| - if YT_POOL.client &.head("/vi/#{id}/#{thumb[:url]}.jpg", headers).status_code == 200 - name = thumb[:url] + ".jpg" - break - end - end - end - url = "/vi/#{id}/#{name}" - - REQUEST_HEADERS_WHITELIST.each do |header| - if env.request.headers[header]? - headers[header] = env.request.headers[header] - end - end - - begin - YT_POOL.client &.get(url, headers) do |response| - env.response.status_code = response.status_code - response.headers.each do |key, value| - if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) - env.response.headers[key] = value - end - end - - env.response.headers["Access-Control-Allow-Origin"] = "*" - - if response.status_code >= 300 && response.status_code != 404 - env.response.headers.delete("Transfer-Encoding") - break - end - - proxy_file(response, env) - end - rescue ex - end -end - get "/Captcha" do |env| headers = HTTP::Headers{":authority" => "accounts.google.com"} response = YT_POOL.client &.get(env.request.resource, headers) diff --git a/src/invidious/helpers/extractors.cr b/src/invidious/helpers/extractors.cr index 1ebbe889..0277d43b 100644 --- a/src/invidious/helpers/extractors.cr +++ b/src/invidious/helpers/extractors.cr @@ -321,11 +321,13 @@ private module Parsers content_container = item_contents["contents"] end - raw_contents = content_container["items"].as_a - raw_contents.each do |item| - result = extract_item(item) - if !result.nil? - contents << result + raw_contents = content_container["items"]?.try &.as_a + if !raw_contents.nil? + raw_contents.each do |item| + result = extract_item(item) + if !result.nil? + contents << result + end end end @@ -399,7 +401,7 @@ private module Extractors items_container = renderer_container_contents end - items_container["items"].as_a.each do |item| + items_container["items"]?.try &.as_a.each do |item| raw_items << item end end diff --git a/src/invidious/routes/images.cr b/src/invidious/routes/images.cr new file mode 100644 index 00000000..bb924cdf --- /dev/null +++ b/src/invidious/routes/images.cr @@ -0,0 +1,191 @@ +module Invidious::Routes::Images + # Avatars, banners and other large image assets. + def self.ggpht(env) + url = env.request.path.lchop("/ggpht") + + headers = HTTP::Headers{":authority" => "yt3.ggpht.com"} + REQUEST_HEADERS_WHITELIST.each do |header| + if env.request.headers[header]? + headers[header] = env.request.headers[header] + end + end + + begin + YT_POOL.client &.get(url, headers) do |response| + env.response.status_code = response.status_code + response.headers.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + env.response.headers[key] = value + end + end + + env.response.headers["Access-Control-Allow-Origin"] = "*" + + if response.status_code >= 300 + env.response.headers.delete("Transfer-Encoding") + break + end + + proxy_file(response, env) + end + rescue ex + end + end + + def self.options_storyboard(env) + env.response.headers["Access-Control-Allow-Origin"] = "*" + env.response.headers["Access-Control-Allow-Methods"] = "GET, OPTIONS" + env.response.headers["Access-Control-Allow-Headers"] = "Content-Type, Range" + end + + def self.get_storyboard(env) + authority = env.params.url["authority"] + id = env.params.url["id"] + storyboard = env.params.url["storyboard"] + index = env.params.url["index"] + + url = "/sb/#{id}/#{storyboard}/#{index}?#{env.params.query}" + + headers = HTTP::Headers.new + + headers[":authority"] = "#{authority}.ytimg.com" + + REQUEST_HEADERS_WHITELIST.each do |header| + if env.request.headers[header]? + headers[header] = env.request.headers[header] + end + end + + begin + YT_POOL.client &.get(url, headers) do |response| + env.response.status_code = response.status_code + response.headers.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + env.response.headers[key] = value + end + end + + env.response.headers["Connection"] = "close" + env.response.headers["Access-Control-Allow-Origin"] = "*" + + if response.status_code >= 300 + env.response.headers.delete("Transfer-Encoding") + break + end + + proxy_file(response, env) + end + rescue ex + end + end + + # ??? maybe also for storyboards? + def self.s_p_image(env) + id = env.params.url["id"] + name = env.params.url["name"] + + url = env.request.resource + + headers = HTTP::Headers{":authority" => "i9.ytimg.com"} + REQUEST_HEADERS_WHITELIST.each do |header| + if env.request.headers[header]? + headers[header] = env.request.headers[header] + end + end + + begin + YT_POOL.client &.get(url, headers) do |response| + env.response.status_code = response.status_code + response.headers.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + env.response.headers[key] = value + end + end + + env.response.headers["Access-Control-Allow-Origin"] = "*" + + if response.status_code >= 300 && response.status_code != 404 + env.response.headers.delete("Transfer-Encoding") + break + end + + proxy_file(response, env) + end + rescue ex + end + end + + def self.yts_image(env) + headers = HTTP::Headers.new + REQUEST_HEADERS_WHITELIST.each do |header| + if env.request.headers[header]? + headers[header] = env.request.headers[header] + end + end + + begin + YT_POOL.client &.get(env.request.resource, headers) do |response| + env.response.status_code = response.status_code + response.headers.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + env.response.headers[key] = value + end + end + + env.response.headers["Access-Control-Allow-Origin"] = "*" + + if response.status_code >= 300 && response.status_code != 404 + env.response.headers.delete("Transfer-Encoding") + break + end + + proxy_file(response, env) + end + rescue ex + end + end + + def self.thumbnails(env) + id = env.params.url["id"] + name = env.params.url["name"] + + headers = HTTP::Headers{":authority" => "i.ytimg.com"} + + if name == "maxres.jpg" + build_thumbnails(id).each do |thumb| + if YT_POOL.client &.head("/vi/#{id}/#{thumb[:url]}.jpg", headers).status_code == 200 + name = thumb[:url] + ".jpg" + break + end + end + end + url = "/vi/#{id}/#{name}" + + REQUEST_HEADERS_WHITELIST.each do |header| + if env.request.headers[header]? + headers[header] = env.request.headers[header] + end + end + + begin + YT_POOL.client &.get(url, headers) do |response| + env.response.status_code = response.status_code + response.headers.each do |key, value| + if !RESPONSE_HEADERS_BLACKLIST.includes?(key.downcase) + env.response.headers[key] = value + end + end + + env.response.headers["Access-Control-Allow-Origin"] = "*" + + if response.status_code >= 300 && response.status_code != 404 + env.response.headers.delete("Transfer-Encoding") + break + end + + proxy_file(response, env) + end + rescue ex + end + end +end diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr index b7020598..3fb2fe18 100644 --- a/src/invidious/views/template.ecr +++ b/src/invidious/views/template.ecr @@ -149,9 +149,7 @@ <div class="pure-u-1 pure-u-md-1-3"> <span> <i class="icon ion-ios-wallet"></i> - <%= translate(locale, "footer_donate") %> - <a href="bitcoin:bc1qfhe7rq3lqzuayzjxzyt9waz9ytrs09kla3tsgr">BTC</a> / - <a href="monero:41nMCtek197boJtiUvGnTFYMatrLEpnpkQDmUECqx5Es2uX3sTKKWVhSL76suXsG3LXqkEJBrCZBgPTwJrDp1FrZJfycGPR">XMR</a> + <a href="https://invidious.io/donate/"><%= translate(locale, "footer_donate_page") %></a> </span> <span><%= translate(locale, "Current version: ") %> <%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %> @ <%= CURRENT_BRANCH %></span> </div> |
