This commit is contained in:
諏訪子 2023-10-24 20:07:18 +09:00
commit 1a2c740282
66 changed files with 2353 additions and 816 deletions

View file

@ -82,7 +82,7 @@
**Data import/export**
- Import subscriptions from YouTube, NewPipe and Freetube
- Import watch history from NewPipe
- Import watch history from YouTube and NewPipe
- Export subscriptions to NewPipe and Freetube
- Import/Export Invidious user data
@ -149,7 +149,7 @@ Weblate also allows you to log-in with major SSO providers like Github, Gitlab,
- [CloudTube](https://sr.ht/~cadence/tube/): A JavaScript-rich alternate YouTube player.
- [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-wa): Progressive Web App connecting on Invidious API's with search, playlists and favorites.
- [HoloPlay](https://github.com/stephane-r/holoplay-pwa): Progressive Web App connecting on Invidious API's with search, playlists and favorites.
- [WatchTube](https://github.com/WatchTubeTeam/WatchTube): Powerful YouTube client for Apple Watch.
- [Yattee](https://github.com/yattee/yattee): Alternative YouTube frontend for iPhone, iPad, Mac and Apple TV.
- [TubiTui](https://codeberg.org/777/TubiTui): A lightweight, libre, TUI-based YouTube client.

View file

@ -392,11 +392,19 @@ p.video-data { margin: 0; font-weight: bold; font-size: 80%; }
* Comments & community posts
*/
#comments {
.comments {
max-width: 800px;
margin: auto;
}
/*
* We don't want the top and bottom margin on the post page.
*/
.comments.post-comments {
margin-bottom: 0;
margin-top: 0;
}
.video-iframe-wrapper {
position: relative;
height: 0;
@ -433,16 +441,26 @@ p.video-data { margin: 0; font-weight: bold; font-size: 80%; }
*/
footer {
color: #919191;
margin-top: auto;
padding: 1.5em 0;
text-align: center;
max-height: 30vh;
}
footer a {
color: #919191 !important;
text-decoration: underline;
.light-theme footer {
color: #7c7c7c;
}
.dark-theme footer {
color: #adadad;
}
.light-theme footer a {
color: #7c7c7c !important;
}
.dark-theme footer a {
color: #adadad !important;
}
footer span {
@ -494,7 +512,7 @@ span > select {
}
.dark-theme a {
color: #a0a0a0;
color: #adadad;
text-decoration: none;
}
@ -552,7 +570,7 @@ body.dark-theme, body.light-theme {
}
.no-theme a {
color: #a0a0a0;
color: #adadad;
text-decoration: none;
}
@ -583,6 +601,14 @@ body.dark-theme, body.light-theme {
background-color: inherit;
color: inherit;
}
.no-theme footer {
color: #adadad;
}
.no-theme footer a {
color: #adadad !important;
}
}
@ -676,3 +702,7 @@ h1, h2, h3, h4, h5, p,
.channel-emoji {
margin: 0 2px;
}
#download_widget {
width: 100%;
}

174
assets/js/comments.js Normal file
View file

@ -0,0 +1,174 @@
var video_data = JSON.parse(document.getElementById('video_data').textContent);
var spinnerHTML = '<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var spinnerHTMLwithHR = spinnerHTML + '<hr>';
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g, function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
});
};
function toggle_comments(event) {
var target = event.target;
var body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === 'none') {
target.textContent = '[ ]';
body.style.display = '';
} else {
target.textContent = '[ + ]';
body.style.display = 'none';
}
}
function hide_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body.style.display = 'none';
target.textContent = sub_text;
target.onclick = show_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
}
function show_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body.style.display = '';
target.textContent = sub_text;
target.onclick = hide_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
}
function get_youtube_comments() {
var comments = document.getElementById('comments');
var fallback = comments.innerHTML;
comments.innerHTML = spinnerHTML;
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
var url = baseUrl +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode;
if (video_data.ucid) {
url += '&ucid=' + video_data.ucid
}
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
if (video_data.params.comments[1] === 'youtube')
onNon200 = function (xhr) {};
helpers.xhr('GET', url, {retries: 5, entity_name: 'comments'}, {
on200: function (response) {
var commentInnerHtml = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ ]</a> \
{commentsText} \
</h3> \
<b> \
'
if (video_data.support_reddit) {
commentInnerHtml += ' <a href="javascript:void(0)" data-comments="reddit"> \
{redditComments} \
</a> \
'
}
commentInnerHtml += ' </b> \
</div> \
<div>{contentHtml}</div> \
<hr>'
commentInnerHtml = commentInnerHtml.supplant({
contentHtml: response.contentHtml,
redditComments: video_data.reddit_comments_text,
commentsText: video_data.comments_text.supplant({
// toLocaleString correctly splits number with local thousands separator. e.g.:
// '1,234,567.89' for user with English locale
// '1 234 567,89' for user with Russian locale
// '1.234.567,89' for user with Portuguese locale
commentCount: response.commentCount.toLocaleString()
})
});
comments.innerHTML = commentInnerHtml;
comments.children[0].children[0].children[0].onclick = toggle_comments;
if (video_data.support_reddit) {
comments.children[0].children[1].children[0].onclick = swap_comments;
}
},
onNon200: onNon200, // declared above
onError: function (xhr) {
comments.innerHTML = spinnerHTML;
},
onTimeout: function (xhr) {
comments.innerHTML = spinnerHTML;
}
});
}
function get_youtube_replies(target, load_more, load_replies) {
var continuation = target.getAttribute('data-continuation');
var body = target.parentNode.parentNode;
var fallback = body.innerHTML;
body.innerHTML = spinnerHTML;
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
var url = baseUrl +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode +
'&continuation=' + continuation;
if (video_data.ucid) {
url += '&ucid=' + video_data.ucid
}
if (load_replies) url += '&action=action_get_comment_replies';
helpers.xhr('GET', url, {}, {
on200: function (response) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.insertAdjacentHTML('beforeend', response.contentHtml);
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', video_data.hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text);
a.textContent = video_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = response.contentHtml;
body.appendChild(p);
body.appendChild(div);
}
},
onNon200: function (xhr) {
body.innerHTML = fallback;
},
onTimeout: function (xhr) {
console.warn('Pulling comments failed');
body.innerHTML = fallback;
}
});
}

View file

@ -98,11 +98,13 @@ if (video_data.params.quality === 'dash') {
/**
* Function for add time argument to url
*
* @param {String} url
* @param {String} [base]
* @returns {URL} urlWithTimeArg
*/
function addCurrentTimeToURL(url) {
var urlUsed = new URL(url);
function addCurrentTimeToURL(url, base) {
var urlUsed = new URL(url, base);
urlUsed.searchParams.delete('start');
var currentTime = Math.ceil(player.currentTime());
if (currentTime > 0)
@ -112,6 +114,50 @@ function addCurrentTimeToURL(url) {
return urlUsed;
}
/**
* Global variable to save the last timestamp (in full seconds) at which the external
* links were updated by the 'timeupdate' callback below.
*
* It is initialized to 5s so that the video will always restart from the beginning
* if the user hasn't really started watching before switching to the other website.
*/
var timeupdate_last_ts = 5;
/**
* Callback that updates the timestamp on all external links
*/
player.on('timeupdate', function () {
// Only update once every second
let current_ts = Math.floor(player.currentTime());
if (current_ts > timeupdate_last_ts) timeupdate_last_ts = current_ts;
else return;
// YouTube links
let elem_yt_watch = document.getElementById('link-yt-watch');
let elem_yt_embed = document.getElementById('link-yt-embed');
let base_url_yt_watch = elem_yt_watch.getAttribute('data-base-url');
let base_url_yt_embed = elem_yt_embed.getAttribute('data-base-url');
elem_yt_watch.href = addCurrentTimeToURL(base_url_yt_watch);
elem_yt_embed.href = addCurrentTimeToURL(base_url_yt_embed);
// Invidious links
let domain = window.location.origin;
let elem_iv_embed = document.getElementById('link-iv-embed');
let elem_iv_other = document.getElementById('link-iv-other');
let base_url_iv_embed = elem_iv_embed.getAttribute('data-base-url');
let base_url_iv_other = elem_iv_other.getAttribute('data-base-url');
elem_iv_embed.href = addCurrentTimeToURL(base_url_iv_embed, domain);
elem_iv_other.href = addCurrentTimeToURL(base_url_iv_other, domain);
});
var shareOptions = {
socials: ['fbFeed', 'tw', 'reddit', 'email'],

3
assets/js/post.js Normal file
View file

@ -0,0 +1,3 @@
addEventListener('load', function (e) {
get_youtube_comments();
});

View file

@ -1,14 +1,4 @@
'use strict';
var video_data = JSON.parse(document.getElementById('video_data').textContent);
var spinnerHTML = '<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
var spinnerHTMLwithHR = spinnerHTML + '<hr>';
String.prototype.supplant = function (o) {
return this.replace(/{([^{}]*)}/g, function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
});
};
function toggle_parent(target) {
var body = target.parentNode.parentNode.children[1];
@ -21,18 +11,6 @@ function toggle_parent(target) {
}
}
function toggle_comments(event) {
var target = event.target;
var body = target.parentNode.parentNode.parentNode.children[1];
if (body.style.display === 'none') {
target.textContent = '[ ]';
body.style.display = '';
} else {
target.textContent = '[ + ]';
body.style.display = 'none';
}
}
function swap_comments(event) {
var source = event.target.getAttribute('data-comments');
@ -43,36 +21,6 @@ function swap_comments(event) {
}
}
function hide_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body.style.display = 'none';
target.textContent = sub_text;
target.onclick = show_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
}
function show_youtube_replies(event) {
var target = event.target;
var sub_text = target.getAttribute('data-inner-text');
var inner_text = target.getAttribute('data-sub-text');
var body = target.parentNode.parentNode.children[1];
body.style.display = '';
target.textContent = sub_text;
target.onclick = hide_youtube_replies;
target.setAttribute('data-inner-text', inner_text);
target.setAttribute('data-sub-text', sub_text);
}
var continue_button = document.getElementById('continue');
if (continue_button) {
continue_button.onclick = continue_autoplay;
@ -208,111 +156,6 @@ function get_reddit_comments() {
});
}
function get_youtube_comments() {
var comments = document.getElementById('comments');
var fallback = comments.innerHTML;
comments.innerHTML = spinnerHTML;
var url = '/api/v1/comments/' + video_data.id +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode;
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
if (video_data.params.comments[1] === 'youtube')
onNon200 = function (xhr) {};
helpers.xhr('GET', url, {retries: 5, entity_name: 'comments'}, {
on200: function (response) {
comments.innerHTML = ' \
<div> \
<h3> \
<a href="javascript:void(0)">[ ]</a> \
{commentsText} \
</h3> \
<b> \
<a href="javascript:void(0)" data-comments="reddit"> \
{redditComments} \
</a> \
</b> \
</div> \
<div>{contentHtml}</div> \
<hr>'.supplant({
contentHtml: response.contentHtml,
redditComments: video_data.reddit_comments_text,
commentsText: video_data.comments_text.supplant({
// toLocaleString correctly splits number with local thousands separator. e.g.:
// '1,234,567.89' for user with English locale
// '1 234 567,89' for user with Russian locale
// '1.234.567,89' for user with Portuguese locale
commentCount: response.commentCount.toLocaleString()
})
});
comments.children[0].children[0].children[0].onclick = toggle_comments;
comments.children[0].children[1].children[0].onclick = swap_comments;
},
onNon200: onNon200, // declared above
onError: function (xhr) {
comments.innerHTML = spinnerHTML;
},
onTimeout: function (xhr) {
comments.innerHTML = spinnerHTML;
}
});
}
function get_youtube_replies(target, load_more, load_replies) {
var continuation = target.getAttribute('data-continuation');
var body = target.parentNode.parentNode;
var fallback = body.innerHTML;
body.innerHTML = spinnerHTML;
var url = '/api/v1/comments/' + video_data.id +
'?format=html' +
'&hl=' + video_data.preferences.locale +
'&thin_mode=' + video_data.preferences.thin_mode +
'&continuation=' + continuation;
if (load_replies) url += '&action=action_get_comment_replies';
helpers.xhr('GET', url, {}, {
on200: function (response) {
if (load_more) {
body = body.parentNode.parentNode;
body.removeChild(body.lastElementChild);
body.insertAdjacentHTML('beforeend', response.contentHtml);
} else {
body.removeChild(body.lastElementChild);
var p = document.createElement('p');
var a = document.createElement('a');
p.appendChild(a);
a.href = 'javascript:void(0)';
a.onclick = hide_youtube_replies;
a.setAttribute('data-sub-text', video_data.hide_replies_text);
a.setAttribute('data-inner-text', video_data.show_replies_text);
a.textContent = video_data.hide_replies_text;
var div = document.createElement('div');
div.innerHTML = response.contentHtml;
body.appendChild(p);
body.appendChild(div);
}
},
onNon200: function (xhr) {
body.innerHTML = fallback;
},
onTimeout: function (xhr) {
console.warn('Pulling comments failed');
body.innerHTML = fallback;
}
});
}
if (video_data.play_next) {
player.on('ended', function () {
var url = new URL('https://example.com/watch?v=' + video_data.next_video);

View file

@ -15,5 +15,7 @@
],
"theme_color": "#575757",
"background_color": "#575757",
"display": "standalone"
"display": "standalone",
"description": "An alternative front-end to YouTube",
"start_url": "/"
}

View file

@ -1,4 +1,5 @@
FROM crystallang/crystal:1.4.1-alpine AS builder
FROM crystallang/crystal:1.8.2-alpine AS builder
RUN apk add --no-cache sqlite-static yaml-static
ARG release
@ -19,8 +20,7 @@ COPY ./assets/ ./assets/
COPY ./videojs-dependencies.yml ./videojs-dependencies.yml
RUN crystal spec --warnings all \
--link-flags "-lxml2 -llzma"
--link-flags "-lxml2 -llzma"
RUN if [[ "${release}" == 1 ]] ; then \
crystal build ./src/invidious.cr \
--release \
@ -32,8 +32,7 @@ RUN if [[ "${release}" == 1 ]] ; then \
--link-flags "-lxml2 -llzma"; \
fi
FROM alpine:3.16
FROM alpine:3.18
RUN apk add --no-cache librsvg ttf-opensans tini
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \

View file

@ -1,5 +1,5 @@
FROM alpine:3.16 AS builder
RUN apk add --no-cache 'crystal=1.4.1-r0' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev
FROM alpine:3.18 AS builder
RUN apk add --no-cache 'crystal=1.8.2-r0' shards sqlite-static yaml-static yaml-dev libxml2-static zlib-static openssl-libs-static openssl-dev musl-dev xz-static
ARG release
@ -32,7 +32,7 @@ RUN if [[ "${release}" == 1 ]] ; then \
--link-flags "-lxml2 -llzma"; \
fi
FROM alpine:3.16
FROM alpine:3.18
RUN apk add --no-cache librsvg ttf-opensans tini
WORKDIR /invidious
RUN addgroup -g 1000 -S invidious && \

View file

@ -1,6 +1,6 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami/
version: 12.1.9
digest: sha256:71ff342a6c0a98bece3d7fe199983afb2113f8db65a3e3819de875af2c45add7
generated: "2023-01-20T20:42:32.757707004Z"
version: 12.11.1
digest: sha256:3c10008175c4f5c1cec38782f5a7316154b89074c77ebbd9bcc4be4f5ff21122
generated: "2023-09-14T22:40:43.171275362Z"

View file

@ -17,6 +17,6 @@ maintainers:
email: mail@leonklingele.de
dependencies:
- name: postgresql
version: ~12.1.6
version: ~12.11.0
repository: "https://charts.bitnami.com/bitnami/"
engine: gotpl

View file

@ -548,5 +548,11 @@
"generic_button_rss": "RSS",
"channel_tab_releases_label": "الإصدارات",
"playlist_button_add_items": "إضافة مقاطع فيديو",
"channel_tab_podcasts_label": "البودكاست"
"channel_tab_podcasts_label": "البودكاست",
"generic_channels_count_0": "{{count}} قناة",
"generic_channels_count_1": "{{count}} قناة",
"generic_channels_count_2": "{{count}} قناتان",
"generic_channels_count_3": "{{count}} قنوات",
"generic_channels_count_4": "{{count}} قنوات",
"generic_channels_count_5": "{{count}} قناة"
}

490
locales/bg.json Normal file
View file

@ -0,0 +1,490 @@
{
"Korean (auto-generated)": "Корейски (автоматично генерирано)",
"search_filters_features_option_three_sixty": "360°",
"published - reverse": "публикувани - в обратен ред",
"preferences_quality_dash_option_worst": "Най-ниско качество",
"Password is a required field": "Парола е задължитело поле",
"channel_tab_podcasts_label": "Подкасти",
"Token is expired, please try again": "Токенът е изтекъл, моля опитайте отново",
"Turkish": "Турски",
"preferences_save_player_pos_label": "Запази позицията на плейъра: ",
"View Reddit comments": "Виж Reddit коментари",
"Export data as JSON": "Експортиране на Invidious информацията като JSON",
"About": "За сайта",
"Save preferences": "Запази промените",
"Load more": "Зареди още",
"Import/export": "Импортиране/експортиране",
"Albanian": "Албански",
"New password": "Нова парола",
"Southern Sotho": "Южен Сото",
"channel_tab_videos_label": "Видеа",
"Spanish (Mexico)": "Испански (Мексико)",
"preferences_player_style_label": "Стил на плейъра: ",
"preferences_region_label": "Държавата на съдържанието: ",
"Premieres in `x`": "Премиера в `x`",
"Watch history": "История на гледане",
"generic_subscriptions_count": "{{count}} абонамент",
"generic_subscriptions_count_plural": "{{count}} абонамента",
"preferences_continue_label": "Пускай следващото видео автоматично: ",
"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. Натисни тук за да видиш коментарите, но обърни внимание, че може да отнеме повече време да заредят.",
"Polish": "Полски",
"Icelandic": "Исландски",
"preferences_local_label": "Пускане на видеа през прокси: ",
"Hebrew": "Иврит",
"Fallback captions: ": "Резервни надписи: ",
"search_filters_title": "Филтри",
"search_filters_apply_button": "Приложете избрани филтри",
"Download is disabled": "Изтеглянето е деактивирано",
"User ID is a required field": "Потребителско име е задължително поле",
"comments_points_count": "{{count}} точка",
"comments_points_count_plural": "{{count}} точки",
"next_steps_error_message_go_to_youtube": "Отидеш в YouTube",
"preferences_quality_dash_option_2160p": "2160p",
"search_filters_type_option_video": "Видео",
"Spanish (Latin America)": "Испански (Латинска Америка)",
"Download as: ": "Изтегли като: ",
"Default": "По подразбиране",
"search_filters_sort_option_views": "Гледания",
"search_filters_features_option_four_k": "4K",
"Igbo": "Игбо",
"Subscriptions": "Абонаменти",
"German (auto-generated)": "Немски (автоматично генерирано)",
"`x` is live": "`x` е на живо",
"Azerbaijani": "Азербайджански",
"Premieres `x`": "Премиера `x`",
"Japanese (auto-generated)": "Японски (автоматично генерирано)",
"preferences_quality_option_medium": "Средно",
"footer_donate_page": "Даряване",
"Show replies": "Покажи отговорите",
"Esperanto": "Есперанто",
"search_message_change_filters_or_query": "Опитай да разшириш търсенето си и/или да смениш филтрите.",
"CAPTCHA enabled: ": "Активиране на CAPTCHA: ",
"View playlist on YouTube": "Виж плейлиста в YouTube",
"crash_page_before_reporting": "Преди докладването на бъг, бъди сигурен, че си:",
"Top enabled: ": "Активиране на страница с топ видеа: ",
"preferences_quality_dash_option_best": "Най-високо",
"search_filters_duration_label": "Продължителност",
"Slovak": "Словашки",
"Channel Sponsor": "Канален спонсор",
"generic_videos_count": "{{count}} видео",
"generic_videos_count_plural": "{{count}} видеа",
"videoinfo_started_streaming_x_ago": "Започна да излъчва преди `x`",
"videoinfo_youTube_embed_link": "Вграждане",
"channel_tab_streams_label": "Стриймове",
"oldest": "най-стари",
"playlist_button_add_items": "Добавяне на видеа",
"Import NewPipe data (.zip)": "Импортиране на NewPipe информация (.zip)",
"Clear watch history": "Изчистване на историята на гледане",
"generic_count_minutes": "{{count}} минута",
"generic_count_minutes_plural": "{{count}} минути",
"published": "публикувани",
"Show annotations": "Покажи анотации",
"Login enabled: ": "Активиране на впизване: ",
"Somali": "Сомалийски",
"YouTube comment permalink": "Постоянна връзка на коментарите на YouTube",
"Kurdish": "Кюрдски",
"search_filters_date_option_hour": "Последния час",
"Lao": "Лаоски",
"Maltese": "Малтийски",
"Register": "Регистрация",
"View channel on YouTube": "Виж канала в YouTube",
"Playlist privacy": "Поверителен плейлист",
"preferences_unseen_only_label": "Показвай само негледаните: ",
"Gujarati": "Гуджарати",
"Please log in": "Моля влезте",
"search_filters_sort_option_rating": "Рейтинг",
"Manage subscriptions": "Управление на абонаментите",
"preferences_quality_dash_option_720p": "720p",
"preferences_watch_history_label": "Активирай историята на гледане: ",
"user_saved_playlists": "`x` запази плейлисти",
"preferences_extend_desc_label": "Автоматично разшири описанието на видеото ",
"preferences_max_results_label": "Брой видеа показани на началната страница: ",
"Spanish (Spain)": "Испански (Испания)",
"invidious": "Invidious",
"crash_page_refresh": "пробвал да <a href=\"`x`\">опресниш страницата</a>",
"Image CAPTCHA": "CAPTCHA с Изображение",
"search_filters_features_option_hd": "HD",
"Chinese (Hong Kong)": "Китайски (Хонг Конг)",
"Import Invidious data": "Импортиране на Invidious JSON информацията",
"Blacklisted regions: ": "Неразрешени региони: ",
"Only show latest video from channel: ": "Показвай само най-новите видеа в канала: ",
"Hmong": "Хмонг",
"French": "Френски",
"search_filters_type_option_channel": "Канал",
"Artist: ": "Артист: ",
"generic_count_months": "{{count}} месец",
"generic_count_months_plural": "{{count}} месеца",
"preferences_annotations_subscribed_label": "Показвай анотаций по подразбиране за абонирани канали? ",
"search_message_use_another_instance": " Можеш също да <a href=\"`x`\">търсиш на друга инстанция</a>.",
"Danish": "Датски",
"generic_subscribers_count": "{{count}} абонат",
"generic_subscribers_count_plural": "{{count}} абоната",
"Galician": "Галисий",
"newest": "най-нови",
"Empty playlist": "Плейлиста е празен",
"download_subtitles": "Субритри - `x` (.vtt)",
"preferences_category_misc": "Различни предпочитания",
"Uzbek": "Узбекски",
"View JavaScript license information.": "Виж Javascript лиценза.",
"Filipino": "Филипински",
"Malagasy": "Мадагаскарски",
"generic_button_save": "Запиши",
"Dark mode: ": "Тъмен режим: ",
"Public": "Публичен",
"Basque": "Баскски",
"channel:`x`": "Канал:`x`",
"Armenian": "Арменски",
"This channel does not exist.": "Този канал не съществува.",
"Luxembourgish": "Люксембургски",
"preferences_related_videos_label": "Покажи подобни видеа: ",
"English": "Английски",
"Delete account": "Изтриване на акаунт",
"Gaming": "Игри",
"Video mode": "Видео режим",
"preferences_dark_mode_label": "Тема: ",
"crash_page_search_issue": "потърсил за <a href=\"`x`\">съществуващи проблеми в GitHub</a>",
"preferences_category_subscription": "Предпочитания за абонаменти",
"last": "най-скорощни",
"Chinese (Simplified)": "Китайски (Опростен)",
"Could not create mix.": "Създаването на микс е неуспешно.",
"generic_button_cancel": "Отказ",
"search_filters_type_option_movie": "Филм",
"search_filters_date_option_year": "Тази година",
"Swedish": "Шведски",
"Previous page": "Предишна страница",
"none": "нищо",
"popular": "най-популярни",
"Unsubscribe": "Отписване",
"Slovenian": "Словенски",
"Nepali": "Непалски",
"Time (h:mm:ss):": "Време (h:mm:ss):",
"English (auto-generated)": "Английски (автоматично генерирано)",
"search_filters_sort_label": "Сортирай по",
"View more comments on Reddit": "Виж повече коментари в Reddit",
"Sinhala": "Синхалски",
"preferences_feed_menu_label": "Меню с препоръки: ",
"preferences_autoplay_label": "Автоматично пускане: ",
"Pashto": "Пущунски",
"English (United States)": "Английски (САЩ)",
"Sign In": "Вход",
"subscriptions_unseen_notifs_count": "{{count}} невидяно известие",
"subscriptions_unseen_notifs_count_plural": "{{count}} невидяни известия",
"Log in": "Вход",
"Engagement: ": "Участие: ",
"Album: ": "Албум: ",
"preferences_speed_label": "Скорост по подразбиране: ",
"Import FreeTube subscriptions (.db)": "Импортиране на FreeTube абонаменти (.db)",
"preferences_quality_option_dash": "DASH (адаптивно качество)",
"preferences_show_nick_label": "Показвай потребителското име отгоре: ",
"Private": "Частен",
"Samoan": "Самоански",
"preferences_notifications_only_label": "Показвай само известията (ако има такива): ",
"Create playlist": "Създаване на плейлист",
"next_steps_error_message_refresh": "Опресниш",
"Top": "Топ",
"preferences_quality_dash_option_1080p": "1080p",
"Malayalam": "Малаялам",
"Token": "Токен",
"preferences_comments_label": "Коментари по подразбиране: ",
"Movies": "Филми",
"light": "светла",
"Unlisted": "Скрит",
"preferences_category_admin": "Администраторни предпочитания",
"Erroneous token": "Невалиден токен",
"No": "Не",
"CAPTCHA is a required field": "CAPTCHA е задължително поле",
"Video unavailable": "Неналично видео",
"footer_source_code": "Изходен код",
"New passwords must match": "Новите пароли трябва да съвпадат",
"Playlist does not exist.": "Плейлиста не съществува.",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Експортиране на абонаментите като OPML (за NewPipe и FreeTube)",
"search_filters_duration_option_short": "Кратко (< 4 минути)",
"search_filters_duration_option_long": "Дълго (> 20 минути)",
"tokens_count": "{{count}} токен",
"tokens_count_plural": "{{count}} токена",
"Yes": "Да",
"Dutch": "Холандски",
"Arabic": "Арабски",
"An alternative front-end to YouTube": "Алтернативен преден план на YouTube",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Виж `x` коментар",
"": "Виж `x` коментари"
},
"Chinese (China)": "Китайски (Китай)",
"Italian (auto-generated)": "Италиански (автоматично генерирано)",
"alphabetically - reverse": "обратно на азбучния ред",
"channel_tab_shorts_label": "Shorts",
"`x` marked it with a ❤": "`x` го маркира със ❤",
"Current version: ": "Текуща версия: ",
"channel_tab_community_label": "Общност",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_360p": "360p",
"`x` uploaded a video": "`x` качи видео",
"Welsh": "Уелски",
"search_message_no_results": "Няма намерени резултати.",
"channel_tab_releases_label": "Версии",
"Bangla": "Бенгалски",
"preferences_quality_dash_option_144p": "144p",
"Indonesian": "Индонезийски",
"`x` ago": "преди `x`",
"Invidious Private Feed for `x`": "Invidious персонални видеа за `x`",
"Finnish": "Финландски",
"Amharic": "Амхарски",
"Malay": "Малайски",
"Interlingue": "Интерлинг",
"search_filters_date_option_month": "Този месец",
"Georgian": "Грузински",
"Xhosa": "Кхоса",
"Marathi": "Маратхи",
"Yoruba": "Йоруба",
"Song: ": "Музика: ",
"Scottish Gaelic": "Шотландски гелски",
"search_filters_features_label": "Функции",
"preferences_quality_label": "Предпочитано качество на видеото: ",
"generic_channels_count": "{{count}} канал",
"generic_channels_count_plural": "{{count}} канала",
"Croatian": "Хърватски",
"Thai": "Тайски",
"Chinese (Taiwan)": "Китайски (Тайван)",
"youtube": "YouTube",
"Source available here.": "Източник наличен тук.",
"LIVE": "На живо",
"Ukrainian": "Украински",
"Russian": "Руски",
"Tajik": "Таджикски",
"Token manager": "Управляване на токени",
"preferences_quality_dash_label": "Предпочитано DASH качество на видеото: ",
"adminprefs_modified_source_code_url_label": "URL до хранилището на променения изходен код",
"Japanese": "Японски",
"Title": "Заглавие",
"Authorize token for `x`?": "Разреши токена за `x`?",
"reddit": "Reddit",
"permalink": "постоянна връзка",
"Trending": "На върха",
"Turkish (auto-generated)": "Турски (автоматично генерирано)",
"Bulgarian": "Български",
"Indonesian (auto-generated)": "Индонезийски (автоматично генерирано)",
"Enable web notifications": "Активирай уеб известия",
"Western Frisian": "Западен фризски",
"search_filters_date_option_week": "Тази седмица",
"Yiddish": "Идиш",
"preferences_category_player": "Предпочитания за плейъра",
"Shared `x` ago": "Споделено преди `x`",
"Swahili": "Суахили",
"Portuguese (auto-generated)": "Португалски (автоматично генерирано)",
"generic_count_years": "{{count}} година",
"generic_count_years_plural": "{{count}} години",
"Wilson score: ": "Wilson оценка: ",
"Genre: ": "Жанр: ",
"videoinfo_invidious_embed_link": "Вграждане на линк",
"Popular enabled: ": "Активиране на популярната страница: ",
"Wrong username or password": "Грешно потребителско име или парола",
"Vietnamese": "Виетнамски",
"alphabetically": "по азбучен ред",
"Afrikaans": "Африкаанс",
"Zulu": "Зулуски",
"(edited)": "(редактирано)",
"Whitelisted regions: ": "Разрешени региони: ",
"Spanish (auto-generated)": "Испански (автоматично генерирано)",
"Could not fetch comments": "Получаването на коментарите е неуспешно",
"Sindhi": "Синдхи",
"News": "Новини",
"preferences_video_loop_label": "Винаги повтаряй: ",
"%A %B %-d, %Y": "%-d %B %Y, %A",
"preferences_quality_option_small": "Ниско",
"English (United Kingdom)": "Английски (Великобритания)",
"Rating: ": "Рейтинг: ",
"channel_tab_playlists_label": "Плейлисти",
"generic_button_edit": "Редактирай",
"Report statistics: ": "Активиране на статистики за репортиране: ",
"Cebuano": "Себуано",
"Chinese (Traditional)": "Китайски (Традиционен)",
"generic_playlists_count": "{{count}} плейлист",
"generic_playlists_count_plural": "{{count}} плейлиста",
"Import NewPipe subscriptions (.json)": "Импортиране на NewPipe абонаменти (.json)",
"Preferences": "Предпочитания",
"Subscribe": "Абониране",
"Import and Export Data": "Импортиране и експортиране на информация",
"preferences_quality_option_hd720": "HD720",
"search_filters_type_option_playlist": "Плейлист",
"Serbian": "Сръбски",
"Kazakh": "Казахски",
"Telugu": "Телугу",
"search_filters_features_option_purchased": "Купено",
"revoke": "отмяна",
"search_filters_sort_option_date": "Дата на качване",
"preferences_category_data": "Предпочитания за информацията",
"search_filters_date_option_none": "Всякаква дата",
"Log out": "Излизане",
"Search": "Търсене",
"preferences_quality_dash_option_auto": "Автоматично",
"dark": "тъмна",
"Cantonese (Hong Kong)": "Кантонски (Хонг Конг)",
"crash_page_report_issue": "Ако никои от горепосочените не помогнаха, моля <a href=\"`x`\">отворете нов проблем в GitHub</a> (предпочитано на Английски) и добавете следния текст в съобщението (НЕ превеждайте този текст):",
"Czech": "Чешки",
"crash_page_switch_instance": "пробвал да <a href=\"`x`\">ползваш друга инстанция</a>",
"generic_count_weeks": "{{count}} седмица",
"generic_count_weeks_plural": "{{count}} седмици",
"search_filters_features_option_subtitles": "Субтитри",
"videoinfo_watch_on_youTube": "Виж в YouTube",
"Portuguese": "Португалски",
"Music in this video": "Музика в това видео",
"Hide replies": "Скрий отговорите",
"Password cannot be longer than 55 characters": "Паролата не може да бъде по-дълга от 55 символа",
"footer_modfied_source_code": "Променен изходен код",
"Bosnian": "Босненски",
"Deleted or invalid channel": "Изтрит или невалиден канал",
"Popular": "Популярно",
"search_filters_type_label": "Тип",
"preferences_locale_label": "Език: ",
"Playlists": "Плейлисти",
"generic_button_rss": "RSS",
"Export": "Експортиране",
"preferences_quality_dash_option_4320p": "4320p",
"Erroneous challenge": "Невалиден тест",
"History": "История",
"generic_count_hours": "{{count}} час",
"generic_count_hours_plural": "{{count}} часа",
"Registration enabled: ": "Активиране на регистрация: ",
"Music": "Музика",
"Incorrect password": "Грешна парола",
"Persian": "Перскийски",
"Import": "Импортиране",
"Import/export data": "Импортиране/Експортиране на информация",
"Shared `x`": "Споделено `x`",
"Javanese": "Явански",
"French (auto-generated)": "Френски (автоматично генерирано)",
"Norwegian Bokmål": "Норвежки",
"Catalan": "Каталунски",
"Hindi": "Хинди",
"Tamil": "Тамилски",
"search_filters_features_option_live": "На живо",
"crash_page_read_the_faq": "прочел <a href=\"`x`\">Често задавани въпроси (FAQ)</a>",
"preferences_default_home_label": "Начална страница по подразбиране: ",
"Download": "Изтегляне",
"Show less": "Покажи по-малко",
"Password": "Парола",
"User ID": "Потребителско име",
"Subscription manager": "Управляване на абонаменти",
"search": "търсене",
"No such user": "Няма такъв потребител",
"View privacy policy.": "Виж политиката за поверителност.",
"Only show latest unwatched video from channel: ": "Показвай само най-новите негледани видеа в канала: ",
"user_created_playlists": "`x` създаде плейлисти",
"Editing playlist `x`": "Редактиране на плейлист `x`",
"preferences_thin_mode_label": "Тънък режим: ",
"E-mail": "Имейл",
"Haitian Creole": "Хаитянски креол",
"Irish": "Ирландски",
"channel_tab_channels_label": "Канали",
"Delete account?": "Изтрий акаунта?",
"Redirect homepage to feed: ": "Препращане на началната страница до препоръки ",
"Urdu": "Урду",
"preferences_vr_mode_label": "Интерактивни 360 градусови видеа (изисква WebGL): ",
"Password cannot be empty": "Паролата не може да бъде празна",
"Mongolian": "Монголски",
"Authorize token?": "Разреши токена?",
"search_filters_type_option_all": "Всякакъв тип",
"Romanian": "Румънски",
"Belarusian": "Беларуски",
"channel name - reverse": "име на канал - в обратен ред",
"Erroneous CAPTCHA": "Невалидна CAPTCHA",
"Watch on YouTube": "Гледай в YouTube",
"search_filters_features_option_location": "Местоположение",
"Could not pull trending pages.": "Получаването на трендинг страниците е неуспешно.",
"German": "Немски",
"search_filters_features_option_c_commons": "Creative Commons",
"Family friendly? ": "За всяка възраст? ",
"Hidden field \"token\" is a required field": "Скритото поле \"токен\" е задължително поле",
"Russian (auto-generated)": "Руски (автоматично генерирано)",
"preferences_quality_dash_option_480p": "480p",
"Corsican": "Корсикански",
"Macedonian": "Македонски",
"comments_view_x_replies": "Виж {{count}} отговор",
"comments_view_x_replies_plural": "Виж {{count}} отговора",
"footer_original_source_code": "Оригинален изходен код",
"Import YouTube subscriptions": "Импортиране на YouTube/OPML абонаменти",
"Lithuanian": "Литовски",
"Nyanja": "Нянджа",
"Updated `x` ago": "Актуализирано преди `x`",
"JavaScript license information": "Информация за Javascript лиценза",
"Spanish": "Испански",
"Latin": "Латински",
"Shona": "Шона",
"Portuguese (Brazil)": "Португалски (Бразилия)",
"Show more": "Покажи още",
"Clear watch history?": "Изчисти историята на търсене?",
"Manage tokens": "Управление на токени",
"Hausa": "Хауса",
"search_filters_features_option_vr180": "VR180",
"preferences_category_visual": "Визуални предпочитания",
"Italian": "Италиански",
"preferences_volume_label": "Сила на звука на плейъра: ",
"error_video_not_in_playlist": "Заявеното видео не съществува в този плейлист. <a href=\"`x`\">Натиснете тук за началната страница на плейлиста.</a>",
"preferences_listen_label": "Само звук по подразбиране: ",
"Dutch (auto-generated)": "Холандски (автоматично генерирано)",
"preferences_captions_label": "Надписи по подразбиране: ",
"generic_count_days": "{{count}} ден",
"generic_count_days_plural": "{{count}} дни",
"Hawaiian": "Хавайски",
"Could not get channel info.": "Получаването на информация за канала е неуспешно.",
"View as playlist": "Виж като плейлист",
"Vietnamese (auto-generated)": "Виетнамски (автоматично генерирано)",
"search_filters_duration_option_none": "Всякаква продължителност",
"preferences_quality_dash_option_240p": "240p",
"Latvian": "Латвийски",
"search_filters_features_option_hdr": "HDR",
"preferences_sort_label": "Сортирай видеата по: ",
"Estonian": "Естонски",
"Hidden field \"challenge\" is a required field": "Скритото поле \"тест\" е задължително поле",
"footer_documentation": "Документация",
"Kyrgyz": "Киргизски",
"preferences_continue_autoplay_label": "Пускай следващотото видео автоматично: ",
"Chinese": "Китайски",
"search_filters_sort_option_relevance": "Уместност",
"source": "източник",
"Fallback comments: ": "Резервни коментари: ",
"preferences_automatic_instance_redirect_label": "Автоматично препращане на инстанция (чрез redirect.invidious.io): ",
"Maori": "Маори",
"generic_button_delete": "Изтрий",
"Import YouTube playlist (.csv)": "Импортиране на YouTube плейлист (.csv)",
"Switch Invidious Instance": "Смени Invidious инстанция",
"channel name": "име на канал",
"Audio mode": "Аудио режим",
"search_filters_type_option_show": "Сериал",
"search_filters_date_option_today": "Днес",
"search_filters_features_option_three_d": "3D",
"next_steps_error_message": "След което можеш да пробваш да: ",
"Hide annotations": "Скрий анотации",
"Standard YouTube license": "Стандартен YouTube лиценз",
"Text CAPTCHA": "Текст CAPTCHA",
"Log in/register": "Вход/регистрация",
"Punjabi": "Пенджаби",
"Change password": "Смяна на паролата",
"License: ": "Лиценз: ",
"search_filters_duration_option_medium": "Средно (4 - 20 минути)",
"Delete playlist": "Изтриване на плейлист",
"Delete playlist `x`?": "Изтрий плейлиста `x`?",
"Korean": "Корейски",
"Export subscriptions as OPML": "Експортиране на абонаментите като OPML",
"unsubscribe": "отписване",
"View YouTube comments": "Виж YouTube коментарите",
"Kannada": "Каннада",
"Not a playlist.": "Невалиден плейлист.",
"Wrong answer": "Грешен отговор",
"Released under the AGPLv3 on Github.": "Публикувано под AGPLv3 в GitHub.",
"Burmese": "Бирмански",
"Sundanese": "Сундански",
"Hungarian": "Унгарски",
"generic_count_seconds": "{{count}} секунда",
"generic_count_seconds_plural": "{{count}} секунди",
"search_filters_date_label": "Дата на качване",
"Greek": "Гръцки",
"crash_page_you_found_a_bug": "Изглежда намери бъг в Invidious!",
"View all playlists": "Виж всички плейлисти",
"Khmer": "Кхмерски",
"preferences_annotations_label": "Покажи анотаций по подразбиране: ",
"generic_views_count": "{{count}} гледане",
"generic_views_count_plural": "{{count}} гледания",
"Next page": "Следваща страница"
}

View file

@ -476,5 +476,15 @@
"Redirect homepage to feed: ": "Redirigeix la pàgina d'inici al feed: ",
"Standard YouTube license": "Llicència estàndard de YouTube",
"Download is disabled": "Les baixades s'han inhabilitat",
"Import YouTube playlist (.csv)": "Importar llista de reproducció de YouTube (.csv)"
"Import YouTube playlist (.csv)": "Importar llista de reproducció de YouTube (.csv)",
"channel_tab_podcasts_label": "Podcasts",
"playlist_button_add_items": "Afegeix vídeos",
"generic_button_save": "Desa",
"generic_button_cancel": "Cancel·la",
"channel_tab_releases_label": "Publicacions",
"generic_channels_count": "{{count}} canal",
"generic_channels_count_plural": "{{count}} canals",
"generic_button_edit": "Edita",
"generic_button_rss": "RSS",
"generic_button_delete": "Suprimeix"
}

View file

@ -500,5 +500,8 @@
"channel_tab_releases_label": "Vydání",
"generic_button_edit": "Upravit",
"generic_button_rss": "RSS",
"playlist_button_add_items": "Přidat videa"
"playlist_button_add_items": "Přidat videa",
"generic_channels_count_0": "{{count}} kanál",
"generic_channels_count_1": "{{count}} kanály",
"generic_channels_count_2": "{{count}} kanálů"
}

View file

@ -97,7 +97,7 @@
"Change password": "Passwort ändern",
"Manage subscriptions": "Abonnements verwalten",
"Manage tokens": "Tokens verwalten",
"Watch history": "Verlauf",
"Watch history": "Wiedergabeverlauf",
"Delete account": "Account löschen",
"preferences_category_admin": "Administrator-Einstellungen",
"preferences_default_home_label": "Standard-Startseite: ",
@ -476,11 +476,15 @@
"Standard YouTube license": "Standard YouTube-Lizenz",
"Song: ": "Musik: ",
"Download is disabled": "Herunterladen ist deaktiviert",
"Import YouTube playlist (.csv)": "YouTube Playlist Importieren (.csv)",
"Import YouTube playlist (.csv)": "YouTube Wiedergabeliste importieren (.csv)",
"generic_button_delete": "Löschen",
"generic_button_edit": "Bearbeiten",
"generic_button_save": "Speichern",
"generic_button_cancel": "Abbrechen",
"generic_button_rss": "RSS",
"playlist_button_add_items": "Videos hinzufügen"
"playlist_button_add_items": "Videos hinzufügen",
"channel_tab_podcasts_label": "Podcasts",
"channel_tab_releases_label": "Veröffentlichungen",
"generic_channels_count": "{{count}} Kanal",
"generic_channels_count_plural": "{{count}} Kanäle"
}

View file

@ -41,7 +41,7 @@
"Time (h:mm:ss):": "Ώρα (ω:λλ:δδ):",
"Text CAPTCHA": "Κείμενο CAPTCHA",
"Image CAPTCHA": "Εικόνα CAPTCHA",
"Sign In": "Σύνδεση",
"Sign In": "Εγγραφή",
"Register": "Εγγραφή",
"E-mail": "Ηλεκτρονικό ταχυδρομείο",
"Preferences": "Προτιμήσεις",
@ -145,7 +145,7 @@
"View YouTube comments": "Προβολή σχολίων από το YouTube",
"View more comments on Reddit": "Προβολή περισσότερων σχολίων στο Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Προβολή `x` σχολίων",
"([^.,0-9]|^)1([^.,0-9]|$)": "Προβολή `x` σχολίου",
"": "Προβολή `x` σχολίων"
},
"View Reddit comments": "Προβολή σχολίων από το Reddit",
@ -349,7 +349,7 @@
"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_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}} προβολές",
@ -442,5 +442,49 @@
"search_filters_type_option_show": "Μπάρα προόδου διαβάσματος",
"preferences_watch_history_label": "Ενεργοποίηση ιστορικού παρακολούθησης: ",
"search_filters_title": "Φίλτρο",
"search_message_no_results": "Δε βρέθηκαν αποτελέσματα."
"search_message_no_results": "Δε βρέθηκαν αποτελέσματα.",
"channel_tab_podcasts_label": "Podcast",
"preferences_save_player_pos_label": "Αποθήκευση σημείου αναπαραγωγής: ",
"search_filters_apply_button": "Εφαρμογή επιλεγμένων φίλτρων",
"Download is disabled": "Είναι απενεργοποιημένη η λήψη",
"comments_points_count": "{{count}} βαθμός",
"comments_points_count_plural": "{{count}} βαθμοί",
"search_filters_sort_option_views": "Προβολές",
"search_message_change_filters_or_query": "Προσπαθήστε να διευρύνετε το ερώτημα αναζήτησης ή/και να αλλάξετε τα φίλτρα.",
"Channel Sponsor": "Χορηγός Καναλιού",
"channel_tab_streams_label": "Ζωντανή μετάδοση",
"playlist_button_add_items": "Προσθήκη βίντεο",
"Artist: ": "Καλλιτέχνης: ",
"search_message_use_another_instance": " Μπορείτε επίσης <a href=\"`x`\">να αναζητήσετε σε άλλο instance</a>.",
"generic_button_save": "Αποθήκευση",
"generic_button_cancel": "Ακύρωση",
"subscriptions_unseen_notifs_count": "{{count}} μη αναγνωσμένη ειδοποίηση",
"subscriptions_unseen_notifs_count_plural": "{{count}} μη αναγνωσμένες ειδοποιήσεις",
"Album: ": "Δίσκος: ",
"tokens_count": "{{count}} σύμβολο",
"tokens_count_plural": "{{count}} σύμβολα",
"channel_tab_shorts_label": "Short",
"channel_tab_releases_label": "Κυκλοφορίες",
"Song: ": "Τραγούδι: ",
"generic_channels_count": "{{count}} κανάλι",
"generic_channels_count_plural": "{{count}} κανάλια",
"Popular enabled: ": "Ενεργοποιημένα Δημοφιλή: ",
"channel_tab_playlists_label": "Λίστες αναπαραγωγής",
"generic_button_edit": "Επεξεργασία",
"search_filters_date_option_none": "Οποιαδήποτε ημερομηνία",
"crash_page_switch_instance": "προσπάθεια <a href=\"`x`\">χρήσης άλλου instance</a>",
"Music in this video": "Μουσική σε αυτό το βίντεο",
"generic_button_rss": "RSS",
"channel_tab_channels_label": "Κανάλια",
"search_filters_type_option_all": "Οποιοσδήποτε τύπος",
"search_filters_features_option_vr180": "VR180",
"error_video_not_in_playlist": "Το αιτούμενο βίντεο δεν υπάρχει στη δεδομένη λίστα αναπαραγωγής. <a href=\"`x`\">Πατήστε εδώ για επιστροφή στη κεντρική σελίδα λιστών αναπαραγωγής.</a>",
"search_filters_duration_option_none": "Οποιαδήποτε διάρκεια",
"preferences_automatic_instance_redirect_label": "Αυτόματη ανακατεύθυνση instance (εναλλακτική σε redirect.invidious.io): ",
"generic_button_delete": "Διαγραφή",
"Import YouTube playlist (.csv)": "Εισαγωγή λίστας αναπαραγωγής YouTube (.csv)",
"Switch Invidious Instance": "Αλλαγή Instance Invidious",
"Standard YouTube license": "Τυπική άδεια YouTube",
"search_filters_duration_option_medium": "Μεσαία (4 - 20 λεπτά)",
"search_filters_date_label": "Ημερομηνία αναφόρτωσης"
}

View file

@ -40,6 +40,7 @@
"Import Invidious data": "Import Invidious JSON data",
"Import YouTube subscriptions": "Import YouTube/OPML subscriptions",
"Import YouTube playlist (.csv)": "Import YouTube playlist (.csv)",
"Import YouTube watch history (.json)": "Import YouTube watch history (.json)",
"Import FreeTube subscriptions (.db)": "Import FreeTube subscriptions (.db)",
"Import NewPipe subscriptions (.json)": "Import NewPipe subscriptions (.json)",
"Import NewPipe data (.zip)": "Import NewPipe data (.zip)",

View file

@ -484,5 +484,7 @@
"channel_tab_podcasts_label": "Podkastoj",
"generic_button_cancel": "Nuligi",
"channel_tab_releases_label": "Eldonoj",
"generic_button_save": "Konservi"
"generic_button_save": "Konservi",
"generic_channels_count": "{{count}} kanalo",
"generic_channels_count_plural": "{{count}} kanaloj"
}

View file

@ -484,5 +484,7 @@
"generic_button_cancel": "Cancelar",
"generic_button_rss": "RSS",
"channel_tab_podcasts_label": "Podcasts",
"channel_tab_releases_label": "Publicaciones"
"channel_tab_releases_label": "Publicaciones",
"generic_channels_count": "{{count}} canal",
"generic_channels_count_plural": "{{count}} canales"
}

View file

@ -1,16 +1,22 @@
{
"generic_channels_count": "{{count}} chaîne",
"generic_channels_count_plural": "{{count}} chaînes",
"generic_views_count": "{{count}} vue",
"generic_views_count_plural": "{{count}} vues",
"generic_videos_count": "{{count}} vidéo",
"generic_videos_count_plural": "{{count}} vidéos",
"generic_playlists_count": "{{count}} liste de lecture",
"generic_playlists_count_plural": "{{count}} listes de lecture",
"generic_subscribers_count": "{{count}} abonné",
"generic_subscribers_count_plural": "{{count}} abonnés",
"generic_subscriptions_count": "{{count}} abonnement",
"generic_subscriptions_count_plural": "{{count}} abonnements",
"generic_channels_count_0": "{{count}} chaîne",
"generic_channels_count_1": "{{count}} de chaînes",
"generic_channels_count_2": "{{count}} chaînes",
"generic_views_count_0": "{{count}} vue",
"generic_views_count_1": "{{count}} de vues",
"generic_views_count_2": "{{count}} vues",
"generic_videos_count_0": "{{count}} vidéo",
"generic_videos_count_1": "{{count}} de vidéos",
"generic_videos_count_2": "{{count}} vidéos",
"generic_playlists_count_0": "{{count}} liste de lecture",
"generic_playlists_count_1": "{{count}} listes de lecture",
"generic_playlists_count_2": "{{count}} listes de lecture",
"generic_subscribers_count_0": "{{count}} abonné",
"generic_subscribers_count_1": "{{count}} d'abonnés",
"generic_subscribers_count_2": "{{count}} abonnés",
"generic_subscriptions_count_0": "{{count}} abonnement",
"generic_subscriptions_count_1": "{{count}} d'abonnements",
"generic_subscriptions_count_2": "{{count}} abonnements",
"generic_button_delete": "Supprimer",
"generic_button_edit": "Editer",
"generic_button_save": "Enregistrer",
@ -130,14 +136,16 @@
"Subscription manager": "Gestionnaire d'abonnement",
"Token manager": "Gestionnaire de token",
"Token": "Token",
"tokens_count": "{{count}} jeton",
"tokens_count_plural": "{{count}} jetons",
"tokens_count_0": "{{count}} jeton",
"tokens_count_1": "{{count}} de jetons",
"tokens_count_2": "{{count}} jetons",
"Import/export": "Importer/Exporter",
"unsubscribe": "se désabonner",
"revoke": "révoquer",
"Subscriptions": "Abonnements",
"subscriptions_unseen_notifs_count": "{{count}} notification non vue",
"subscriptions_unseen_notifs_count_plural": "{{count}} notifications non vues",
"subscriptions_unseen_notifs_count_0": "{{count}} notification non vue",
"subscriptions_unseen_notifs_count_1": "{{count}} de notifications non vues",
"subscriptions_unseen_notifs_count_2": "{{count}} notifications non vues",
"search": "rechercher",
"Log out": "Se déconnecter",
"Released under the AGPLv3 on Github.": "Publié sous licence AGPLv3 sur GitHub.",
@ -199,12 +207,14 @@
"This channel does not exist.": "Cette chaine n'existe pas.",
"Could not get channel info.": "Impossible de charger les informations de cette chaîne.",
"Could not fetch comments": "Impossible de charger les commentaires",
"comments_view_x_replies": "Voir {{count}} réponse",
"comments_view_x_replies_plural": "Voir {{count}} réponses",
"comments_view_x_replies_0": "Voir {{count}} réponse",
"comments_view_x_replies_1": "Voir {{count}} de réponses",
"comments_view_x_replies_2": "Voir {{count}} réponses",
"`x` ago": "il y a `x`",
"Load more": "Voir plus",
"comments_points_count": "{{count}} point",
"comments_points_count_plural": "{{count}} points",
"comments_points_count_0": "{{count}} point",
"comments_points_count_1": "{{count}} de points",
"comments_points_count_2": "{{count}} points",
"Could not create mix.": "Impossible de charger cette liste de lecture.",
"Empty playlist": "La liste de lecture est vide",
"Not a playlist.": "La liste de lecture est invalide.",
@ -322,20 +332,27 @@
"Yiddish": "Yiddish",
"Yoruba": "Yoruba",
"Zulu": "Zoulou",
"generic_count_years": "{{count}} an",
"generic_count_years_plural": "{{count}} ans",
"generic_count_months": "{{count}} mois",
"generic_count_months_plural": "{{count}} mois",
"generic_count_weeks": "{{count}} semaine",
"generic_count_weeks_plural": "{{count}} semaines",
"generic_count_days": "{{count}} jour",
"generic_count_days_plural": "{{count}} jours",
"generic_count_hours": "{{count}} heure",
"generic_count_hours_plural": "{{count}} heures",
"generic_count_minutes": "{{count}} minute",
"generic_count_minutes_plural": "{{count}} minutes",
"generic_count_seconds": "{{count}} seconde",
"generic_count_seconds_plural": "{{count}} secondes",
"generic_count_years_0": "{{count}} an",
"generic_count_years_1": "{{count}} ans",
"generic_count_years_2": "{{count}} ans",
"generic_count_months_0": "{{count}} mois",
"generic_count_months_1": "{{count}} mois",
"generic_count_months_2": "{{count}} mois",
"generic_count_weeks_0": "{{count}} semaine",
"generic_count_weeks_1": "{{count}} semaines",
"generic_count_weeks_2": "{{count}} semaines",
"generic_count_days_0": "{{count}} jour",
"generic_count_days_1": "{{count}} jours",
"generic_count_days_2": "{{count}} jours",
"generic_count_hours_0": "{{count}} heure",
"generic_count_hours_1": "{{count}} heures",
"generic_count_hours_2": "{{count}} heures",
"generic_count_minutes_0": "{{count}} minute",
"generic_count_minutes_1": "{{count}} minutes",
"generic_count_minutes_2": "{{count}} minutes",
"generic_count_seconds_0": "{{count}} seconde",
"generic_count_seconds_1": "{{count}} secondes",
"generic_count_seconds_2": "{{count}} secondes",
"Fallback comments: ": "Commentaires alternatifs : ",
"Popular": "Populaire",
"Search": "Rechercher",

View file

@ -500,5 +500,8 @@
"generic_button_save": "Spremi",
"generic_button_cancel": "Odustani",
"generic_button_rss": "RSS",
"channel_tab_releases_label": "Izdanja"
"channel_tab_releases_label": "Izdanja",
"generic_channels_count_0": "{{count}} kanal",
"generic_channels_count_1": "{{count}} kanala",
"generic_channels_count_2": "{{count}} kanala"
}

View file

@ -446,5 +446,28 @@
"crash_page_read_the_faq": "baca <a href=\"`x`\">Soal Sering Ditanya (SSD/FAQ)</a>",
"crash_page_search_issue": "mencari <a href=\"`x`\">isu yang ada di GitHub</a>",
"crash_page_report_issue": "Jika yang di atas tidak membantu, <a href=\"`x`\">buka isu baru di GitHub</a> (sebaiknya dalam bahasa Inggris) dan sertakan teks berikut dalam pesan Anda (JANGAN terjemahkan teks tersebut):",
"Popular enabled: ": "Populer diaktifkan: "
"Popular enabled: ": "Populer diaktifkan: ",
"channel_tab_podcasts_label": "Podcast",
"Download is disabled": "Download dinonaktifkan",
"Channel Sponsor": "Saluran Sponsor",
"channel_tab_streams_label": "Streaming langsung",
"playlist_button_add_items": "Tambahkan video",
"Artist: ": "Artis: ",
"generic_button_save": "Simpan",
"generic_button_cancel": "Batal",
"Album: ": "Album: ",
"channel_tab_shorts_label": "Shorts",
"channel_tab_releases_label": "Terbit",
"Interlingue": "Interlingue",
"Song: ": "Lagu: ",
"generic_channels_count_0": "Saluran {{count}}",
"channel_tab_playlists_label": "Daftar putar",
"generic_button_edit": "Ubah",
"Music in this video": "Musik dalam video ini",
"generic_button_rss": "RSS",
"channel_tab_channels_label": "Saluran",
"error_video_not_in_playlist": "Video yang diminta tidak ada dalam daftar putar ini. <a href=\"`x`\">Klik di sini untuk halaman beranda daftar putar.</a>",
"generic_button_delete": "Hapus",
"Import YouTube playlist (.csv)": "Impor daftar putar YouTube (.csv)",
"Standard YouTube license": "Lisensi YouTube standar"
}

View file

@ -1,10 +1,13 @@
{
"generic_subscribers_count": "{{count}} iscritto",
"generic_subscribers_count_plural": "{{count}} iscritti",
"generic_videos_count": "{{count}} video",
"generic_videos_count_plural": "{{count}} video",
"generic_playlists_count": "{{count}} playlist",
"generic_playlists_count_plural": "{{count}} playlist",
"generic_subscribers_count_0": "{{count}} iscritto",
"generic_subscribers_count_1": "{{count}} iscritti",
"generic_subscribers_count_2": "{{count}} iscritti",
"generic_videos_count_0": "{{count}} video",
"generic_videos_count_1": "{{count}} video",
"generic_videos_count_2": "{{count}} video",
"generic_playlists_count_0": "{{count}} playlist",
"generic_playlists_count_1": "{{count}} playlist",
"generic_playlists_count_2": "{{count}} playlist",
"LIVE": "IN DIRETTA",
"Shared `x` ago": "Condiviso `x` fa",
"Unsubscribe": "Disiscriviti",
@ -113,16 +116,19 @@
"Subscription manager": "Gestione delle iscrizioni",
"Token manager": "Gestione dei gettoni",
"Token": "Gettone",
"generic_subscriptions_count": "{{count}} iscrizione",
"generic_subscriptions_count_plural": "{{count}} iscrizioni",
"tokens_count": "{{count}} gettone",
"tokens_count_plural": "{{count}} gettoni",
"generic_subscriptions_count_0": "{{count}} iscrizione",
"generic_subscriptions_count_1": "{{count}} iscrizioni",
"generic_subscriptions_count_2": "{{count}} iscrizioni",
"tokens_count_0": "{{count}} gettone",
"tokens_count_1": "{{count}} gettoni",
"tokens_count_2": "{{count}} gettoni",
"Import/export": "Importa/esporta",
"unsubscribe": "disiscriviti",
"revoke": "revoca",
"Subscriptions": "Iscrizioni",
"subscriptions_unseen_notifs_count": "{{count}} notifica non visualizzata",
"subscriptions_unseen_notifs_count_plural": "{{count}} notifiche non visualizzate",
"subscriptions_unseen_notifs_count_0": "{{count}} notifica non visualizzata",
"subscriptions_unseen_notifs_count_1": "{{count}} notifiche non visualizzate",
"subscriptions_unseen_notifs_count_2": "{{count}} notifiche non visualizzate",
"search": "Cerca",
"Log out": "Esci",
"Source available here.": "Codice sorgente.",
@ -151,8 +157,9 @@
"Whitelisted regions: ": "Regioni in lista bianca: ",
"Blacklisted regions: ": "Regioni in lista nera: ",
"Shared `x`": "Condiviso `x`",
"generic_views_count": "{{count}} visualizzazione",
"generic_views_count_plural": "{{count}} visualizzazioni",
"generic_views_count_0": "{{count}} visualizzazione",
"generic_views_count_1": "{{count}} visualizzazioni",
"generic_views_count_2": "{{count}} visualizzazioni",
"Premieres in `x`": "In anteprima in `x`",
"Premieres `x`": "In anteprima `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.": "Ciao, Sembra che tu abbia disattivato JavaScript. Clicca qui per visualizzare i commenti, ma considera che il caricamento potrebbe richiedere più tempo.",
@ -300,20 +307,27 @@
"Yiddish": "Yiddish",
"Yoruba": "Yoruba",
"Zulu": "Zulu",
"generic_count_years": "{{count}} anno",
"generic_count_years_plural": "{{count}} anni",
"generic_count_months": "{{count}} mese",
"generic_count_months_plural": "{{count}} mesi",
"generic_count_weeks": "{{count}} settimana",
"generic_count_weeks_plural": "{{count}} settimane",
"generic_count_days": "{{count}} giorno",
"generic_count_days_plural": "{{count}} giorni",
"generic_count_hours": "{{count}} ora",
"generic_count_hours_plural": "{{count}} ore",
"generic_count_minutes": "{{count}} minuto",
"generic_count_minutes_plural": "{{count}} minuti",
"generic_count_seconds": "{{count}} secondo",
"generic_count_seconds_plural": "{{count}} secondi",
"generic_count_years_0": "{{count}} anno",
"generic_count_years_1": "{{count}} anni",
"generic_count_years_2": "{{count}} anni",
"generic_count_months_0": "{{count}} mese",
"generic_count_months_1": "{{count}} mesi",
"generic_count_months_2": "{{count}} mesi",
"generic_count_weeks_0": "{{count}} settimana",
"generic_count_weeks_1": "{{count}} settimane",
"generic_count_weeks_2": "{{count}} settimane",
"generic_count_days_0": "{{count}} giorno",
"generic_count_days_1": "{{count}} giorni",
"generic_count_days_2": "{{count}} giorni",
"generic_count_hours_0": "{{count}} ora",
"generic_count_hours_1": "{{count}} ore",
"generic_count_hours_2": "{{count}} ore",
"generic_count_minutes_0": "{{count}} minuto",
"generic_count_minutes_1": "{{count}} minuti",
"generic_count_minutes_2": "{{count}} minuti",
"generic_count_seconds_0": "{{count}} secondo",
"generic_count_seconds_1": "{{count}} secondi",
"generic_count_seconds_2": "{{count}} secondi",
"Fallback comments: ": "Commenti alternativi: ",
"Popular": "Popolare",
"Search": "Cerca",
@ -417,10 +431,12 @@
"search_filters_duration_option_short": "Corto (< 4 minuti)",
"search_filters_duration_option_long": "Lungo (> 20 minuti)",
"search_filters_features_option_purchased": "Acquistato",
"comments_view_x_replies": "Vedi {{count}} risposta",
"comments_view_x_replies_plural": "Vedi {{count}} risposte",
"comments_points_count": "{{count}} punto",
"comments_points_count_plural": "{{count}} punti",
"comments_view_x_replies_0": "Vedi {{count}} risposta",
"comments_view_x_replies_1": "Vedi {{count}} risposte",
"comments_view_x_replies_2": "Vedi {{count}} risposte",
"comments_points_count_0": "{{count}} punto",
"comments_points_count_1": "{{count}} punti",
"comments_points_count_2": "{{count}} punti",
"Portuguese (auto-generated)": "Portoghese (generati automaticamente)",
"crash_page_you_found_a_bug": "Sembra che tu abbia trovato un bug in Invidious!",
"crash_page_switch_instance": "provato a <a href=\"`x`\">usare un'altra istanza</a>",
@ -484,5 +500,8 @@
"generic_button_delete": "Elimina",
"generic_button_save": "Salva",
"playlist_button_add_items": "Aggiungi video",
"channel_tab_podcasts_label": "Podcast"
"channel_tab_podcasts_label": "Podcast",
"generic_channels_count_0": "{{count}} canale",
"generic_channels_count_1": "{{count}} canali",
"generic_channels_count_2": "{{count}} canali"
}

View file

@ -468,5 +468,6 @@
"generic_button_edit": "編集",
"generic_button_save": "保存",
"generic_button_rss": "RSS",
"playlist_button_add_items": "動画を追加"
"playlist_button_add_items": "動画を追加",
"generic_channels_count_0": "{{count}}個のチャンネル"
}

View file

@ -468,5 +468,6 @@
"generic_button_save": "저장",
"generic_button_cancel": "취소",
"generic_button_rss": "RSS",
"channel_tab_releases_label": "출시"
"channel_tab_releases_label": "출시",
"generic_channels_count_0": "{{count}} 채널"
}

View file

@ -484,5 +484,7 @@
"generic_button_save": "Lagre",
"generic_button_cancel": "Avbryt",
"generic_button_rss": "RSS",
"playlist_button_add_items": "Legg til videoer"
"playlist_button_add_items": "Legg til videoer",
"generic_channels_count": "{{count}} kanal",
"generic_channels_count_plural": "{{count}} kanaler"
}

View file

@ -500,5 +500,8 @@
"channel_tab_releases_label": "Wydania",
"generic_button_delete": "Usuń",
"generic_button_save": "Zapisz",
"playlist_button_add_items": "Dodaj filmy"
"playlist_button_add_items": "Dodaj filmy",
"generic_channels_count_0": "{{count}} kanał",
"generic_channels_count_1": "{{count}} kanały",
"generic_channels_count_2": "{{count}} kanałów"
}

View file

@ -112,8 +112,9 @@
"Subscription manager": "Gerenciador de inscrições",
"Token manager": "Gerenciador de tokens",
"Token": "Token",
"tokens_count": "{{count}} token",
"tokens_count_plural": "{{count}} tokens",
"tokens_count_0": "{{count}} token",
"tokens_count_1": "{{count}} tokens",
"tokens_count_2": "{{count}} tokens",
"Import/export": "Importar/Exportar",
"unsubscribe": "cancelar inscrição",
"revoke": "revogar",
@ -297,20 +298,27 @@
"Yiddish": "Iídiche",
"Yoruba": "Iorubá",
"Zulu": "Zulu",
"generic_count_years": "{{count}} ano",
"generic_count_years_plural": "{{count}} anos",
"generic_count_months": "{{count}} mês",
"generic_count_months_plural": "{{count}} meses",
"generic_count_weeks": "{{count}} semana",
"generic_count_weeks_plural": "{{count}} semanas",
"generic_count_days": "{{count}} dia",
"generic_count_days_plural": "{{count}} dias",
"generic_count_hours": "{{count}} hora",
"generic_count_hours_plural": "{{count}} horas",
"generic_count_minutes": "{{count}} minuto",
"generic_count_minutes_plural": "{{count}} minutos",
"generic_count_seconds": "{{count}} segundo",
"generic_count_seconds_plural": "{{count}} segundos",
"generic_count_years_0": "{{count}} ano",
"generic_count_years_1": "{{count}} anos",
"generic_count_years_2": "{{count}} anos",
"generic_count_months_0": "{{count}} mês",
"generic_count_months_1": "{{count}} meses",
"generic_count_months_2": "{{count}} meses",
"generic_count_weeks_0": "{{count}} semana",
"generic_count_weeks_1": "{{count}} semanas",
"generic_count_weeks_2": "{{count}} semanas",
"generic_count_days_0": "{{count}} dia",
"generic_count_days_1": "{{count}} dias",
"generic_count_days_2": "{{count}} dias",
"generic_count_hours_0": "{{count}} hora",
"generic_count_hours_1": "{{count}} horas",
"generic_count_hours_2": "{{count}} horas",
"generic_count_minutes_0": "{{count}} minuto",
"generic_count_minutes_1": "{{count}} minutos",
"generic_count_minutes_2": "{{count}} minutos",
"generic_count_seconds_0": "{{count}} segundo",
"generic_count_seconds_1": "{{count}} segundos",
"generic_count_seconds_2": "{{count}} segundos",
"Fallback comments: ": "Comentários alternativos: ",
"Popular": "Populares",
"Search": "Procurar",
@ -377,20 +385,27 @@
"preferences_quality_dash_label": "Qualidade de vídeo do painel preferida: ",
"preferences_region_label": "País do conteúdo: ",
"preferences_quality_dash_option_4320p": "4320p",
"generic_videos_count": "{{count}} vídeo",
"generic_videos_count_plural": "{{count}} vídeos",
"generic_playlists_count": "{{count}} lista de reprodução",
"generic_playlists_count_plural": "{{count}} listas de reprodução",
"generic_subscribers_count": "{{count}} inscrito",
"generic_subscribers_count_plural": "{{count}} inscritos",
"generic_subscriptions_count": "{{count}} inscrição",
"generic_subscriptions_count_plural": "{{count}} inscrições",
"subscriptions_unseen_notifs_count": "{{count}} notificação não vista",
"subscriptions_unseen_notifs_count_plural": "{{count}} notificações não vistas",
"comments_view_x_replies": "Ver {{count}} resposta",
"comments_view_x_replies_plural": "Ver {{count}} respostas",
"comments_points_count": "{{count}} ponto",
"comments_points_count_plural": "{{count}} pontos",
"generic_videos_count_0": "{{count}} vídeo",
"generic_videos_count_1": "{{count}} vídeos",
"generic_videos_count_2": "{{count}} vídeos",
"generic_playlists_count_0": "{{count}} lista de reprodução",
"generic_playlists_count_1": "{{count}} listas de reprodução",
"generic_playlists_count_2": "{{count}} listas de reprodução",
"generic_subscribers_count_0": "{{count}} inscrito",
"generic_subscribers_count_1": "{{count}} inscritos",
"generic_subscribers_count_2": "{{count}} inscritos",
"generic_subscriptions_count_0": "{{count}} inscrição",
"generic_subscriptions_count_1": "{{count}} inscrições",
"generic_subscriptions_count_2": "{{count}} inscrições",
"subscriptions_unseen_notifs_count_0": "{{count}} notificação não vista",
"subscriptions_unseen_notifs_count_1": "{{count}} notificações não vistas",
"subscriptions_unseen_notifs_count_2": "{{count}} notificações não vistas",
"comments_view_x_replies_0": "Ver {{count}} resposta",
"comments_view_x_replies_1": "Ver {{count}} respostas",
"comments_view_x_replies_2": "Ver {{count}} respostas",
"comments_points_count_0": "{{count}} ponto",
"comments_points_count_1": "{{count}} pontos",
"comments_points_count_2": "{{count}} pontos",
"crash_page_you_found_a_bug": "Parece que você encontrou um erro no Invidious!",
"crash_page_before_reporting": "Antes de reportar um erro, verifique se você:",
"preferences_save_player_pos_label": "Salvar a posição de reprodução: ",
@ -400,8 +415,9 @@
"crash_page_search_issue": "procurou por um <a href=\"`x`\">erro existente no GitHub</a>",
"crash_page_report_issue": "Se nenhuma opção acima ajudou, por favor <a href=\"`x`\">abra um novo problema no Github</a> (preferencialmente em inglês) e inclua o seguinte texto (NÃO traduza):",
"crash_page_read_the_faq": "leia as <a href=\"`x`\">Perguntas frequentes (FAQ)</a>",
"generic_views_count": "{{count}} visualização",
"generic_views_count_plural": "{{count}} visualizações",
"generic_views_count_0": "{{count}} visualização",
"generic_views_count_1": "{{count}} visualizações",
"generic_views_count_2": "{{count}} visualizações",
"preferences_quality_option_dash": "DASH (qualidade adaptável)",
"preferences_quality_option_hd720": "HD720",
"preferences_quality_option_small": "Pequeno",
@ -484,5 +500,8 @@
"channel_tab_releases_label": "Lançamentos",
"channel_tab_podcasts_label": "Podcasts",
"generic_button_cancel": "Cancelar",
"generic_button_rss": "RSS"
"generic_button_rss": "RSS",
"generic_channels_count_0": "{{count}} canal",
"generic_channels_count_1": "{{count}} canais",
"generic_channels_count_2": "{{count}} canais"
}

View file

@ -500,5 +500,8 @@
"generic_button_cancel": "Отменить",
"generic_button_rss": "RSS",
"playlist_button_add_items": "Добавить видео",
"channel_tab_podcasts_label": "Подкасты"
"channel_tab_podcasts_label": "Подкасты",
"generic_channels_count_0": "{{count}} канал",
"generic_channels_count_1": "{{count}} канала",
"generic_channels_count_2": "{{count}} каналов"
}

View file

@ -516,5 +516,9 @@
"generic_button_rss": "RSS",
"playlist_button_add_items": "Dodaj videoposnetke",
"channel_tab_podcasts_label": "Poddaje",
"channel_tab_releases_label": "Izdaje"
"channel_tab_releases_label": "Izdaje",
"generic_channels_count_0": "{{count}} kanal",
"generic_channels_count_1": "{{count}} kanala",
"generic_channels_count_2": "{{count}} kanali",
"generic_channels_count_3": "{{count}} kanalov"
}

View file

@ -257,7 +257,7 @@
"Video mode": "Mënyrë video",
"channel_tab_videos_label": "Video",
"search_filters_sort_option_rating": "Vlerësim",
"search_filters_sort_option_date": "Datë ngarkimi",
"search_filters_sort_option_date": "Datë Ngarkimi",
"search_filters_sort_option_views": "Numër parjesh",
"search_filters_type_label": "Lloj",
"search_filters_duration_label": "Kohëzgjatje",
@ -345,7 +345,7 @@
"View YouTube comments": "Shihni komente Youtube",
"View more comments on Reddit": "Shihni më tepër komente në Reddit",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Shihni `x` komente",
"([^.,0-9]|^)1([^.,0-9]|$)": "Shihni `x` koment",
"": "Shihni `x` komente"
},
"View Reddit comments": "Shihni komente Reddit",
@ -462,5 +462,20 @@
"channel_tab_channels_label": "Kanale",
"Music in this video": "Muzikë në këtë video",
"channel_tab_shorts_label": "Të shkurtra",
"channel_tab_streams_label": "Transmetime të drejtpërdrejta"
"channel_tab_streams_label": "Transmetime të drejtpërdrejta",
"generic_button_cancel": "Anuloje",
"generic_channels_count": "{{count}} kanal",
"generic_channels_count_plural": "{{count}} kanale",
"generic_button_rss": "RSS",
"generic_button_delete": "Fshije",
"generic_button_save": "Ruaje",
"generic_button_edit": "Përpunoni",
"playlist_button_add_items": "Shtoni video",
"Report statistics: ": "Statistika raportimesh: ",
"Download is disabled": "Shkarkimi është i çaktivizuar",
"Channel Sponsor": "Sponsor Kanali",
"channel_tab_releases_label": "Hedhje në qarkullim",
"Song: ": "Pjesë: ",
"Import YouTube playlist (.csv)": "Importoni luajlistë YouTube (.csv)",
"Standard YouTube license": "Licencë YouTube standarde"
}

View file

@ -1,90 +1,90 @@
{
"LIVE": "UŽIVO",
"Shared `x` ago": "Podeljeno pre `x`",
"Shared `x` ago": "Deljeno pre `x`",
"Unsubscribe": "Prekini praćenje",
"Subscribe": "Prati",
"Subscribe": "Zaprati",
"View channel on YouTube": "Pogledaj kanal na YouTube-u",
"View playlist on YouTube": "Pogledaj spisak izvođenja na YouTube-u",
"View playlist on YouTube": "Pogledaj plejlistu na YouTube-u",
"newest": "najnovije",
"oldest": "najstarije",
"popular": "popularno",
"last": "poslednje",
"Next page": "Sledeća stranica",
"Previous page": "Prethodna stranica",
"Clear watch history?": "Izbrisati povest pregledanja?",
"Clear watch history?": "Očistiti istoriju gledanja?",
"New password": "Nova lozinka",
"New passwords must match": "Nove lozinke moraju biti istovetne",
"Authorize token?": "Ovlasti žeton?",
"Authorize token for `x`?": "Ovlasti žeton za `x`?",
"New passwords must match": "Nove lozinke moraju da se podudaraju",
"Authorize token?": "Autorizovati token?",
"Authorize token for `x`?": "Autorizovati token za `x`?",
"Yes": "Da",
"No": "Ne",
"Import and Export Data": "Uvoz i Izvoz Podataka",
"Import and Export Data": "Uvoz i izvoz podataka",
"Import": "Uvezi",
"Import Invidious data": "Uvezi podatke sa Invidious-a",
"Import YouTube subscriptions": "Uvezi praćenja sa YouTube-a",
"Import FreeTube subscriptions (.db)": "Uvezi praćenja sa FreeTube-a (.db)",
"Import NewPipe subscriptions (.json)": "Uvezi praćenja sa NewPipe-a (.json)",
"Import NewPipe data (.zip)": "Uvezi podatke sa NewPipe-a (.zip)",
"Import Invidious data": "Uvezi Invidious JSON podatke",
"Import YouTube subscriptions": "Uvezi YouTube/OPML praćenja",
"Import FreeTube subscriptions (.db)": "Uvezi FreeTube praćenja (.db)",
"Import NewPipe subscriptions (.json)": "Uvezi NewPipe praćenja (.json)",
"Import NewPipe data (.zip)": "Uvezi NewPipe podatke (.zip)",
"Export": "Izvezi",
"Export subscriptions as OPML": "Izvezi praćenja kao OPML datoteku",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Izvezi praćenja kao OPML datoteku (za NewPipe i FreeTube)",
"Export data as JSON": "Izvezi podatke kao JSON datoteku",
"Delete account?": "Izbrišite nalog?",
"Export subscriptions as OPML": "Izvezi praćenja kao OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Izvezi praćenja kao OPML (za NewPipe i FreeTube)",
"Export data as JSON": "Izvezi Invidious podatke kao JSON",
"Delete account?": "Izbrisati nalog?",
"History": "Istorija",
"An alternative front-end to YouTube": "Zamenski korisnički sloj za YouTube",
"JavaScript license information": "Izveštaj o JavaScript odobrenju",
"An alternative front-end to YouTube": "Alternativni front-end za YouTube",
"JavaScript license information": "Informacije o JavaScript licenci",
"source": "izvor",
"Log in": "Prijavi se",
"Log in/register": "Prijavi se/Otvori nalog",
"User ID": "Korisnički ID",
"Log in": "Prijava",
"Log in/register": "Prijava/registracija",
"User ID": "ID korisnika",
"Password": "Lozinka",
"Time (h:mm:ss):": "Vreme (č:mm:ss):",
"Text CAPTCHA": "Znakovni CAPTCHA",
"Image CAPTCHA": "Slikovni CAPTCHA",
"Text CAPTCHA": "Tekst CAPTCHA",
"Image CAPTCHA": "Slika CAPTCHA",
"Sign In": "Prijava",
"Register": "Otvori nalog",
"E-mail": "E-pošta",
"Register": "Registracija",
"E-mail": "Imejl",
"Preferences": "Podešavanja",
"preferences_category_player": "Podešavanja reproduktora",
"preferences_category_player": "Podešavanja plejera",
"preferences_video_loop_label": "Uvek ponavljaj: ",
"preferences_autoplay_label": "Samopuštanje: ",
"preferences_continue_label": "Uvek podrazumevano puštaj sledeće: ",
"preferences_continue_autoplay_label": "Samopuštanje sledećeg video zapisa: ",
"preferences_listen_label": "Uvek podrazumevano uključen samo zvuk: ",
"preferences_local_label": "Prikaz video zapisa preko posrednika: ",
"Playlist privacy": "Podešavanja privatnosti plej liste",
"Editing playlist `x`": "Izmena plej liste `x`",
"Playlist does not exist.": "Nepostojeća plej lista.",
"preferences_autoplay_label": "Automatski pusti: ",
"preferences_continue_label": "Podrazumevano pusti sledeće: ",
"preferences_continue_autoplay_label": "Automatski pusti sledeći video snimak: ",
"preferences_listen_label": "Podrazumevano uključi samo zvuk: ",
"preferences_local_label": "Proksi video snimci: ",
"Playlist privacy": "Privatnost plejliste",
"Editing playlist `x`": "Izmenjivanje plejliste `x`",
"Playlist does not exist.": "Plejlista ne postoji.",
"Erroneous challenge": "Pogrešan izazov",
"Maltese": "Malteški",
"Download": "Preuzmi",
"Download as: ": "Preuzmi kao: ",
"Bangla": "Bangla/Bengalski",
"preferences_quality_dash_label": "Preferirani kvalitet DASH video formata: ",
"Token manager": "Upravljanje žetonima",
"Token": "Žeton",
"Import/export": "Uvezi/Izvezi",
"Download as: ": "Preuzeti kao: ",
"Bangla": "Bengalski",
"preferences_quality_dash_label": "Preferirani DASH kvalitet video snimka: ",
"Token manager": "Upravljanje tokenima",
"Token": "Token",
"Import/export": "Uvoz/izvoz",
"revoke": "opozovi",
"search": "pretraga",
"Log out": "Odjava",
"Source available here.": "Izvorna koda je ovde dostupna.",
"Source available here.": "Izvorni kôd je dostupan ovde.",
"Trending": "U trendu",
"Updated `x` ago": "Ažurirano pre `x`",
"Delete playlist `x`?": "Obriši plej listu `x`?",
"Create playlist": "Napravi plej listu",
"Delete playlist `x`?": "Izbrisati plejlistu `x`?",
"Create playlist": "Napravi plejlistu",
"Show less": "Prikaži manje",
"Switch Invidious Instance": "Promeni Invidious instancu",
"Hide annotations": "Sakrij napomene",
"User ID is a required field": "Korisnički ID je obavezno polje",
"User ID is a required field": "ID korisnika je obavezno polje",
"Wrong username or password": "Pogrešno korisničko ime ili lozinka",
"Please log in": "Molimo vas da se prijavite",
"Please log in": "Molimo, prijavite se",
"channel:`x`": "kanal:`x`",
"Could not fetch comments": "Uzimanje komentara nije uspelo",
"Could not create mix.": "Pravljenje miksa nije uspelo.",
"Empty playlist": "Prazna plej lista",
"Not a playlist.": "Nije plej lista.",
"Could not pull trending pages.": "Učitavanje 'U toku' stranica nije uspelo.",
"Token is expired, please try again": "Žeton je istekao, molimo vas da pokušate ponovo",
"Could not fetch comments": "Nije moguće prikupiti komentare",
"Could not create mix.": "Nije moguće napraviti miks.",
"Empty playlist": "Prazna plejlista",
"Not a playlist.": "Nije plejlista.",
"Could not pull trending pages.": "Nije moguće povući stranice „U trendu“.",
"Token is expired, please try again": "Token je istekao, pokušajte ponovo",
"English (auto-generated)": "Engleski (automatski generisano)",
"Afrikaans": "Afrikans",
"Albanian": "Albanski",
@ -95,19 +95,19 @@
"Bulgarian": "Bugarski",
"Burmese": "Burmanski",
"Catalan": "Katalonski",
"Cebuano": "Sebuano",
"Cebuano": "Cebuanski",
"Chinese (Traditional)": "Kineski (Tradicionalni)",
"Corsican": "Korzikanski",
"Danish": "Danski",
"Kannada": "Kanada (Jezik)",
"Kannada": "Kanada",
"Kazakh": "Kazaški",
"Russian": "Ruski",
"Scottish Gaelic": "Škotski Gelski",
"Sinhala": "Sinhalki",
"Sinhala": "Sinhalski",
"Slovak": "Slovački",
"Spanish": "Španski",
"Spanish (Latin America)": "Španski (Južna Amerika)",
"Sundanese": "Sundski",
"Spanish (Latin America)": "Španski (Latinska Amerika)",
"Sundanese": "Sundanski",
"Swedish": "Švedski",
"Tajik": "Tadžički",
"Telugu": "Telugu",
@ -116,77 +116,77 @@
"Urdu": "Urdu",
"Uzbek": "Uzbečki",
"Vietnamese": "Vijetnamski",
"Rating: ": "Ocena/e: ",
"View as playlist": "Pogledaj kao plej listu",
"Default": "Podrazumevan/o",
"Gaming": "Igrice",
"Rating: ": "Ocena: ",
"View as playlist": "Pogledaj kao plejlistu",
"Default": "Podrazumevano",
"Gaming": "Video igre",
"Movies": "Filmovi",
"%A %B %-d, %Y": "%A %B %-d, %Y",
"(edited)": "(izmenjeno)",
"YouTube comment permalink": "YouTube komentar trajna veza",
"Audio mode": "Audio mod",
"Playlists": "Plej liste",
"YouTube comment permalink": "Trajni link YouTube komentara",
"Audio mode": "Režim audio snimka",
"Playlists": "Plejliste",
"search_filters_sort_option_relevance": "Relevantnost",
"search_filters_sort_option_rating": "Ocene",
"search_filters_sort_option_rating": "Ocena",
"search_filters_sort_option_date": "Datum otpremanja",
"search_filters_sort_option_views": "Broj pregleda",
"`x` marked it with a ❤": "`x` je označio/la ovo sa ❤",
"`x` marked it with a ❤": "`x` je označio/la sa ❤",
"search_filters_duration_label": "Trajanje",
"search_filters_features_label": "Karakteristike",
"search_filters_date_option_hour": "Poslednji sat",
"search_filters_date_option_week": "Ove sedmice",
"search_filters_date_option_month": "Ovaj mesec",
"search_filters_date_option_week": "Ove nedelje",
"search_filters_date_option_month": "Ovog meseca",
"search_filters_date_option_year": "Ove godine",
"search_filters_type_option_video": "Video",
"search_filters_type_option_playlist": "Plej lista",
"search_filters_type_option_video": "Video snimak",
"search_filters_type_option_playlist": "Plejlista",
"search_filters_type_option_movie": "Film",
"search_filters_duration_option_long": "Dugo (> 20 minuta)",
"search_filters_features_option_hd": "HD",
"search_filters_features_option_c_commons": "Creative Commons (Licenca)",
"search_filters_features_option_c_commons": "Creative Commons",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_hdr": "Video Visoke Rezolucije",
"next_steps_error_message": "Nakon čega bi trebali probati: ",
"next_steps_error_message_go_to_youtube": "Idi na YouTube",
"search_filters_features_option_hdr": "HDR",
"next_steps_error_message": "Nakon toga treba da pokušate da: ",
"next_steps_error_message_go_to_youtube": "Odete na YouTube",
"footer_documentation": "Dokumentacija",
"preferences_region_label": "Država porekla sadržaja: ",
"preferences_region_label": "Država sadržaja: ",
"preferences_player_style_label": "Stil plejera: ",
"preferences_dark_mode_label": "Izgled/Tema: ",
"light": "svetlo",
"preferences_dark_mode_label": "Tema: ",
"light": "svetla",
"preferences_thin_mode_label": "Kompaktni režim: ",
"preferences_category_misc": "Ostala podešavanja",
"preferences_automatic_instance_redirect_label": "Automatsko prebacivanje na drugu instancu u slučaju otkazivanja (preči će nazad na redirect.invidious.io): ",
"alphabetically - reverse": "po alfabetu - obrnuto",
"Enable web notifications": "Omogući obaveštenja u veb pretraživaču",
"`x` is live": "`x` prenosi uživo",
"Manage tokens": "Upravljaj žetonima",
"preferences_automatic_instance_redirect_label": "Automatsko preusmeravanje instance (povratak na redirect.invidious.io): ",
"alphabetically - reverse": "abecedno - obrnuto",
"Enable web notifications": "Omogući veb obaveštenja",
"`x` is live": "`x` je uživo",
"Manage tokens": "Upravljaj tokenima",
"Watch history": "Istorija gledanja",
"preferences_feed_menu_label": "Dovodna stranica: ",
"preferences_feed_menu_label": "Fid meni: ",
"preferences_show_nick_label": "Prikaži nadimke na vrhu: ",
"CAPTCHA enabled: ": "CAPTCHA omogućena: ",
"Registration enabled: ": "Registracija omogućena: ",
"Subscription manager": "Upravljanje praćenjima",
"Wilson score: ": "Wilsonova ocena: ",
"Wilson score: ": "Vilsonova ocena: ",
"Engagement: ": "Angažovanje: ",
"Whitelisted regions: ": "Dozvoljene oblasti: ",
"Shared `x`": "Podeljeno `x`",
"Premieres in `x`": "Premera u `x`",
"Premieres `x`": "Premere u `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.": "Hej! Izgleda da ste onemogućili JavaScript. Kliknite ovde da vidite komentare, čuvajte na umu da ovo može da potraje duže dok se ne učitaju.",
"Whitelisted regions: ": "Dostupni regioni: ",
"Shared `x`": "Deljeno `x`",
"Premieres in `x`": "Premijera u `x`",
"Premieres `x`": "Premijera `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.": "Hej! Izgleda da ste isključili JavaScript. Kliknite ovde da biste videli komentare, imajte na umu da će možda potrajati malo duže da se učitaju.",
"View `x` comments": {
"([^.,0-9]|^)1([^.,0-9]|$)": "Prikaži `x` komentar",
"": "Prikaži `x` komentara"
"([^.,0-9]|^)1([^.,0-9]|$)": "Pogledaj `x` komentar",
"": "Pogledaj`x` komentare"
},
"View Reddit comments": "Prikaži Reddit komentare",
"View Reddit comments": "Pogledaj Reddit komentare",
"CAPTCHA is a required field": "CAPTCHA je obavezno polje",
"Croatian": "Hrvatski",
"Estonian": "Estonski",
"Filipino": "Filipino",
"Filipino": "Filipinski",
"French": "Francuski",
"Galician": "Galicijski",
"German": "Nemački",
"Greek": "Grčki",
"Hausa": "Hausa",
"Italian": "Talijanski",
"Italian": "Italijanski",
"Khmer": "Kmerski",
"Kurdish": "Kurdski",
"Kyrgyz": "Kirgiski",
@ -195,68 +195,68 @@
"Macedonian": "Makedonski",
"Malagasy": "Malgaški",
"Malay": "Malajski",
"Marathi": "Marathi",
"Marathi": "Maratski",
"Mongolian": "Mongolski",
"Norwegian Bokmål": "Norveški Bokmal",
"Nyanja": "Čeva",
"Nyanja": "Nijandža",
"Pashto": "Paštunski",
"Persian": "Persijski",
"Punjabi": "Pundžabi",
"Punjabi": "Pandžapski",
"Romanian": "Rumunski",
"Welsh": "Velški",
"Western Frisian": "Zapadnofrizijski",
"Fallback comments: ": "Komentari u slučaju otkazivanja: ",
"Fallback comments: ": "Rezervni komentari: ",
"Popular": "Popularno",
"Search": "Pretraga",
"About": "O programu",
"footer_source_code": "Izvorna Koda",
"footer_original_source_code": "Originalna Izvorna Koda",
"preferences_related_videos_label": "Prikaži slične video klipove: ",
"preferences_annotations_label": "Prikaži napomene podrazumevano: ",
"preferences_extend_desc_label": "Automatski prikaži ceo opis videa: ",
"preferences_vr_mode_label": "Interaktivni video klipovi u 360 stepeni: ",
"preferences_category_visual": "Vizuelne preference",
"preferences_captions_label": "Podrazumevani titl: ",
"About": "O sajtu",
"footer_source_code": "Izvorni kôd",
"footer_original_source_code": "Originalni izvorni kôd",
"preferences_related_videos_label": "Prikaži povezane video snimke: ",
"preferences_annotations_label": "Podrazumevano prikaži napomene: ",
"preferences_extend_desc_label": "Automatski proširi opis video snimka: ",
"preferences_vr_mode_label": "Interaktivni video snimci od 360 stepeni (zahteva WebGl): ",
"preferences_category_visual": "Vizuelna podešavanja",
"preferences_captions_label": "Podrazumevani titlovi: ",
"Music": "Muzika",
"search_filters_type_label": "Tip",
"search_filters_type_label": "Vrsta",
"Tamil": "Tamilski",
"Save preferences": "Sačuvaj podešavanja",
"Only show latest unwatched video from channel: ": "Prikaži samo poslednje video klipove koji nisu pogledani sa kanala: ",
"Xhosa": "Kosa (Jezik)",
"Only show latest unwatched video from channel: ": "Prikaži samo najnoviji neodgledani video snimak sa kanala: ",
"Xhosa": "Kosa (Khosa)",
"search_filters_type_option_channel": "Kanal",
"Hungarian": "Mađarski",
"Maori": "Maori (Jezik)",
"Manage subscriptions": "Upravljaj zapisima",
"Maori": "Maorski",
"Manage subscriptions": "Upravljaj praćenjima",
"Hindi": "Hindi",
"`x` ago": "pre `x`",
"Import/export data": "Uvezi/Izvezi podatke",
"`x` uploaded a video": "`x` je otpremio/la video klip",
"Delete account": "Obriši nalog",
"`x` uploaded a video": "`x` je otpremio/la video snimak",
"Delete account": "Izbriši nalog",
"preferences_default_home_label": "Podrazumevana početna stranica: ",
"Serbian": "Srpski",
"License: ": "Licenca: ",
"search_filters_features_option_live": "Uživo",
"Report statistics: ": "Izveštavaj o statistici: ",
"Only show latest video from channel: ": "Prikazuj poslednje video klipove samo sa kanala: ",
"Report statistics: ": "Izveštavaj statistike: ",
"Only show latest video from channel: ": "Prikaži samo najnoviji video snimak sa kanala: ",
"channel name - reverse": "ime kanala - obrnuto",
"Could not get channel info.": "Uzimanje podataka o kanalu nije uspelo.",
"View privacy policy.": "Pogledaj izveštaj o privatnosti.",
"Could not get channel info.": "Nije moguće prikupiti informacije o kanalu.",
"View privacy policy.": "Pogledaj politiku privatnosti.",
"Change password": "Promeni lozinku",
"Malayalam": "Malajalam",
"View more comments on Reddit": "Prikaži više komentara na Reddit-u",
"Malayalam": "Malajalamski",
"View more comments on Reddit": "Pogledaj više komentara na Reddit-u",
"Portuguese": "Portugalski",
"View YouTube comments": "Prikaži YouTube komentare",
"View YouTube comments": "Pogledaj YouTube komentare",
"published - reverse": "objavljeno - obrnuto",
"Dutch": "Holandski",
"preferences_volume_label": "Jačina zvuka: ",
"preferences_volume_label": "Jačina zvuka plejera: ",
"preferences_locale_label": "Jezik: ",
"adminprefs_modified_source_code_url_label": "URL veza do skladišta sa Izmenjenom Izvornom Kodom",
"adminprefs_modified_source_code_url_label": "URL adresa do repozitorijuma izmenjenog izvornog koda",
"channel_tab_community_label": "Zajednica",
"Video mode": "Video mod",
"Fallback captions: ": "Titl u slučaju da glavni nije dostupan: ",
"Video mode": "Režim video snimka",
"Fallback captions: ": "Rezervni titlovi: ",
"Private": "Privatno",
"alphabetically": "po alfabetu",
"No such user": "Nepostoji korisnik",
"alphabetically": "abecedno",
"No such user": "Ne postoji korisnik",
"Subscriptions": "Praćenja",
"search_filters_date_option_today": "Danas",
"Finnish": "Finski",
@ -265,30 +265,30 @@
"Shona": "Šona",
"search_filters_features_option_location": "Lokacija",
"Load more": "Učitaj više",
"Released under the AGPLv3 on Github.": "Izbačeno pod licencom AGPLv3 na GitHub-u.",
"Released under the AGPLv3 on Github.": "Objavljeno pod licencom AGPLv3 na GitHub-u.",
"Slovenian": "Slovenački",
"View JavaScript license information.": "Pogledaj informacije licence vezane za JavaScript.",
"View JavaScript license information.": "Pogledaj informacije o JavaScript licenci.",
"Chinese (Simplified)": "Kineski (Pojednostavljeni)",
"preferences_comments_label": "Podrazumevani komentari: ",
"Incorrect password": "Netačna lozinka",
"Show replies": "Prikaži odgovore",
"Invidious Private Feed for `x`": "Invidious Privatni Dovod za `x`",
"Invidious Private Feed for `x`": "Invidious privatni fid za `x`",
"Watch on YouTube": "Gledaj na YouTube-u",
"Wrong answer": "Pogrešan odgovor",
"preferences_quality_label": "Preferirani video kvalitet: ",
"preferences_quality_label": "Preferirani kvalitet video snimka: ",
"Hide replies": "Sakrij odgovore",
"Erroneous CAPTCHA": "Pogrešna CAPTCHA",
"Erroneous token": "Pogrešan žeton",
"Erroneous token": "Pogrešan token",
"Czech": "Češki",
"Latin": "Latinski",
"channel_tab_videos_label": "Video klipovi",
"channel_tab_videos_label": "Video snimci",
"search_filters_features_option_four_k": "4К",
"footer_donate_page": "Doniraj",
"English": "Engleski",
"Arabic": "Arapski",
"Unlisted": "Nenavedeno",
"Hidden field \"challenge\" is a required field": "Sakriveno \"challenge\" polje je obavezno",
"Hidden field \"token\" is a required field": "Sakriveno \"token\" polje je obavezno",
"Unlisted": "Po pozivu",
"Hidden field \"challenge\" is a required field": "Skriveno polje „izazov“ je obavezno polje",
"Hidden field \"token\" is a required field": "Skriveno polje „token“ je obavezno polje",
"Georgian": "Gruzijski",
"Hawaiian": "Havajski",
"Hebrew": "Hebrejski",
@ -297,68 +297,211 @@
"Japanese": "Japanski",
"Javanese": "Javanski",
"Sindhi": "Sindi",
"Swahili": "Svahili",
"Swahili": "Suvali",
"Yiddish": "Jidiš",
"Zulu": "Zulu",
"search_filters_features_option_subtitles": "Titl/Prevod",
"Password cannot be longer than 55 characters": "Lozinka ne može biti duža od 55 karaktera",
"search_filters_features_option_subtitles": "Titlovi/Skriveni titlovi",
"Password cannot be longer than 55 characters": "Lozinka ne može biti duža od 55 znakova",
"This channel does not exist.": "Ovaj kanal ne postoji.",
"Belarusian": "Beloruski",
"Gujarati": "Gudžarati",
"Haitian Creole": "Haićanski Kreolski",
"Somali": "Somalijski",
"Top": "Vrh",
"footer_modfied_source_code": "Izmenjena Izvorna Koda",
"Top": "Top",
"footer_modfied_source_code": "Izmenjeni izvorni kôd",
"preferences_category_subscription": "Podešavanja praćenja",
"preferences_annotations_subscribed_label": "Podrazumevano prikazati napomene za kanale koje pratite? ",
"preferences_max_results_label": "Broj video klipova prikazanih u dovodnoj listi: ",
"preferences_sort_label": "Sortiraj video klipove po: ",
"preferences_unseen_only_label": "Prikaži samo video klipove koji nisu pogledani: ",
"preferences_notifications_only_label": "Prikaži samo obaveštenja (ako ih uopšte ima): ",
"preferences_max_results_label": "Broj video snimaka prikazanih u fidu: ",
"preferences_sort_label": "Sortiraj video snimke po: ",
"preferences_unseen_only_label": "Prikaži samo neodgledano: ",
"preferences_notifications_only_label": "Prikaži samo obaveštenja (ako ih ima): ",
"preferences_category_data": "Podešavanja podataka",
"Clear watch history": "Obriši istoriju gledanja",
"preferences_category_admin": "Administratorska podešavanja",
"Clear watch history": "Očisti istoriju gledanja",
"preferences_category_admin": "Podešavanja administratora",
"published": "objavljeno",
"search_filters_sort_label": "Poredaj prema",
"search_filters_sort_label": "Sortiranje po",
"search_filters_type_option_show": "Emisija",
"search_filters_duration_option_short": "Kratko (< 4 minute)",
"search_filters_duration_option_short": "Kratko (< 4 minuta)",
"Current version: ": "Trenutna verzija: ",
"Top enabled: ": "Vrh omogućen: ",
"Top enabled: ": "Top omogućeno: ",
"Public": "Javno",
"Delete playlist": "Obriši plej listu",
"Delete playlist": "Izbriši plejlistu",
"Title": "Naslov",
"Show annotations": "Prikaži napomene",
"Password cannot be empty": "Lozinka ne može biti prazna",
"Deleted or invalid channel": "Obrisan ili nepostojeći kanal",
"Deleted or invalid channel": "Izbrisan ili nevažeći kanal",
"Esperanto": "Esperanto",
"Hmong": "Hmong",
"Luxembourgish": "Luksemburški",
"Nepali": "Nepalski",
"Samoan": "Samoanski",
"News": "Vesti",
"permalink": "trajna veza",
"permalink": "trajni link",
"Password is a required field": "Lozinka je obavezno polje",
"Amharic": "Amharski",
"Indonesian": "Indonežanski",
"Indonesian": "Indonezijski",
"Irish": "Irski",
"Korean": "Korejski",
"Southern Sotho": "Južni Soto",
"Thai": "Tajski",
"preferences_speed_label": "Podrazumevana brzina: ",
"Dark mode: ": "Tamni režim: ",
"dark": "tamno",
"Redirect homepage to feed: ": "Prebaci sa početne stranice na dovodnu listu: ",
"dark": "tamna",
"Redirect homepage to feed: ": "Preusmeri početnu stranicu na fid: ",
"channel name": "ime kanala",
"View all playlists": "Pregledaj sve plej liste",
"View all playlists": "Pogledaj sve plejliste",
"Show more": "Prikaži više",
"Genre: ": "Žanr: ",
"Family friendly? ": "Pogodno za porodicu? ",
"next_steps_error_message_refresh": "Osveži stranicu",
"next_steps_error_message_refresh": "Osvežite",
"youtube": "YouTube",
"reddit": "Reddit",
"unsubscribe": "prekini sa praćenjem",
"Blacklisted regions: ": "Zabranjene oblasti: ",
"unsubscribe": "prekini praćenje",
"Blacklisted regions: ": "Nedostupni regioni: ",
"Polish": "Poljski",
"Yoruba": "Joruba",
"search_filters_title": "Filter"
"search_filters_title": "Filteri",
"Korean (auto-generated)": "Korejski (automatski generisano)",
"search_filters_features_option_three_sixty": "360°",
"preferences_quality_dash_option_worst": "Najgore",
"channel_tab_podcasts_label": "Podkasti",
"preferences_save_player_pos_label": "Sačuvaj poziciju reprodukcije: ",
"Spanish (Mexico)": "Španski (Meksiko)",
"generic_subscriptions_count_0": "{{count}} praćenje",
"generic_subscriptions_count_1": "{{count}} praćenja",
"generic_subscriptions_count_2": "{{count}} praćenja",
"search_filters_apply_button": "Primeni izabrane filtere",
"Download is disabled": "Preuzimanje je onemogućeno",
"comments_points_count_0": "{{count}} poen",
"comments_points_count_1": "{{count}} poena",
"comments_points_count_2": "{{count}} poena",
"preferences_quality_dash_option_2160p": "2160p",
"German (auto-generated)": "Nemački (automatski generisano)",
"Japanese (auto-generated)": "Japanski (automatski generisano)",
"preferences_quality_option_medium": "Srednje",
"search_message_change_filters_or_query": "Pokušajte da proširite upit za pretragu i/ili promenite filtere.",
"crash_page_before_reporting": "Pre nego što prijavite grešku, uverite se da ste:",
"preferences_quality_dash_option_best": "Najbolje",
"Channel Sponsor": "Sponzor kanala",
"generic_videos_count_0": "{{count}} video snimak",
"generic_videos_count_1": "{{count}} video snimka",
"generic_videos_count_2": "{{count}} video snimaka",
"videoinfo_started_streaming_x_ago": "Započeto strimovanje pre `x`",
"videoinfo_youTube_embed_link": "Ugrađeno",
"channel_tab_streams_label": "Strimovi uživo",
"playlist_button_add_items": "Dodaj video snimke",
"generic_count_minutes_0": "{{count}} minut",
"generic_count_minutes_1": "{{count}} minuta",
"generic_count_minutes_2": "{{count}} minuta",
"preferences_quality_dash_option_720p": "720p",
"preferences_watch_history_label": "Omogući istoriju gledanja: ",
"user_saved_playlists": "Sačuvanih plejlista: `x`",
"Spanish (Spain)": "Španski (Španija)",
"invidious": "Invidious",
"crash_page_refresh": "pokušali da <a href=\"`x`\">osvežite stranicu</a>",
"Chinese (Hong Kong)": "Kineski (Hong Kong)",
"Artist: ": "Izvođač: ",
"generic_count_months_0": "{{count}} mesec",
"generic_count_months_1": "{{count}} meseca",
"generic_count_months_2": "{{count}} meseci",
"search_message_use_another_instance": " Takođe, možete <a href=\"`x`\">pretraživati na drugoj instanci</a>.",
"generic_subscribers_count_0": "{{count}} pratilac",
"generic_subscribers_count_1": "{{count}} pratioca",
"generic_subscribers_count_2": "{{count}} pratilaca",
"download_subtitles": "Titlovi - `x` (.vtt)",
"generic_button_save": "Sačuvaj",
"crash_page_search_issue": "pretražili <a href=\"`x`\">postojeće izveštaje o problemima na GitHub-u</a>",
"generic_button_cancel": "Otkaži",
"none": "nijedno",
"English (United States)": "Engleski (Sjedinjene Američke Države)",
"subscriptions_unseen_notifs_count_0": "{{count}} neviđeno obaveštenje",
"subscriptions_unseen_notifs_count_1": "{{count}} neviđena obaveštenja",
"subscriptions_unseen_notifs_count_2": "{{count}} neviđenih obaveštenja",
"Album: ": "Album: ",
"preferences_quality_option_dash": "DASH (adaptivni kvalitet)",
"preferences_quality_dash_option_1080p": "1080p",
"Video unavailable": "Video snimak nedostupan",
"tokens_count_0": "{{count}} token",
"tokens_count_1": "{{count}} tokena",
"tokens_count_2": "{{count}} tokena",
"Chinese (China)": "Kineski (Kina)",
"Italian (auto-generated)": "Italijanski (automatski generisano)",
"channel_tab_shorts_label": "Shorts",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_360p": "360p",
"search_message_no_results": "Nisu pronađeni rezultati.",
"channel_tab_releases_label": "Izdanja",
"preferences_quality_dash_option_144p": "144p",
"Interlingue": "Interlingva",
"Song: ": "Pesma: ",
"generic_channels_count_0": "{{count}} kanal",
"generic_channels_count_1": "{{count}} kanala",
"generic_channels_count_2": "{{count}} kanala",
"Chinese (Taiwan)": "Kineski (Tajvan)",
"Turkish (auto-generated)": "Turski (automatski generisano)",
"Indonesian (auto-generated)": "Indonezijski (automatski generisano)",
"Portuguese (auto-generated)": "Portugalski (automatski generisano)",
"generic_count_years_0": "{{count}} godina",
"generic_count_years_1": "{{count}} godine",
"generic_count_years_2": "{{count}} godina",
"videoinfo_invidious_embed_link": "Ugrađeni link",
"Popular enabled: ": "Popularno omogućeno: ",
"Spanish (auto-generated)": "Španski (automatski generisano)",
"preferences_quality_option_small": "Malo",
"English (United Kingdom)": "Engleski (Ujedinjeno Kraljevstvo)",
"channel_tab_playlists_label": "Plejliste",
"generic_button_edit": "Izmeni",
"generic_playlists_count_0": "{{count}} plejlista",
"generic_playlists_count_1": "{{count}} plejliste",
"generic_playlists_count_2": "{{count}} plejlista",
"preferences_quality_option_hd720": "HD720",
"search_filters_features_option_purchased": "Kupljeno",
"search_filters_date_option_none": "Bilo koji datum",
"preferences_quality_dash_option_auto": "Automatski",
"Cantonese (Hong Kong)": "Kantonski (Hong Kong)",
"crash_page_report_issue": "Ako ništa od gorenavedenog nije pomoglo, <a href=\"`x`\">otvorite novi izveštaj o problemu na GitHub-u</a> (po mogućnosti na engleskom) i uključite sledeći tekst u svoju poruku (NE prevodite taj tekst):",
"crash_page_switch_instance": "pokušali da <a href=\"`x`\">koristite drugu instancu</a>",
"generic_count_weeks_0": "{{count}} nedelja",
"generic_count_weeks_1": "{{count}} nedelje",
"generic_count_weeks_2": "{{count}} nedelja",
"videoinfo_watch_on_youTube": "Gledaj na YouTube-u",
"Music in this video": "Muzika u ovom video snimku",
"generic_button_rss": "RSS",
"preferences_quality_dash_option_4320p": "4320p",
"generic_count_hours_0": "{{count}} sat",
"generic_count_hours_1": "{{count}} sata",
"generic_count_hours_2": "{{count}} sati",
"French (auto-generated)": "Francuski (automatski generisano)",
"crash_page_read_the_faq": "pročitali <a href=\"`x`\">Često Postavljana Pitanja (ČPP)</a>",
"user_created_playlists": "Napravljenih plejlista: `x`",
"channel_tab_channels_label": "Kanali",
"search_filters_type_option_all": "Bilo koja vrsta",
"Russian (auto-generated)": "Ruski (automatski generisano)",
"preferences_quality_dash_option_480p": "480p",
"comments_view_x_replies_0": "Pogledaj {{count}} odgovor",
"comments_view_x_replies_1": "Pogledaj {{count}} odgovora",
"comments_view_x_replies_2": "Pogledaj {{count}} odgovora",
"Portuguese (Brazil)": "Portugalski (Brazil)",
"search_filters_features_option_vr180": "VR180",
"error_video_not_in_playlist": "Traženi video snimak ne postoji na ovoj plejlisti. <a href=\"`x`\">Kliknite ovde za početnu stranicu plejliste.</a>",
"Dutch (auto-generated)": "Holandski (automatski generisano)",
"generic_count_days_0": "{{count}} dan",
"generic_count_days_1": "{{count}} dana",
"generic_count_days_2": "{{count}} dana",
"Vietnamese (auto-generated)": "Vijetnamski (automatski generisano)",
"search_filters_duration_option_none": "Bilo koje trajanje",
"preferences_quality_dash_option_240p": "240p",
"Chinese": "Kineski",
"generic_button_delete": "Izbriši",
"Import YouTube playlist (.csv)": "Uvezi YouTube plejlistu (.csv)",
"Standard YouTube license": "Standardna YouTube licenca",
"search_filters_duration_option_medium": "Srednje (4 - 20 minuta)",
"generic_count_seconds_0": "{{count}} sekunda",
"generic_count_seconds_1": "{{count}} sekunde",
"generic_count_seconds_2": "{{count}} sekundi",
"search_filters_date_label": "Datum otpremanja",
"crash_page_you_found_a_bug": "Izgleda da ste pronašli grešku u Invidious-u!",
"generic_views_count_0": "{{count}} pregled",
"generic_views_count_1": "{{count}} pregleda",
"generic_views_count_2": "{{count}} pregleda"
}

View file

@ -1,166 +1,166 @@
{
"LIVE": "УЖИВО",
"Shared `x` ago": "Подељено пре `x`",
"Shared `x` ago": "Дељено пре `x`",
"Unsubscribe": "Прекини праћење",
"Subscribe": "Прати",
"Subscribe": "Запрати",
"View channel on YouTube": "Погледај канал на YouTube-у",
"View playlist on YouTube": "Погледај списак извођења на YоуТубе-у",
"View playlist on YouTube": "Погледај плејлисту на YouTube-у",
"newest": "најновије",
"oldest": "најстарије",
"popular": "популарно",
"last": "последње",
"Next page": "Следећа страна",
"Previous page": "Претходна страна",
"Clear watch history?": "Избрисати повест прегледања?",
"Next page": "Следећа страница",
"Previous page": "Претходна страница",
"Clear watch history?": "Очистити историју гледања?",
"New password": "Нова лозинка",
"New passwords must match": "Нове лозинке морају бити истоветне",
"Authorize token?": "Овласти жетон?",
"Authorize token for `x`?": "Овласти жетон за `x`?",
"New passwords must match": "Нове лозинке морају да се подударају",
"Authorize token?": "Ауторизовати токен?",
"Authorize token for `x`?": "Ауторизовати токен за `x`?",
"Yes": "Да",
"No": "Не",
"Import and Export Data": "Увоз и извоз података",
"Import": "Увези",
"Import Invidious data": "Увези податке са Individious-а",
"Import YouTube subscriptions": "Увези праћења са YouTube-а",
"Import FreeTube subscriptions (.db)": "Увези праћења са FreeTube-а (.db)",
"Import NewPipe subscriptions (.json)": "Увези праћења са NewPipe-а (.json)",
"Import NewPipe data (.zip)": "Увези податке са NewPipe-a (.zip)",
"Import Invidious data": "Увези Invidious JSON податке",
"Import YouTube subscriptions": "Увези YouTube/OPML праћења",
"Import FreeTube subscriptions (.db)": "Увези FreeTube праћења (.db)",
"Import NewPipe subscriptions (.json)": "Увези NewPipe праћења (.json)",
"Import NewPipe data (.zip)": "Увези NewPipe податке (.zip)",
"Export": "Извези",
"Export subscriptions as OPML": "Извези праћења као ОПМЛ датотеку",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Извези праћења као ОПМЛ датотеку (за NewPipe и FreeTube)",
"Export data as JSON": "Извези податке као JSON датотеку",
"Delete account?": "Избришите налог?",
"Export subscriptions as OPML": "Извези праћења као OPML",
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Извези праћења као OPML (за NewPipe и FreeTube)",
"Export data as JSON": "Извези Invidious податке као JSON",
"Delete account?": "Избрисати налог?",
"History": "Историја",
"An alternative front-end to YouTube": "Заменски кориснички слој за YouTube",
"JavaScript license information": звештај о JavaScript одобрењу",
"An alternative front-end to YouTube": "Алтернативни фронт-енд за YouTube",
"JavaScript license information": нформације о JavaScript лиценци",
"source": "извор",
"Log in": "Пријави се",
"Log in/register": "Пријави се/Отворите налог",
"User ID": "Кориснички ИД",
"Log in": "Пријава",
"Log in/register": "Пријава/регистрација",
"User ID": "ID корисника",
"Password": "Лозинка",
"Time (h:mm:ss):": "Време (ч:мм:сс):",
"Text CAPTCHA": "Знаковни ЦАПТЧА",
"Image CAPTCHA": "Сликовни CAPTCHA",
"Text CAPTCHA": "Текст CAPTCHA",
"Image CAPTCHA": "Слика CAPTCHA",
"Sign In": "Пријава",
"Register": "Отвори налог",
"E-mail": "Е-пошта",
"Register": "Регистрација",
"E-mail": "Имејл",
"Preferences": "Подешавања",
"preferences_category_player": "Подешавања репродуктора",
"preferences_category_player": "Подешавања плејера",
"preferences_video_loop_label": "Увек понављај: ",
"preferences_autoplay_label": "Самопуштање: ",
"preferences_continue_label": "Увек подразумевано пуштај следеће: ",
"preferences_continue_autoplay_label": "Самопуштање следећег видео записа: ",
"preferences_listen_label": "Увек подразумевано укључен само звук: ",
"preferences_local_label": "Приказ видео записа преко посредника: ",
"preferences_autoplay_label": "Аутоматски пусти: ",
"preferences_continue_label": "Подразумевано пусти следеће: ",
"preferences_continue_autoplay_label": "Аутоматски пусти следећи видео снимак: ",
"preferences_listen_label": "Подразумевано укључи само звук: ",
"preferences_local_label": "Прокси видео снимци: ",
"preferences_speed_label": "Подразумевана брзина: ",
"preferences_quality_label": "Преферирани видео квалитет: ",
"preferences_volume_label": "Јачина звука: ",
"preferences_quality_label": "Преферирани квалитет видео снимка: ",
"preferences_volume_label": "Јачина звука плејера: ",
"preferences_comments_label": "Подразумевани коментари: ",
"youtube": "YouTube",
"reddit": "Reddit",
"preferences_captions_label": "Подразумевани титл: ",
"Fallback captions: ": "Титл у случају да главни није доступан: ",
"preferences_related_videos_label": "Прикажи сличне видео клипове: ",
"preferences_annotations_label": рикажи напомене подразумевано: ",
"preferences_category_visual": "Визуелне преференце",
"preferences_captions_label": "Подразумевани титлови: ",
"Fallback captions: ": "Резервни титлови: ",
"preferences_related_videos_label": "Прикажи повезане видео снимке: ",
"preferences_annotations_label": одразумевано прикажи напомене: ",
"preferences_category_visual": "Визуелна подешавања",
"preferences_player_style_label": "Стил плејера: ",
"Dark mode: ": "Тамни режим: ",
"preferences_dark_mode_label": "Изглед/Тема: ",
"dark": "тамно",
"light": "светло",
"preferences_dark_mode_label": "Тема: ",
"dark": "тамна",
"light": "светла",
"preferences_thin_mode_label": "Компактни режим: ",
"preferences_category_subscription": "Подешавања праћења",
"preferences_annotations_subscribed_label": "Подразумевано приказати напомене за канале које пратите? ",
"Redirect homepage to feed: ": "Пребаци са почетне странице на доводну листу: ",
"preferences_max_results_label": "Број видео клипова приказаних у доводној листи: ",
"preferences_sort_label": "Сортирај видео клипове по: ",
"Redirect homepage to feed: ": "Преусмери почетну страницу на фид: ",
"preferences_max_results_label": "Број видео снимака приказаних у фиду: ",
"preferences_sort_label": "Сортирај видео снимке по: ",
"published": "објављено",
"published - reverse": "објављено - обрнуто",
"alphabetically": "по алфабету",
"alphabetically - reverse": "по алфабету - обрнуто",
"alphabetically": "абецедно",
"alphabetically - reverse": "абецедно - обрнуто",
"channel name": "име канала",
"channel name - reverse": "име канала - обрнуто",
"Only show latest video from channel: ": "Приказуј последње видео клипове само са канала: ",
"Only show latest unwatched video from channel: ": "Прикажи само последње видео клипове који нису погледани са канала: ",
"preferences_unseen_only_label": "Прикажи само видео клипове који нису погледани: ",
"preferences_notifications_only_label": "Прикажи само обавештења (ако их уопште има): ",
"Enable web notifications": "Омогући обавештења у веб претраживачу",
"`x` uploaded a video": "`x` је отпремио/ла видео клип",
"`x` is live": "`x` преноси уживо",
"Only show latest video from channel: ": "Прикажи само најновији видео снимак са канала: ",
"Only show latest unwatched video from channel: ": "Прикажи само најновији неодгледани видео снимак са канала: ",
"preferences_unseen_only_label": "Прикажи само недогледано: ",
"preferences_notifications_only_label": "Прикажи само обавештења (ако их има): ",
"Enable web notifications": "Омогући веб обавештења",
"`x` uploaded a video": "`x` је отпремио/ла видео снимак",
"`x` is live": "`x` је уживо",
"preferences_category_data": "Подешавања података",
"Clear watch history": "Обриши историју гледања",
"Clear watch history": "Очисти историју гледања",
"Import/export data": "Увези/Извези податке",
"Change password": "Промени лозинку",
"Manage subscriptions": "Управљај записима",
"Manage tokens": "Управљај жетонима",
"Manage subscriptions": "Управљај праћењима",
"Manage tokens": "Управљај токенима",
"Watch history": "Историја гледања",
"Delete account": "Обриши налог",
"preferences_category_admin": "Администраторска подешавања",
"Delete account": "Избриши налог",
"preferences_category_admin": "Подешавања администратора",
"preferences_default_home_label": "Подразумевана почетна страница: ",
"preferences_feed_menu_label": "Доводна страница: ",
"preferences_feed_menu_label": "Фид мени: ",
"CAPTCHA enabled: ": "CAPTCHA омогућена: ",
"Login enabled: ": "Пријава омогућена: ",
"Registration enabled: ": "Регистрација омогућена: ",
"Save preferences": "Сачувај подешавања",
"Subscription manager": "Управљање праћењима",
"Token manager": "Управљање жетонима",
"Token": "Жетон",
"Import/export": "Увези/Извези",
"unsubscribe": "прекини са праћењем",
"Token manager": "Управљање токенима",
"Token": "Токен",
"Import/export": "Увоз/извоз",
"unsubscribe": "прекини праћење",
"revoke": "опозови",
"Subscriptions": "Праћења",
"search": "претрага",
"Log out": "Одјава",
"Source available here.": "Изворна кода је овде доступна.",
"View JavaScript license information.": "Погледај информације лиценце везане за JavaScript.",
"View privacy policy.": "Погледај извештај о приватности.",
"Source available here.": "Изворни кôд је доступан овде.",
"View JavaScript license information.": "Погледај информације о JavaScript лиценци.",
"View privacy policy.": "Погледај политику приватности.",
"Trending": "У тренду",
"Public": "Јавно",
"Unlisted": "Ненаведено",
"Unlisted": "По позиву",
"Private": "Приватно",
"View all playlists": регледај све плеј листе",
"View all playlists": огледај све плејлисте",
"Updated `x` ago": "Ажурирано пре `x`",
"Delete playlist `x`?": "Обриши плеј листу `x`?",
"Delete playlist": "Обриши плеј листу",
"Create playlist": "Направи плеј листу",
"Delete playlist `x`?": "Избрисати плејлисту `x`?",
"Delete playlist": "Избриши плејлисту",
"Create playlist": "Направи плејлисту",
"Title": "Наслов",
"Playlist privacy": одешавања приватности плеј листе",
"Editing playlist `x`": "Измена плеј листе `x`",
"Playlist privacy": риватност плејлисте",
"Editing playlist `x`": "Измењивање плејлисте `x`",
"Watch on YouTube": "Гледај на YouTube-у",
"Hide annotations": "Сакриј напомене",
"Show annotations": "Прикажи напомене",
"Genre: ": "Жанр: ",
"License: ": "Лиценца: ",
"Engagement: ": "Ангажовање: ",
"Whitelisted regions: ": "Дозвољене области: ",
"Blacklisted regions: ": "Забрањене области: ",
"Premieres in `x`": "Премера у `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": рикажи YouTube коментаре",
"View more comments on Reddit": рикажи више коментара на Reddit-у",
"View Reddit comments": рикажи Reddit коментаре",
"Whitelisted regions: ": "Доступни региони: ",
"Blacklisted regions: ": "Недоступни региони: ",
"Premieres in `x`": "Премијера у `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": огледај YouTube коментаре",
"View more comments on Reddit": огледај више коментара на Reddit-у",
"View Reddit comments": огледај Reddit коментаре",
"Hide replies": "Сакриј одговоре",
"Show replies": "Прикажи одговоре",
"Incorrect password": "Нетачна лозинка",
"Current version: ": "Тренутна верзија: ",
"Wilson score: ": "Wилсонова оцена: ",
"Wilson score: ": "Вилсонова оцена: ",
"Burmese": "Бурмански",
"preferences_quality_dash_label": "Преферирани квалитет DASH видео формата: ",
"Erroneous token": "Погрешан жетон",
"preferences_quality_dash_label": "Преферирани DASH квалитет видео снимка: ",
"Erroneous token": "Погрешан токен",
"CAPTCHA is a required field": "CAPTCHA је обавезно поље",
"No such user": "Непостојећи корисник",
"No such user": "Не постоји корисник",
"Chinese (Traditional)": "Кинески (Традиционални)",
"adminprefs_modified_source_code_url_label": "УРЛ веза до складишта са Измењеном Изворном Кодом",
"adminprefs_modified_source_code_url_label": "URL адреса до репозиторијума измењеног изворног кода",
"Lao": "Лаоски",
"Czech": "Чешки",
"Kannada": "Канада (Језик)",
"Kannada": "Канада",
"Polish": "Пољски",
"Cebuano": "Себуано",
"Cebuano": "Цебуански",
"preferences_show_nick_label": "Прикажи надимке на врху: ",
"Report statistics: ": "Извештавај о статистици: ",
"Report statistics: ": "Извештавај статистике: ",
"Show more": "Прикажи више",
"Wrong answer": "Погрешан одговор",
"Hidden field \"token\" is a required field": "Сакривено \"token\" поље је обавезно",
"Hidden field \"token\" is a required field": "Скривено поље „токен“ је обавезно поље",
"English": "Енглески",
"Albanian": "Албански",
"Amharic": "Амхарски",
@ -176,38 +176,38 @@
"Georgian": "Грузијски",
"Greek": "Грчки",
"Hausa": "Хауса",
"search_filters_type_option_video": "Видео",
"search_filters_type_option_playlist": "Плеј листа",
"search_filters_type_option_video": "Видео снимак",
"search_filters_type_option_playlist": "Плејлиста",
"search_filters_type_option_movie": "Филм",
"search_filters_duration_option_long": "Дуго (> 20 минута)",
"search_filters_features_option_c_commons": "Creative Commons (Лиценца)",
"search_filters_features_option_c_commons": "Creative Commons",
"search_filters_features_option_live": "Уживо",
"search_filters_features_option_location": "Локација",
"next_steps_error_message": "Након чега би требали пробати: ",
"next_steps_error_message": "Након тога би требало да покушате да: ",
"footer_donate_page": "Донирај",
"footer_documentation": "Документација",
"footer_modfied_source_code": "Измењена Изворна Кода",
"preferences_region_label": "Држава порекла садржаја: ",
"footer_modfied_source_code": "Измењени изворни кôд",
"preferences_region_label": "Држава садржаја: ",
"preferences_category_misc": "Остала подешавања",
"User ID is a required field": "Кориснички ИД је обавезно поље",
"User ID is a required field": "ID корисника је обавезно поље",
"Password is a required field": "Лозинка је обавезно поље",
"Wrong username or password": "Погрешно корисничко име или лозинка",
"Password cannot be empty": "Лозинка не може бити празна",
"Password cannot be longer than 55 characters": "Лозинка не може бити дужа од 55 карактера",
"Invidious Private Feed for `x`": "Инвидиоус Приватни Довод за `x`",
"Deleted or invalid channel": "Обрисан или непостојећи канал",
"Password cannot be longer than 55 characters": "Лозинка не може бити дужа од 55 знакова",
"Invidious Private Feed for `x`": "Invidious приватни фид за `x`",
"Deleted or invalid channel": "Избрисан или неважећи канал",
"This channel does not exist.": "Овај канал не постоји.",
"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": "Сакривено \"challenge\" поље је обавезно",
"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": "Скривено поље „изазов“ је обавезно поље",
"Telugu": "Телугу",
"Turkish": "Турски",
"Urdu": "Урду",
"Western Frisian": "Западнофрисијски",
"Xhosa": "Коса (Језик)",
"Western Frisian": "Западнофризијски",
"Xhosa": "Коса (Кхоса)",
"Yiddish": "Јидиш",
"Hawaiian": "Хавајски",
"Hmong": "Хмонг",
@ -217,58 +217,58 @@
"Khmer": "Кмерски",
"Kyrgyz": "Киргиски",
"Macedonian": "Македонски",
"Maori": "Маори (Језик)",
"Marathi": "Маратхи",
"Maori": "Маорски",
"Marathi": "Маратски",
"Nepali": "Непалски",
"Norwegian Bokmål": "Норвешки Бокмал",
"Nyanja": "Чева",
"Nyanja": "Нијанџа",
"Russian": "Руски",
"Scottish Gaelic": "Шкотски Гелски",
"Shona": "Шона",
"Slovak": "Словачки",
"Spanish (Latin America)": "Шпански (Јужна Америка)",
"Sundanese": "Сундски",
"Swahili": "Свахили",
"Spanish (Latin America)": "Шпански (Латинска Америка)",
"Sundanese": "Сундански",
"Swahili": "Сували",
"Tajik": "Таџички",
"Search": "Претрага",
"Rating: ": "Ocena/e: ",
"Default": "Подразумеван/о",
"Rating: ": "Оцена: ",
"Default": "Подразумевано",
"News": "Вести",
"Download": "Преузми",
"(edited)": "(измењено)",
"`x` marked it with a ❤": "`x` је означио/ла ово са ❤",
"Audio mode": "Аудио мод",
"channel_tab_videos_label": "Видео клипови",
"`x` marked it with a ❤": "`x` је означио/ла са ❤",
"Audio mode": "Режим аудио снимка",
"channel_tab_videos_label": "Видео снимци",
"search_filters_sort_option_views": "Број прегледа",
"search_filters_features_label": "Карактеристике",
"search_filters_date_option_today": "Данас",
"%A %B %-d, %Y": "%A %B %-d, %Y",
"preferences_locale_label": "Језик: ",
"Persian": "Перзијски",
"Persian": "Персијски",
"View `x` comments": {
"": рикажи `x` коментара",
"([^.,0-9]|^)1([^.,0-9]|$)": рикажи `x` коментар"
"": огледај `x` коментаре",
"([^.,0-9]|^)1([^.,0-9]|$)": огледај `x` коментар"
},
"search_filters_type_option_channel": "Канал",
"Haitian Creole": "Хаићански Креолски",
"Armenian": "Јерменски",
"next_steps_error_message_go_to_youtube": "Иди на YouTube",
"Indonesian": "Индонежански",
"preferences_vr_mode_label": "Интерактивни видео клипови у 360 степени: ",
"next_steps_error_message_go_to_youtube": "Одете на YouTube",
"Indonesian": "Индонезијски",
"preferences_vr_mode_label": "Интерактивни видео снимци од 360 степени (захтева WebGL): ",
"Switch Invidious Instance": "Промени Invidious инстанцу",
"Portuguese": "Португалски",
"search_filters_date_option_week": "Ове седмице",
"search_filters_date_option_week": "Ове недеље",
"search_filters_type_option_show": "Емисија",
"Fallback comments: ": "Коментари у случају отказивања: ",
"search_filters_features_option_hdr": "Видео Високе Резолуције",
"About": "О програму",
"Fallback comments: ": "Резервни коментари: ",
"search_filters_features_option_hdr": "HDR",
"About": "О сајту",
"Kazakh": "Казашки",
"Shared `x`": "Подељено `x`",
"Playlists": "Плеј листе",
"Shared `x`": "Дељено `x`",
"Playlists": "Плејлисте",
"Yoruba": "Јоруба",
"Erroneous challenge": "Погрешан изазов",
"Danish": "Дански",
"Could not get channel info.": "Узимање података о каналу није успело.",
"Could not get channel info.": "Није могуће прикупити информације о каналу.",
"search_filters_features_option_hd": "HD",
"Slovenian": "Словеначки",
"Load more": "Учитај више",
@ -276,53 +276,53 @@
"Luxembourgish": "Луксембуршки",
"Mongolian": "Монголски",
"Latvian": "Летонски",
"channel:`x`": "kanal:`x`",
"channel:`x`": "канал:`x`",
"Southern Sotho": "Јужни Сото",
"Popular": "Популарно",
"Gujarati": "Гуџарати",
"search_filters_date_option_year": "Ове године",
"Irish": "Ирски",
"YouTube comment permalink": "YouTube коментар трајна веза",
"YouTube comment permalink": "Трајни линк YouTube коментара",
"Malagasy": "Малгашки",
"Token is expired, please try again": "Жетон је истекао, молимо вас да покушате поново",
"search_filters_duration_option_short": "Кратко (< 4 минуте)",
"Token is expired, please try again": "Токен је истекао, покушајте поново",
"search_filters_duration_option_short": "Кратко (< 4 минута)",
"Samoan": "Самоански",
"Tamil": "Тамилски",
"Ukrainian": "Украјински",
"permalink": "трајна веза",
"permalink": "трајни линк",
"Pashto": "Паштунски",
"channel_tab_community_label": "Заједница",
"Sindhi": "Синди",
"Could not fetch comments": "Узимање коментара није успело",
"Bangla": англа/Бенгалски",
"Could not fetch comments": "Није могуће прикупити коментаре",
"Bangla": енгалски",
"Uzbek": "Узбечки",
"Lithuanian": "Литвански",
"Icelandic": "Исландски",
"Thai": "Тајски",
"search_filters_date_option_month": "Овај месец",
"search_filters_type_label": "Тип",
"search_filters_date_option_month": "Овог месеца",
"search_filters_type_label": "Врста",
"search_filters_date_option_hour": "Последњи сат",
"Spanish": "Шпански",
"search_filters_sort_option_date": "Датум отпремања",
"View as playlist": "Погледај као плеј листу",
"View as playlist": "Погледај као плејлисту",
"search_filters_sort_option_relevance": "Релевантност",
"Estonian": "Естонски",
"Sinhala": "Синхалешки",
"Sinhala": "Синхалски",
"Corsican": "Корзикански",
"Filipino": "Филипино",
"Gaming": "Игрице",
"Filipino": "Филипински",
"Gaming": "Видео игре",
"Movies": "Филмови",
"search_filters_sort_option_rating": "Оцене",
"Top enabled: ": "Врх омогућен: ",
"Released under the AGPLv3 on Github.": "Избачено под лиценцом AGPLv3 на GitHub-у.",
"search_filters_sort_option_rating": "Оцена",
"Top enabled: ": "Топ омогућено: ",
"Released under the AGPLv3 on Github.": "Објављено под лиценцом AGPLv3 на GitHub-у.",
"Afrikaans": "Африканс",
"preferences_automatic_instance_redirect_label": "Аутоматско пребацивање на другу инстанцу у случају отказивања (пречи ће назад на редирецт.инвидиоус.ио): ",
"Please log in": "Молимо вас да се пријавите",
"preferences_automatic_instance_redirect_label": "Аутоматско преусмеравање инстанце (повратак на redirect.invidious.io): ",
"Please log in": "Молимо, пријавите се",
"English (auto-generated)": "Енглески (аутоматски генерисано)",
"Hindi": "Хинди",
"Italian": "Талијански",
"Malayalam": "Малајалам",
"Punjabi": унџаби",
"Italian": "Италијански",
"Malayalam": "Малајаламски",
"Punjabi": анџапски",
"Somali": "Сомалијски",
"Vietnamese": "Вијетнамски",
"Welsh": "Велшки",
@ -330,25 +330,25 @@
"Maltese": "Малтешки",
"Swedish": "Шведски",
"Music": "Музика",
"Download as: ": "Преузми као: ",
"Download as: ": "Преузети као: ",
"search_filters_duration_label": "Трајање",
"search_filters_sort_label": "Поредај према",
"search_filters_features_option_subtitles": "Титл/Превод",
"preferences_extend_desc_label": "Аутоматски прикажи цео опис видеа: ",
"search_filters_sort_label": "Сортирање по",
"search_filters_features_option_subtitles": "Титлови/Скривени титлови",
"preferences_extend_desc_label": "Аутоматски прошири опис видео снимка: ",
"Show less": "Прикажи мање",
"Family friendly? ": "Погодно за породицу? ",
"Premieres `x`": "Премерe у `x`",
"Premieres `x`": "Премијера `x`",
"Bosnian": "Босански",
"Catalan": "Каталонски",
"Japanese": "Јапански",
"Latin": "Латински",
"next_steps_error_message_refresh": "Освежи страницу",
"footer_original_source_code": "Оригинална Изворна Кода",
"next_steps_error_message_refresh": "Освежите",
"footer_original_source_code": "Оригинални изворни кôд",
"Romanian": "Румунски",
"Serbian": "Српски",
"Top": "Врх",
"Video mode": "Видео мод",
"footer_source_code": "Изворна Кода",
"Top": "Топ",
"Video mode": "Режим видео снимка",
"footer_source_code": "Изворни кôд",
"search_filters_features_option_three_d": "3D",
"search_filters_features_option_four_k": "4K",
"Erroneous CAPTCHA": "Погрешна CAPTCHA",
@ -360,5 +360,148 @@
"Korean": "Корејски",
"Kurdish": "Курдски",
"Malay": "Малајски",
"search_filters_title": "Филтер"
"search_filters_title": "Филтери",
"Korean (auto-generated)": "Корејски (аутоматски генерисано)",
"search_filters_features_option_three_sixty": "360°",
"preferences_quality_dash_option_worst": "Најгоре",
"channel_tab_podcasts_label": "Подкасти",
"preferences_save_player_pos_label": "Сачувај позицију репродукције: ",
"Spanish (Mexico)": "Шпански (Мексико)",
"generic_subscriptions_count_0": "{{count}} праћење",
"generic_subscriptions_count_1": "{{count}} праћења",
"generic_subscriptions_count_2": "{{count}} праћења",
"search_filters_apply_button": "Примени изабране филтере",
"Download is disabled": "Преузимање је онемогућено",
"comments_points_count_0": "{{count}} поен",
"comments_points_count_1": "{{count}} поена",
"comments_points_count_2": "{{count}} поена",
"preferences_quality_dash_option_2160p": "2160p",
"German (auto-generated)": "Немачки (аутоматски генерисано)",
"Japanese (auto-generated)": "Јапански (аутоматски генерисано)",
"preferences_quality_option_medium": "Средње",
"search_message_change_filters_or_query": "Покушајте да проширите упит за претрагу и/или промените филтере.",
"crash_page_before_reporting": "Пре него што пријавите грешку, уверите се да сте:",
"preferences_quality_dash_option_best": "Најбоље",
"Channel Sponsor": "Спонзор канала",
"generic_videos_count_0": "{{count}} видео снимак",
"generic_videos_count_1": "{{count}} видео снимка",
"generic_videos_count_2": "{{count}} видео снимака",
"videoinfo_started_streaming_x_ago": "Започето стримовање пре `x`",
"videoinfo_youTube_embed_link": "Уграђено",
"channel_tab_streams_label": "Стримови уживо",
"playlist_button_add_items": "Додај видео снимке",
"generic_count_minutes_0": "{{count}} минут",
"generic_count_minutes_1": "{{count}} минута",
"generic_count_minutes_2": "{{count}} минута",
"preferences_quality_dash_option_720p": "720p",
"preferences_watch_history_label": "Омогући историју гледања: ",
"user_saved_playlists": "Сачуваних плејлиста: `x`",
"Spanish (Spain)": "Шпански (Шпанија)",
"invidious": "Invidious",
"crash_page_refresh": "покушали да <a href=\"`x`\">освежите страницу</a>",
"Chinese (Hong Kong)": "Кинески (Хонг Конг)",
"Artist: ": "Извођач: ",
"generic_count_months_0": "{{count}} месец",
"generic_count_months_1": "{{count}} месеца",
"generic_count_months_2": "{{count}} месеци",
"search_message_use_another_instance": " Такође, можете <a href=\"`x`\">претраживати на другој инстанци</a>.",
"generic_subscribers_count_0": "{{count}} пратилац",
"generic_subscribers_count_1": "{{count}} пратиоца",
"generic_subscribers_count_2": "{{count}} пратилаца",
"download_subtitles": "Титлови - `x` (.vtt)",
"generic_button_save": "Сачувај",
"crash_page_search_issue": "претражили <a href=\"`x`\">постојеће извештаје о проблемима на GitHub-у</a>",
"generic_button_cancel": "Откажи",
"none": "ниједно",
"English (United States)": "Енглески (Сједињене Америчке Државе)",
"subscriptions_unseen_notifs_count_0": "{{count}} невиђено обавештење",
"subscriptions_unseen_notifs_count_1": "{{count}} невиђена обавештења",
"subscriptions_unseen_notifs_count_2": "{{count}} невиђених обавештења",
"Album: ": "Албум: ",
"preferences_quality_option_dash": "DASH (адаптивни квалитет)",
"preferences_quality_dash_option_1080p": "1080p",
"Video unavailable": "Видео снимак недоступан",
"tokens_count_0": "{{count}} токен",
"tokens_count_1": "{{count}} токена",
"tokens_count_2": "{{count}} токена",
"Chinese (China)": "Кинески (Кина)",
"Italian (auto-generated)": "Италијански (аутоматски генерисано)",
"channel_tab_shorts_label": "Shorts",
"preferences_quality_dash_option_1440p": "1440p",
"preferences_quality_dash_option_360p": "360p",
"search_message_no_results": "Нису пронађени резултати.",
"channel_tab_releases_label": "Издања",
"preferences_quality_dash_option_144p": "144p",
"Interlingue": "Интерлингва",
"Song: ": "Песма: ",
"generic_channels_count_0": "{{count}} канал",
"generic_channels_count_1": "{{count}} канала",
"generic_channels_count_2": "{{count}} канала",
"Chinese (Taiwan)": "Кинески (Тајван)",
"Turkish (auto-generated)": "Турски (аутоматски генерисано)",
"Indonesian (auto-generated)": "Индонезијски (аутоматски генерисано)",
"Portuguese (auto-generated)": "Португалски (аутоматски генерисано)",
"generic_count_years_0": "{{count}} година",
"generic_count_years_1": "{{count}} године",
"generic_count_years_2": "{{count}} година",
"videoinfo_invidious_embed_link": "Уграђени линк",
"Popular enabled: ": "Популарно омогућено: ",
"Spanish (auto-generated)": "Шпански (аутоматски генерисано)",
"preferences_quality_option_small": "Мало",
"English (United Kingdom)": "Енглески (Уједињено Краљевство)",
"channel_tab_playlists_label": "Плејлисте",
"generic_button_edit": "Измени",
"generic_playlists_count_0": "{{count}} плејлиста",
"generic_playlists_count_1": "{{count}} плејлисте",
"generic_playlists_count_2": "{{count}} плејлиста",
"preferences_quality_option_hd720": "HD720",
"search_filters_features_option_purchased": "Купљено",
"search_filters_date_option_none": "Било који датум",
"preferences_quality_dash_option_auto": "Аутоматски",
"Cantonese (Hong Kong)": "Кантонски (Хонг Конг)",
"crash_page_report_issue": "Ако ништа од горенаведеног није помогло, <a href=\"`x`\">отворите нови извештај о проблему на GitHub-у</a> (по могућности на енглеском) и укључите следећи текст у своју поруку (НЕ преводите тај текст):",
"crash_page_switch_instance": "покушали да <a href=\"`x`\">користите другу инстанцу</a>",
"generic_count_weeks_0": "{{count}} недеља",
"generic_count_weeks_1": "{{count}} недеље",
"generic_count_weeks_2": "{{count}} недеља",
"videoinfo_watch_on_youTube": "Гледај на YouTube-у",
"Music in this video": "Музика у овом видео снимку",
"generic_button_rss": "RSS",
"preferences_quality_dash_option_4320p": "4320p",
"generic_count_hours_0": "{{count}} сат",
"generic_count_hours_1": "{{count}} сата",
"generic_count_hours_2": "{{count}} сати",
"French (auto-generated)": "Француски (аутоматски генерисано)",
"crash_page_read_the_faq": "прочитали <a href=\"`x`\">Често Постављана Питања (ЧПП)</a>",
"user_created_playlists": "Направљених плејлиста: `x`",
"channel_tab_channels_label": "Канали",
"search_filters_type_option_all": "Било која врста",
"Russian (auto-generated)": "Руски (аутоматски генерисано)",
"preferences_quality_dash_option_480p": "480p",
"comments_view_x_replies_0": "Погледај {{count}} одговор",
"comments_view_x_replies_1": "Погледај {{count}} одговора",
"comments_view_x_replies_2": "Погледај {{count}} одговора",
"Portuguese (Brazil)": "Португалски (Бразил)",
"search_filters_features_option_vr180": "VR180",
"error_video_not_in_playlist": "Тражени видео снимак не постоји на овој плејлисти. <a href=\"`x`\">Кликните овде за почетну страницу плејлисте.</a>",
"Dutch (auto-generated)": "Холандски (аутоматски генерисано)",
"generic_count_days_0": "{{count}} дан",
"generic_count_days_1": "{{count}} дана",
"generic_count_days_2": "{{count}} дана",
"Vietnamese (auto-generated)": "Вијетнамски (аутоматски генерисано)",
"search_filters_duration_option_none": "Било које трајање",
"preferences_quality_dash_option_240p": "240p",
"Chinese": "Кинески",
"generic_button_delete": "Избриши",
"Import YouTube playlist (.csv)": "Увези YouTube плејлисту (.csv)",
"Standard YouTube license": "Стандардна YouTube лиценца",
"search_filters_duration_option_medium": "Средње (4 - 20 минута)",
"generic_count_seconds_0": "{{count}} секунда",
"generic_count_seconds_1": "{{count}} секунде",
"generic_count_seconds_2": "{{count}} секунди",
"search_filters_date_label": "Датум отпремања",
"crash_page_you_found_a_bug": "Изгледа да сте пронашли грешку у Invidious-у!",
"generic_views_count_0": "{{count}} преглед",
"generic_views_count_1": "{{count}} прегледа",
"generic_views_count_2": "{{count}} прегледа"
}

View file

@ -484,5 +484,7 @@
"generic_button_rss": "RSS",
"channel_tab_releases_label": "Yayınlar",
"playlist_button_add_items": "Video ekle",
"channel_tab_podcasts_label": "Podcast'ler"
"channel_tab_podcasts_label": "Podcast'ler",
"generic_channels_count": "{{count}} kanal",
"generic_channels_count_plural": "{{count}} kanal"
}

View file

@ -500,5 +500,8 @@
"channel_tab_releases_label": "Випуски",
"generic_button_delete": "Видалити",
"generic_button_edit": "Змінити",
"generic_button_save": "Зберегти"
"generic_button_save": "Зберегти",
"generic_channels_count_0": "{{count}} канал",
"generic_channels_count_1": "{{count}} канали",
"generic_channels_count_2": "{{count}} каналів"
}

View file

@ -461,6 +461,7 @@
"Standard YouTube license": "标准 YouTube 许可证",
"Download is disabled": "已禁用下载",
"Import YouTube playlist (.csv)": "导入 YouTube 播放列表(.csv",
"Import YouTube watch history (.json)": "导入 YouTube 观看历史(.json",
"generic_button_cancel": "取消",
"playlist_button_add_items": "添加视频",
"generic_button_delete": "删除",
@ -468,5 +469,6 @@
"generic_button_edit": "编辑",
"generic_button_save": "保存",
"generic_button_rss": "RSS",
"channel_tab_releases_label": "公告"
"channel_tab_releases_label": "公告",
"generic_channels_count_0": "{{count}} 个频道"
}

View file

@ -461,6 +461,7 @@
"Standard YouTube license": "標準 YouTube 授權條款",
"Download is disabled": "已停用下載",
"Import YouTube playlist (.csv)": "匯入 YouTube 播放清單 (.csv)",
"Import YouTube watch history (.json)": "匯入 YouTube 觀看歷史 (.json)",
"generic_button_cancel": "取消",
"generic_button_edit": "編輯",
"generic_button_save": "儲存",
@ -468,5 +469,6 @@
"generic_button_delete": "刪除",
"playlist_button_add_items": "新增影片",
"channel_tab_podcasts_label": "Podcast",
"channel_tab_releases_label": "發布"
"channel_tab_releases_label": "發布",
"generic_channels_count_0": "{{count}} 個頻道"
}

View file

@ -0,0 +1,64 @@
require "../../spec_helper.cr"
MockLines = [
{
"start_time": Time::Span.new(seconds: 1),
"end_time": Time::Span.new(seconds: 2),
"text": "Line 1",
},
{
"start_time": Time::Span.new(seconds: 2),
"end_time": Time::Span.new(seconds: 3),
"text": "Line 2",
},
]
Spectator.describe "WebVTT::Builder" do
it "correctly builds a vtt file" do
result = WebVTT.build do |vtt|
MockLines.each do |line|
vtt.cue(line["start_time"], line["end_time"], line["text"])
end
end
expect(result).to eq([
"WEBVTT",
"",
"00:00:01.000 --> 00:00:02.000",
"Line 1",
"",
"00:00:02.000 --> 00:00:03.000",
"Line 2",
"",
"",
].join('\n'))
end
it "correctly builds a vtt file with setting fields" do
setting_fields = {
"Kind" => "captions",
"Language" => "en",
}
result = WebVTT.build(setting_fields) do |vtt|
MockLines.each do |line|
vtt.cue(line["start_time"], line["end_time"], line["text"])
end
end
expect(result).to eq([
"WEBVTT",
"Kind: captions",
"Language: en",
"",
"00:00:01.000 --> 00:00:02.000",
"Line 1",
"",
"00:00:02.000 --> 00:00:03.000",
"Line 2",
"",
"",
].join('\n'))
end
end

View file

@ -15,12 +15,15 @@ FORM_TESTS = {
"ar" => I18next::Plurals::PluralForms::Special_Arabic,
"be" => I18next::Plurals::PluralForms::Dual_Slavic,
"cy" => I18next::Plurals::PluralForms::Special_Welsh,
"fr" => I18next::Plurals::PluralForms::Special_French_Portuguese,
"en" => I18next::Plurals::PluralForms::Single_not_one,
"fr" => I18next::Plurals::PluralForms::Single_gt_one,
"es" => I18next::Plurals::PluralForms::Single_not_one,
"ga" => I18next::Plurals::PluralForms::Special_Irish,
"gd" => I18next::Plurals::PluralForms::Special_Scottish_Gaelic,
"he" => I18next::Plurals::PluralForms::Special_Hebrew,
"hr" => I18next::Plurals::PluralForms::Special_Hungarian_Serbian,
"is" => I18next::Plurals::PluralForms::Special_Icelandic,
"it" => I18next::Plurals::PluralForms::Special_Spanish_Italian,
"jv" => I18next::Plurals::PluralForms::Special_Javanese,
"kw" => I18next::Plurals::PluralForms::Special_Cornish,
"lt" => I18next::Plurals::PluralForms::Special_Lithuanian,
@ -31,12 +34,12 @@ FORM_TESTS = {
"or" => I18next::Plurals::PluralForms::Special_Odia,
"pl" => I18next::Plurals::PluralForms::Special_Polish_Kashubian,
"pt" => I18next::Plurals::PluralForms::Single_gt_one,
"pt-PT" => I18next::Plurals::PluralForms::Single_not_one,
"pt-BR" => I18next::Plurals::PluralForms::Single_gt_one,
"pt-BR" => I18next::Plurals::PluralForms::Special_French_Portuguese,
"ro" => I18next::Plurals::PluralForms::Special_Romanian,
"su" => I18next::Plurals::PluralForms::None,
"sk" => I18next::Plurals::PluralForms::Special_Czech_Slovak,
"sl" => I18next::Plurals::PluralForms::Special_Slovenian,
"su" => I18next::Plurals::PluralForms::None,
"sr" => I18next::Plurals::PluralForms::Special_Hungarian_Serbian,
}
SUFFIX_TESTS = {
@ -73,10 +76,18 @@ SUFFIX_TESTS = {
{num: 1, suffix: ""},
{num: 10, suffix: "_plural"},
],
"fr" => [
{num: 0, suffix: ""},
"es" => [
{num: 0, suffix: "_plural"},
{num: 1, suffix: ""},
{num: 10, suffix: "_plural"},
{num: 6_000_000, suffix: "_plural"},
],
"fr" => [
{num: 0, suffix: "_0"},
{num: 1, suffix: "_0"},
{num: 10, suffix: "_2"},
{num: 4_000_000, suffix: "_1"},
{num: 6_260_000, suffix: "_2"},
],
"ga" => [
{num: 1, suffix: "_0"},
@ -155,31 +166,24 @@ SUFFIX_TESTS = {
{num: 1, suffix: "_0"},
{num: 5, suffix: "_2"},
],
"pt" => [
{num: 0, suffix: ""},
{num: 1, suffix: ""},
{num: 10, suffix: "_plural"},
"pt-BR" => [
{num: 0, suffix: "_0"},
{num: 1, suffix: "_0"},
{num: 10, suffix: "_2"},
{num: 42, suffix: "_2"},
{num: 9_000_000, suffix: "_1"},
],
"pt-PT" => [
{num: 0, suffix: "_plural"},
{num: 1, suffix: ""},
{num: 10, suffix: "_plural"},
],
"pt-BR" => [
{num: 0, suffix: ""},
{num: 1, suffix: ""},
{num: 10, suffix: "_plural"},
{num: 9_000_000, suffix: "_plural"},
],
"ro" => [
{num: 0, suffix: "_1"},
{num: 1, suffix: "_0"},
{num: 20, suffix: "_2"},
],
"su" => [
{num: 0, suffix: "_0"},
{num: 1, suffix: "_0"},
{num: 10, suffix: "_0"},
],
"sk" => [
{num: 0, suffix: "_2"},
{num: 1, suffix: "_0"},
@ -191,6 +195,18 @@ SUFFIX_TESTS = {
{num: 2, suffix: "_2"},
{num: 3, suffix: "_3"},
],
"su" => [
{num: 0, suffix: "_0"},
{num: 1, suffix: "_0"},
{num: 10, suffix: "_0"},
],
"sr" => [
{num: 1, suffix: "_0"},
{num: 51, suffix: "_0"},
{num: 32, suffix: "_1"},
{num: 100, suffix: "_2"},
{num: 100_000, suffix: "_2"},
],
}
Spectator.describe "i18next_Plural_Resolver" do

View file

@ -24,7 +24,33 @@ def fetch_channel_community(ucid, cursor, locale, format, thin_mode)
return extract_channel_community(items, ucid: ucid, locale: locale, format: format, thin_mode: thin_mode)
end
def extract_channel_community(items, *, ucid, locale, format, thin_mode)
def fetch_channel_community_post(ucid, post_id, locale, format, thin_mode)
object = {
"2:string" => "community",
"25:embedded" => {
"22:string" => post_id.to_s,
},
"45:embedded" => {
"2:varint" => 1_i64,
"3:varint" => 1_i64,
},
}
params = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
.try { |i| URI.encode_www_form(i) }
initial_data = YoutubeAPI.browse(ucid, params: params)
items = [] of JSON::Any
extract_items(initial_data) do |item|
items << item
end
return extract_channel_community(items, ucid: ucid, locale: locale, format: format, thin_mode: thin_mode, is_single_post: true)
end
def extract_channel_community(items, *, ucid, locale, format, thin_mode, is_single_post : Bool = false)
if message = items[0]["messageRenderer"]?
error_message = (message["text"]["simpleText"]? ||
message["text"]["runs"]?.try &.[0]?.try &.["text"]?)
@ -39,6 +65,9 @@ def extract_channel_community(items, *, ucid, locale, format, thin_mode)
response = JSON.build do |json|
json.object do
json.field "authorId", ucid
if is_single_post
json.field "singlePost", true
end
json.field "comments" do
json.array do
items.each do |post|
@ -240,8 +269,10 @@ def extract_channel_community(items, *, ucid, locale, format, thin_mode)
end
end
end
if cont = items.dig?(-1, "continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token")
json.field "continuation", extract_channel_community_cursor(cont.as_s)
if !is_single_post
if cont = items.dig?(-1, "continuationItemRenderer", "continuationEndpoint", "continuationCommand", "token")
json.field "continuation", extract_channel_community_cursor(cont.as_s)
end
end
end
end

View file

@ -13,6 +13,51 @@ module Invidious::Comments
client_config = YoutubeAPI::ClientConfig.new(region: region)
response = YoutubeAPI.next(continuation: ctoken, client_config: client_config)
return parse_youtube(id, response, format, locale, thin_mode, sort_by)
end
def fetch_community_post_comments(ucid, post_id)
object = {
"2:string" => "community",
"25:embedded" => {
"22:string" => post_id,
},
"45:embedded" => {
"2:varint" => 1_i64,
"3:varint" => 1_i64,
},
"53:embedded" => {
"4:embedded" => {
"6:varint" => 0_i64,
"27:varint" => 1_i64,
"29:string" => post_id,
"30:string" => ucid,
},
"8:string" => "comments-section",
},
}
object_parsed = object.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
object2 = {
"80226972:embedded" => {
"2:string" => ucid,
"3:string" => object_parsed,
},
}
continuation = object2.try { |i| Protodec::Any.cast_json(i) }
.try { |i| Protodec::Any.from_json(i) }
.try { |i| Base64.urlsafe_encode(i) }
.try { |i| URI.encode_www_form(i) }
initial_data = YoutubeAPI.browse(continuation: continuation)
return initial_data
end
def parse_youtube(id, response, format, locale, thin_mode, sort_by = "top", isPost = false)
contents = nil
if on_response_received_endpoints = response["onResponseReceivedEndpoints"]?
@ -68,7 +113,11 @@ module Invidious::Comments
json.field "commentCount", comment_count
end
json.field "videoId", id
if isPost
json.field "postId", id
else
json.field "videoId", id
end
json.field "comments" do
json.array do

View file

@ -23,6 +23,24 @@ module Invidious::Frontend::Comments
</div>
</div>
END_HTML
elsif comments["authorId"]? && !comments["singlePost"]?
# for posts we should display a link to the post
replies_count_text = translate_count(locale,
"comments_view_x_replies",
child["replyCount"].as_i64 || 0,
NumberFormatting::Separator
)
replies_html = <<-END_HTML
<div class="pure-g">
<div class="pure-u-1-24"></div>
<div class="pure-u-23-24">
<p>
<a href="/post/#{child["commentId"]}?ucid=#{comments["authorId"]}">#{replies_count_text}</a>
</p>
</div>
</div>
END_HTML
end
if !thin_mode

View file

@ -42,8 +42,7 @@ module Invidious::Frontend::WatchPage
str << translate(locale, "Download as: ")
str << "</label>\n"
# TODO: remove inline style
str << "\t\t<select style=\"width:100%\" name='download_widget' id='download_widget'>\n"
str << "\t\t<select name='download_widget' id='download_widget'>\n"
# Non-DASH videos (audio+video)

View file

@ -35,19 +35,27 @@ module I18next::Plurals
Special_Slovenian = 21
Special_Hebrew = 22
Special_Odia = 23
# Mixed v3/v4 rules in Weblate
# `es`, `pt` and `pt-PT` doesn't seem to have been refreshed
# by weblate yet, but I suspect it will happen one day.
# See: https://github.com/translate/translate/issues/4873
Special_French_Portuguese
Special_Hungarian_Serbian
Special_Spanish_Italian
end
private PLURAL_SETS = {
PluralForms::Single_gt_one => [
"ach", "ak", "am", "arn", "br", "fil", "fr", "gun", "ln", "mfe", "mg",
"mi", "oc", "pt", "pt-BR", "tg", "tl", "ti", "tr", "uz", "wa",
"ach", "ak", "am", "arn", "br", "fil", "gun", "ln", "mfe", "mg",
"mi", "oc", "pt", "tg", "tl", "ti", "tr", "uz", "wa",
],
PluralForms::Single_not_one => [
"af", "an", "ast", "az", "bg", "bn", "ca", "da", "de", "dev", "el", "en",
"eo", "es", "et", "eu", "fi", "fo", "fur", "fy", "gl", "gu", "ha", "hi",
"hu", "hy", "ia", "it", "kk", "kn", "ku", "lb", "mai", "ml", "mn", "mr",
"hu", "hy", "ia", "kk", "kn", "ku", "lb", "mai", "ml", "mn", "mr",
"nah", "nap", "nb", "ne", "nl", "nn", "no", "nso", "pa", "pap", "pms",
"ps", "pt-PT", "rm", "sco", "se", "si", "so", "son", "sq", "sv", "sw",
"ps", "rm", "sco", "se", "si", "so", "son", "sq", "sv", "sw",
"ta", "te", "tk", "ur", "yo",
],
PluralForms::None => [
@ -55,7 +63,7 @@ module I18next::Plurals
"lo", "ms", "sah", "su", "th", "tt", "ug", "vi", "wo", "zh",
],
PluralForms::Dual_Slavic => [
"be", "bs", "cnr", "dz", "hr", "ru", "sr", "uk",
"be", "bs", "cnr", "dz", "ru", "uk",
],
}
@ -81,6 +89,12 @@ module I18next::Plurals
"ro" => PluralForms::Special_Romanian,
"sk" => PluralForms::Special_Czech_Slovak,
"sl" => PluralForms::Special_Slovenian,
# Mixed v3/v4 rules
"fr" => PluralForms::Special_French_Portuguese,
"hr" => PluralForms::Special_Hungarian_Serbian,
"it" => PluralForms::Special_Spanish_Italian,
"pt-BR" => PluralForms::Special_French_Portuguese,
"sr" => PluralForms::Special_Hungarian_Serbian,
}
# These are the v1 and v2 compatible suffixes.
@ -150,9 +164,8 @@ module I18next::Plurals
end
def get_plural_form(locale : String) : PluralForms
# Extract the ISO 639-1 or 639-2 code from an RFC 5646 language code,
# except for pt-BR and pt-PT which needs to be kept as-is.
if !locale.matches?(/^pt-(BR|PT)$/)
# Extract the ISO 639-1 or 639-2 code from an RFC 5646 language code
if !locale.matches?(/^pt-BR$/)
locale = locale.split('-')[0]
end
@ -246,6 +259,10 @@ module I18next::Plurals
when .special_slovenian? then return special_slovenian(count)
when .special_hebrew? then return special_hebrew(count)
when .special_odia? then return special_odia(count)
# Mixed v3/v4 forms
when .special_spanish_italian? then return special_cldr_Spanish_Italian(count)
when .special_french_portuguese? then return special_cldr_French_Portuguese(count)
when .special_hungarian_serbian? then return special_cldr_Hungarian_Serbian(count)
else
# default, if nothing matched above
return 0_u8
@ -507,5 +524,42 @@ module I18next::Plurals
def self.special_odia(count : Int) : UInt8
return (count == 1) ? 0_u8 : 1_u8
end
# -------------------
# "v3.5" rules
# -------------------
# Plural form for Spanish & Italian languages
#
# This rule is mostly compliant to CLDR v42
#
def self.special_cldr_Spanish_Italian(count : Int) : UInt8
return 0_u8 if (count == 1) # one
return 1_u8 if (count != 0 && count % 1_000_000 == 0) # many
return 2_u8 # other
end
# Plural form for French and Portuguese
#
# This rule is mostly compliant to CLDR v42
#
def self.special_cldr_French_Portuguese(count : Int) : UInt8
return 0_u8 if (count == 0 || count == 1) # one
return 1_u8 if (count % 1_000_000 == 0) # many
return 2_u8 # other
end
# Plural form for Hungarian and Serbian
#
# This rule is mostly compliant to CLDR v42
#
def self.special_cldr_Hungarian_Serbian(count : Int) : UInt8
n_mod_10 = count % 10
n_mod_100 = count % 100
return 0_u8 if (n_mod_10 == 1 && n_mod_100 != 11) # one
return 1_u8 if (2 <= n_mod_10 <= 4 && (n_mod_100 < 12 || 14 < n_mod_100)) # few
return 2_u8 # other
end
end
end

View file

@ -186,6 +186,7 @@ struct SearchChannel
property author_thumbnail : String
property subscriber_count : Int32
property video_count : Int32
property channel_handle : String?
property description_html : String
property auto_generated : Bool
property author_verified : Bool
@ -214,6 +215,7 @@ struct SearchChannel
json.field "autoGenerated", self.auto_generated
json.field "subCount", self.subscriber_count
json.field "videoCount", self.video_count
json.field "channelHandle", self.channel_handle
json.field "description", html_to_content(self.description_html)
json.field "descriptionHtml", self.description_html

View file

@ -0,0 +1,67 @@
# Namespace for logic relating to generating WebVTT files
#
# Probably not compliant to WebVTT's specs but it is enough for Invidious.
module WebVTT
# A WebVTT builder generates WebVTT files
private class Builder
def initialize(@io : IO)
end
# Writes an vtt cue with the specified time stamp and contents
def cue(start_time : Time::Span, end_time : Time::Span, text : String)
timestamp(start_time, end_time)
@io << text
@io << "\n\n"
end
private def timestamp(start_time : Time::Span, end_time : Time::Span)
timestamp_component(start_time)
@io << " --> "
timestamp_component(end_time)
@io << '\n'
end
private def timestamp_component(timestamp : Time::Span)
@io << timestamp.hours.to_s.rjust(2, '0')
@io << ':' << timestamp.minutes.to_s.rjust(2, '0')
@io << ':' << timestamp.seconds.to_s.rjust(2, '0')
@io << '.' << timestamp.milliseconds.to_s.rjust(3, '0')
end
def document(setting_fields : Hash(String, String)? = nil, &)
@io << "WEBVTT\n"
if setting_fields
setting_fields.each do |name, value|
@io << name << ": " << value << '\n'
end
end
@io << '\n'
yield
end
end
# Returns the resulting `String` of writing WebVTT to the yielded `WebVTT::Builder`
#
# ```
# string = WebVTT.build do |vtt|
# vtt.cue(Time::Span.new(seconds: 1), Time::Span.new(seconds: 2), "Line 1")
# vtt.cue(Time::Span.new(seconds: 2), Time::Span.new(seconds: 3), "Line 2")
# end
#
# string # => "WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nLine 1\n\n00:00:02.000 --> 00:00:03.000\nLine 2\n\n"
# ```
#
# Accepts an optional settings fields hash to add settings attribute to the resulting vtt file.
def self.build(setting_fields : Hash(String, String)? = nil, &)
String.build do |str|
builder = Builder.new(str)
builder.document(setting_fields) do
yield builder
end
end
end
end

View file

@ -39,6 +39,7 @@ module Invidious::JSONify::APIv1
json.field "author", video.author
json.field "authorId", video.ucid
json.field "authorUrl", "/channel/#{video.ucid}"
json.field "authorVerified", video.author_verified
json.field "authorThumbnails" do
json.array do

View file

@ -343,6 +343,59 @@ module Invidious::Routes::API::V1::Channels
end
end
def self.post(env)
locale = env.get("preferences").as(Preferences).locale
env.response.content_type = "application/json"
id = env.params.url["id"].to_s
ucid = env.params.query["ucid"]?
thin_mode = env.params.query["thin_mode"]?
thin_mode = thin_mode == "true"
format = env.params.query["format"]?
format ||= "json"
if ucid.nil?
response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}")
return error_json(400, "Invalid post ID") if response["error"]?
ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s
else
ucid = ucid.to_s
end
begin
fetch_channel_community_post(ucid, id, locale, format, thin_mode)
rescue ex
return error_json(500, ex)
end
end
def self.post_comments(env)
locale = env.get("preferences").as(Preferences).locale
env.response.content_type = "application/json"
id = env.params.url["id"]
thin_mode = env.params.query["thin_mode"]?
thin_mode = thin_mode == "true"
format = env.params.query["format"]?
format ||= "json"
continuation = env.params.query["continuation"]?
case continuation
when nil, ""
ucid = env.params.query["ucid"]
comments = Comments.fetch_community_post_comments(ucid, id)
else
comments = YoutubeAPI.browse(continuation: continuation)
end
return Comments.parse_youtube(id, comments, format, locale, thin_mode, isPost: true)
end
def self.channels(env)
locale = env.get("preferences").as(Preferences).locale
ucid = env.params.url["ucid"]

View file

@ -162,17 +162,20 @@ module Invidious::Routes::API::V1::Misc
resolved_url = YoutubeAPI.resolve_url(url.as(String))
endpoint = resolved_url["endpoint"]
pageType = endpoint.dig?("commandMetadata", "webCommandMetadata", "webPageType").try &.as_s || ""
if resolved_ucid = endpoint.dig?("watchEndpoint", "videoId")
elsif resolved_ucid = endpoint.dig?("browseEndpoint", "browseId")
elsif pageType == "WEB_PAGE_TYPE_UNKNOWN"
if pageType == "WEB_PAGE_TYPE_UNKNOWN"
return error_json(400, "Unknown url")
end
sub_endpoint = endpoint["watchEndpoint"]? || endpoint["browseEndpoint"]? || endpoint
params = sub_endpoint.try &.dig?("params")
rescue ex
return error_json(500, ex)
end
JSON.build do |json|
json.object do
json.field "ucid", resolved_ucid.try &.as_s || ""
json.field "ucid", sub_endpoint["browseId"].as_s if sub_endpoint["browseId"]?
json.field "videoId", sub_endpoint["videoId"].as_s if sub_endpoint["videoId"]?
json.field "params", params.try &.as_s
json.field "pageType", pageType
end
end

View file

@ -101,20 +101,17 @@ module Invidious::Routes::API::V1::Videos
if caption.name.includes? "auto-generated"
caption_xml = YT_POOL.client &.get(url).body
settings_field = {
"Kind" => "captions",
"Language" => "#{tlang || caption.language_code}",
}
if caption_xml.starts_with?("<?xml")
webvtt = caption.timedtext_to_vtt(caption_xml, tlang)
else
caption_xml = XML.parse(caption_xml)
webvtt = String.build do |str|
str << <<-END_VTT
WEBVTT
Kind: captions
Language: #{tlang || caption.language_code}
END_VTT
webvtt = WebVTT.build(settings_field) do |webvtt|
caption_nodes = caption_xml.xpath_nodes("//transcript/text")
caption_nodes.each_with_index do |node, i|
start_time = node["start"].to_f.seconds
@ -127,9 +124,6 @@ module Invidious::Routes::API::V1::Videos
end_time = start_time + duration
end
start_time = "#{start_time.hours.to_s.rjust(2, '0')}:#{start_time.minutes.to_s.rjust(2, '0')}:#{start_time.seconds.to_s.rjust(2, '0')}.#{start_time.milliseconds.to_s.rjust(3, '0')}"
end_time = "#{end_time.hours.to_s.rjust(2, '0')}:#{end_time.minutes.to_s.rjust(2, '0')}:#{end_time.seconds.to_s.rjust(2, '0')}.#{end_time.milliseconds.to_s.rjust(3, '0')}"
text = HTML.unescape(node.content)
text = text.gsub(/<font color="#[a-fA-F0-9]{6}">/, "")
text = text.gsub(/<\/font>/, "")
@ -137,27 +131,22 @@ module Invidious::Routes::API::V1::Videos
text = "<v #{md["name"]}>#{md["text"]}</v>"
end
str << <<-END_CUE
#{start_time} --> #{end_time}
#{text}
END_CUE
webvtt.cue(start_time, end_time, text)
end
end
end
else
# Some captions have "align:[start/end]" and "position:[num]%"
# attributes. Those are causing issues with VideoJS, which is unable
# to properly align the captions on the video, so we remove them.
#
# See: https://github.com/iv-org/invidious/issues/2391
webvtt = YT_POOL.client &.get("#{url}&format=vtt").body
webvtt = YT_POOL.client &.get("#{url}&fmt=vtt").body
if webvtt.starts_with?("<?xml")
webvtt = caption.timedtext_to_vtt(webvtt)
else
webvtt = YT_POOL.client &.get("#{url}&format=vtt").body
.gsub(/([0-9:.]{12} --> [0-9:.]{12}).+/, "\\1")
# Some captions have "align:[start/end]" and "position:[num]%"
# attributes. Those are causing issues with VideoJS, which is unable
# to properly align the captions on the video, so we remove them.
#
# See: https://github.com/iv-org/invidious/issues/2391
webvtt = webvtt.gsub(/([0-9:.]{12} --> [0-9:.]{12}).+/, "\\1")
end
end
end
@ -215,11 +204,7 @@ module Invidious::Routes::API::V1::Videos
storyboard = storyboard[0]
end
String.build do |str|
str << <<-END_VTT
WEBVTT
END_VTT
WebVTT.build do |vtt|
start_time = 0.milliseconds
end_time = storyboard[:interval].milliseconds
@ -231,12 +216,8 @@ module Invidious::Routes::API::V1::Videos
storyboard[:storyboard_height].times do |j|
storyboard[:storyboard_width].times do |k|
str << <<-END_CUE
#{start_time}.000 --> #{end_time}.000
#{url}#xywh=#{storyboard[:width] * k},#{storyboard[:height] * j},#{storyboard[:width] - 2},#{storyboard[:height]}
END_CUE
current_cue_url = "#{url}#xywh=#{storyboard[:width] * k},#{storyboard[:height] * j},#{storyboard[:width] - 2},#{storyboard[:height]}"
vtt.cue(start_time, end_time, current_cue_url)
start_time += storyboard[:interval].milliseconds
end_time += storyboard[:interval].milliseconds

View file

@ -1,6 +1,12 @@
{% skip_file if flag?(:api_only) %}
module Invidious::Routes::Channels
# Redirection for unsupported routes ("tabs")
def self.redirect_home(env)
ucid = env.params.url["ucid"]
return env.redirect "/channel/#{URI.encode_www_form(ucid)}"
end
def self.home(env)
self.videos(env)
end
@ -159,6 +165,11 @@ module Invidious::Routes::Channels
end
locale, user, subscriptions, continuation, ucid, channel = data
# redirect to post page
if lb = env.params.query["lb"]?
env.redirect "/post/#{URI.encode_www_form(lb)}?ucid=#{URI.encode_www_form(ucid)}"
end
thin_mode = env.params.query["thin_mode"]? || env.get("preferences").as(Preferences).thin_mode
thin_mode = thin_mode == "true"
@ -187,6 +198,44 @@ module Invidious::Routes::Channels
templated "community"
end
def self.post(env)
# /post/{postId}
id = env.params.url["id"]
ucid = env.params.query["ucid"]?
prefs = env.get("preferences").as(Preferences)
locale = prefs.locale
thin_mode = env.params.query["thin_mode"]? || prefs.thin_mode
thin_mode = thin_mode == "true"
nojs = env.params.query["nojs"]?
nojs ||= "0"
nojs = nojs == "1"
if !ucid.nil?
ucid = ucid.to_s
post_response = fetch_channel_community_post(ucid, id, locale, "json", thin_mode)
else
# resolve the url to get the author's UCID
response = YoutubeAPI.resolve_url("https://www.youtube.com/post/#{id}")
return error_template(400, "Invalid post ID") if response["error"]?
ucid = response.dig("endpoint", "browseEndpoint", "browseId").as_s
post_response = fetch_channel_community_post(ucid, id, locale, "json", thin_mode)
end
post_response = JSON.parse(post_response)
if nojs
comments = Comments.fetch_community_post_comments(ucid, id)
comment_html = JSON.parse(Comments.parse_youtube(id, comments, "html", locale, thin_mode, isPost: true))["contentHtml"]
end
templated "post"
end
def self.channels(env)
data = self.fetch_basic_information(env)
return data if !data.is_a?(Tuple)
@ -217,6 +266,11 @@ module Invidious::Routes::Channels
env.redirect "/channel/#{ucid}"
end
private KNOWN_TABS = {
"home", "videos", "shorts", "streams", "podcasts",
"releases", "playlists", "community", "channels", "about",
}
# Redirects brand url channels to a normal /channel/:ucid route
def self.brand_redirect(env)
locale = env.get("preferences").as(Preferences).locale
@ -227,7 +281,10 @@ module Invidious::Routes::Channels
yt_url_params = URI::Params.encode(env.params.query.to_h.select(["a", "u", "user"]))
# Retrieves URL params that only Invidious uses
invidious_url_params = URI::Params.encode(env.params.query.to_h.select!(["a", "u", "user"]))
invidious_url_params = env.params.query.dup
invidious_url_params.delete_all("a")
invidious_url_params.delete_all("u")
invidious_url_params.delete_all("user")
begin
resolved_url = YoutubeAPI.resolve_url("https://youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
@ -236,14 +293,17 @@ module Invidious::Routes::Channels
return error_template(404, translate(locale, "This channel does not exist."))
end
selected_tab = env.request.path.split("/")[-1]
if {"home", "videos", "shorts", "streams", "playlists", "community", "channels", "about"}.includes? selected_tab
selected_tab = env.params.url["tab"]?
if KNOWN_TABS.includes? selected_tab
url = "/channel/#{ucid}/#{selected_tab}"
else
url = "/channel/#{ucid}"
end
env.redirect url
url += "?#{invidious_url_params}" if !invidious_url_params.empty?
return env.redirect url
end
# Handles redirects for the /profile endpoint

View file

@ -279,6 +279,15 @@ module Invidious::Routes::PreferencesRoute
response: error_template(415, "Invalid playlist file uploaded")
)
end
when "import_youtube_wh"
filename = part.filename || ""
success = Invidious::User::Import.from_youtube_wh(user, body, filename, type)
if !success
haltf(env, status_code: 415,
response: error_template(415, "Invalid watch history file uploaded")
)
end
when "import_freetube"
Invidious::User::Import.from_freetube(user, body)
when "import_newpipe_subscriptions"

View file

@ -30,14 +30,6 @@ module Invidious::Routes::Watch
return env.redirect "/"
end
embed_link = "/embed/#{id}"
if env.params.query.size > 1
embed_params = HTTP::Params.parse(env.params.query.to_s)
embed_params.delete_all("v")
embed_link += "?"
embed_link += embed_params.to_s
end
plid = env.params.query["list"]?.try &.gsub(/[^a-zA-Z0-9_-]/, "")
continuation = process_continuation(env.params.query, plid, id)

View file

@ -123,28 +123,42 @@ module Invidious::Routing
get "/channel/:ucid/community", Routes::Channels, :community
get "/channel/:ucid/channels", Routes::Channels, :channels
get "/channel/:ucid/about", Routes::Channels, :about
get "/channel/:ucid/live", Routes::Channels, :live
get "/user/:user/live", Routes::Channels, :live
get "/c/:user/live", Routes::Channels, :live
get "/post/:id", Routes::Channels, :post
{"", "/videos", "/shorts", "/streams", "/playlists", "/community", "/about"}.each do |path|
# /c/LinusTechTips
get "/c/:user#{path}", Routes::Channels, :brand_redirect
# /user/linustechtips | Not always the same as /c/
get "/user/:user#{path}", Routes::Channels, :brand_redirect
# /@LinusTechTips | Handle
get "/@:user#{path}", Routes::Channels, :brand_redirect
# /attribution_link?a=anything&u=/channel/UCZYTClx2T1of7BRZ86-8fow
get "/attribution_link#{path}", Routes::Channels, :brand_redirect
# /profile?user=linustechtips
get "/profile/#{path}", Routes::Channels, :profile
end
# Channel catch-all, to redirect future routes to the channel's home
# NOTE: defined last in order to be processed after the other routes
get "/channel/:ucid/*", Routes::Channels, :redirect_home
# /c/LinusTechTips
get "/c/:user", Routes::Channels, :brand_redirect
get "/c/:user/:tab", Routes::Channels, :brand_redirect
# /user/linustechtips (Not always the same as /c/)
get "/user/:user", Routes::Channels, :brand_redirect
get "/user/:user/:tab", Routes::Channels, :brand_redirect
# /@LinusTechTips (Handle)
get "/@:user", Routes::Channels, :brand_redirect
get "/@:user/:tab", Routes::Channels, :brand_redirect
# /attribution_link?a=anything&u=/channel/UCZYTClx2T1of7BRZ86-8fow
get "/attribution_link", Routes::Channels, :brand_redirect
get "/attribution_link/:tab", Routes::Channels, :brand_redirect
# /profile?user=linustechtips
get "/profile", Routes::Channels, :profile
get "/profile/*", Routes::Channels, :profile
end
def register_watch_routes
get "/watch", Routes::Watch, :handle
post "/watch_ajax", Routes::Watch, :mark_watched
get "/watch/:id", Routes::Watch, :redirect
get "/live/:id", Routes::Watch, :redirect
get "/shorts/:id", Routes::Watch, :redirect
get "/clip/:clip", Routes::Watch, :clip
get "/w/:id", Routes::Watch, :redirect
@ -239,6 +253,10 @@ module Invidious::Routing
get "/api/v1/channels/:ucid/#{{{route}}}", {{namespace}}::Channels, :{{route}}
{% end %}
# Posts
get "/api/v1/post/:id", {{namespace}}::Channels, :post
get "/api/v1/post/:id/comments", {{namespace}}::Channels, :post_comments
# 301 redirects to new /api/v1/channels/community/:ucid and /:ucid/community
get "/api/v1/channels/comments/:ucid", {{namespace}}::Channels, :channel_comments_redirect
get "/api/v1/channels/:ucid/comments", {{namespace}}::Channels, :channel_comments_redirect
@ -248,6 +266,7 @@ module Invidious::Routing
get "/api/v1/search/suggestions", {{namespace}}::Search, :search_suggestions
get "/api/v1/hashtag/:hashtag", {{namespace}}::Search, :hashtag
# Authenticated
# The notification APIs cannot be extracted yet! They require the *local* notifications constant defined in invidious.cr

View file

@ -218,6 +218,26 @@ struct Invidious::User
end
end
def from_youtube_wh(user : User, body : String, filename : String, type : String) : Bool
extension = filename.split(".").last
if extension == "json" || type == "application/json"
data = JSON.parse(body)
watched = data.as_a.compact_map do |item|
next unless url = item["titleUrl"]?
next unless match = url.as_s.match(/\?v=(?<video_id>[a-zA-Z0-9_-]+)$/)
match["video_id"]
end
watched.reverse! # YouTube have newest first
user.watched += watched
user.watched.uniq!
Invidious::Database::Users.update_watch_history(user)
return true
else
return false
end
end
# -------------------
# Freetube
# -------------------
@ -228,8 +248,12 @@ struct Invidious::User
subs = matches.map(&.["channel_id"])
if subs.empty?
data = JSON.parse(body)["subscriptions"]
subs = data.as_a.map(&.["id"].as_s)
profiles = body.split('\n', remove_empty: true)
profiles.each do |profile|
if data = JSON.parse(profile)["subscriptions"]?
subs += data.as_a.map(&.["id"].as_s)
end
end
end
user.subscriptions += subs

View file

@ -52,17 +52,13 @@ module Invidious::Videos
break
end
end
result = String.build do |result|
result << <<-END_VTT
WEBVTT
Kind: captions
Language: #{tlang || @language_code}
settings_field = {
"Kind" => "captions",
"Language" => "#{tlang || @language_code}",
}
END_VTT
result << "\n\n"
result = WebVTT.build(settings_field) do |vtt|
cues.each_with_index do |node, i|
start_time = node["t"].to_f.milliseconds
@ -76,29 +72,16 @@ module Invidious::Videos
end_time = start_time + duration
end
# start_time
result << start_time.hours.to_s.rjust(2, '0')
result << ':' << start_time.minutes.to_s.rjust(2, '0')
result << ':' << start_time.seconds.to_s.rjust(2, '0')
result << '.' << start_time.milliseconds.to_s.rjust(3, '0')
result << " --> "
# end_time
result << end_time.hours.to_s.rjust(2, '0')
result << ':' << end_time.minutes.to_s.rjust(2, '0')
result << ':' << end_time.seconds.to_s.rjust(2, '0')
result << '.' << end_time.milliseconds.to_s.rjust(3, '0')
result << "\n"
node.children.each do |s|
result << s.content
text = String.build do |io|
node.children.each do |s|
io << s.content
end
end
result << "\n"
result << "\n"
vtt.cue(start_time, end_time, text)
end
end
return result
end
end

View file

@ -137,9 +137,8 @@ end
def try_fetch_streaming_data(id : String, client_config : YoutubeAPI::ClientConfig) : Hash(String, JSON::Any)?
LOGGER.debug("try_fetch_streaming_data: [#{id}] Using #{client_config.client_type} client.")
# CgIQBg is a workaround for streaming URLs that returns a 403.
# See https://github.com/iv-org/invidious/issues/4027#issuecomment-1666944520
response = YoutubeAPI.player(video_id: id, params: "CgIQBg", client_config: client_config)
# 2AMBCgIQBg is a workaround for streaming URLs that returns a 403.
response = YoutubeAPI.player(video_id: id, params: "2AMBCgIQBg", client_config: client_config)
playability_status = response["playabilityStatus"]["status"]
LOGGER.debug("try_fetch_streaming_data: [#{id}] Got playabilityStatus == #{playability_status}.")

View file

@ -34,41 +34,15 @@ module Invidious::Videos
# Convert into array of TranscriptLine
lines = self.parse(initial_data)
settings_field = {
"Kind" => "captions",
"Language" => target_language,
}
# Taken from Invidious::Videos::Captions::Metadata.timedtext_to_vtt()
vtt = String.build do |vtt|
vtt << <<-END_VTT
WEBVTT
Kind: captions
Language: #{target_language}
END_VTT
vtt << "\n\n"
vtt = WebVTT.build(settings_field) do |vtt|
lines.each do |line|
start_time = line.start_ms
end_time = line.end_ms
# start_time
vtt << start_time.hours.to_s.rjust(2, '0')
vtt << ':' << start_time.minutes.to_s.rjust(2, '0')
vtt << ':' << start_time.seconds.to_s.rjust(2, '0')
vtt << '.' << start_time.milliseconds.to_s.rjust(3, '0')
vtt << " --> "
# end_time
vtt << end_time.hours.to_s.rjust(2, '0')
vtt << ':' << end_time.minutes.to_s.rjust(2, '0')
vtt << ':' << end_time.seconds.to_s.rjust(2, '0')
vtt << '.' << end_time.milliseconds.to_s.rjust(3, '0')
vtt << "\n"
vtt << line.line
vtt << "\n"
vtt << "\n"
vtt.cue(line.start_ms, line.end_ms, line.line)
end
end

View file

@ -26,7 +26,7 @@
<p><%= error_message %></p>
</div>
<% else %>
<div class="h-box pure-g" id="comments">
<div class="h-box pure-g comments" id="comments">
<%= IV::Frontend::Comments.template_youtube(items.not_nil!, locale, thin_mode) %>
</div>
<% end %>

View file

@ -26,8 +26,9 @@
</a></div>
</div>
<% if !item.channel_handle.nil? %><p class="channel-name" dir="auto"><%= item.channel_handle %></p><% end %>
<p><%= translate_count(locale, "generic_subscribers_count", item.subscriber_count, NumberFormatting::Separator) %></p>
<% if !item.auto_generated %><p><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p><% end %>
<% if !item.auto_generated && item.channel_handle.nil? %><p><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p><% end %>
<h5><%= item.description_html %></h5>
<% when SearchHashtag %>
<% if !thin_mode %>

View file

@ -0,0 +1,48 @@
<% content_for "header" do %>
<title>Invidious</title>
<% end %>
<div>
<div id="post" class="comments post-comments">
<%= IV::Frontend::Comments.template_youtube(post_response.not_nil!, locale, thin_mode) %>
</div>
<% if nojs %>
<hr>
<% end %>
<br />
<div id="comments" class="comments post-comments">
<% if nojs %>
<%= comment_html %>
<% else %>
<noscript>
<a href="/post/<%= id %>?ucid=<%= ucid %>&nojs=1">
<%= translate(locale, "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.") %>
</a>
</noscript>
<% end %>
</div>
</div>
<script id="video_data" type="application/json">
<%=
{
"id" => id,
"youtube_comments_text" => HTML.escape(translate(locale, "View YouTube comments")),
"reddit_comments_text" => "",
"reddit_permalink_text" => "",
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")),
"params" => {
"comments": ["youtube"]
},
"preferences" => prefs,
"base_url" => "/api/v1/post/#{URI.encode_www_form(id)}/comments",
"ucid" => ucid
}.to_pretty_json
%>
</script>
<script src="/js/comments.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/js/post.js?v=<%= ASSET_COMMIT %>"></script>

View file

@ -26,6 +26,11 @@
<input type="file" id="import_youtube_pl" name="import_youtube_pl">
</div>
<div class="pure-control-group">
<label for="import_youtube_wh"><%= translate(locale, "Import YouTube watch history (.json)") %></label>
<input type="file" id="import_youtube_wh" name="import_youtube_wh">
</div>
<div class="pure-control-group">
<label for="import_freetube"><%= translate(locale, "Import FreeTube subscriptions (.db)") %></label>
<input type="file" id="import_freetube" name="import_freetube">

View file

@ -64,7 +64,8 @@ we're going to need to do it here in order to allow for translations.
"premiere_timestamp" => video.premiere_timestamp.try &.to_unix,
"vr" => video.is_vr,
"projection_type" => video.projection_type,
"local_disabled" => CONFIG.disabled?("local")
"local_disabled" => CONFIG.disabled?("local"),
"support_reddit" => true
}.to_pretty_json
%>
</script>
@ -112,19 +113,36 @@ we're going to need to do it here in order to allow for translations.
<div class="pure-u-1 pure-u-lg-1-5">
<div class="h-box">
<span id="watch-on-youtube">
<a href="https://www.youtube.com/watch?v=<%= video.id %>"><%= translate(locale, "videoinfo_watch_on_youTube") %></a>
(<a href="https://www.youtube.com/embed/<%= video.id %>"><%= translate(locale, "videoinfo_youTube_embed_link") %></a>)
<%-
link_yt_watch = URI.new(scheme: "https", host: "www.youtube.com", path: "/watch", query: "v=#{video.id}")
link_yt_embed = URI.new(scheme: "https", host: "www.youtube.com", path: "/embed/#{video.id}")
if !plid.nil? && !continuation.nil?
link_yt_param = URI::Params{"plid" => [plid], "index" => [continuation.to_s]}
link_yt_watch = IV::HttpServer::Utils.add_params_to_url(link_yt_watch, link_yt_param)
link_yt_embed = IV::HttpServer::Utils.add_params_to_url(link_yt_embed, link_yt_param)
end
-%>
<a id="link-yt-watch" data-base-url="<%= link_yt_watch %>" href="<%= link_yt_watch %>"><%= translate(locale, "videoinfo_watch_on_youTube") %></a>
(<a id="link-yt-embed" data-base-url="<%= link_yt_embed %>" href="<%= link_yt_embed %>"><%= translate(locale, "videoinfo_youTube_embed_link") %></a>)
</span>
<p id="watch-on-another-invidious-instance">
<% if env.get("preferences").as(Preferences).automatic_instance_redirect%>
<a href="/redirect?referer=<%= env.get?("current_page") %>"><%= translate(locale, "Switch Invidious Instance") %></a>
<% else %>
<a href="https://redirect.invidious.io<%= env.request.resource %>"><%= translate(locale, "Switch Invidious Instance") %></a>
<% end %>
<%- link_iv_other = IV::Frontend::Misc.redirect_url(env) -%>
<a id="link-iv-other" data-base-url="<%= link_iv_other %>" href="<%= link_iv_other %>"><%= translate(locale, "Switch Invidious Instance") %></a>
</p>
<p id="embed-link">
<a href="<%= embed_link %>"><%= translate(locale, "videoinfo_invidious_embed_link") %></a>
<%-
params_iv_embed = env.params.query.dup
params_iv_embed.delete_all("v")
link_iv_embed = URI.new(path: "/embed/#{id}")
link_iv_embed = IV::HttpServer::Utils.add_params_to_url(link_iv_embed, params_iv_embed)
-%>
<a id="link-iv-embed" data-base-url="<%= link_iv_embed %>" href="<%= link_iv_embed %>"><%= translate(locale, "videoinfo_invidious_embed_link") %></a>
</p>
<p id="annotations">
<% if params.annotations %>
<a href="/watch?<%= env.params.query %>&iv_load_policy=3">
@ -270,7 +288,7 @@ we're going to need to do it here in order to allow for translations.
<hr>
<% end %>
<div id="comments">
<div id="comments" class="comments">
<% if nojs %>
<%= comment_html %>
<% else %>
@ -352,4 +370,5 @@ we're going to need to do it here in order to allow for translations.
</div>
<% end %>
</div>
<script src="/js/comments.js?v=<%= ASSET_COMMIT %>"></script>
<script src="/js/watch.js?v=<%= ASSET_COMMIT %>"></script>

View file

@ -175,17 +175,18 @@ private module Parsers
# Always simpleText
# TODO change default value to nil
subscriber_count = item_contents.dig?("subscriberCountText", "simpleText")
subscriber_count = item_contents.dig?("subscriberCountText", "simpleText").try &.as_s
channel_handle = subscriber_count if (subscriber_count.try &.starts_with? "@")
# Since youtube added channel handles, `VideoCountText` holds the number of
# subscribers and `subscriberCountText` holds the handle, except when the
# channel doesn't have a handle (e.g: some topic music channels).
# See https://github.com/iv-org/invidious/issues/3394#issuecomment-1321261688
if !subscriber_count || !subscriber_count.as_s.includes? " subscriber"
subscriber_count = item_contents.dig?("videoCountText", "simpleText")
if !subscriber_count || !subscriber_count.includes? " subscriber"
subscriber_count = item_contents.dig?("videoCountText", "simpleText").try &.as_s
end
subscriber_count = subscriber_count
.try { |s| short_text_to_number(s.as_s.split(" ")[0]).to_i32 } || 0
.try { |s| short_text_to_number(s.split(" ")[0]).to_i32 } || 0
# Auto-generated channels doesn't have videoCountText
# Taken from: https://github.com/iv-org/invidious/pull/2228#discussion_r717620922
@ -200,6 +201,7 @@ private module Parsers
author_thumbnail: author_thumbnail,
subscriber_count: subscriber_count,
video_count: video_count,
channel_handle: channel_handle,
description_html: description_html,
auto_generated: auto_generated,
author_verified: author_verified,