Merge branch 'master' of https://github.com/iv-org/invidious
This commit is contained in:
commit
1a2c740282
|
@ -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.
|
||||
|
|
|
@ -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
174
assets/js/comments.js
Normal 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;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -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
3
assets/js/post.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
addEventListener('load', function (e) {
|
||||
get_youtube_comments();
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -15,5 +15,7 @@
|
|||
],
|
||||
"theme_color": "#575757",
|
||||
"background_color": "#575757",
|
||||
"display": "standalone"
|
||||
"display": "standalone",
|
||||
"description": "An alternative front-end to YouTube",
|
||||
"start_url": "/"
|
||||
}
|
||||
|
|
|
@ -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 && \
|
||||
|
|
|
@ -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 && \
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
490
locales/bg.json
Normal 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": "Следваща страница"
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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ů"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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": "Ημερομηνία αναφόρτωσης"
|
||||
}
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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}}個のチャンネル"
|
||||
}
|
||||
|
|
|
@ -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}} 채널"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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}} каналов"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
465
locales/sr.json
465
locales/sr.json
|
@ -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": "Sinhaleški",
|
||||
"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": "Nepostojeći 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"
|
||||
}
|
||||
|
|
|
@ -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}} прегледа"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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}} каналів"
|
||||
}
|
||||
|
|
|
@ -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}} 个频道"
|
||||
}
|
||||
|
|
|
@ -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}} 個頻道"
|
||||
}
|
||||
|
|
64
spec/helpers/vtt/builder_spec.cr
Normal file
64
spec/helpers/vtt/builder_spec.cr
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
67
src/invidious/helpers/webvtt.cr
Normal file
67
src/invidious/helpers/webvtt.cr
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}.")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 %>
|
||||
|
|
|
@ -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 %>
|
||||
|
|
48
src/invidious/views/post.ecr
Normal file
48
src/invidious/views/post.ecr
Normal 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>
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue