summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md35
-rw-r--r--.github/ISSUE_TEMPLATE/enhancement.md24
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md24
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--README.md6
-rw-r--r--docker/Dockerfile2
-rw-r--r--locales/fi.json8
-rw-r--r--locales/he.json414
-rw-r--r--locales/id.json116
-rw-r--r--shard.lock4
-rw-r--r--shard.yml6
-rw-r--r--src/invidious.cr48
-rw-r--r--src/invidious/comments.cr10
-rw-r--r--src/invidious/helpers/helpers.cr4
-rw-r--r--src/invidious/helpers/proxy.cr6
-rw-r--r--src/invidious/helpers/utils.cr2
-rw-r--r--src/invidious/jobs/bypass_captcha_job.cr2
-rw-r--r--src/invidious/routes/embed.cr (renamed from src/invidious/routes/embed/show.cr)32
-rw-r--r--src/invidious/routes/embed/index.cr25
-rw-r--r--src/invidious/routes/licenses.cr6
-rw-r--r--src/invidious/routes/login.cr2
-rw-r--r--src/invidious/routes/misc.cr (renamed from src/invidious/routes/home.cr)14
-rw-r--r--src/invidious/routes/preferences.cr (renamed from src/invidious/routes/user_preferences.cr)2
-rw-r--r--src/invidious/routes/privacy.cr6
-rw-r--r--src/invidious/routes/watch.cr4
-rw-r--r--src/invidious/views/channel.ecr4
-rw-r--r--src/invidious/views/community.ecr4
-rw-r--r--src/invidious/views/components/item.ecr6
-rw-r--r--src/invidious/views/components/player.ecr2
-rw-r--r--src/invidious/views/playlists.ecr4
-rw-r--r--src/invidious/views/watch.ecr3
31 files changed, 661 insertions, 166 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..c0485266
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,35 @@
+---
+name: Bug report
+about: Create a bug report to help us improve Invidious
+title: '[Bug] '
+labels: bug
+assignees: ''
+
+---
+
+<!-- Please use the search function to check if the bug you found has already been reported by someone else -->
+<!-- If you want to suggest a new feature please use "Feature request" instead -->
+<!-- If you want to suggest an enhancement to an existing feature please use "Enhancement" instead -->
+
+**Describe the bug**
+<!-- A clear and concise description of what the bug is. -->
+
+**Steps to Reproduce**
+<!-- Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+-->
+
+**Logs**
+<!-- If applicable, copy the log that appear in the browser page where the error is reported. -->
+
+**Screenshots**
+<!-- If applicable, add screenshots to help explain your problem. -->
+
+**Additional context**
+<!-- Add any other context about the problem here.
+ - Browser (if applicable):
+ - OS (if applicable):
+-->
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
new file mode 100644
index 00000000..7823e1df
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -0,0 +1,24 @@
+---
+name: Enhancement
+about: Suggest an enhancement for an existing feature
+title: '[Enhancement] '
+labels: enhancement
+assignees: ''
+
+---
+
+<!-- Please use the search function to check if the desired function has already been requested by someone else -->
+ <!-- If you want to suggest a new feature please use "Feature request" instead -->
+<!-- If you want to report a bug, please use "Bug report" instead -->
+
+**Is your enhancement request related to a problem? Please describe.**
+<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
+
+**Describe the solution you'd like**
+<!-- A clear and concise description of what you want to happen. -->
+
+**Describe alternatives you've considered**
+<!-- A clear and concise description of any alternative solutions or features you've considered. -->
+
+**Additional context**
+<!-- Add any other context or screenshots about the enhancement here. -->
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..59692a51
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,24 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: '[Feature request] '
+labels: feature-request
+assignees: ''
+
+---
+
+<!-- Please use the search function to check if the desired function has already been requested by someone else -->
+<!-- If you want to suggest an enhancement to an existing feature please use "Enhancement" instead -->
+<!-- If you want to report a bug, please use "Bug report" instead -->
+
+**Is your feature request related to a problem? Please describe.**
+<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
+
+**Describe the solution you'd like**
+<!-- A clear and concise description of what you want to happen. -->
+
+**Describe alternatives you've considered**
+<!-- A clear and concise description of any alternative solutions or features you've considered. -->
+
+**Additional context**
+<!-- Add any other context or screenshots about the feature request here. -->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fc0e8096..66aacff9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,7 +19,7 @@ jobs:
- name: Install Crystal
uses: oprypin/install-crystal@v1.2.4
with:
- crystal: 0.35.1
+ crystal: 0.36.1
- name: Cache Shards
uses: actions/cache@v2
diff --git a/README.md b/README.md
index e06fa7dc..a3ddfe3b 100644
--- a/README.md
+++ b/README.md
@@ -91,10 +91,8 @@ $ sudo pacman -S base-devel shards crystal librsvg postgresql
# Ubuntu or Debian
# First you have to add the repository to your APT configuration. For easy setup just run in your command line:
-$ curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash
-# That will add the signing key and the repository configuration. If you prefer to do it manually, execute the following commands:
-$ curl -sL "https://keybase.io/crystal/pgp_keys.asc" | sudo apt-key add -
-$ echo "deb https://dist.crystal-lang.org/apt crystal main" | sudo tee /etc/apt/sources.list.d/crystal.list
+$ curl -fsSL https://crystal-lang.org/install.sh | sudo bash
+# That will add the signing key and the repository configuration. If you prefer to do it manually, Follow the instructions here https://crystal-lang.org/install
$ sudo apt-get update
$ sudo apt install crystal libssl-dev libxml2-dev libyaml-dev libgmp-dev libreadline-dev postgresql librsvg2-bin libsqlite3-dev zlib1g-dev
```
diff --git a/docker/Dockerfile b/docker/Dockerfile
index ce4cc765..b88a76c0 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM crystallang/crystal:0.35.1-alpine AS builder
+FROM crystallang/crystal:0.36.1-alpine AS builder
RUN apk add --no-cache curl sqlite-static
WORKDIR /invidious
COPY ./shard.yml ./shard.yml
diff --git a/locales/fi.json b/locales/fi.json
index 0b2db9a1..5dfd4ea2 100644
--- a/locales/fi.json
+++ b/locales/fi.json
@@ -1,10 +1,10 @@
{
"`x` subscribers.([^.,0-9]|^)1([^.,0-9]|$)": "`x` tilaaja",
- "`x` subscribers.": "`x` tilaajaa",
+ "`x` subscribers.": "`x` tilaajaa.",
"`x` videos.([^.,0-9]|^)1([^.,0-9]|$)": "`x` video",
- "`x` videos.": "`x` videota",
+ "`x` videos.": "`x` videota.",
"`x` playlists.([^.,0-9]|^)1([^.,0-9]|$)": "`x` soittolista.([^.,0-9]|^)1([^.,0-9]|$)",
- "`x` playlists.": "`x` soittolistaa",
+ "`x` playlists.": "`x` soittolistaa.",
"LIVE": "SUORA",
"Shared `x` ago": "Jaettu `x` sitten",
"Unsubscribe": "Peruuta tilaus",
@@ -41,7 +41,7 @@
"An alternative front-end to YouTube": "Vaihtoehtoinen käyttöliittymä YouTubelle",
"JavaScript license information": "JavaScript-käyttöoikeustiedot",
"source": "lähde",
- "Log in": "Kirjaudu sisään",
+ "Log in": "Kirjaudu",
"Log in/register": "Kirjaudu sisään / Rekisteröidy",
"Log in with Google": "Kirjaudu sisään Googlella",
"User ID": "Käyttäjätunnus",
diff --git a/locales/he.json b/locales/he.json
new file mode 100644
index 00000000..f5e33877
--- /dev/null
+++ b/locales/he.json
@@ -0,0 +1,414 @@
+{
+ "`x` subscribers": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` רשומים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` רשומים."
+ },
+ "`x` videos": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` סרטונים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` סרטונים."
+ },
+ "`x` playlists": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` פלייליסטים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` פלייליסטים."
+ },
+ "LIVE": "שידור חי",
+ "Shared `x` ago": "",
+ "Unsubscribe": "ביטול מינוי",
+ "Subscribe": "הרשמה למינוי",
+ "View channel on YouTube": "צפייה בערוץ ב־YouTube",
+ "View playlist on YouTube": "צפייה בפלייליסט ב־YouTube",
+ "newest": "החדש ביותר",
+ "oldest": "הישן ביותר",
+ "popular": "פופולארי",
+ "last": "אחרון",
+ "Next page": "העמוד הבא",
+ "Previous page": "העמוד הקודם",
+ "Clear watch history?": "לנקות את היסטוריית הצפייה?",
+ "New password": "סיסמה חדשה",
+ "New passwords must match": "על הסיסמאות החדשות להתאים",
+ "Cannot change password for Google accounts": "לא ניתן לשנות את הסיסמה לחשבונות Google",
+ "Authorize token?": "",
+ "Authorize token for `x`?": "",
+ "Yes": "כן",
+ "No": "לא",
+ "Import and Export Data": "ייבוא וייצוא נתונים",
+ "Import": "ייבוא",
+ "Import Invidious data": "ייבוא נתוני Invidious",
+ "Import YouTube subscriptions": "ייבוא מינויים מ־YouTube",
+ "Import FreeTube subscriptions (.db)": "ייבוא מינויים מ־FreeTube‏ (.db)",
+ "Import NewPipe subscriptions (.json)": "ייבוא מינויים מ־NewPipe‏ (.json)",
+ "Import NewPipe data (.zip)": "ייבוא נתוני NewPipe‏ (.zip)",
+ "Export": "ייצוא",
+ "Export subscriptions as OPML": "ייצוא המינויים בתור OPML",
+ "Export subscriptions as OPML (for NewPipe & FreeTube)": "ייצוא המינויים בתור OPML (עבור NewPipe ו־FreeTube)",
+ "Export data as JSON": "ייצוא הנתונים בתור קובץ JSON",
+ "Delete account?": "למחוק את החשבון?",
+ "History": "היסטוריה",
+ "An alternative front-end to YouTube": "ממשק משתמש חלופי ל־YouTube",
+ "JavaScript license information": "",
+ "source": "source",
+ "Log in": "כניסה",
+ "Log in/register": "כניסה/הרשמה",
+ "Log in with Google": "כניסה עם Google",
+ "User ID": "שם משתמש",
+ "Password": "סיסמה",
+ "Time (h:mm:ss):": "זמן (h:mm:ss):",
+ "Text CAPTCHA": "Text CAPTCHA",
+ "Image CAPTCHA": "Image CAPTCHA",
+ "Sign In": "התחברות",
+ "Register": "הרשמה",
+ "E-mail": "דוא״ל",
+ "Google verification code": "קוד האימות של Google",
+ "Preferences": "העדפות",
+ "Player preferences": "העדפות הנגן",
+ "Always loop: ": "",
+ "Autoplay: ": "ניגון אוטומטי: ",
+ "Play next by default: ": "",
+ "Autoplay next video: ": "נגן אוטומטית את הסרטון הבא ",
+ "Listen by default: ": "האזן כברירת מחדל: ",
+ "Proxy videos: ": "",
+ "Default speed: ": "מהירות ברירת המחדל: ",
+ "Preferred video quality: ": "איכות הווידאו המועדפת: ",
+ "Player volume: ": "עוצמת שמע בנגן: ",
+ "Default comments: ": "תגובות ברירת מחדל ",
+ "youtube": "יוטיוב",
+ "reddit": "reddit",
+ "Default captions: ": "כתוביות ברירת מחדל ",
+ "Fallback captions: ": "כתוביות גיבוי ",
+ "Show related videos: ": "הראה סרטונים קשורים: ",
+ "Show annotations by default: ": "הראה הסברים כברירת מחדל: ",
+ "Visual preferences": "העדפות חזותיות",
+ "Player style: ": "סגנון הנגן: ",
+ "Dark mode: ": "מצב כהה: ",
+ "Theme: ": "ערכת נושא: ",
+ "dark": "כהה",
+ "light": "בהיר",
+ "Thin mode: ": "",
+ "Subscription preferences": "העדפות מינויים",
+ "Show annotations by default for subscribed channels: ": "Show annotations by default for subscribed channels? ",
+ "Redirect homepage to feed: ": "",
+ "Number of videos shown in feed: ": "מספר הסרטונים שמוצגים בהזנה: ",
+ "Sort videos by: ": "מיון הסרטונים לפי: ",
+ "published": "פורסם",
+ "published - reverse": "",
+ "alphabetically": "בסדר אלפביתי",
+ "alphabetically - reverse": "בסדר אלפביתי - הפוך",
+ "channel name": "שם הערוץ",
+ "channel name - reverse": "שם הערוץ - הפוך",
+ "Only show latest video from channel: ": "הראה רק את הסרטון האחרון מהערוץ: ",
+ "Only show latest unwatched video from channel: ": "הראה רק את הסרטון האחרון שלא נצפה מהערוץ: ",
+ "Only show unwatched: ": "הראה רק סרטונים שלא נצפו ",
+ "Only show notifications (if there are any): ": "הראה רק התראות (אם יש) ",
+ "Enable web notifications": "",
+ "`x` uploaded a video": "סרטון הועלה על ידי `x`",
+ "`x` is live": "`x` בשידור חי",
+ "Data preferences": "העדפות נתונים",
+ "Clear watch history": "ניקוי היסטוריית הצפייה",
+ "Import/export data": "ייבוא/ייצוא נתונים",
+ "Change password": "שינוי הסיסמה",
+ "Manage subscriptions": "ניהול מינויים",
+ "Manage tokens": "",
+ "Watch history": "היסטוריית צפייה",
+ "Delete account": "מחיקת החשבון",
+ "Administrator preferences": "",
+ "Default homepage: ": "Default homepage: ",
+ "Feed menu: ": "תפריט ההזנה: ",
+ "Top enabled: ": "",
+ "CAPTCHA enabled: ": "",
+ "Login enabled: ": "",
+ "Registration enabled: ": "",
+ "Report statistics: ": "",
+ "Save preferences": "שמירת ההעדפות",
+ "Subscription manager": "מנהל המינויים",
+ "Token manager": "Token manager",
+ "Token": "Token",
+ "`x` subscriptions": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` מינויים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` מינויים."
+ },
+ "`x` tokens": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "",
+ "": ""
+ },
+ "Import/export": "ייבוא/ייצוא",
+ "unsubscribe": "ביטול מנוי",
+ "revoke": "",
+ "Subscriptions": "מינויים",
+ "`x` unseen notifications": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` הודעות שלא נראו.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` הודעות שלא נראו."
+ },
+ "search": "חיפוש",
+ "Log out": "יציאה",
+ "Released under the AGPLv3 by Omar Roth.": "מופץ תחת רישיון AGPLv3 על ידי עמר רות׳ (Omar Roth).",
+ "Source available here.": "קוד המקור זמין כאן.",
+ "View JavaScript license information.": "",
+ "View privacy policy.": "להצגת מדיניות הפרטיות.",
+ "Trending": "הסרטונים החמים",
+ "Public": "ציבורי",
+ "Unlisted": "לא רשום",
+ "Private": "פרטי",
+ "View all playlists": "הצגת כל הפלייליסטים",
+ "Updated `x` ago": "הועלה לפני `x`",
+ "Delete playlist `x`?": "למחוק את פלייליסט `x`?",
+ "Delete playlist": "מחיקת פלייליסט",
+ "Create playlist": "יצירת פלייליסט",
+ "Title": "",
+ "Playlist privacy": "Playlist privacy",
+ "Editing playlist `x`": "",
+ "Watch on YouTube": "צפייה ב־YouTube",
+ "Hide annotations": "",
+ "Show annotations": "",
+ "Genre: ": "Genre: ",
+ "License: ": "רישיון: ",
+ "Family friendly? ": "לכל המשפחה? ",
+ "Wilson score: ": "",
+ "Engagement: ": "",
+ "Whitelisted regions: ": "",
+ "Blacklisted regions: ": "",
+ "Shared `x`": "",
+ "`x` views": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` צפיות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` צפיות."
+ },
+ "Premieres in `x`": "",
+ "Premieres `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.": "שלום! נראה ש־JavaScript כבוי. יש ללחוץ כאן להצגת התגובות, נא לקחת בחשבון שהטעינה תיקח קצת יותר זמן.",
+ "View YouTube comments": "",
+ "View more comments on Reddit": "",
+ "View `x` comments": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "הצגת `x` תגובות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "הצגת `x` תגובות."
+ },
+ "View Reddit comments": "",
+ "Hide replies": "הסתרת תגובות",
+ "Show replies": "הצגת תגובות",
+ "Incorrect password": "סיסמה שגויה",
+ "Quota exceeded, try again in a few hours": "",
+ "Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "",
+ "Invalid TFA code": "",
+ "Login failed. This may be because two-factor authentication is not turned on for your account.": "",
+ "Wrong answer": "תשובה שגויה",
+ "Erroneous CAPTCHA": "",
+ "CAPTCHA is a required field": "",
+ "User ID is a required field": "חובה למלא את שדה שם המשתמש",
+ "Password is a required field": "חובה למלא את שדה הסיסמה",
+ "Wrong username or password": "שם משתמש שגוי או סיסמה שגויה",
+ "Please sign in using 'Log in with Google'": "",
+ "Password cannot be empty": "",
+ "Password cannot be longer than 55 characters": "",
+ "Please log in": "נא להתחבר",
+ "Invidious Private Feed for `x`": "",
+ "channel:`x`": "ערוץ:`x`",
+ "Deleted or invalid channel": "",
+ "This channel does not exist.": "הערוץ הזה אינו קיים.",
+ "Could not get channel info.": "לא היה ניתן לקבל מידע על הערוץ.",
+ "Could not fetch comments": "לא היה ניתן למשוך את התגובות",
+ "View `x` replies": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "הצגת `x` תגובות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "הצגת `x` תגובות."
+ },
+ "`x` ago": "לפני `x`",
+ "Load more": "לטעון עוד",
+ "`x` points": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "",
+ "": ""
+ },
+ "Could not create mix.": "",
+ "Empty playlist": "פלייליסט ריק",
+ "Not a playlist.": "לא פלייליסט.",
+ "Playlist does not exist.": "הפלייליסט אינו קיים.",
+ "Could not pull trending pages.": "",
+ "Hidden field \"challenge\" is a required field": "",
+ "Hidden field \"token\" is a required field": "",
+ "Erroneous challenge": "",
+ "Erroneous token": "",
+ "No such user": "אין משתמש כזה",
+ "Token is expired, please try again": "",
+ "English": "אנגלית",
+ "English (auto-generated)": "אנגלית (נוצר באופן אוטומטי)",
+ "Afrikaans": "Afrikaans",
+ "Albanian": "אלבנית",
+ "Amharic": "אמהרית",
+ "Arabic": "ערבית",
+ "Armenian": "ארמנית",
+ "Azerbaijani": "Azerbaijani",
+ "Bangla": "בנגלית",
+ "Basque": "בסקית",
+ "Belarusian": "Belarusian",
+ "Bosnian": "Bosnian",
+ "Bulgarian": "בולגרית",
+ "Burmese": "Burmese",
+ "Catalan": "Catalan",
+ "Cebuano": "סבואנו",
+ "Chinese (Simplified)": "סינית (מפושטת)",
+ "Chinese (Traditional)": "סינית (מסורתית)",
+ "Corsican": "קורסיקאית",
+ "Croatian": "קרואטית",
+ "Czech": "צ׳כית",
+ "Danish": "Danish",
+ "Dutch": "Dutch",
+ "Esperanto": "אספרנטו",
+ "Estonian": "אסטונית",
+ "Filipino": "Filipino",
+ "Finnish": "Finnish",
+ "French": "צרפתית",
+ "Galician": "גליסית",
+ "Georgian": "גאורגית",
+ "German": "גרמנית",
+ "Greek": "יוונית",
+ "Gujarati": "גוג׳ראטית",
+ "Haitian Creole": "קריאולית האיטית",
+ "Hausa": "האוסה",
+ "Hawaiian": "הוואית",
+ "Hebrew": "עברית",
+ "Hindi": "הינדית",
+ "Hmong": "",
+ "Hungarian": "הונגרית",
+ "Icelandic": "איסלנדית",
+ "Igbo": "",
+ "Indonesian": "אינדונזית",
+ "Irish": "Irish",
+ "Italian": "איטלקית",
+ "Japanese": "יפנית",
+ "Javanese": "ג'אווה",
+ "Kannada": "קאנדה",
+ "Kazakh": "קזחית",
+ "Khmer": "חמרית",
+ "Korean": "קוריאנית",
+ "Kurdish": "כורדית",
+ "Kyrgyz": "קירגיזית",
+ "Lao": "לאית",
+ "Latin": "לטינית",
+ "Latvian": "לטבית",
+ "Lithuanian": "ליטאית",
+ "Luxembourgish": "לוקסמבורגית",
+ "Macedonian": "מקדונית",
+ "Malagasy": "מלגשית",
+ "Malay": "מלאית",
+ "Malayalam": "",
+ "Maltese": "מלטזית",
+ "Maori": "מאורית",
+ "Marathi": "מראטהית",
+ "Mongolian": "מונגולית",
+ "Nepali": "נפאלית",
+ "Norwegian Bokmål": "Norwegian Bokmål",
+ "Nyanja": "",
+ "Pashto": "פשטו",
+ "Persian": "פרסית",
+ "Polish": "פולנית",
+ "Portuguese": "פורטוגלית",
+ "Punjabi": "פנג'אבי",
+ "Romanian": "רומנית",
+ "Russian": "רוסית",
+ "Samoan": "",
+ "Scottish Gaelic": "גאלית סקוטית",
+ "Serbian": "Serbian",
+ "Shona": "",
+ "Sindhi": "סינדהי",
+ "Sinhala": "סינהלית",
+ "Slovak": "Slovak",
+ "Slovenian": "Slovenian",
+ "Somali": "סומלית",
+ "Southern Sotho": "",
+ "Spanish": "ספרדית",
+ "Spanish (Latin America)": "ספרדית (אמריקה הלטינית)",
+ "Sundanese": "",
+ "Swahili": "סווהילי",
+ "Swedish": "שוודית",
+ "Tajik": "טג׳יקית",
+ "Tamil": "טמילית",
+ "Telugu": "טלוגו",
+ "Thai": "תאית",
+ "Turkish": "טורקית",
+ "Ukrainian": "אוקראינית",
+ "Urdu": "אורדו",
+ "Uzbek": "אוזבקית",
+ "Vietnamese": "וייטנאמית",
+ "Welsh": "ולשית",
+ "Western Frisian": "",
+ "Xhosa": "קוסה",
+ "Yiddish": "יידיש",
+ "Yoruba": "",
+ "Zulu": "זולו",
+ "`x` years": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` שנים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` שנים."
+ },
+ "`x` months": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` חודשים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` חודשים."
+ },
+ "`x` weeks": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` שבועות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` שבועות."
+ },
+ "`x` days": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` ימים.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` ימים."
+ },
+ "`x` hours": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` שעות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` שעות."
+ },
+ "`x` minutes": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` דקות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` דקות."
+ },
+ "`x` seconds": {
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` שניות.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` שניות."
+ },
+ "Fallback comments: ": "",
+ "Popular": "",
+ "Top": "Top",
+ "About": "על אודות",
+ "Rating: ": "דירוג: ",
+ "Language: ": "שפה: ",
+ "View as playlist": "הצגה כפלייליסט",
+ "Default": "ברירת מחדל",
+ "Music": "מוזיקה",
+ "Gaming": "משחקים",
+ "News": "חדשות",
+ "Movies": "סרטים",
+ "Download": "הורדה",
+ "Download as: ": "הורדה בתור: ",
+ "%A %B %-d, %Y": "%A %B %-d, %Y",
+ "(edited)": "",
+ "YouTube comment permalink": "",
+ "permalink": "",
+ "`x` marked it with a ❤": "סומנה ב־❤ על ידי `x`",
+ "Audio mode": "Audio mode",
+ "Video mode": "Video mode",
+ "Videos": "סרטונים",
+ "Playlists": "פלייליסטים",
+ "Community": "קהילה",
+ "relevance": "רלוונטיות",
+ "rating": "דירוג",
+ "date": "תאריך העלאה",
+ "views": "מספר צפיות",
+ "content_type": "סוג",
+ "duration": "משך זמן",
+ "features": "תכונות",
+ "sort": "מיון לפי",
+ "hour": "השעה האחרונה",
+ "today": "היום",
+ "week": "השבוע",
+ "month": "החודש",
+ "year": "השנה",
+ "video": "סרטון",
+ "channel": "ערוץ",
+ "playlist": "פלייליסט",
+ "movie": "סרט",
+ "show": "תכנית טלוויזיה",
+ "hd": "HD",
+ "subtitles": "כתוביות",
+ "creative_commons": "Creative Commons",
+ "3d": "3D",
+ "live": "Live",
+ "4k": "4K",
+ "location": "מיקום",
+ "hdr": "HDR",
+ "filter": "סינון",
+ "Current version: ": "הגרסה הנוכחית: "
+}
diff --git a/locales/id.json b/locales/id.json
index 62577127..66662c69 100644
--- a/locales/id.json
+++ b/locales/id.json
@@ -74,7 +74,7 @@
"youtube": "youtube",
"reddit": "reddit",
"Default captions: ": "Subtitel default: ",
- "Fallback captions: ": "",
+ "Fallback captions: ": "Subtitel fallback: ",
"Show related videos: ": "Tampilkan video terkait: ",
"Show annotations by default: ": "Tampilkan anotasi secara default: ",
"Visual preferences": "Preferensi visual",
@@ -163,7 +163,7 @@
"License: ": "Lisensi: ",
"Family friendly? ": "Ramah keluarga? ",
"Wilson score: ": "Skor Wilson: ",
- "Engagement: ": "Keterikatan: ",
+ "Engagement: ": "Keterlibatan: ",
"Whitelisted regions: ": "Wilayah daftar-putih: ",
"Blacklisted regions: ": "Wilayah daftar-hitam: ",
"Shared `x`": "Berbagi`x`",
@@ -211,10 +211,10 @@
"`x` ago": "`x` lalu",
"Load more": "Muat lebih banyak",
"`x` points": {
- "([^.,0-9]|^)1([^.,0-9]|$)": "",
- "": ""
+ "([^.,0-9]|^)1([^.,0-9]|$)": "`x` titik.([^.,0-9]|^)1([^.,0-9]|$)",
+ "": "`x` titik."
},
- "Could not create mix.": "",
+ "Could not create mix.": "Tidak dapat membuat mix.",
"Empty playlist": "Daftar putar kosong",
"Not a playlist.": "Bukan daftar putar.",
"Playlist does not exist.": "Daftar putar tidak ada.",
@@ -232,100 +232,100 @@
"Amharic": "Bahasa Amharik",
"Arabic": "Bahasa arab",
"Armenian": "Bahasa Armenia",
- "Azerbaijani": "",
- "Bangla": "",
- "Basque": "",
- "Belarusian": "",
+ "Azerbaijani": "Bahasa Azeri",
+ "Bangla": "Bahasa Bangla",
+ "Basque": "Bahasa Basque",
+ "Belarusian": "Bahasa Belarusia",
"Bosnian": "Bahasa Bosnia",
"Bulgarian": "Bahasa Bulgaria",
"Burmese": "Bahasa Birma",
- "Catalan": "",
- "Cebuano": "",
- "Chinese (Simplified)": "",
- "Chinese (Traditional)": "",
+ "Catalan": "Bahasa Catalan",
+ "Cebuano": "Bahasa Cebu",
+ "Chinese (Simplified)": "Bahasa Cina",
+ "Chinese (Traditional)": "Bahasa Cina (Tradisonal)",
"Corsican": "",
"Croatian": "Bahasa Kroasia",
"Czech": "Bahasa Ceko",
- "Danish": "",
+ "Danish": "Bahasa Denmak",
"Dutch": "Bahasa Belanda",
- "Esperanto": "",
- "Estonian": "",
- "Filipino": "",
- "Finnish": "",
- "French": "",
+ "Esperanto": "Bahasa Esperanto",
+ "Estonian": "Bahasa Estonia",
+ "Filipino": "Bahasa Filipina",
+ "Finnish": "Bahasa Finlandia",
+ "French": "Bahasa Perancis",
"Galician": "",
- "Georgian": "",
- "German": "",
+ "Georgian": "Bahasa Georgia",
+ "German": "Bahasa Jerman",
"Greek": "Bahasa Yunani",
"Gujarati": "",
"Haitian Creole": "",
"Hausa": "",
- "Hawaiian": "",
- "Hebrew": "",
- "Hindi": "",
+ "Hawaiian": "Bahasa Hawai",
+ "Hebrew": "Bahasa Ibrani",
+ "Hindi": "Bahasa Hindi",
"Hmong": "",
- "Hungarian": "",
- "Icelandic": "",
- "Igbo": "",
+ "Hungarian": "Bahasa Hungaria",
+ "Icelandic": "Bahasa Islandia",
+ "Igbo": "Bahasa Igbo",
"Indonesian": "Bahasa Indonesia",
- "Irish": "",
- "Italian": "",
+ "Irish": "Bahasa Irlandia",
+ "Italian": "Bahasa Italia",
"Japanese": "Bahasa Jepang",
"Javanese": "Bahasa Jawa",
"Kannada": "",
"Kazakh": "",
"Khmer": "",
"Korean": "Bahasa Korea",
- "Kurdish": "",
+ "Kurdish": "Bahasa Kurdistan",
"Kyrgyz": "",
"Lao": "",
- "Latin": "",
- "Latvian": "",
- "Lithuanian": "",
+ "Latin": "Bahasa Latin",
+ "Latvian": "Bahasa Latvia",
+ "Lithuanian": "Bahasa Lithuania",
"Luxembourgish": "",
"Macedonian": "",
"Malagasy": "",
"Malay": "Bahasa Melayu",
"Malayalam": "",
"Maltese": "",
- "Maori": "",
- "Marathi": "",
- "Mongolian": "",
- "Nepali": "",
+ "Maori": "Bahasa Maori",
+ "Marathi": "Bahasa Marathi",
+ "Mongolian": "Bahasa Mongolia",
+ "Nepali": "Bahasa Nepal",
"Norwegian Bokmål": "",
"Nyanja": "",
"Pashto": "",
- "Persian": "",
- "Polish": "",
- "Portuguese": "",
- "Punjabi": "",
- "Romanian": "",
- "Russian": "",
+ "Persian": "Bahasa Persia",
+ "Polish": "Bahasa Polandia",
+ "Portuguese": "Bahasa Portugis",
+ "Punjabi": "Bahasa Punjabi",
+ "Romanian": "Bahasa Romania",
+ "Russian": "Bahasa Russia",
"Samoan": "",
"Scottish Gaelic": "",
- "Serbian": "",
+ "Serbian": "Bahasa Serbia",
"Shona": "",
"Sindhi": "",
"Sinhala": "",
- "Slovak": "",
- "Slovenian": "",
- "Somali": "",
+ "Slovak": "Bahasa Slovakia",
+ "Slovenian": "Bahasa Slovenia",
+ "Somali": "Bahasa Somalia",
"Southern Sotho": "",
- "Spanish": "",
- "Spanish (Latin America)": "",
+ "Spanish": "Bahasa Spanyol",
+ "Spanish (Latin America)": "Bahasa Spanyol (Amerika Latin)",
"Sundanese": "Bahasa Sunda",
- "Swahili": "",
- "Swedish": "",
+ "Swahili": "Bahasa Swahili",
+ "Swedish": "Bahasa Swedia",
"Tajik": "",
- "Tamil": "",
+ "Tamil": "Bahasa Tamil",
"Telugu": "",
"Thai": "Bahasa Thailand",
- "Turkish": "",
- "Ukrainian": "",
- "Urdu": "",
- "Uzbek": "",
+ "Turkish": "Bahasa Turki",
+ "Ukrainian": "Bahasa Ukraina",
+ "Urdu": "Bahasa Urdu",
+ "Uzbek": "Bahasa Uzbek",
"Vietnamese": "Bahasa Vietnam",
- "Welsh": "",
+ "Welsh": "Bahasa Wales",
"Western Frisian": "",
"Xhosa": "",
"Yiddish": "",
@@ -376,7 +376,7 @@
"%A %B %-d, %Y": "",
"(edited)": "(disunting)",
"YouTube comment permalink": "",
- "permalink": "",
+ "permalink": "permalink",
"`x` marked it with a ❤": "`x` telah ditandai dengan ❤",
"Audio mode": "Mode audio",
"Video mode": "Mode video",
diff --git a/shard.lock b/shard.lock
index 5dbac470..a9074b32 100644
--- a/shard.lock
+++ b/shard.lock
@@ -22,7 +22,7 @@ shards:
pg:
git: https://github.com/will/crystal-pg.git
- version: 0.22.1
+ version: 0.23.1
pool:
git: https://github.com/ysbaddaden/pool.git
@@ -38,5 +38,5 @@ shards:
sqlite3:
git: https://github.com/crystal-lang/crystal-sqlite3.git
- version: 0.17.0
+ version: 0.18.0
diff --git a/shard.yml b/shard.yml
index e0fa1d25..42eda04c 100644
--- a/shard.yml
+++ b/shard.yml
@@ -12,10 +12,10 @@ targets:
dependencies:
pg:
github: will/crystal-pg
- version: ~> 0.22.1
+ version: ~> 0.23.1
sqlite3:
github: crystal-lang/crystal-sqlite3
- version: ~> 0.17.0
+ version: ~> 0.18.0
kemal:
github: kemalcr/kemal
version: ~> 0.27.0
@@ -29,6 +29,6 @@ dependencies:
github: iv-org/lsquic.cr
version: ~> 2.18.1-1
-crystal: 0.35.1
+crystal: 0.36.1
license: AGPLv3
diff --git a/src/invidious.cr b/src/invidious.cr
index 713d193e..563a3768 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -84,7 +84,9 @@ LOCALES = {
"fa" => load_locale("fa"),
"fi" => load_locale("fi"),
"fr" => load_locale("fr"),
+ "he" => load_locale("he"),
"hr" => load_locale("hr"),
+ "id" => load_locale("id"),
"is" => load_locale("is"),
"it" => load_locale("it"),
"ja" => load_locale("ja"),
@@ -311,12 +313,12 @@ before_all do |env|
env.set "current_page", URI.encode_www_form(current_page)
end
-Invidious::Routing.get "/", Invidious::Routes::Home
-Invidious::Routing.get "/privacy", Invidious::Routes::Privacy
-Invidious::Routing.get "/licenses", Invidious::Routes::Licenses
+Invidious::Routing.get "/", Invidious::Routes::Misc, :home
+Invidious::Routing.get "/privacy", Invidious::Routes::Misc, :privacy
+Invidious::Routing.get "/licenses", Invidious::Routes::Misc, :licenses
Invidious::Routing.get "/watch", Invidious::Routes::Watch
-Invidious::Routing.get "/embed/", Invidious::Routes::Embed::Index
-Invidious::Routing.get "/embed/:id", Invidious::Routes::Embed::Show
+Invidious::Routing.get "/embed/", Invidious::Routes::Embed, :redirect
+Invidious::Routing.get "/embed/:id", Invidious::Routes::Embed, :show
Invidious::Routing.get "/view_all_playlists", Invidious::Routes::Playlists, :index
Invidious::Routing.get "/create_playlist", Invidious::Routes::Playlists, :new
Invidious::Routing.post "/create_playlist", Invidious::Routes::Playlists, :create
@@ -335,9 +337,9 @@ Invidious::Routing.get "/search", Invidious::Routes::Search, :search
Invidious::Routing.get "/login", Invidious::Routes::Login, :login_page
Invidious::Routing.post "/login", Invidious::Routes::Login, :login
Invidious::Routing.post "/signout", Invidious::Routes::Login, :signout
-Invidious::Routing.get "/preferences", Invidious::Routes::UserPreferences, :show
-Invidious::Routing.post "/preferences", Invidious::Routes::UserPreferences, :update
-Invidious::Routing.get "/toggle_theme", Invidious::Routes::UserPreferences, :toggle_theme
+Invidious::Routing.get "/preferences", Invidious::Routes::PreferencesRoute, :show
+Invidious::Routing.post "/preferences", Invidious::Routes::PreferencesRoute, :update
+Invidious::Routing.get "/toggle_theme", Invidious::Routes::PreferencesRoute, :toggle_theme
# Users
@@ -1428,9 +1430,9 @@ get "/feed/playlist/:plid" do |env|
node.attributes.each do |attribute|
case attribute.name
when "url", "href"
- full_path = URI.parse(node[attribute.name]).full_path
- query_string_opt = full_path.starts_with?("/watch?v=") ? "&#{params}" : ""
- node[attribute.name] = "#{HOST_URL}#{full_path}#{query_string_opt}"
+ request_target = URI.parse(node[attribute.name]).request_target
+ query_string_opt = request_target.starts_with?("/watch?v=") ? "&#{params}" : ""
+ node[attribute.name] = "#{HOST_URL}#{request_target}#{query_string_opt}"
else nil # Skip
end
end
@@ -1439,7 +1441,7 @@ get "/feed/playlist/:plid" do |env|
document = document.to_xml(options: XML::SaveOptions::NO_DECL)
document.scan(/<uri>(?<url>[^<]+)<\/uri>/).each do |match|
- content = "#{HOST_URL}#{URI.parse(match["url"]).full_path}"
+ content = "#{HOST_URL}#{URI.parse(match["url"]).request_target}"
document = document.gsub(match[0], "<uri>#{content}</uri>")
end
@@ -1634,7 +1636,7 @@ end
get "/attribution_link" do |env|
if query = env.params.query["u"]?
- url = URI.parse(query).full_path
+ url = URI.parse(query).request_target
else
url = "/"
end
@@ -1978,7 +1980,7 @@ get "/api/v1/captions/:id" do |env|
caption = caption[0]
end
- url = URI.parse("#{caption.baseUrl}&tlang=#{tlang}").full_path
+ url = URI.parse("#{caption.baseUrl}&tlang=#{tlang}").request_target
# Auto-generated captions often have cues that aren't aligned properly with the video,
# as well as some other markup that makes it cumbersome, so we try to fix that here
@@ -3184,7 +3186,7 @@ get "/api/manifest/dash/id/:id" do |env|
end
if dashmpd = video.dash_manifest_url
- manifest = YT_POOL.client &.get(URI.parse(dashmpd).full_path).body
+ manifest = YT_POOL.client &.get(URI.parse(dashmpd).request_target).body
manifest = manifest.gsub(/<BaseURL>[^<]+<\/BaseURL>/) do |baseurl|
url = baseurl.lchop("<BaseURL>")
@@ -3192,7 +3194,7 @@ get "/api/manifest/dash/id/:id" do |env|
if local
uri = URI.parse(url)
- url = "#{uri.full_path}host/#{uri.host}/"
+ url = "#{uri.request_target}host/#{uri.host}/"
end
"<BaseURL>#{url}</BaseURL>"
@@ -3205,7 +3207,7 @@ get "/api/manifest/dash/id/:id" do |env|
if local
adaptive_fmts.each do |fmt|
- fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path)
+ fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target)
end
end
@@ -3403,7 +3405,7 @@ get "/latest_version" do |env|
next
end
- url = URI.parse(url).full_path.not_nil! if local
+ url = URI.parse(url).request_target.not_nil! if local
url = "#{url}&title=#{title}" if title
env.redirect url
@@ -3515,7 +3517,7 @@ get "/videoplayback" do |env|
client = make_client(URI.parse(new_host), region)
end
- url = "#{location.full_path}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
+ url = "#{location.request_target}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
else
break
end
@@ -3555,7 +3557,7 @@ get "/videoplayback" do |env|
if location = response.headers["Location"]?
location = URI.parse(location)
- location = "#{location.full_path}&host=#{location.host}"
+ location = "#{location.request_target}&host=#{location.host}"
if region
location += "&region=#{region}"
@@ -3619,7 +3621,7 @@ get "/videoplayback" do |env|
if location = response.headers["Location"]?
location = URI.parse(location)
- location = "#{location.full_path}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
+ location = "#{location.request_target}&host=#{location.host}#{region ? "&region=#{region}" : ""}"
env.redirect location
break
@@ -3859,7 +3861,7 @@ end
get "/watch_videos" do |env|
response = YT_POOL.client &.get(env.request.resource)
if url = response.headers["Location"]?
- url = URI.parse(url).full_path
+ url = URI.parse(url).request_target
next env.redirect url
end
@@ -3874,7 +3876,7 @@ error 404 do |env|
response = YT_POOL.client &.get("/#{item}")
if response.status_code == 301
- response = YT_POOL.client &.get(URI.parse(response.headers["Location"]).full_path)
+ response = YT_POOL.client &.get(URI.parse(response.headers["Location"]).request_target)
end
if response.body.empty?
diff --git a/src/invidious/comments.cr b/src/invidious/comments.cr
index 0ac99ba5..a8bbf74b 100644
--- a/src/invidious/comments.cr
+++ b/src/invidious/comments.cr
@@ -294,7 +294,7 @@ def template_youtube_comments(comments, locale, thin_mode)
end
if !thin_mode
- author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).full_path}"
+ author_thumbnail = "/ggpht#{URI.parse(child["authorThumbnails"][-1]["url"].as_s).request_target}"
else
author_thumbnail = ""
end
@@ -322,7 +322,7 @@ def template_youtube_comments(comments, locale, thin_mode)
html << <<-END_HTML
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
- <img style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).full_path}">
+ <img style="width:100%" src="/ggpht#{URI.parse(attachment["url"].as_s).request_target}">
</div>
</div>
END_HTML
@@ -375,7 +375,7 @@ def template_youtube_comments(comments, locale, thin_mode)
if child["creatorHeart"]?
if !thin_mode
- creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).full_path}"
+ creator_thumbnail = "/ggpht#{URI.parse(child["creatorHeart"]["creatorThumbnail"].as_s).request_target}"
else
creator_thumbnail = ""
end
@@ -473,7 +473,7 @@ def replace_links(html)
params = HTTP::Params.parse(url.query.not_nil!)
anchor["href"] = params["q"]?
else
- anchor["href"] = url.full_path
+ anchor["href"] = url.request_target
end
elsif url.to_s == "#"
begin
@@ -544,7 +544,7 @@ def content_to_comment_html(content)
if url.path == "/redirect"
url = HTTP::Params.parse(url.query.not_nil!)["q"]
else
- url = url.full_path
+ url = url.request_target
end
end
diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr
index 00087143..944d869b 100644
--- a/src/invidious/helpers/helpers.cr
+++ b/src/invidious/helpers/helpers.cr
@@ -231,7 +231,7 @@ def extract_item(item : JSON::Any, author_fallback : String? = nil, author_id_fa
video_id = i["videoId"].as_s
title = i["title"].try { |t| t["simpleText"]?.try &.as_s || t["runs"]?.try &.as_a.map(&.["text"].as_s).join("") } || ""
- author_info = i["ownerText"]?.try &.["runs"].as_a[0]?
+ author_info = i["ownerText"]?.try &.["runs"]?.try &.as_a?.try &.[0]?
author = author_info.try &.["text"].as_s || author_fallback || ""
author_id = author_info.try &.["navigationEndpoint"]?.try &.["browseEndpoint"]["browseId"].as_s || author_id_fallback || ""
@@ -322,7 +322,7 @@ def extract_item(item : JSON::Any, author_fallback : String? = nil, author_id_fa
video_count = i["videoCount"]?.try &.as_s.to_i || 0
playlist_thumbnail = i["thumbnails"].as_a[0]?.try &.["thumbnails"]?.try &.as_a[0]?.try &.["url"].as_s || ""
- author_info = i["shortBylineText"]?.try &.["runs"].as_a[0]?
+ author_info = i["shortBylineText"]?.try &.["runs"]?.try &.as_a?.try &.[0]?
author = author_info.try &.["text"].as_s || author_fallback || ""
author_id = author_info.try &.["navigationEndpoint"]?.try &.["browseEndpoint"]["browseId"].as_s || author_id_fallback || ""
diff --git a/src/invidious/helpers/proxy.cr b/src/invidious/helpers/proxy.cr
index 7a42ef41..3418d887 100644
--- a/src/invidious/helpers/proxy.cr
+++ b/src/invidious/helpers/proxy.cr
@@ -71,14 +71,14 @@ end
class HTTPClient < HTTP::Client
def set_proxy(proxy : HTTPProxy)
begin
- @socket = proxy.open(host: @host, port: @port, tls: @tls, connection_options: proxy_connection_options)
+ @io = proxy.open(host: @host, port: @port, tls: @tls, connection_options: proxy_connection_options)
rescue IO::Error
- @socket = nil
+ @io = nil
end
end
def unset_proxy
- @socket = nil
+ @io = nil
end
def proxy_connection_options
diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr
index 7d94a6e5..2c95a373 100644
--- a/src/invidious/helpers/utils.cr
+++ b/src/invidious/helpers/utils.cr
@@ -329,7 +329,7 @@ def get_referer(env, fallback = "/", unroll = true)
end
end
- referer = referer.full_path
+ referer = referer.request_target
referer = "/" + referer.gsub(/[^\/?@&%=\-_.0-9a-zA-Z]/, "").lstrip("/\\")
if referer == env.request.path
diff --git a/src/invidious/jobs/bypass_captcha_job.cr b/src/invidious/jobs/bypass_captcha_job.cr
index 8b1aed5f..4269e123 100644
--- a/src/invidious/jobs/bypass_captcha_job.cr
+++ b/src/invidious/jobs/bypass_captcha_job.cr
@@ -60,7 +60,7 @@ class Invidious::Jobs::BypassCaptchaJob < Invidious::Jobs::BaseJob
elsif response.headers["Location"]?.try &.includes?("/sorry/index")
location = response.headers["Location"].try { |u| URI.parse(u) }
headers = HTTP::Headers{":authority" => location.host.not_nil!}
- response = YT_POOL.client &.get(location.full_path, headers)
+ response = YT_POOL.client &.get(location.request_target, headers)
html = XML.parse_html(response.body)
form = html.xpath_node(%(//form[@action="index"])).not_nil!
diff --git a/src/invidious/routes/embed/show.cr b/src/invidious/routes/embed.cr
index 8a655556..5db32788 100644
--- a/src/invidious/routes/embed/show.cr
+++ b/src/invidious/routes/embed.cr
@@ -1,5 +1,29 @@
-class Invidious::Routes::Embed::Show < Invidious::Routes::BaseRoute
- def handle(env)
+class Invidious::Routes::Embed < Invidious::Routes::BaseRoute
+ def redirect(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+
+ if plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
+ begin
+ playlist = get_playlist(PG_DB, plid, locale: locale)
+ offset = env.params.query["index"]?.try &.to_i? || 0
+ videos = get_playlist_videos(PG_DB, playlist, offset: offset, locale: locale)
+ rescue ex
+ return error_template(500, ex)
+ end
+
+ url = "/embed/#{videos[0].id}?#{env.params.query}"
+
+ if env.params.query.size > 0
+ url += "?#{env.params.query}"
+ end
+ else
+ url = "/"
+ end
+
+ env.redirect url
+ end
+
+ def show(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
id = env.params.url["id"]
@@ -120,8 +144,8 @@ class Invidious::Routes::Embed::Show < Invidious::Routes::BaseRoute
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
+ fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
end
video_streams = video.video_streams
diff --git a/src/invidious/routes/embed/index.cr b/src/invidious/routes/embed/index.cr
deleted file mode 100644
index 32a4966b..00000000
--- a/src/invidious/routes/embed/index.cr
+++ /dev/null
@@ -1,25 +0,0 @@
-class Invidious::Routes::Embed::Index < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
-
- if plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
- begin
- playlist = get_playlist(PG_DB, plid, locale: locale)
- offset = env.params.query["index"]?.try &.to_i? || 0
- videos = get_playlist_videos(PG_DB, playlist, offset: offset, locale: locale)
- rescue ex
- return error_template(500, ex)
- end
-
- url = "/embed/#{videos[0].id}?#{env.params.query}"
-
- if env.params.query.size > 0
- url += "?#{env.params.query}"
- end
- else
- url = "/"
- end
-
- env.redirect url
- end
-end
diff --git a/src/invidious/routes/licenses.cr b/src/invidious/routes/licenses.cr
deleted file mode 100644
index 38fde7bb..00000000
--- a/src/invidious/routes/licenses.cr
+++ /dev/null
@@ -1,6 +0,0 @@
-class Invidious::Routes::Licenses < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
- rendered "licenses"
- end
-end
diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr
index 662fdf13..ffe5f568 100644
--- a/src/invidious/routes/login.cr
+++ b/src/invidious/routes/login.cr
@@ -255,7 +255,7 @@ class Invidious::Routes::Login < Invidious::Routes::BaseRoute
traceback << "Unhandled dialog /b/0/SmsAuthInterstitial."
end
- login = client.get(location.full_path, headers)
+ login = client.get(location.request_target, headers)
headers = login.cookies.add_request_headers(headers)
location = login.headers["Location"]?.try { |u| URI.parse(u) }
diff --git a/src/invidious/routes/home.cr b/src/invidious/routes/misc.cr
index 486a7344..bc009633 100644
--- a/src/invidious/routes/home.cr
+++ b/src/invidious/routes/misc.cr
@@ -1,5 +1,5 @@
-class Invidious::Routes::Home < Invidious::Routes::BaseRoute
- def handle(env)
+class Invidious::Routes::Misc < Invidious::Routes::BaseRoute
+ def home(env)
preferences = env.get("preferences").as(Preferences)
locale = LOCALES[preferences.locale]?
user = env.get? "user"
@@ -25,4 +25,14 @@ class Invidious::Routes::Home < Invidious::Routes::BaseRoute
templated "empty"
end
end
+
+ def privacy(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+ templated "privacy"
+ end
+
+ def licenses(env)
+ locale = LOCALES[env.get("preferences").as(Preferences).locale]?
+ rendered "licenses"
+ end
end
diff --git a/src/invidious/routes/user_preferences.cr b/src/invidious/routes/preferences.cr
index a689a2a2..4901d22b 100644
--- a/src/invidious/routes/user_preferences.cr
+++ b/src/invidious/routes/preferences.cr
@@ -1,4 +1,4 @@
-class Invidious::Routes::UserPreferences < Invidious::Routes::BaseRoute
+class Invidious::Routes::PreferencesRoute < Invidious::Routes::BaseRoute
def show(env)
locale = LOCALES[env.get("preferences").as(Preferences).locale]?
diff --git a/src/invidious/routes/privacy.cr b/src/invidious/routes/privacy.cr
deleted file mode 100644
index 4565c94c..00000000
--- a/src/invidious/routes/privacy.cr
+++ /dev/null
@@ -1,6 +0,0 @@
-class Invidious::Routes::Privacy < Invidious::Routes::BaseRoute
- def handle(env)
- locale = LOCALES[env.get("preferences").as(Preferences).locale]?
- templated "privacy"
- end
-end
diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr
index 65604a88..8169e1ed 100644
--- a/src/invidious/routes/watch.cr
+++ b/src/invidious/routes/watch.cr
@@ -126,8 +126,8 @@ class Invidious::Routes::Watch < Invidious::Routes::BaseRoute
adaptive_fmts = video.adaptive_fmts
if params.local
- fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
- adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).full_path) }
+ fmt_stream.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
+ adaptive_fmts.each { |fmt| fmt["url"] = JSON::Any.new(URI.parse(fmt["url"].as_s).request_target) }
end
video_streams = video.video_streams
diff --git a/src/invidious/views/channel.ecr b/src/invidious/views/channel.ecr
index caa0ad0e..061d7eec 100644
--- a/src/invidious/views/channel.ecr
+++ b/src/invidious/views/channel.ecr
@@ -5,7 +5,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -16,7 +16,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/community.ecr b/src/invidious/views/community.ecr
index 69724390..3c4eaabb 100644
--- a/src/invidious/views/community.ecr
+++ b/src/invidious/views/community.ecr
@@ -4,7 +4,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -15,7 +15,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/components/item.ecr b/src/invidious/views/components/item.ecr
index e4a60697..ea7d356c 100644
--- a/src/invidious/views/components/item.ecr
+++ b/src/invidious/views/components/item.ecr
@@ -5,7 +5,7 @@
<a style="width:100%" href="/channel/<%= item.ucid %>">
<% if !env.get("preferences").as(Preferences).thin_mode %>
<center>
- <img style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).full_path %>"/>
+ <img style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>"/>
</center>
<% end %>
<p><%= item.author %></p>
@@ -15,7 +15,7 @@
<h5><%= item.description_html %></h5>
<% when SearchPlaylist, InvidiousPlaylist %>
<% if item.id.starts_with? "RD" %>
- <% url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").full_path.split("/")[2]}" %>
+ <% url = "/mix?list=#{item.id}&continuation=#{URI.parse(item.thumbnail || "/vi/-----------").request_target.split("/")[2]}" %>
<% else %>
<% url = "/playlist?list=#{item.id}" %>
<% end %>
@@ -23,7 +23,7 @@
<a style="width:100%" href="<%= url %>">
<% if !env.get("preferences").as(Preferences).thin_mode %>
<div class="thumbnail">
- <img class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").full_path %>"/>
+ <img class="thumbnail" src="<%= URI.parse(item.thumbnail || "/").request_target %>"/>
<p class="length"><%= number_with_separator(item.video_count) %> videos</p>
</div>
<% end %>
diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr
index 625c6fee..a898a41f 100644
--- a/src/invidious/views/components/player.ecr
+++ b/src/invidious/views/components/player.ecr
@@ -4,7 +4,7 @@
<% if params.video_loop %>loop<% end %>
<% if params.controls %>controls<% end %>>
<% if (hlsvp = video.hls_manifest_url) && !CONFIG.disabled?("livestreams") %>
- <source src="<%= URI.parse(hlsvp).full_path %><% if params.local %>?local=true<% end %>" type="application/x-mpegURL" label="livestream">
+ <source src="<%= URI.parse(hlsvp).request_target %><% if params.local %>?local=true<% end %>" type="application/x-mpegURL" label="livestream">
<% else %>
<% if params.listen %>
<% audio_streams.each_with_index do |fmt, i| %>
diff --git a/src/invidious/views/playlists.ecr b/src/invidious/views/playlists.ecr
index a77d106d..44bdb94d 100644
--- a/src/invidious/views/playlists.ecr
+++ b/src/invidious/views/playlists.ecr
@@ -4,7 +4,7 @@
<% if channel.banner %>
<div class="h-box">
- <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).full_path %>">
+ <img style="width:100%" src="/ggpht<%= URI.parse(channel.banner.not_nil!.gsub("=w1060-", "=w1280-")).request_target %>">
</div>
<div class="h-box">
@@ -15,7 +15,7 @@
<div class="pure-g h-box">
<div class="pure-u-2-3">
<div class="channel-profile">
- <img src="/ggpht<%= URI.parse(channel.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
<span><%= channel.author %></span>
</div>
</div>
diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr
index 786a88b6..924914a5 100644
--- a/src/invidious/views/watch.ecr
+++ b/src/invidious/views/watch.ecr
@@ -22,6 +22,7 @@
<meta name="twitter:player" content="<%= HOST_URL %>/embed/<%= video.id %>">
<meta name="twitter:player:width" content="1280">
<meta name="twitter:player:height" content="720">
+<link rel="alternate" href="https://www.youtube.com/watch?v=<%= video.id %>">
<%= rendered "components/player_sources" %>
<title><%= HTML.escape(video.title) %> - Invidious</title>
<% end %>
@@ -203,7 +204,7 @@
<a href="/channel/<%= video.ucid %>" style="display:block;width:fit-content;width:-moz-fit-content">
<div class="channel-profile">
<% if !video.author_thumbnail.empty? %>
- <img src="/ggpht<%= URI.parse(video.author_thumbnail).full_path %>">
+ <img src="/ggpht<%= URI.parse(video.author_thumbnail).request_target %>">
<% end %>
<span id="channel-name"><%= video.author %></span>
</div>