summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--README.md2
-rw-r--r--assets/css/player.css4
-rw-r--r--docker/Dockerfile.arm642
-rw-r--r--locales/ar.json10
-rw-r--r--locales/en-US.json2
-rw-r--r--locales/eo.json8
-rw-r--r--locales/es.json10
-rw-r--r--locales/ja.json16
-rw-r--r--locales/ko.json10
-rw-r--r--locales/lt.json8
-rw-r--r--locales/pt.json8
-rw-r--r--locales/tr.json8
-rw-r--r--locales/zh-CN.json8
-rw-r--r--locales/zh-TW.json8
-rw-r--r--src/invidious.cr195
-rw-r--r--src/invidious/helpers/extractors.cr14
-rw-r--r--src/invidious/routes/images.cr191
-rw-r--r--src/invidious/views/template.ecr4
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 }}
diff --git a/README.md b/README.md
index 85a2704a..8beb4380 100644
--- a/README.md
+++ b/README.md
@@ -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>&nbsp;/
- <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>