summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--assets/js/player.js4
-rw-r--r--locales/el.json107
-rw-r--r--locales/fi.json141
-rw-r--r--src/invidious.cr17
-rw-r--r--src/invidious/channels/channels.cr24
-rw-r--r--src/invidious/database/base.cr64
-rw-r--r--src/invidious/database/channels.cr31
-rw-r--r--src/invidious/database/playlists.cr26
-rw-r--r--src/invidious/database/sessions.cr4
-rw-r--r--src/invidious/database/users.cr6
-rw-r--r--src/invidious/jobs/refresh_channels_job.cr2
-rw-r--r--src/invidious/routes/api/v1/authenticated.cr2
-rw-r--r--src/invidious/routes/feeds.cr2
-rw-r--r--src/invidious/routes/playlists.cr16
-rw-r--r--src/invidious/routes/preferences.cr10
-rw-r--r--src/invidious/routes/subscriptions.cr2
-rw-r--r--src/invidious/users.cr2
17 files changed, 324 insertions, 136 deletions
diff --git a/assets/js/player.js b/assets/js/player.js
index 5ff55eb3..66d1682f 100644
--- a/assets/js/player.js
+++ b/assets/js/player.js
@@ -23,7 +23,7 @@ var options = {
},
html5: {
preloadTextTracks: false,
- hls: {
+ vhs: {
overrideNative: true
}
}
@@ -50,7 +50,7 @@ var shareOptions = {
embedCode: "<iframe id='ivplayer' width='640' height='360' src='" + embed_url + "' style='border:none;'></iframe>"
}
-videojs.Hls.xhr.beforeRequest = function(options) {
+videojs.Vhs.xhr.beforeRequest = function(options) {
if (options.uri.indexOf('videoplayback') === -1 && options.uri.indexOf('local=true') === -1) {
options.uri = options.uri + '?local=true';
}
diff --git a/locales/el.json b/locales/el.json
index 8800941a..b33fc02f 100644
--- a/locales/el.json
+++ b/locales/el.json
@@ -60,7 +60,7 @@
"preferences_volume_label": "Ένταση αναπαραγωγής: ",
"preferences_comments_label": "Προεπιλεγμένα σχόλια: ",
"youtube": "YouTube",
- "reddit": "reddit",
+ "reddit": "Reddit",
"preferences_captions_label": "Προεπιλεγμένοι υπότιτλοι: ",
"Fallback captions: ": "Εναλλακτικοί υπότιτλοι: ",
"preferences_related_videos_label": "Προβολή σχετικών βίντεο; ",
@@ -318,5 +318,108 @@
"Videos": "Βίντεο",
"Playlists": "Λίστες Αναπαραγωγής",
"Community": "Κοινότητα",
- "Current version: ": "Τρέχουσα έκδοση: "
+ "Current version: ": "Τρέχουσα έκδοση: ",
+ "generic_playlists_count": "{{count}} λίστα αναπαραγωγής",
+ "generic_playlists_count_plural": "{{count}} λίστες αναπαραγωγής",
+ "preferences_quality_dash_option_worst": "Χειρότερη",
+ "preferences_quality_dash_option_2160p": "2160 p",
+ "Video unavailable": "Το βίντεο δεν είναι διαθέσιμο",
+ "preferences_quality_dash_option_auto": "Αυτόματη",
+ "preferences_quality_dash_option_1440p": "1440p",
+ "preferences_quality_dash_option_1080p": "1080p",
+ "comments_view_x_replies": "Προβολή {{count}} απάντησης",
+ "comments_view_x_replies_plural": "Προβολή {{count}} απαντήσεων",
+ "crash_page_report_issue": "Εάν κανένα από τα παραπάνω δεν βοήθησε, παρακαλούμε <a href=\"`x`\">ανοίξτε ένα νέο θέμα στο GitHub</a> (κατά προτίμηση στα αγγλικά) και συμπεριλάβετε το ακόλουθο κείμενο στο μήνυμά σας (ΜΗΝ μεταφράζετε αυτό το κείμενο):",
+ "generic_count_hours": "{{count}} ώρα",
+ "generic_count_hours_plural": "{{count}} ώρες",
+ "generic_count_minutes": "{{count}} λεπτό",
+ "generic_count_minutes_plural": "{{count}} λεπτά",
+ "generic_count_seconds": "{{count}} δευτερόλεπτο",
+ "generic_count_seconds_plural": "{{count}} δευτερόλεπτα",
+ "preferences_quality_dash_label": "Προτιμώμενη ποιότητα βίντεο DASH: ",
+ "preferences_quality_dash_option_best": "Καλύτερη",
+ "preferences_quality_dash_option_480p": "480p",
+ "preferences_quality_dash_option_360p": "360p",
+ "preferences_quality_dash_option_240p": "240p",
+ "preferences_quality_dash_option_144p": "144p",
+ "generic_subscribers_count": "{{count}} συνδρομητής",
+ "generic_subscribers_count_plural": "{{count}} συνδρομητές",
+ "generic_subscriptions_count": "{{count}} συνδρομή",
+ "generic_subscriptions_count_plural": "{{count}} συνδρομές",
+ "generic_count_years": "{{count}} έτος",
+ "generic_count_years_plural": "{{count}} έτη",
+ "generic_count_months": "{{count}} μήνας",
+ "generic_count_months_plural": "{{count}} μήνες",
+ "generic_count_weeks": "{{count}} εβδομάδα",
+ "generic_count_weeks_plural": "{{count}} εβδομάδες",
+ "generic_count_days": "{{count}} ημέρα",
+ "generic_count_days_plural": "{{count}} ημέρες",
+ "crash_page_you_found_a_bug": "Φαίνεται ότι βρήκατε ένα σφάλμα στο Invidious!",
+ "crash_page_before_reporting": "Πριν αναφέρετε ένα σφάλμα, βεβαιωθείτε ότι έχετε:",
+ "crash_page_refresh": "προσπαθήσει να <a href=\"`x`\">ανανεώσετε τη σελίδα</a>",
+ "crash_page_read_the_faq": "διαβάσει τις <a href=\"`x`\">Συχνές Ερωτήσεις (ΣΕ)</a>",
+ "crash_page_search_issue": "αναζητήσει για <a href=\"`x`\">υπάρχοντα θέματα στο Github</a>",
+ "generic_views_count": "{{count}} προβολή",
+ "generic_views_count_plural": "{{count}} προβολές",
+ "generic_videos_count": "{{count}} βίντεο",
+ "generic_videos_count_plural": "{{count}} βίντεο",
+ "preferences_quality_option_hd720": "HD720",
+ "preferences_quality_option_medium": "Μεσαία",
+ "preferences_quality_option_small": "Μικρό",
+ "preferences_quality_option_dash": "DASH (προσαρμοστική ποιότητα)",
+ "preferences_quality_dash_option_4320p": "4320p",
+ "preferences_quality_dash_option_720p": "720p",
+ "invidious": "Invidious",
+ "preferences_region_label": "Χώρα περιεχομένου: ",
+ "preferences_category_misc": "Διάφορες προτιμήσεις",
+ "Show more": "Εμφάνιση περισσότερων",
+ "today": "Σήμερα",
+ "360": "360°",
+ "videoinfo_started_streaming_x_ago": "Ξεκίνησε η ροή `x` πριν από",
+ "videoinfo_watch_on_youTube": "Παρακολουθήστε στο YouTube",
+ "download_subtitles": "Υπότιτλοι - `x` (.vtt)",
+ "user_created_playlists": "`x` δημιουργημένες λίστες αναπαραγωγής",
+ "user_saved_playlists": "`x` αποθηκευμένες λίστες αναπαραγωγής",
+ "rating": "Αξιολόγηση",
+ "relevance": "Συνάφεια",
+ "purchased": "Αγορασμένο",
+ "date": "Ημερομηνία μεταφόρτωσης",
+ "content_type": "Τύπος",
+ "duration": "Διάρκεια",
+ "week": "Αυτή την εβδομάδα",
+ "year": "Φέτος",
+ "channel": "Κανάλι",
+ "playlist": "Λίστα αναπαραγωγής",
+ "long": "Μεγάλο (> 20 λεπτά)",
+ "hd": "HD",
+ "location": "Τοποθεσία",
+ "3d": "3D",
+ "next_steps_error_message": "Μετά από αυτό θα πρέπει να προσπαθήσετε να: ",
+ "next_steps_error_message_go_to_youtube": "Μεταβείτε στο YouTube",
+ "footer_donate_page": "Δωρεά",
+ "footer_original_source_code": "Πρωτότυπος πηγαίος κώδικας",
+ "preferences_show_nick_label": "Εμφάνιση ψευδώνυμου στην κορυφή: ",
+ "hour": "Τελευταία ώρα",
+ "adminprefs_modified_source_code_url_label": "URL σε αποθετήριο τροποποιημένου πηγαίου κώδικα",
+ "subtitles": "Υπότιτλοι/CC",
+ "month": "Αυτόν τον μήνα",
+ "Released under the AGPLv3 on Github.": "Κυκλοφορεί υπό την AGPLv3 στο Github.",
+ "sort": "Ταξινόμηση κατά",
+ "filter": "Φίλτρο",
+ "movie": "Ταινία",
+ "footer_modfied_source_code": "Τροποποιημένος πηγαίος κώδικας",
+ "features": "Χαρακτηριστικά",
+ "4k": "4K",
+ "footer_documentation": "Τεκμηρίωση",
+ "short": "Σύντομο (< 4 λεπτά)",
+ "next_steps_error_message_refresh": "Ανανέωση",
+ "video": "Βίντεο",
+ "live": "Ζωντανά",
+ "creative_commons": "Creative Commons",
+ "Search": "Αναζήτηση",
+ "hdr": "HDR",
+ "preferences_extend_desc_label": "Αυτόματη επέκταση της περιγραφής του βίντεο: ",
+ "preferences_vr_mode_label": "Διαδραστικά βίντεο 360 μοιρών: ",
+ "Show less": "Εμφάνιση λιγότερων",
+ "footer_source_code": "Πηγαίος κώδικας"
}
diff --git a/locales/fi.json b/locales/fi.json
index df7bb2be..7f97e869 100644
--- a/locales/fi.json
+++ b/locales/fi.json
@@ -21,47 +21,47 @@
"No": "Ei",
"Import and Export Data": "Tuo ja vie tietoja",
"Import": "Tuo",
- "Import Invidious data": "Vie Invidious-tietoja",
+ "Import Invidious data": "Tuo Invidious-tietoja",
"Import YouTube subscriptions": "Tuo YouTube-tilaukset",
"Import FreeTube subscriptions (.db)": "Tuo FreeTube-tilaukset (.db)",
"Import NewPipe subscriptions (.json)": "Tuo NewPipe-tilaukset (.json)",
- "Import NewPipe data (.zip)": "Tuo NewPipe data (.zip)",
+ "Import NewPipe data (.zip)": "Tuo NewPipe-tietoja (.zip)",
"Export": "Vie",
- "Export subscriptions as OPML": "Vie tilaukset muodossa OPML",
- "Export subscriptions as OPML (for NewPipe & FreeTube)": "Vie tilaukset muodossa OPML (NewPipe ja FreeTube)",
- "Export data as JSON": "Vie data muodossa JSON",
+ "Export subscriptions as OPML": "Vie tilaukset OPML-muodossa",
+ "Export subscriptions as OPML (for NewPipe & FreeTube)": "Vie tilaukset OPML-muodossa (NewPipe & FreeTube)",
+ "Export data as JSON": "Vie data JSON-muodossa",
"Delete account?": "Poista tili?",
"History": "Historia",
- "An alternative front-end to YouTube": "Vaihtoehtoinen käyttöliittymä YouTubelle",
- "JavaScript license information": "JavaScript-käyttöoikeustiedot",
+ "An alternative front-end to YouTube": "Vaihtoehtoinen front-end YouTubelle",
+ "JavaScript license information": "JavaScript-lisenssitiedot",
"source": "lähde",
- "Log in": "Kirjaudu",
- "Log in/register": "Kirjaudu sisään / Rekisteröidy",
+ "Log in": "Kirjaudu sisään",
+ "Log in/register": "Kirjaudu sisään/rekisteröidy",
"Log in with Google": "Kirjaudu sisään Googlella",
"User ID": "Käyttäjätunnus",
"Password": "Salasana",
"Time (h:mm:ss):": "Aika (h:mm:ss):",
- "Text CAPTCHA": "Teksti CAPTCHA",
- "Image CAPTCHA": "Kuva CAPTCHA",
+ "Text CAPTCHA": "Teksti-CAPTCHA",
+ "Image CAPTCHA": "Kuva-CAPTCHA",
"Sign In": "Kirjaudu sisään",
"Register": "Rekisteröidy",
"E-mail": "Sähköposti",
"Google verification code": "Google-vahvistuskoodi",
"Preferences": "Asetukset",
"preferences_category_player": "Soittimen asetukset",
- "preferences_video_loop_label": "Aina silmukka: ",
+ "preferences_video_loop_label": "Toista jatkuvasti aina: ",
"preferences_autoplay_label": "Automaattinen toisto: ",
"preferences_continue_label": "Toista seuraava oletuksena: ",
"preferences_continue_autoplay_label": "Toista seuraava video automaattisesti: ",
"preferences_listen_label": "Kuuntele oletuksena: ",
- "preferences_local_label": "Proxy videot: ",
+ "preferences_local_label": "Proxytä videot: ",
"preferences_speed_label": "Oletusnopeus: ",
"preferences_quality_label": "Ensisijainen videon laatu: ",
"preferences_volume_label": "Soittimen äänenvoimakkuus: ",
"preferences_comments_label": "Oletuskommentit: ",
"youtube": "YouTube",
"reddit": "Reddit",
- "preferences_captions_label": "Tekstitykset: ",
+ "preferences_captions_label": "Oletustekstitykset: ",
"Fallback captions: ": "Toissijaiset tekstitykset: ",
"preferences_related_videos_label": "Näytä aiheeseen liittyviä videoita: ",
"preferences_annotations_label": "Näytä huomautukset oletuksena: ",
@@ -73,9 +73,9 @@
"preferences_dark_mode_label": "Teema: ",
"dark": "tumma",
"light": "vaalea",
- "preferences_thin_mode_label": "Kapea tila ",
+ "preferences_thin_mode_label": "Kapea tila: ",
"preferences_category_misc": "Sekalaiset asetukset",
- "preferences_automatic_instance_redirect_label": "Automaattinen palveluntarjoajan uudelleenohjaus (perääntyminen sivulle redirect.invidious.io) ",
+ "preferences_automatic_instance_redirect_label": "Automaattinen instanssin uudelleenohjaus (perääntyminen sivulle redirect.invidious.io): ",
"preferences_category_subscription": "Tilausten asetukset",
"preferences_annotations_subscribed_label": "Näytä oletuksena tilattujen kanavien huomautukset: ",
"Redirect homepage to feed: ": "Uudelleenohjaa kotisivu syötteeseen: ",
@@ -122,7 +122,7 @@
"search": "haku",
"Log out": "Kirjaudu ulos",
"Source available here.": "Lähdekoodi on saatavilla täällä.",
- "View JavaScript license information.": "JavaScript-koodin lisenssit.",
+ "View JavaScript license information.": "Katso JavaScript-koodin lisenssitiedot.",
"View privacy policy.": "Katso tietosuojaseloste.",
"Trending": "Nousussa",
"Public": "Julkinen",
@@ -130,7 +130,7 @@
"Private": "Yksityinen",
"View all playlists": "Kaikki soittolistat",
"Updated `x` ago": "Päivitetty `x` sitten",
- "Delete playlist `x`?": "Poistetaanko soittolista `x`?",
+ "Delete playlist `x`?": "Poista soittolista `x`?",
"Delete playlist": "Poista soittolista",
"Create playlist": "Luo soittolista",
"Title": "Nimi",
@@ -139,8 +139,8 @@
"Show more": "Näytä enemmän",
"Show less": "Näytä vähemmän",
"Watch on YouTube": "Katso YouTubessa",
- "Switch Invidious Instance": "Vaihda Invidious-palveluntarjoajaa",
- "Broken? Try another Invidious Instance": "Rikki? Kokeile toista Invidious-palveluntarjoajaa",
+ "Switch Invidious Instance": "Vaihda Invidious-instanssia",
+ "Broken? Try another Invidious Instance": "Rikki? Kokeile toista Invidious-instanssia",
"Hide annotations": "Piilota merkkaukset",
"Show annotations": "Näytä merkkaukset",
"Genre: ": "Genre: ",
@@ -157,10 +157,10 @@
"View YouTube comments": "Näytä YouTube-kommentit",
"View more comments on Reddit": "Katso lisää kommentteja Redditissä",
"View `x` comments": {
- "([^.,0-9]|^)1([^.,0-9]|$)": "Näytä `x` komenttia",
- "": "Näytä `x` kommenttia"
+ "([^.,0-9]|^)1([^.,0-9]|$)": "Katso `x` kommentti",
+ "": "Katso `x` kommenttia"
},
- "View Reddit comments": "Näytä Reddit-kommentit",
+ "View Reddit comments": "Katso Reddit-kommentit",
"Hide replies": "Piilota vastaukset",
"Show replies": "Näytä vastaukset",
"Incorrect password": "Väärä salasana",
@@ -178,7 +178,7 @@
"Password cannot be empty": "Salasana ei voi olla tyhjä",
"Password cannot be longer than 55 characters": "Salasana ei voi olla yli 55 merkkiä pitkä",
"Please log in": "Kirjaudu sisään, ole hyvä",
- "Invidious Private Feed for `x`": "Invidousin yksityinen syöte `x`:lle",
+ "Invidious Private Feed for `x`": "Invidiousin yksityinen syöte `x`:lle",
"channel:`x`": "kanava:`x`",
"Deleted or invalid channel": "Poistettu tai virheellinen kanava",
"This channel does not exist.": "Tätä kanavaa ei ole olemassa.",
@@ -192,11 +192,11 @@
"Playlist does not exist.": "Soittolistaa ei ole olemassa.",
"Could not pull trending pages.": "Nousussa olevien sivujen lataus epäonnistui.",
"Hidden field \"challenge\" is a required field": "Piilotettu kenttä \"challenge\" vaaditaan",
- "Hidden field \"token\" is a required field": "Piilotettu kenttä \"tunniste\" vaaditaan",
+ "Hidden field \"token\" is a required field": "Piilotettu kenttä \"tunnus\" vaaditaan",
"Erroneous challenge": "Virheellinen haaste",
- "Erroneous token": "Virheellinen tunniste",
+ "Erroneous token": "Virheellinen tunnus",
"No such user": "Käyttäjää ei ole olemassa",
- "Token is expired, please try again": "Tunniste on vanhentunut, yritä uudestaan",
+ "Token is expired, please try again": "Tunnus on vanhentunut, yritä uudestaan",
"English": "englanti",
"English (auto-generated)": "englanti (automaattisesti luotu)",
"Afrikaans": "afrikaans",
@@ -221,7 +221,7 @@
"Danish": "tanska",
"Dutch": "hollanti",
"Esperanto": "esperanto",
- "Estonian": "eesti",
+ "Estonian": "viro",
"Filipino": "filipino",
"Finnish": "suomi",
"French": "ranska",
@@ -310,7 +310,7 @@
"About": "Tietoa",
"Rating: ": "Arvosana: ",
"preferences_locale_label": "Kieli: ",
- "View as playlist": "Näytä soittolistana",
+ "View as playlist": "Katso soittolistana",
"Default": "Oletus",
"Music": "Musiikki",
"Gaming": "Videopelit",
@@ -322,7 +322,7 @@
"(edited)": "(muokattu)",
"YouTube comment permalink": "Pysyvä linkki YouTube-kommenttiin",
"permalink": "pysyvä linkki",
- "`x` marked it with a ❤": "`x` merkattu ❤:llä",
+ "`x` marked it with a ❤": "`x` merkkasi ❤:llä",
"Audio mode": "Äänitila",
"Video mode": "Videotila",
"Videos": "Videot",
@@ -358,5 +358,84 @@
"Current version: ": "Tämänhetkinen versio: ",
"next_steps_error_message": "Sinun tulisi kokeilla seuraavia: ",
"next_steps_error_message_refresh": "Päivitä",
- "next_steps_error_message_go_to_youtube": "Siirry YouTubeen"
+ "next_steps_error_message_go_to_youtube": "Siirry YouTubeen",
+ "generic_count_hours": "{{count}} tunti",
+ "generic_count_hours_plural": "{{count}} tuntia",
+ "download_subtitles": "Tekstitykset - `x` (.vtt)",
+ "user_created_playlists": "`x` luotua soittolistaa",
+ "Video unavailable": "Video ei ole saatavilla",
+ "videoinfo_youTube_embed_link": "Upota",
+ "tokens_count": "{{count}} tunnus",
+ "tokens_count_plural": "{{count}} tunnusta",
+ "generic_videos_count": "{{count}} video",
+ "generic_videos_count_plural": "{{count}} videota",
+ "generic_playlists_count": "{{count}} soittolista",
+ "generic_playlists_count_plural": "{{count}} soittolistaa",
+ "generic_subscriptions_count": "{{count}} tilaus",
+ "generic_subscriptions_count_plural": "{{count}} tilausta",
+ "comments_view_x_replies": "Katso {{count}} vastaus",
+ "comments_view_x_replies_plural": "Katso {{count}} vastausta",
+ "generic_count_months": "{{count}} kuukausi",
+ "generic_count_months_plural": "{{count}} kuukautta",
+ "generic_count_weeks": "{{count}} viikko",
+ "generic_count_weeks_plural": "{{count}} viikkoa",
+ "generic_count_days": "{{count}} päivä",
+ "generic_count_days_plural": "{{count}} päivää",
+ "generic_count_minutes": "{{count}} minuutti",
+ "generic_count_minutes_plural": "{{count}} minuuttia",
+ "comments_points_count": "{{count}} piste",
+ "comments_points_count_plural": "{{count}} pistettä",
+ "generic_count_seconds": "{{count}} sekunti",
+ "generic_count_seconds_plural": "{{count}} sekuntia",
+ "crash_page_before_reporting": "Varmista ennen bugin ilmoittamista, että sinä olet:",
+ "crash_page_refresh": "yrittänyt <a href=\"`x`\">päivittää sivun</a>",
+ "crash_page_read_the_faq": "lukenut <a href=\"`x`\">Usein kysytyt kysymykset (FAQ)</a>",
+ "crash_page_search_issue": "etsinyt <a href=\"`x`\">olemassa olevia issueita Githubissa</a>",
+ "generic_views_count": "{{count}} katselu",
+ "generic_views_count_plural": "{{count}} katselua",
+ "preferences_quality_dash_option_720p": "720p",
+ "generic_subscribers_count": "{{count}} tilaaja",
+ "generic_subscribers_count_plural": "{{count}} tilaajaa",
+ "preferences_quality_dash_option_1440p": "1440p",
+ "crash_page_you_found_a_bug": "Vaikuttaa siltä, että löysit bugin Invidiousista!",
+ "subscriptions_unseen_notifs_count": "{{count}} näkemätön ilmoitus",
+ "subscriptions_unseen_notifs_count_plural": "{{count}} näkemätöntä ilmoitusta",
+ "crash_page_switch_instance": "yrittänyt <a href=\"`x`\">käyttää toista instassia</a>",
+ "videoinfo_invidious_embed_link": "Upotuslinkki",
+ "user_saved_playlists": "`x` tallennetua soittolistaa",
+ "crash_page_report_issue": "Jos mikään näistä ei auttanut, <a href=\"`x`\">avaathan uuden issuen GitHubissa</a> (mieluiten englanniksi) ja sisällytät seuraavan tekstin viestissäsi (ÄLÄ käännä tätä tekstiä):",
+ "preferences_quality_option_hd720": "HD720",
+ "preferences_quality_dash_option_worst": "Huonoin",
+ "preferences_quality_dash_option_4320p": "4320p",
+ "preferences_quality_dash_option_2160p": "2160p",
+ "preferences_quality_dash_option_1080p": "1080p",
+ "preferences_quality_dash_option_480p": "480p",
+ "preferences_quality_dash_option_360p": "360p",
+ "preferences_quality_dash_option_240p": "240p",
+ "preferences_quality_dash_option_144p": "144p",
+ "invidious": "Invidious",
+ "preferences_region_label": "Sisältömaa: ",
+ "preferences_quality_option_medium": "Keskitaso",
+ "preferences_quality_option_small": "Pieni",
+ "preferences_quality_dash_option_auto": "Auto",
+ "preferences_quality_dash_option_best": "Paras",
+ "preferences_quality_option_dash": "DASH (mukautuva laatu)",
+ "preferences_quality_dash_label": "Haluttava DASH-videolaatu: ",
+ "generic_count_years": "{{count}} vuosi",
+ "generic_count_years_plural": "{{count}} vuotta",
+ "purchased": "Ostettu",
+ "360": "360°",
+ "videoinfo_watch_on_youTube": "Katso YouTubessa",
+ "none": "ei mikään",
+ "videoinfo_started_streaming_x_ago": "Striimaaminen aloitettu `x` sitten",
+ "preferences_save_player_pos_label": "Tallenna toistokohta: ",
+ "footer_donate_page": "Lahjoita",
+ "footer_source_code": "Lähdekoodi",
+ "adminprefs_modified_source_code_url_label": "URL muokattuun lähdekoodirepositoryyn",
+ "Released under the AGPLv3 on Github.": "Julkaistu AGPLv3-lisenssin alla GitHubissa.",
+ "short": "Lyhyt (< 4 minuuttia)",
+ "long": "Pitkä (> 20 minuuttia)",
+ "footer_documentation": "Dokumentaatio",
+ "footer_original_source_code": "Alkuperäinen lähdekoodi",
+ "footer_modfied_source_code": "Muokattu lähdekoodi"
}
diff --git a/src/invidious.cr b/src/invidious.cr
index 8ba62503..b09f31c2 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -112,22 +112,7 @@ OUTPUT = CONFIG.output.upcase == "STDOUT" ? STDOUT : File.open(CONFIG.output, mo
LOGGER = Invidious::LogHandler.new(OUTPUT, CONFIG.log_level)
# Check table integrity
-if CONFIG.check_tables
- Invidious::Database.check_enum(PG_DB, "privacy", PlaylistPrivacy)
-
- Invidious::Database.check_table(PG_DB, "channels", InvidiousChannel)
- Invidious::Database.check_table(PG_DB, "channel_videos", ChannelVideo)
- Invidious::Database.check_table(PG_DB, "playlists", InvidiousPlaylist)
- Invidious::Database.check_table(PG_DB, "playlist_videos", PlaylistVideo)
- Invidious::Database.check_table(PG_DB, "nonces", Nonce)
- Invidious::Database.check_table(PG_DB, "session_ids", SessionId)
- Invidious::Database.check_table(PG_DB, "users", User)
- Invidious::Database.check_table(PG_DB, "videos", Video)
-
- if CONFIG.cache_annotations
- Invidious::Database.check_table(PG_DB, "annotations", Annotation)
- end
-end
+Invidious::Database.check_integrity(CONFIG)
# Resolve player dependencies. This is done at compile time.
#
diff --git a/src/invidious/channels/channels.cr b/src/invidious/channels/channels.cr
index 155ec559..6905b6f8 100644
--- a/src/invidious/channels/channels.cr
+++ b/src/invidious/channels/channels.cr
@@ -114,8 +114,9 @@ class ChannelRedirect < Exception
end
end
-def get_batch_channels(channels, refresh = false, pull_all_videos = true, max_threads = 10)
+def get_batch_channels(channels)
finished_channel = Channel(String | Nil).new
+ max_threads = 10
spawn do
active_threads = 0
@@ -130,7 +131,7 @@ def get_batch_channels(channels, refresh = false, pull_all_videos = true, max_th
active_threads += 1
spawn do
begin
- get_channel(ucid, refresh, pull_all_videos)
+ get_channel(ucid)
finished_channel.send(ucid)
rescue ex
finished_channel.send(nil)
@@ -151,23 +152,20 @@ def get_batch_channels(channels, refresh = false, pull_all_videos = true, max_th
return final
end
-def get_channel(id, refresh = true, pull_all_videos = true)
- if channel = Invidious::Database::Channels.select(id)
- if refresh && Time.utc - channel.updated > 10.minutes
- channel = fetch_channel(id, pull_all_videos: pull_all_videos)
- Invidious::Database::Channels.insert(channel, update_on_conflict: true)
- end
- else
- channel = fetch_channel(id, pull_all_videos: pull_all_videos)
- Invidious::Database::Channels.insert(channel)
+def get_channel(id) : InvidiousChannel
+ channel = Invidious::Database::Channels.select(id)
+
+ if channel.nil? || (Time.utc - channel.updated) > 2.days
+ channel = fetch_channel(id, pull_all_videos: false)
+ Invidious::Database::Channels.insert(channel, update_on_conflict: true)
end
return channel
end
-def fetch_channel(ucid, pull_all_videos = true, locale = nil)
+def fetch_channel(ucid, pull_all_videos : Bool)
LOGGER.debug("fetch_channel: #{ucid}")
- LOGGER.trace("fetch_channel: #{ucid} : pull_all_videos = #{pull_all_videos}, locale = #{locale}")
+ LOGGER.trace("fetch_channel: #{ucid} : pull_all_videos = #{pull_all_videos}")
LOGGER.trace("fetch_channel: #{ucid} : Downloading RSS feed")
rss = YT_POOL.client &.get("/feeds/videos.xml?channel_id=#{ucid}").body
diff --git a/src/invidious/database/base.cr b/src/invidious/database/base.cr
index 6e49ea1a..0fb1b6af 100644
--- a/src/invidious/database/base.cr
+++ b/src/invidious/database/base.cr
@@ -3,26 +3,52 @@ require "pg"
module Invidious::Database
extend self
- def check_enum(db, enum_name, struct_type = nil)
+ # Checks table integrity
+ #
+ # Note: config is passed as a parameter to avoid complex
+ # dependencies between different parts of the software.
+ def check_integrity(cfg)
+ return if !cfg.check_tables
+ Invidious::Database.check_enum("privacy", PlaylistPrivacy)
+
+ Invidious::Database.check_table("channels", InvidiousChannel)
+ Invidious::Database.check_table("channel_videos", ChannelVideo)
+ Invidious::Database.check_table("playlists", InvidiousPlaylist)
+ Invidious::Database.check_table("playlist_videos", PlaylistVideo)
+ Invidious::Database.check_table("nonces", Nonce)
+ Invidious::Database.check_table("session_ids", SessionId)
+ Invidious::Database.check_table("users", User)
+ Invidious::Database.check_table("videos", Video)
+
+ if cfg.cache_annotations
+ Invidious::Database.check_table("annotations", Annotation)
+ end
+ end
+
+ #
+ # Table/enum integrity checks
+ #
+
+ def check_enum(enum_name, struct_type = nil)
return # TODO
- if !db.query_one?("SELECT true FROM pg_type WHERE typname = $1", enum_name, as: Bool)
+ if !PG_DB.query_one?("SELECT true FROM pg_type WHERE typname = $1", enum_name, as: Bool)
LOGGER.info("check_enum: CREATE TYPE #{enum_name}")
- db.using_connection do |conn|
+ PG_DB.using_connection do |conn|
conn.as(PG::Connection).exec_all(File.read("config/sql/#{enum_name}.sql"))
end
end
end
- def check_table(db, table_name, struct_type = nil)
+ def check_table(table_name, struct_type = nil)
# Create table if it doesn't exist
begin
- db.exec("SELECT * FROM #{table_name} LIMIT 0")
+ PG_DB.exec("SELECT * FROM #{table_name} LIMIT 0")
rescue ex
LOGGER.info("check_table: check_table: CREATE TABLE #{table_name}")
- db.using_connection do |conn|
+ PG_DB.using_connection do |conn|
conn.as(PG::Connection).exec_all(File.read("config/sql/#{table_name}.sql"))
end
end
@@ -30,7 +56,7 @@ module Invidious::Database
return if !struct_type
struct_array = struct_type.type_array
- column_array = get_column_array(db, table_name)
+ column_array = get_column_array(PG_DB, table_name)
column_types = File.read("config/sql/#{table_name}.sql").match(/CREATE TABLE public\.#{table_name}\n\((?<types>[\d\D]*?)\);/)
.try &.["types"].split(",").map(&.strip).reject &.starts_with?("CONSTRAINT")
@@ -41,14 +67,14 @@ module Invidious::Database
if !column_array[i]?
new_column = column_types.select(&.starts_with?(name))[0]
LOGGER.info("check_table: ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
- db.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
+ PG_DB.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
next
end
# Column doesn't exist
if !column_array.includes? name
new_column = column_types.select(&.starts_with?(name))[0]
- db.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
+ PG_DB.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
end
# Column exists but in the wrong position, rotate
@@ -59,29 +85,29 @@ module Invidious::Database
# There's a column we didn't expect
if !new_column
LOGGER.info("check_table: ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]}")
- db.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
+ PG_DB.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
- column_array = get_column_array(db, table_name)
+ column_array = get_column_array(PG_DB, table_name)
next
end
LOGGER.info("check_table: ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
- db.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
+ PG_DB.exec("ALTER TABLE #{table_name} ADD COLUMN #{new_column}")
LOGGER.info("check_table: UPDATE #{table_name} SET #{column_array[i]}_new=#{column_array[i]}")
- db.exec("UPDATE #{table_name} SET #{column_array[i]}_new=#{column_array[i]}")
+ PG_DB.exec("UPDATE #{table_name} SET #{column_array[i]}_new=#{column_array[i]}")
LOGGER.info("check_table: ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
- db.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
+ PG_DB.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
LOGGER.info("check_table: ALTER TABLE #{table_name} RENAME COLUMN #{column_array[i]}_new TO #{column_array[i]}")
- db.exec("ALTER TABLE #{table_name} RENAME COLUMN #{column_array[i]}_new TO #{column_array[i]}")
+ PG_DB.exec("ALTER TABLE #{table_name} RENAME COLUMN #{column_array[i]}_new TO #{column_array[i]}")
- column_array = get_column_array(db, table_name)
+ column_array = get_column_array(PG_DB, table_name)
end
else
LOGGER.info("check_table: ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
- db.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
+ PG_DB.exec("ALTER TABLE #{table_name} DROP COLUMN #{column_array[i]} CASCADE")
end
end
end
@@ -91,14 +117,14 @@ module Invidious::Database
column_array.each do |column|
if !struct_array.includes? column
LOGGER.info("check_table: ALTER TABLE #{table_name} DROP COLUMN #{column} CASCADE")
- db.exec("ALTER TABLE #{table_name} DROP COLUMN #{column} CASCADE")
+ PG_DB.exec("ALTER TABLE #{table_name} DROP COLUMN #{column} CASCADE")
end
end
end
def get_column_array(db, table_name)
column_array = [] of String
- db.query("SELECT * FROM #{table_name} LIMIT 0") do |rs|
+ PG_DB.query("SELECT * FROM #{table_name} LIMIT 0") do |rs|
rs.column_count.times do |i|
column = rs.as(PG::ResultSet).field(i)
column_array << column.name
diff --git a/src/invidious/database/channels.cr b/src/invidious/database/channels.cr
index 134cf59d..df44e485 100644
--- a/src/invidious/database/channels.cr
+++ b/src/invidious/database/channels.cr
@@ -35,21 +35,31 @@ module Invidious::Database::Channels
def update_author(id : String, author : String)
request = <<-SQL
UPDATE channels
- SET updated = $1, author = $2, deleted = false
- WHERE id = $3
+ SET updated = now(), author = $1, deleted = false
+ WHERE id = $2
+ SQL
+
+ PG_DB.exec(request, author, id)
+ end
+
+ def update_subscription_time(id : String)
+ request = <<-SQL
+ UPDATE channels
+ SET subscribed = now()
+ WHERE id = $1
SQL
- PG_DB.exec(request, Time.utc, author, id)
+ PG_DB.exec(request, id)
end
def update_mark_deleted(id : String)
request = <<-SQL
UPDATE channels
- SET updated = $1, deleted = true
- WHERE id = $2
+ SET updated = now(), deleted = true
+ WHERE id = $1
SQL
- PG_DB.exec(request, Time.utc, id)
+ PG_DB.exec(request, id)
end
# -------------------
@@ -67,14 +77,13 @@ module Invidious::Database::Channels
def select(ids : Array(String)) : Array(InvidiousChannel)?
return [] of InvidiousChannel if ids.empty?
- values = ids.map { |id| %(('#{id}')) }.join(",")
request = <<-SQL
SELECT * FROM channels
- WHERE id = ANY(VALUES #{values})
+ WHERE id = ANY($1)
SQL
- return PG_DB.query_all(request, as: InvidiousChannel)
+ return PG_DB.query_all(request, ids, as: InvidiousChannel)
end
end
@@ -117,11 +126,11 @@ module Invidious::Database::ChannelVideos
request = <<-SQL
SELECT * FROM channel_videos
- WHERE id IN (#{arg_array(ids)})
+ WHERE id = ANY($1)
ORDER BY published DESC
SQL
- return PG_DB.query_all(request, args: ids, as: ChannelVideo)
+ return PG_DB.query_all(request, ids, as: ChannelVideo)
end
def select_notfications(ucid : String, since : Time) : Array(ChannelVideo)
diff --git a/src/invidious/database/playlists.cr b/src/invidious/database/playlists.cr
index 7a5f61dc..c6754a1e 100644
--- a/src/invidious/database/playlists.cr
+++ b/src/invidious/database/playlists.cr
@@ -59,11 +59,11 @@ module Invidious::Database::Playlists
def update_subscription_time(id : String)
request = <<-SQL
UPDATE playlists
- SET subscribed = $1
- WHERE id = $2
+ SET subscribed = now()
+ WHERE id = $1
SQL
- PG_DB.exec(request, Time.utc, id)
+ PG_DB.exec(request, id)
end
def update_video_added(id : String, index : String | Int64)
@@ -71,11 +71,11 @@ module Invidious::Database::Playlists
UPDATE playlists
SET index = array_append(index, $1),
video_count = cardinality(index) + 1,
- updated = $2
- WHERE id = $3
+ updated = now()
+ WHERE id = $2
SQL
- PG_DB.exec(request, index, Time.utc, id)
+ PG_DB.exec(request, index, id)
end
def update_video_removed(id : String, index : String | Int64)
@@ -83,28 +83,24 @@ module Invidious::Database::Playlists
UPDATE playlists
SET index = array_remove(index, $1),
video_count = cardinality(index) - 1,
- updated = $2
- WHERE id = $3
+ updated = now()
+ WHERE id = $2
SQL
- PG_DB.exec(request, index, Time.utc, id)
+ PG_DB.exec(request, index, id)
end
# -------------------
# Salect
# -------------------
- def select(*, id : String, raise_on_fail : Bool = false) : InvidiousPlaylist?
+ def select(*, id : String) : InvidiousPlaylist?
request = <<-SQL
SELECT * FROM playlists
WHERE id = $1
SQL
- if raise_on_fail
- return PG_DB.query_one(request, id, as: InvidiousPlaylist)
- else
- return PG_DB.query_one?(request, id, as: InvidiousPlaylist)
- end
+ return PG_DB.query_one?(request, id, as: InvidiousPlaylist)
end
def select_all(*, author : String) : Array(InvidiousPlaylist)
diff --git a/src/invidious/database/sessions.cr b/src/invidious/database/sessions.cr
index d5f85dd6..96587082 100644
--- a/src/invidious/database/sessions.cr
+++ b/src/invidious/database/sessions.cr
@@ -10,12 +10,12 @@ module Invidious::Database::SessionIDs
def insert(sid : String, email : String, handle_conflicts : Bool = false)
request = <<-SQL
INSERT INTO session_ids
- VALUES ($1, $2, $3)
+ VALUES ($1, $2, now())
SQL
request += " ON CONFLICT (id) DO NOTHING" if handle_conflicts
- PG_DB.exec(request, sid, email, Time.utc)
+ PG_DB.exec(request, sid, email)
end
# -------------------
diff --git a/src/invidious/database/users.cr b/src/invidious/database/users.cr
index 53724dbf..26be4270 100644
--- a/src/invidious/database/users.cr
+++ b/src/invidious/database/users.cr
@@ -143,11 +143,11 @@ module Invidious::Database::Users
def clear_notifications(user : User)
request = <<-SQL
UPDATE users
- SET notifications = '{}', updated = $1
- WHERE email = $2
+ SET notifications = '{}', updated = now()
+ WHERE email = $1
SQL
- PG_DB.exec(request, Time.utc, user.email)
+ PG_DB.exec(request, user.email)
end
# -------------------
diff --git a/src/invidious/jobs/refresh_channels_job.cr b/src/invidious/jobs/refresh_channels_job.cr
index 941089c1..55fb8154 100644
--- a/src/invidious/jobs/refresh_channels_job.cr
+++ b/src/invidious/jobs/refresh_channels_job.cr
@@ -30,7 +30,7 @@ class Invidious::Jobs::RefreshChannelsJob < Invidious::Jobs::BaseJob
spawn do
begin
LOGGER.trace("RefreshChannelsJob: #{id} fiber : Fetching channel")
- channel = fetch_channel(id, CONFIG.full_refresh)
+ channel = fetch_channel(id, pull_all_videos: CONFIG.full_refresh)
lim_fibers = max_fibers
diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr
index fda655ef..4d0fe030 100644
--- a/src/invidious/routes/api/v1/authenticated.cr
+++ b/src/invidious/routes/api/v1/authenticated.cr
@@ -92,7 +92,7 @@ module Invidious::Routes::API::V1::Authenticated
ucid = env.params.url["ucid"]
if !user.subscriptions.includes? ucid
- get_channel(ucid, false, false)
+ get_channel(ucid)
Invidious::Database::Users.subscribe_channel(user, ucid)
end
diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr
index fd8c25ce..c323cdf7 100644
--- a/src/invidious/routes/feeds.cr
+++ b/src/invidious/routes/feeds.cr
@@ -362,7 +362,7 @@ module Invidious::Routes::Feeds
end
if ucid = HTTP::Params.parse(URI.parse(topic).query.not_nil!)["channel_id"]?
- PG_DB.exec("UPDATE channels SET subscribed = $1 WHERE id = $2", Time.utc, ucid)
+ Invidious::Database::Channels.update_subscription_time(ucid)
elsif plid = HTTP::Params.parse(URI.parse(topic).query.not_nil!)["playlist_id"]?
Invidious::Database::Playlists.update_subscription_time(plid)
else
diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr
index d437b79c..1c4f1bef 100644
--- a/src/invidious/routes/playlists.cr
+++ b/src/invidious/routes/playlists.cr
@@ -151,12 +151,8 @@ module Invidious::Routes::Playlists
page = env.params.query["page"]?.try &.to_i?
page ||= 1
- begin
- playlist = Invidious::Database::Playlists.select(id: plid, raise_on_fail: true)
- if !playlist || playlist.author != user.email
- return env.redirect referer
- end
- rescue ex
+ playlist = Invidious::Database::Playlists.select(id: plid)
+ if !playlist || playlist.author != user.email
return env.redirect referer
end
@@ -235,12 +231,8 @@ module Invidious::Routes::Playlists
page = env.params.query["page"]?.try &.to_i?
page ||= 1
- begin
- playlist = Invidious::Database::Playlists.select(id: plid, raise_on_fail: true)
- if !playlist || playlist.author != user.email
- return env.redirect referer
- end
- rescue ex
+ playlist = Invidious::Database::Playlists.select(id: plid)
+ if !playlist || playlist.author != user.email
return env.redirect referer
end
diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr
index faae03bc..9c740cf2 100644
--- a/src/invidious/routes/preferences.cr
+++ b/src/invidious/routes/preferences.cr
@@ -327,7 +327,7 @@ module Invidious::Routes::PreferencesRoute
user.subscriptions += body["subscriptions"].as_a.map(&.as_s)
user.subscriptions.uniq!
- user.subscriptions = get_batch_channels(user.subscriptions, false, false)
+ user.subscriptions = get_batch_channels(user.subscriptions)
Invidious::Database::Users.update_subscriptions(user)
end
@@ -409,7 +409,7 @@ module Invidious::Routes::PreferencesRoute
end
user.subscriptions.uniq!
- user.subscriptions = get_batch_channels(user.subscriptions, false, false)
+ user.subscriptions = get_batch_channels(user.subscriptions)
Invidious::Database::Users.update_subscriptions(user)
when "import_freetube"
@@ -418,7 +418,7 @@ module Invidious::Routes::PreferencesRoute
end
user.subscriptions.uniq!
- user.subscriptions = get_batch_channels(user.subscriptions, false, false)
+ user.subscriptions = get_batch_channels(user.subscriptions)
Invidious::Database::Users.update_subscriptions(user)
when "import_newpipe_subscriptions"
@@ -437,7 +437,7 @@ module Invidious::Routes::PreferencesRoute
end
user.subscriptions.uniq!
- user.subscriptions = get_batch_channels(user.subscriptions, false, false)
+ user.subscriptions = get_batch_channels(user.subscriptions)
Invidious::Database::Users.update_subscriptions(user)
when "import_newpipe"
@@ -456,7 +456,7 @@ module Invidious::Routes::PreferencesRoute
user.subscriptions += db.query_all("SELECT url FROM subscriptions", as: String).map(&.lchop("https://www.youtube.com/channel/"))
user.subscriptions.uniq!
- user.subscriptions = get_batch_channels(user.subscriptions, false, false)
+ user.subscriptions = get_batch_channels(user.subscriptions)
Invidious::Database::Users.update_subscriptions(user)
diff --git a/src/invidious/routes/subscriptions.cr b/src/invidious/routes/subscriptions.cr
index 29152afb..ec8fe67b 100644
--- a/src/invidious/routes/subscriptions.cr
+++ b/src/invidious/routes/subscriptions.cr
@@ -51,7 +51,7 @@ module Invidious::Routes::Subscriptions
case action
when "action_create_subscription_to_channel"
if !user.subscriptions.includes? channel_id
- get_channel(channel_id, false, false)
+ get_channel(channel_id)
Invidious::Database::Users.subscribe_channel(user, channel_id)
end
when "action_remove_subscriptions"
diff --git a/src/invidious/users.cr b/src/invidious/users.cr
index 49074994..a7ee72a9 100644
--- a/src/invidious/users.cr
+++ b/src/invidious/users.cr
@@ -74,7 +74,7 @@ def fetch_user(sid, headers)
end
end
- channels = get_batch_channels(channels, false, false)
+ channels = get_batch_channels(channels)
email = feed.xpath_node(%q(//a[@class="yt-masthead-picker-header yt-masthead-picker-active-account"]))
if email