diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index ff28d49b..11168aea 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -22,3 +22,5 @@ jobs: stale-issue-label: "stale" stale-pr-label: "stale" ascending: true + # Never mark feature requests/enhancements as stale + exempt-issue-labels: "feature-request,enhancement" diff --git a/README.md b/README.md index f1a7bddc..28d3323d 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ Weblate also allows you to log-in with major SSO providers like Github, Gitlab, - [FreeTube](https://github.com/FreeTubeApp/FreeTube): A libre software YouTube app for privacy. - [CloudTube](https://sr.ht/~cadence/tube/): A JavaScript-rich alternate YouTube player. -- [PeerTubeify](https://gitlab.com/Cha_deL/peertubeify): On YouTube, displays a link to the same video on PeerTube, if it exists. +- [PeerTubeify](https://gitlab.com/Cha_de_L/peertubeify): On YouTube, displays a link to the same video on PeerTube, if it exists. - [MusicPiped](https://github.com/deep-gaurav/MusicPiped): A material design music player that streams music from YouTube. - [HoloPlay](https://github.com/stephane-r/HoloPlay): Funny Android application connecting on Invidious API's with search, playlists and favorites. - [WatchTube](https://github.com/WatchTubeTeam/WatchTube): Powerful YouTube client for Apple Watch. diff --git a/config/config.example.yml b/config/config.example.yml index 10734c3a..160a2750 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -453,7 +453,13 @@ feed_threads: 1 ## #modified_source_code_url: "" - +## +## Maximum custom playlist length limit. +## +## Accepted values: Integer +## Default: 500 +## +#playlist_length_limit: 500 ######################################### # @@ -859,7 +865,7 @@ default_user_preferences: ## Default: false ## #automatic_instance_redirect: false - + ## ## Show the entire video description by default (when set to 'false', ## only the first few lines of the description are shown and a diff --git a/locales/fr.json b/locales/fr.json index e526648f..2f384eb1 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -471,5 +471,6 @@ "search_filters_type_option_all": "Tous les types", "search_filters_date_label": "Date d'ajout", "search_filters_features_option_vr180": "VR180", - "search_filters_duration_option_none": "Toutes les durées" + "search_filters_duration_option_none": "Toutes les durées", + "error_video_not_in_playlist": "La vidéo demandée n'existe pas dans cette liste de lecture. Cliquez ici pour retourner à la liste de lecture." } diff --git a/locales/ko.json b/locales/ko.json index 0964a563..26412d0c 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -72,7 +72,7 @@ "Previous page": "이전 페이지", "Next page": "다음 페이지", "last": "마지막", - "Shared `x` ago": "`x` 전에 공유", + "Shared `x` ago": "`x` 전", "popular": "인기", "oldest": "오래된순", "newest": "최신순", @@ -313,10 +313,10 @@ "Swahili": "스와힐리어", "Sundanese": "순다어", "generic_count_years_0": "{{count}} 년", - "generic_count_months_0": "{{count}} 월", + "generic_count_months_0": "{{count}} 개월", "generic_count_weeks_0": "{{count}} 주", "generic_count_days_0": "{{count}} 일", - "generic_count_hours_0": "{{count}} 시", + "generic_count_hours_0": "{{count}} 시간", "generic_count_minutes_0": "{{count}} 분", "generic_count_seconds_0": "{{count}} 초", "Zulu": "줄루어", @@ -438,5 +438,6 @@ "search_filters_type_option_all": "모든 유형", "footer_donate_page": "기부하기", "preferences_quality_option_dash": "DASH (적절한 화질)", - "preferences_quality_dash_option_360p": "360p" + "preferences_quality_dash_option_360p": "360p", + "preferences_save_player_pos_label": "이어서 보기 활성화 " } diff --git a/locales/pl.json b/locales/pl.json index 37f951a3..f1a07490 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -54,7 +54,7 @@ "preferences_continue_label": "Domyślnie odtwarzaj następny: ", "preferences_continue_autoplay_label": "Odtwórz następny film: ", "preferences_listen_label": "Tryb dźwiękowy: ", - "preferences_local_label": "Filmy przez proxy? ", + "preferences_local_label": "Wideo przez proxy? ", "preferences_speed_label": "Domyślna prędkość: ", "preferences_quality_label": "Preferowana jakość filmów: ", "preferences_volume_label": "Głośność odtwarzacza: ", @@ -112,7 +112,7 @@ "Registration enabled: ": "Rejestracja włączona? ", "Report statistics: ": "Raportować statystyki? ", "Save preferences": "Zapisz preferencje", - "Subscription manager": "Manager subskrybcji", + "Subscription manager": "Menedżer subskrypcji", "Token manager": "Menedżer tokenów", "Token": "Token", "Import/export": "Import/Eksport", @@ -283,7 +283,7 @@ "Somali": "somalijski", "Southern Sotho": "sotho południowy", "Spanish": "hiszpański", - "Spanish (Latin America)": "hiszpański (ameryka łacińska)", + "Spanish (Latin America)": "hiszpański (Ameryka Łacińska)", "Sundanese": "sundajski", "Swahili": "suahili", "Swedish": "szwedzki", @@ -329,32 +329,32 @@ "Community": "Społeczność", "search_filters_sort_option_relevance": "Trafność", "search_filters_sort_option_rating": "Ocena", - "search_filters_sort_option_date": "data", + "search_filters_sort_option_date": "Data przesłania", "search_filters_sort_option_views": "Liczba wyświetleń", "search_filters_type_label": "Typ", "search_filters_duration_label": "Długość", "search_filters_features_label": "Funkcje", - "search_filters_sort_label": "sortuj", - "search_filters_date_option_hour": "godzina", - "search_filters_date_option_today": "dzisiaj", - "search_filters_date_option_week": "tydzień", - "search_filters_date_option_month": "miesiąc", - "search_filters_date_option_year": "rok", - "search_filters_type_option_video": "Film", - "search_filters_type_option_channel": "kanał", - "search_filters_type_option_playlist": "playlista", - "search_filters_type_option_movie": "film", - "search_filters_type_option_show": "pokaż", - "search_filters_features_option_hd": "hd", - "search_filters_features_option_subtitles": "napisy", - "search_filters_features_option_c_commons": "creative_commons", - "search_filters_features_option_three_d": "3d", + "search_filters_sort_label": "Sortuj wg", + "search_filters_date_option_hour": "Ostatnia godzina", + "search_filters_date_option_today": "Dzisiaj", + "search_filters_date_option_week": "W tym tygodniu", + "search_filters_date_option_month": "W tym miesiącu", + "search_filters_date_option_year": "W tym roku", + "search_filters_type_option_video": "Wideo", + "search_filters_type_option_channel": "Kanał", + "search_filters_type_option_playlist": "Playlista", + "search_filters_type_option_movie": "Film", + "search_filters_type_option_show": "Pokaż", + "search_filters_features_option_hd": "HD", + "search_filters_features_option_subtitles": "Napisy/CC", + "search_filters_features_option_c_commons": "Creative Commons", + "search_filters_features_option_three_d": "3D", "search_filters_features_option_live": "Na żywo", - "search_filters_features_option_four_k": "4k", + "search_filters_features_option_four_k": "4K", "search_filters_features_option_location": "Lokalizacja", - "search_filters_features_option_hdr": "hdr", + "search_filters_features_option_hdr": "HDR", "Current version: ": "Aktualna wersja: ", - "next_steps_error_message": "Po czym powinien*ś spróbować: ", + "next_steps_error_message": "Po czym należy spróbować: ", "next_steps_error_message_refresh": "Odśwież", "next_steps_error_message_go_to_youtube": "Przejdź do YouTube", "invidious": "Invidious", @@ -397,11 +397,11 @@ "generic_count_seconds_0": "{{count}} sekunda", "generic_count_seconds_1": "{{count}} sekundy", "generic_count_seconds_2": "{{count}} sekund", - "crash_page_you_found_a_bug": "Wygląda na to że udało ci się znaleźć błąd w Invidious!", + "crash_page_you_found_a_bug": "Wygląda na to, że udało ci się znaleźć błąd w Invidious!", "crash_page_refresh": "próbowano odświeżyć stronę", - "crash_page_switch_instance": "spróbowano użyć innej instancji", - "crash_page_read_the_faq": "przeczytaj Często Zadawane Pytania (FAQ)", - "crash_page_search_issue": "próbowano poszukać istniejących zgłoszeń na GitHub'ie", + "crash_page_switch_instance": "próbowano użyć innej instancji", + "crash_page_read_the_faq": "przeczytaj Najczęściej zadawane pytania (FAQ)", + "crash_page_search_issue": "próbowano poszukać istniejących zgłoszeń na GitHubie", "preferences_quality_dash_option_1440p": "1440p", "preferences_quality_dash_option_720p": "720p", "preferences_quality_dash_option_144p": "144p", @@ -418,12 +418,12 @@ "generic_count_years_0": "{{count}} rok", "generic_count_years_1": "{{count}} lata", "generic_count_years_2": "{{count}} lat", - "crash_page_before_reporting": "Przed zgłoszeniem błędu, upewnij się że masz:", - "crash_page_report_issue": "Jeżeli nic z powyższych opcji nie pomogło, proszę otworzyć nowe zgłoszenie na GitHub'ie (najlepiej po Angielsku) i dodać poniższy tekst w twojej wiadomości (NIE tłumacz tego tekstu):", + "crash_page_before_reporting": "Przed zgłoszeniem błędu, upewnij się, że masz:", + "crash_page_report_issue": "Jeżeli nic z powyższych opcji nie pomogło, proszę otworzyć nowe zgłoszenie na GitHubie (najlepiej po angielsku) i dodać poniższy tekst w twojej wiadomości (NIE tłumacz tego tekstu):", "preferences_quality_dash_option_auto": "Automatyczna", "preferences_quality_dash_option_best": "Najlepsza", "preferences_quality_dash_option_worst": "Najgorsza", - "preferences_quality_option_dash": "DASH (jakość adaptywna)", + "preferences_quality_option_dash": "DASH (jakość adaptacyjna)", "preferences_quality_option_hd720": "HD720", "preferences_quality_option_medium": "Średnia", "preferences_quality_option_small": "Mała", @@ -445,19 +445,19 @@ "preferences_save_player_pos_label": "Zapisz pozycję odtwarzania: ", "preferences_region_label": "Region zawartości: ", "Released under the AGPLv3 on Github.": "Wydany na licencji AGPLv3 na GitHub.", - "search_filters_duration_option_short": "Krótkie (< 4 minutes)", - "search_filters_duration_option_long": "Długie (> 20 minutes)", + "search_filters_duration_option_short": "Krótka (< 4 minut)", + "search_filters_duration_option_long": "Długa (> 20 minut)", "footer_documentation": "Dokumentacja", "footer_source_code": "Kod źródłowy", - "footer_modfied_source_code": "Zmodyfikowany Kod źródłowy", + "footer_modfied_source_code": "Zmodyfikowany kod źródłowy", "footer_original_source_code": "Oryginalny kod źródłowy", - "adminprefs_modified_source_code_url_label": "Adres URL do repozytorium z zmodyfikowanym kodem źródłowym", + "adminprefs_modified_source_code_url_label": "Adres URL do repozytorium ze zmodyfikowanym kodem źródłowym", "English (United Kingdom)": "angielski (Wielka Brytania)", "English (United States)": "angielski (Stany Zjednoczone)", - "Cantonese (Hong Kong)": "kantoński (Hong Kong)", + "Cantonese (Hong Kong)": "kantoński (Hongkong)", "Chinese": "chiński", "Chinese (China)": "chiński (Chiny)", - "Chinese (Hong Kong)": "chiński (Hong Kong)", + "Chinese (Hong Kong)": "chiński (Hongkong)", "Chinese (Taiwan)": "chiński (Tajwan)", "Dutch (auto-generated)": "niderlandzki (wygenerowany automatycznie)", "French (auto-generated)": "francuski (wygenerowany automatycznie)", @@ -475,5 +475,18 @@ "Russian (auto-generated)": "rosyjski (wygenerowany automatycznie)", "Portuguese (auto-generated)": "portugalski (wygenerowany automatycznie)", "Portuguese (Brazil)": "portugalski (Brazylia)", - "search_filters_title": "Filtr" + "search_filters_title": "Filtr", + "error_video_not_in_playlist": "Żądany film nie istnieje na tej playliście. Kliknij tutaj, aby przejść do strony głównej playlisty.", + "Popular enabled: ": "Popularne włączone: ", + "search_message_no_results": "Nie znaleziono wyników.", + "preferences_watch_history_label": "Włącz historię oglądania: ", + "search_filters_apply_button": "Zastosuj wybrane filtry", + "search_message_change_filters_or_query": "Spróbuj poszerzyć zapytanie i/lub zmienić filtry.", + "search_filters_date_label": "Data przesłania", + "search_filters_features_option_vr180": "VR180", + "search_filters_date_option_none": "Dowolna data", + "search_message_use_another_instance": " Możesz także wyszukać w innej instancji.", + "search_filters_type_option_all": "Dowolny typ", + "search_filters_duration_option_none": "Dowolna długość", + "search_filters_duration_option_medium": "Średnia (4-20 minut)" } diff --git a/locales/pt.json b/locales/pt.json index 654cfdeb..b550bc87 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -471,5 +471,6 @@ "search_filters_date_option_none": "Qualquer data", "search_filters_type_option_all": "Qualquer tipo", "search_filters_duration_option_none": "Qualquer duração", - "Popular enabled: ": "Página \"popular\" ativada: " + "Popular enabled: ": "Página \"popular\" ativada: ", + "error_video_not_in_playlist": "O vídeo pedido não existe nesta lista de reprodução. Clique aqui para a página inicial da lista de reprodução." } diff --git a/locales/ru.json b/locales/ru.json index 962c82ec..93c9cbec 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -487,5 +487,6 @@ "search_message_change_filters_or_query": "Попробуйте расширить поисковый запрос или изменить фильтры.", "search_filters_duration_option_medium": "Средние (4 - 20 минут)", "search_filters_apply_button": "Применить фильтры", - "Popular enabled: ": "Популярное включено: " + "Popular enabled: ": "Популярное включено: ", + "error_video_not_in_playlist": "Запрошенного видео нет в этом плейлисте. Нажмите тут, чтобы вернуться к странице плейлиста." } diff --git a/src/invidious/config.cr b/src/invidious/config.cr index 38c15439..c1ec3e21 100644 --- a/src/invidious/config.cr +++ b/src/invidious/config.cr @@ -131,6 +131,9 @@ class Config # API URL for Anti-Captcha property captcha_api_url : String = "https://api.anti-captcha.com" + # Playlist length limit + property playlist_length_limit : Int32 = 500 + def disabled?(option) case disabled = CONFIG.disable_proxy when Bool diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index 1f5ad8ef..421355bb 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -226,8 +226,8 @@ module Invidious::Routes::API::V1::Authenticated return error_json(403, "Invalid user") end - if playlist.index.size >= 500 - return error_json(400, "Playlist cannot have more than 500 videos") + if playlist.index.size >= CONFIG.playlist_length_limit + return error_json(400, "Playlist cannot have more than #{CONFIG.playlist_length_limit} videos") end video_id = env.params.json["videoId"].try &.as(String) diff --git a/src/invidious/routes/playlists.cr b/src/invidious/routes/playlists.cr index fe7e4e1c..0d242ee6 100644 --- a/src/invidious/routes/playlists.cr +++ b/src/invidious/routes/playlists.cr @@ -330,11 +330,11 @@ module Invidious::Routes::Playlists when "action_edit_playlist" # TODO: Playlist stub when "action_add_video" - if playlist.index.size >= 500 + if playlist.index.size >= CONFIG.playlist_length_limit if redirect - return error_template(400, "Playlist cannot have more than 500 videos") + return error_template(400, "Playlist cannot have more than #{CONFIG.playlist_length_limit} videos") else - return error_json(400, "Playlist cannot have more than 500 videos") + return error_json(400, "Playlist cannot have more than #{CONFIG.playlist_length_limit} videos") end end diff --git a/src/invidious/user/imports.cr b/src/invidious/user/imports.cr index f8b9e4e4..20ae0d47 100644 --- a/src/invidious/user/imports.cr +++ b/src/invidious/user/imports.cr @@ -71,7 +71,9 @@ struct Invidious::User Invidious::Database::Playlists.update_description(playlist.id, description) videos = item["videos"]?.try &.as_a?.try &.each_with_index do |video_id, idx| - raise InfoException.new("Playlist cannot have more than 500 videos") if idx > 500 + if idx > CONFIG.playlist_length_limit + raise InfoException.new("Playlist cannot have more than #{CONFIG.playlist_length_limit} videos") + end video_id = video_id.try &.as_s? next if !video_id