フォーク元 suwako/invidious-mod
Merge branch 'master' of github.com:iv-org/invidious
このコミットが含まれているのは:
コミット
ed6c7850ed
|
@ -291,7 +291,7 @@ input[type="search"]::-webkit-search-cancel-button {
|
||||||
|
|
||||||
.flexible { display: flex; }
|
.flexible { display: flex; }
|
||||||
.flex-left { flex: 1 1 100%; flex-wrap: wrap; }
|
.flex-left { flex: 1 1 100%; flex-wrap: wrap; }
|
||||||
.flex-right { flex: 1 0 max-content; flex-wrap: nowrap; }
|
.flex-right { flex: 1 0 auto; flex-wrap: nowrap; }
|
||||||
|
|
||||||
p.channel-name { margin: 0; }
|
p.channel-name { margin: 0; }
|
||||||
p.video-data { margin: 0; font-weight: bold; font-size: 80%; }
|
p.video-data { margin: 0; font-weight: bold; font-size: 80%; }
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-js.player-style-youtube .vjs-progress-control .vjs-progress-holder, .video-js.player-style-youtube .vjs-progress-control {height: 5px;
|
||||||
|
margin-bottom: 10px;}
|
||||||
|
|
||||||
ul.vjs-menu-content::-webkit-scrollbar {
|
ul.vjs-menu-content::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
var community_data = JSON.parse(document.getElementById('community_data').innerHTML);
|
'use strict';
|
||||||
|
var community_data = JSON.parse(document.getElementById('community_data').textContent);
|
||||||
|
|
||||||
String.prototype.supplant = function (o) {
|
String.prototype.supplant = function (o) {
|
||||||
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
||||||
var r = o[b];
|
var r = o[b];
|
||||||
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function hide_youtube_replies(event) {
|
function hide_youtube_replies(event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
|
|
||||||
sub_text = target.getAttribute('data-inner-text');
|
var sub_text = target.getAttribute('data-inner-text');
|
||||||
inner_text = target.getAttribute('data-sub-text');
|
var inner_text = target.getAttribute('data-sub-text');
|
||||||
|
|
||||||
body = target.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.children[1];
|
||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
|
|
||||||
target.innerHTML = sub_text;
|
target.innerHTML = sub_text;
|
||||||
|
@ -25,10 +26,10 @@ function hide_youtube_replies(event) {
|
||||||
function show_youtube_replies(event) {
|
function show_youtube_replies(event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
|
|
||||||
sub_text = target.getAttribute('data-inner-text');
|
var sub_text = target.getAttribute('data-inner-text');
|
||||||
inner_text = target.getAttribute('data-sub-text');
|
var inner_text = target.getAttribute('data-sub-text');
|
||||||
|
|
||||||
body = target.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.children[1];
|
||||||
body.style.display = '';
|
body.style.display = '';
|
||||||
|
|
||||||
target.innerHTML = sub_text;
|
target.innerHTML = sub_text;
|
||||||
|
@ -63,8 +64,8 @@ function get_youtube_replies(target, load_more) {
|
||||||
xhr.open('GET', url, true);
|
xhr.open('GET', url, true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
if (load_more) {
|
if (load_more) {
|
||||||
body = body.parentNode.parentNode;
|
body = body.parentNode.parentNode;
|
||||||
body.removeChild(body.lastElementChild);
|
body.removeChild(body.lastElementChild);
|
||||||
|
@ -92,12 +93,12 @@ function get_youtube_replies(target, load_more) {
|
||||||
body.innerHTML = fallback;
|
body.innerHTML = fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Pulling comments failed.');
|
console.warn('Pulling comments failed.');
|
||||||
body.innerHTML = fallback;
|
body.innerHTML = fallback;
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
|
'use strict';
|
||||||
|
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||||
|
|
||||||
function get_playlist(plid, retries) {
|
function get_playlist(plid, retries) {
|
||||||
if (retries == undefined) retries = 5;
|
if (retries === undefined) retries = 5;
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to pull playlist');
|
console.warn('Failed to pull playlist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var plid_url;
|
||||||
if (plid.startsWith('RD')) {
|
if (plid.startsWith('RD')) {
|
||||||
var plid_url = '/api/v1/mixes/' + plid +
|
plid_url = '/api/v1/mixes/' + plid +
|
||||||
'?continuation=' + video_data.id +
|
'?continuation=' + video_data.id +
|
||||||
'&format=html&hl=' + video_data.preferences.locale;
|
'&format=html&hl=' + video_data.preferences.locale;
|
||||||
} else {
|
} else {
|
||||||
var plid_url = '/api/v1/playlists/' + plid +
|
plid_url = '/api/v1/playlists/' + plid +
|
||||||
'?index=' + video_data.index +
|
'?index=' + video_data.index +
|
||||||
'&continuation' + video_data.id +
|
'&continuation' + video_data.id +
|
||||||
'&format=html&hl=' + video_data.preferences.locale;
|
'&format=html&hl=' + video_data.preferences.locale;
|
||||||
|
@ -57,17 +59,17 @@ function get_playlist(plid, retries) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
console.log('Pulling playlist failed... ' + retries + '/5');
|
console.warn('Pulling playlist failed... ' + retries + '/5');
|
||||||
setTimeout(function () { get_playlist(plid, retries - 1) }, 1000);
|
setTimeout(function () { get_playlist(plid, retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Pulling playlist failed... ' + retries + '/5');
|
console.warn('Pulling playlist failed... ' + retries + '/5');
|
||||||
get_playlist(plid, retries - 1);
|
get_playlist(plid, retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ window.addEventListener('load', function (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video_data.video_series.length !== 0) {
|
if (video_data.video_series.length !== 0) {
|
||||||
url.searchParams.set('playlist', video_data.video_series.join(','))
|
url.searchParams.set('playlist', video_data.video_series.join(','));
|
||||||
}
|
}
|
||||||
|
|
||||||
location.assign(url.pathname + url.search);
|
location.assign(url.pathname + url.search);
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function (e) {
|
n2a(document.querySelectorAll('[data-onrange="update_volume_value"]')).forEach(function (e) {
|
||||||
var cb = function () { update_volume_value(e); }
|
var cb = function () { update_volume_value(e); };
|
||||||
e.oninput = cb;
|
e.oninput = cb;
|
||||||
e.onchange = cb;
|
e.onchange = cb;
|
||||||
});
|
});
|
||||||
|
@ -102,13 +102,13 @@
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
count.innerText = parseInt(count.innerText) + 1;
|
count.innerText = parseInt(count.innerText) + 1;
|
||||||
row.style.display = '';
|
row.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
|
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||||
xhr.send('csrf_token=' + csrf_token);
|
xhr.send('csrf_token=' + csrf_token);
|
||||||
|
@ -131,20 +131,20 @@
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
count.innerText = parseInt(count.innerText) + 1;
|
count.innerText = parseInt(count.innerText) + 1;
|
||||||
row.style.display = '';
|
row.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
|
var csrf_token = target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||||
xhr.send('csrf_token=' + csrf_token);
|
xhr.send('csrf_token=' + csrf_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle keypresses
|
// Handle keypresses
|
||||||
window.addEventListener('keydown', (event) => {
|
window.addEventListener('keydown', function (event) {
|
||||||
// Ignore modifier keys
|
// Ignore modifier keys
|
||||||
if (event.ctrlKey || event.metaKey) return;
|
if (event.ctrlKey || event.metaKey) return;
|
||||||
|
|
||||||
|
@ -152,14 +152,14 @@
|
||||||
let focused_tag = document.activeElement.tagName.toLowerCase();
|
let focused_tag = document.activeElement.tagName.toLowerCase();
|
||||||
const allowed = /^(button|checkbox|file|radio|submit)$/;
|
const allowed = /^(button|checkbox|file|radio|submit)$/;
|
||||||
|
|
||||||
if (focused_tag === "textarea") return;
|
if (focused_tag === 'textarea') return;
|
||||||
if (focused_tag === "input") {
|
if (focused_tag === 'input') {
|
||||||
let focused_type = document.activeElement.type.toLowerCase();
|
let focused_type = document.activeElement.type.toLowerCase();
|
||||||
if (!focused_type.match(allowed)) return;
|
if (!focused_type.match(allowed)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus search bar on '/'
|
// Focus search bar on '/'
|
||||||
if (event.key == "/") {
|
if (event.key === '/') {
|
||||||
document.getElementById('searchbox').focus();
|
document.getElementById('searchbox').focus();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
var notification_data = JSON.parse(document.getElementById('notification_data').innerHTML);
|
'use strict';
|
||||||
|
var notification_data = JSON.parse(document.getElementById('notification_data').textContent);
|
||||||
|
|
||||||
var notifications, delivered;
|
var notifications, delivered;
|
||||||
|
|
||||||
function get_subscriptions(callback, retries) {
|
function get_subscriptions(callback, retries) {
|
||||||
if (retries == undefined) retries = 5;
|
if (retries === undefined) retries = 5;
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -17,21 +18,21 @@ function get_subscriptions(callback, retries) {
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState === 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status === 200) {
|
if (xhr.status === 200) {
|
||||||
subscriptions = xhr.response;
|
var subscriptions = xhr.response;
|
||||||
callback(subscriptions);
|
callback(subscriptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
console.log('Pulling subscriptions failed... ' + retries + '/5');
|
console.warn('Pulling subscriptions failed... ' + retries + '/5');
|
||||||
setTimeout(function () { get_subscriptions(callback, retries - 1) }, 1000);
|
setTimeout(function () { get_subscriptions(callback, retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Pulling subscriptions failed... ' + retries + '/5');
|
console.warn('Pulling subscriptions failed... ' + retries + '/5');
|
||||||
get_subscriptions(callback, retries - 1);
|
get_subscriptions(callback, retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ function create_notification_stream(subscriptions) {
|
||||||
notifications = new SSE(
|
notifications = new SSE(
|
||||||
'/api/v1/auth/notifications?fields=videoId,title,author,authorId,publishedText,published,authorThumbnails,liveNow', {
|
'/api/v1/auth/notifications?fields=videoId,title,author,authorId,publishedText,published,authorThumbnails,liveNow', {
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId }).join(','),
|
payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId; }).join(','),
|
||||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||||
});
|
});
|
||||||
delivered = [];
|
delivered = [];
|
||||||
|
@ -53,7 +54,7 @@ function create_notification_stream(subscriptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var notification = JSON.parse(event.data);
|
var notification = JSON.parse(event.data);
|
||||||
console.log('Got notification:', notification);
|
console.info('Got notification:', notification);
|
||||||
|
|
||||||
if (start_time < notification.published && !delivered.includes(notification.videoId)) {
|
if (start_time < notification.published && !delivered.includes(notification.videoId)) {
|
||||||
if (Notification.permission === 'granted') {
|
if (Notification.permission === 'granted') {
|
||||||
|
@ -67,7 +68,7 @@ function create_notification_stream(subscriptions) {
|
||||||
|
|
||||||
system_notification.onclick = function (event) {
|
system_notification.onclick = function (event) {
|
||||||
window.open('/watch?v=' + event.currentTarget.tag, '_blank');
|
window.open('/watch?v=' + event.currentTarget.tag, '_blank');
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
delivered.push(notification.videoId);
|
delivered.push(notification.videoId);
|
||||||
|
@ -82,16 +83,16 @@ function create_notification_stream(subscriptions) {
|
||||||
'<i class="icon ion-ios-notifications-outline"></i>';
|
'<i class="icon ion-ios-notifications-outline"></i>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
notifications.addEventListener('error', handle_notification_error);
|
notifications.addEventListener('error', handle_notification_error);
|
||||||
notifications.stream();
|
notifications.stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_notification_error(event) {
|
function handle_notification_error(event) {
|
||||||
console.log('Something went wrong with notifications, trying to reconnect...');
|
console.warn('Something went wrong with notifications, trying to reconnect...');
|
||||||
notifications = { close: function () { } };
|
notifications = { close: function () { } };
|
||||||
setTimeout(function () { get_subscriptions(create_notification_stream) }, 1000);
|
setTimeout(function () { get_subscriptions(create_notification_stream); }, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', function (e) {
|
window.addEventListener('load', function (e) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var player_data = JSON.parse(document.getElementById('player_data').innerHTML);
|
'use strict';
|
||||||
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
|
var player_data = JSON.parse(document.getElementById('player_data').textContent);
|
||||||
|
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
preload: 'auto',
|
preload: 'auto',
|
||||||
|
@ -27,7 +28,7 @@ var options = {
|
||||||
overrideNative: true
|
overrideNative: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if (player_data.aspect_ratio) {
|
if (player_data.aspect_ratio) {
|
||||||
options.aspectRatio = player_data.aspect_ratio;
|
options.aspectRatio = player_data.aspect_ratio;
|
||||||
|
@ -38,7 +39,7 @@ embed_url.searchParams.delete('v');
|
||||||
var short_url = location.origin + '/' + video_data.id + embed_url.search;
|
var short_url = location.origin + '/' + video_data.id + embed_url.search;
|
||||||
embed_url = location.origin + '/embed/' + video_data.id + embed_url.search;
|
embed_url = location.origin + '/embed/' + video_data.id + embed_url.search;
|
||||||
|
|
||||||
var save_player_pos_key = "save_player_pos";
|
var save_player_pos_key = 'save_player_pos';
|
||||||
|
|
||||||
videojs.Vhs.xhr.beforeRequest = function(options) {
|
videojs.Vhs.xhr.beforeRequest = function(options) {
|
||||||
if (options.uri.indexOf('videoplayback') === -1 && options.uri.indexOf('local=true') === -1) {
|
if (options.uri.indexOf('videoplayback') === -1 && options.uri.indexOf('local=true') === -1) {
|
||||||
|
@ -111,12 +112,12 @@ var shareOptions = {
|
||||||
description: player_data.description,
|
description: player_data.description,
|
||||||
image: player_data.thumbnail,
|
image: player_data.thumbnail,
|
||||||
get embedCode() {
|
get embedCode() {
|
||||||
return "<iframe id='ivplayer' width='640' height='360' src='" +
|
return '<iframe id="ivplayer" width="640" height="360" src="' +
|
||||||
addCurrentTimeToURL(embed_url) + "' style='border:none;'></iframe>";
|
addCurrentTimeToURL(embed_url) + '" style="border:none;"></iframe>';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const storage = (() => {
|
const storage = (function () {
|
||||||
try { if (localStorage.length !== -1) return localStorage; }
|
try { if (localStorage.length !== -1) return localStorage; }
|
||||||
catch (e) { console.info('No storage available: ' + e); }
|
catch (e) { console.info('No storage available: ' + e); }
|
||||||
|
|
||||||
|
@ -137,57 +138,57 @@ if (location.pathname.startsWith('/embed/')) {
|
||||||
// Detection code taken from https://stackoverflow.com/a/20293441
|
// Detection code taken from https://stackoverflow.com/a/20293441
|
||||||
|
|
||||||
function isMobile() {
|
function isMobile() {
|
||||||
try{ document.createEvent("TouchEvent"); return true; }
|
try{ document.createEvent('TouchEvent'); return true; }
|
||||||
catch(e){ return false; }
|
catch(e){ return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
player.mobileUi();
|
player.mobileUi();
|
||||||
|
|
||||||
buttons = ["playToggle", "volumePanel", "captionsButton"];
|
var buttons = ['playToggle', 'volumePanel', 'captionsButton'];
|
||||||
|
|
||||||
if (video_data.params.quality !== 'dash') buttons.push("qualitySelector")
|
if (video_data.params.quality !== 'dash') buttons.push('qualitySelector');
|
||||||
|
|
||||||
// Create new control bar object for operation buttons
|
// Create new control bar object for operation buttons
|
||||||
const ControlBar = videojs.getComponent("controlBar");
|
const ControlBar = videojs.getComponent('controlBar');
|
||||||
let operations_bar = new ControlBar(player, {
|
let operations_bar = new ControlBar(player, {
|
||||||
children: [],
|
children: [],
|
||||||
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
|
playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
|
||||||
});
|
});
|
||||||
buttons.slice(1).forEach(child => operations_bar.addChild(child))
|
buttons.slice(1).forEach(function (child) {operations_bar.addChild(child);});
|
||||||
|
|
||||||
// Remove operation buttons from primary control bar
|
// Remove operation buttons from primary control bar
|
||||||
primary_control_bar = player.getChild("controlBar");
|
var primary_control_bar = player.getChild('controlBar');
|
||||||
buttons.forEach(child => primary_control_bar.removeChild(child));
|
buttons.forEach(function (child) {primary_control_bar.removeChild(child);});
|
||||||
|
|
||||||
operations_bar_element = operations_bar.el();
|
var operations_bar_element = operations_bar.el();
|
||||||
operations_bar_element.className += " mobile-operations-bar"
|
operations_bar_element.className += ' mobile-operations-bar';
|
||||||
player.addChild(operations_bar)
|
player.addChild(operations_bar);
|
||||||
|
|
||||||
// Playback menu doesn't work when it's initialized outside of the primary control bar
|
// Playback menu doesn't work when it's initialized outside of the primary control bar
|
||||||
playback_element = document.getElementsByClassName("vjs-playback-rate")[0]
|
var playback_element = document.getElementsByClassName('vjs-playback-rate')[0];
|
||||||
operations_bar_element.append(playback_element)
|
operations_bar_element.append(playback_element);
|
||||||
|
|
||||||
// The share and http source selector element can't be fetched till the players ready.
|
// The share and http source selector element can't be fetched till the players ready.
|
||||||
player.one("playing", () => {
|
player.one('playing', function () {
|
||||||
share_element = document.getElementsByClassName("vjs-share-control")[0]
|
var share_element = document.getElementsByClassName('vjs-share-control')[0];
|
||||||
operations_bar_element.append(share_element)
|
operations_bar_element.append(share_element);
|
||||||
|
|
||||||
if (video_data.params.quality === 'dash') {
|
if (video_data.params.quality === 'dash') {
|
||||||
http_source_selector = document.getElementsByClassName("vjs-http-source-selector vjs-menu-button")[0]
|
var http_source_selector = document.getElementsByClassName('vjs-http-source-selector vjs-menu-button')[0];
|
||||||
operations_bar_element.append(http_source_selector)
|
operations_bar_element.append(http_source_selector);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable VR video support
|
// Enable VR video support
|
||||||
if (!video_data.params.listen && video_data.vr && video_data.params.vr_mode) {
|
if (!video_data.params.listen && video_data.vr && video_data.params.vr_mode) {
|
||||||
player.crossOrigin("anonymous")
|
player.crossOrigin('anonymous');
|
||||||
switch (video_data.projection_type) {
|
switch (video_data.projection_type) {
|
||||||
case "EQUIRECTANGULAR":
|
case 'EQUIRECTANGULAR':
|
||||||
player.vr({projection: "equirectangular"});
|
player.vr({projection: 'equirectangular'});
|
||||||
default: // Should only be "MESH" but we'll use this as a fallback.
|
default: // Should only be 'MESH' but we'll use this as a fallback.
|
||||||
player.vr({projection: "EAC"});
|
player.vr({projection: 'EAC'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,27 +223,27 @@ player.playbackRate(video_data.params.speed);
|
||||||
* @returns cookieValue
|
* @returns cookieValue
|
||||||
*/
|
*/
|
||||||
function getCookieValue(name) {
|
function getCookieValue(name) {
|
||||||
var value = document.cookie.split(";").filter(item => item.includes(name + "="));
|
var value = document.cookie.split(';').filter(function (item) {return item.includes(name + '=');});
|
||||||
|
|
||||||
return (value != null && value.length >= 1)
|
return (value.length >= 1)
|
||||||
? value[0].substring((name + "=").length, value[0].length)
|
? value[0].substring((name + '=').length, value[0].length)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method for updating the "PREFS" cookie (or creating it if missing)
|
* Method for updating the 'PREFS' cookie (or creating it if missing)
|
||||||
*
|
*
|
||||||
* @param {number} newVolume New volume defined (null if unchanged)
|
* @param {number} newVolume New volume defined (null if unchanged)
|
||||||
* @param {number} newSpeed New speed defined (null if unchanged)
|
* @param {number} newSpeed New speed defined (null if unchanged)
|
||||||
*/
|
*/
|
||||||
function updateCookie(newVolume, newSpeed) {
|
function updateCookie(newVolume, newSpeed) {
|
||||||
var volumeValue = newVolume != null ? newVolume : video_data.params.volume;
|
var volumeValue = newVolume !== null ? newVolume : video_data.params.volume;
|
||||||
var speedValue = newSpeed != null ? newSpeed : video_data.params.speed;
|
var speedValue = newSpeed !== null ? newSpeed : video_data.params.speed;
|
||||||
|
|
||||||
var cookieValue = getCookieValue('PREFS');
|
var cookieValue = getCookieValue('PREFS');
|
||||||
var cookieData;
|
var cookieData;
|
||||||
|
|
||||||
if (cookieValue != null) {
|
if (cookieValue !== null) {
|
||||||
var cookieJson = JSON.parse(decodeURIComponent(cookieValue));
|
var cookieJson = JSON.parse(decodeURIComponent(cookieValue));
|
||||||
cookieJson.volume = volumeValue;
|
cookieJson.volume = volumeValue;
|
||||||
cookieJson.speed = speedValue;
|
cookieJson.speed = speedValue;
|
||||||
|
@ -259,7 +260,7 @@ function updateCookie(newVolume, newSpeed) {
|
||||||
var domainUsed = window.location.hostname;
|
var domainUsed = window.location.hostname;
|
||||||
|
|
||||||
// Fix for a bug in FF where the leading dot in the FQDN is not ignored
|
// Fix for a bug in FF where the leading dot in the FQDN is not ignored
|
||||||
if (domainUsed.charAt(0) != '.' && !ipRegex.test(domainUsed) && domainUsed != 'localhost')
|
if (domainUsed.charAt(0) !== '.' && !ipRegex.test(domainUsed) && domainUsed !== 'localhost')
|
||||||
domainUsed = '.' + window.location.hostname;
|
domainUsed = '.' + window.location.hostname;
|
||||||
|
|
||||||
document.cookie = 'PREFS=' + cookieData + '; SameSite=Strict; path=/; domain=' +
|
document.cookie = 'PREFS=' + cookieData + '; SameSite=Strict; path=/; domain=' +
|
||||||
|
@ -279,7 +280,7 @@ player.on('volumechange', function () {
|
||||||
|
|
||||||
player.on('waiting', function () {
|
player.on('waiting', function () {
|
||||||
if (player.playbackRate() > 1 && player.liveTracker.isLive() && player.liveTracker.atLiveEdge()) {
|
if (player.playbackRate() > 1 && player.liveTracker.isLive() && player.liveTracker.atLiveEdge()) {
|
||||||
console.log('Player has caught up to source, resetting playbackRate.')
|
console.info('Player has caught up to source, resetting playbackRate.');
|
||||||
player.playbackRate(1);
|
player.playbackRate(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -290,13 +291,13 @@ if (video_data.premiere_timestamp && Math.round(new Date() / 1000) < video_data.
|
||||||
|
|
||||||
if (video_data.params.save_player_pos) {
|
if (video_data.params.save_player_pos) {
|
||||||
const url = new URL(location);
|
const url = new URL(location);
|
||||||
const hasTimeParam = url.searchParams.has("t");
|
const hasTimeParam = url.searchParams.has('t');
|
||||||
const remeberedTime = get_video_time();
|
const remeberedTime = get_video_time();
|
||||||
let lastUpdated = 0;
|
let lastUpdated = 0;
|
||||||
|
|
||||||
if(!hasTimeParam) set_seconds_after_start(remeberedTime);
|
if(!hasTimeParam) set_seconds_after_start(remeberedTime);
|
||||||
|
|
||||||
const updateTime = () => {
|
const updateTime = function () {
|
||||||
const raw = player.currentTime();
|
const raw = player.currentTime();
|
||||||
const time = Math.floor(raw);
|
const time = Math.floor(raw);
|
||||||
|
|
||||||
|
@ -306,7 +307,7 @@ if (video_data.params.save_player_pos) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
player.on("timeupdate", updateTime);
|
player.on('timeupdate', updateTime);
|
||||||
}
|
}
|
||||||
else remove_all_video_times();
|
else remove_all_video_times();
|
||||||
|
|
||||||
|
@ -316,13 +317,13 @@ if (video_data.params.autoplay) {
|
||||||
|
|
||||||
player.ready(function () {
|
player.ready(function () {
|
||||||
new Promise(function (resolve, reject) {
|
new Promise(function (resolve, reject) {
|
||||||
setTimeout(() => resolve(1), 1);
|
setTimeout(function () {resolve(1);}, 1);
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
var promise = player.play();
|
var promise = player.play();
|
||||||
|
|
||||||
if (promise !== undefined) {
|
if (promise !== undefined) {
|
||||||
promise.then(_ => {
|
promise.then(function () {
|
||||||
}).catch(error => {
|
}).catch(function (error) {
|
||||||
bpb.show();
|
bpb.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -333,16 +334,16 @@ if (video_data.params.autoplay) {
|
||||||
if (!video_data.params.listen && video_data.params.quality === 'dash') {
|
if (!video_data.params.listen && video_data.params.quality === 'dash') {
|
||||||
player.httpSourceSelector();
|
player.httpSourceSelector();
|
||||||
|
|
||||||
if (video_data.params.quality_dash != "auto") {
|
if (video_data.params.quality_dash !== 'auto') {
|
||||||
player.ready(() => {
|
player.ready(function () {
|
||||||
player.on("loadedmetadata", () => {
|
player.on('loadedmetadata', function () {
|
||||||
const qualityLevels = Array.from(player.qualityLevels()).sort((a, b) => a.height - b.height);
|
const qualityLevels = Array.from(player.qualityLevels()).sort(function (a, b) {return a.height - b.height;});
|
||||||
let targetQualityLevel;
|
let targetQualityLevel;
|
||||||
switch (video_data.params.quality_dash) {
|
switch (video_data.params.quality_dash) {
|
||||||
case "best":
|
case 'best':
|
||||||
targetQualityLevel = qualityLevels.length - 1;
|
targetQualityLevel = qualityLevels.length - 1;
|
||||||
break;
|
break;
|
||||||
case "worst":
|
case 'worst':
|
||||||
targetQualityLevel = 0;
|
targetQualityLevel = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -356,7 +357,7 @@ if (!video_data.params.listen && video_data.params.quality === 'dash') {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (let i = 0; i < qualityLevels.length; i++) {
|
for (let i = 0; i < qualityLevels.length; i++) {
|
||||||
qualityLevels[i].enabled = (i == targetQualityLevel);
|
qualityLevels[i].enabled = (i === targetQualityLevel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -390,10 +391,12 @@ if (!video_data.params.listen && video_data.params.annotations) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
window.addEventListener('__ar_annotation_click', e => {
|
window.addEventListener('__ar_annotation_click', function (e) {
|
||||||
const { url, target, seconds } = e.detail;
|
const url = e.detail.url,
|
||||||
|
target = e.detail.target,
|
||||||
|
seconds = e.detail.seconds;
|
||||||
var path = new URL(url);
|
var path = new URL(url);
|
||||||
|
|
||||||
if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) {
|
if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) {
|
||||||
|
@ -463,7 +466,7 @@ function get_video_time() {
|
||||||
|
|
||||||
return timestamp || 0;
|
return timestamp || 0;
|
||||||
}
|
}
|
||||||
catch {
|
catch (e) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,7 +477,7 @@ function set_all_video_times(times) {
|
||||||
try {
|
try {
|
||||||
storage.setItem(save_player_pos_key, JSON.stringify(times));
|
storage.setItem(save_player_pos_key, JSON.stringify(times));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.debug('set_all_video_times: ' + e);
|
console.warn('set_all_video_times: ' + e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
storage.removeItem(save_player_pos_key);
|
storage.removeItem(save_player_pos_key);
|
||||||
|
@ -489,7 +492,7 @@ function get_all_video_times() {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(raw);
|
return JSON.parse(raw);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.debug('get_all_video_times: ' + e);
|
console.warn('get_all_video_times: ' + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,7 +586,7 @@ function increase_playback_rate(steps) {
|
||||||
player.playbackRate(options.playbackRates[newIndex]);
|
player.playbackRate(options.playbackRates[newIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('keydown', e => {
|
window.addEventListener('keydown', function (e) {
|
||||||
if (e.target.tagName.toLowerCase() === 'input') {
|
if (e.target.tagName.toLowerCase() === 'input') {
|
||||||
// Ignore input when focus is on certain elements, e.g. form fields.
|
// Ignore input when focus is on certain elements, e.g. form fields.
|
||||||
return;
|
return;
|
||||||
|
@ -702,7 +705,7 @@ window.addEventListener('keydown', e => {
|
||||||
|
|
||||||
var volumeHover = false;
|
var volumeHover = false;
|
||||||
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
|
var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');
|
||||||
if (volumeSelector != null) {
|
if (volumeSelector !== null) {
|
||||||
volumeSelector.onmouseover = function () { volumeHover = true; };
|
volumeSelector.onmouseover = function () { volumeHover = true; };
|
||||||
volumeSelector.onmouseout = function () { volumeHover = false; };
|
volumeSelector.onmouseout = function () { volumeHover = false; };
|
||||||
}
|
}
|
||||||
|
@ -722,9 +725,9 @@ window.addEventListener('keydown', e => {
|
||||||
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
|
var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (delta == 1) {
|
if (delta === 1) {
|
||||||
increase_volume(volumeStep);
|
increase_volume(volumeStep);
|
||||||
} else if (delta == -1) {
|
} else if (delta === -1) {
|
||||||
increase_volume(-volumeStep);
|
increase_volume(-volumeStep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -733,7 +736,7 @@ window.addEventListener('keydown', e => {
|
||||||
};
|
};
|
||||||
|
|
||||||
player.on('mousewheel', mouseScroll);
|
player.on('mousewheel', mouseScroll);
|
||||||
player.on("DOMMouseScroll", mouseScroll);
|
player.on('DOMMouseScroll', mouseScroll);
|
||||||
}());
|
}());
|
||||||
|
|
||||||
// Since videojs-share can sometimes be blocked, we defer it until last
|
// Since videojs-share can sometimes be blocked, we defer it until last
|
||||||
|
@ -743,13 +746,13 @@ if (player.share) {
|
||||||
|
|
||||||
// show the preferred caption by default
|
// show the preferred caption by default
|
||||||
if (player_data.preferred_caption_found) {
|
if (player_data.preferred_caption_found) {
|
||||||
player.ready(() => {
|
player.ready(function () {
|
||||||
player.textTracks()[1].mode = 'showing';
|
player.textTracks()[1].mode = 'showing';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safari audio double duration fix
|
// Safari audio double duration fix
|
||||||
if (navigator.vendor == "Apple Computer, Inc." && video_data.params.listen) {
|
if (navigator.vendor === 'Apple Computer, Inc.' && video_data.params.listen) {
|
||||||
player.on('loadedmetadata', function () {
|
player.on('loadedmetadata', function () {
|
||||||
player.on('timeupdate', function () {
|
player.on('timeupdate', function () {
|
||||||
if (player.remainingTime() < player.duration() / 2 && player.remainingTime() >= 2) {
|
if (player.remainingTime() < player.duration() / 2 && player.remainingTime() >= 2) {
|
||||||
|
@ -760,18 +763,18 @@ if (navigator.vendor == "Apple Computer, Inc." && video_data.params.listen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch on Invidious link
|
// Watch on Invidious link
|
||||||
if (window.location.pathname.startsWith("/embed/")) {
|
if (window.location.pathname.startsWith('/embed/')) {
|
||||||
const Button = videojs.getComponent('Button');
|
const Button = videojs.getComponent('Button');
|
||||||
let watch_on_invidious_button = new Button(player);
|
let watch_on_invidious_button = new Button(player);
|
||||||
|
|
||||||
// Create hyperlink for current instance
|
// Create hyperlink for current instance
|
||||||
redirect_element = document.createElement("a");
|
var redirect_element = document.createElement('a');
|
||||||
redirect_element.setAttribute("href", `//${window.location.host}/watch?v=${window.location.pathname.replace("/embed/","")}`)
|
redirect_element.setAttribute('href', location.pathname.replace('/embed/', '/watch?v='));
|
||||||
redirect_element.appendChild(document.createTextNode("Invidious"))
|
redirect_element.appendChild(document.createTextNode('Invidious'));
|
||||||
|
|
||||||
watch_on_invidious_button.el().appendChild(redirect_element)
|
watch_on_invidious_button.el().appendChild(redirect_element);
|
||||||
watch_on_invidious_button.addClass("watch-on-invidious")
|
watch_on_invidious_button.addClass('watch-on-invidious');
|
||||||
|
|
||||||
cb = player.getChild('ControlBar')
|
var cb = player.getChild('ControlBar');
|
||||||
cb.addChild(watch_on_invidious_button)
|
cb.addChild(watch_on_invidious_button);
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var playlist_data = JSON.parse(document.getElementById('playlist_data').innerHTML);
|
'use strict';
|
||||||
|
var playlist_data = JSON.parse(document.getElementById('playlist_data').textContent);
|
||||||
|
|
||||||
function add_playlist_video(target) {
|
function add_playlist_video(target) {
|
||||||
var select = target.parentNode.children[0].children[1];
|
var select = target.parentNode.children[0].children[1];
|
||||||
|
@ -14,12 +15,12 @@ function add_playlist_video(target) {
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
option.innerText = '✓' + option.innerText;
|
option.innerText = '✓' + option.innerText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
||||||
}
|
}
|
||||||
|
@ -38,12 +39,12 @@ function add_playlist_item(target) {
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
tile.style.display = '';
|
tile.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
||||||
}
|
}
|
||||||
|
@ -62,12 +63,12 @@ function remove_playlist_item(target) {
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
tile.style.display = '';
|
tile.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
xhr.send('csrf_token=' + playlist_data.csrf_token);
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
var subscribe_data = JSON.parse(document.getElementById('subscribe_data').innerHTML);
|
'use strict';
|
||||||
|
var subscribe_data = JSON.parse(document.getElementById('subscribe_data').textContent);
|
||||||
|
|
||||||
var subscribe_button = document.getElementById('subscribe');
|
var subscribe_button = document.getElementById('subscribe');
|
||||||
subscribe_button.parentNode['action'] = 'javascript:void(0)';
|
subscribe_button.parentNode['action'] = 'javascript:void(0)';
|
||||||
|
@ -9,9 +10,11 @@ if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||||
subscribe_button.onclick = unsubscribe;
|
subscribe_button.onclick = unsubscribe;
|
||||||
}
|
}
|
||||||
|
|
||||||
function subscribe(retries = 5) {
|
function subscribe(retries) {
|
||||||
|
if (retries === undefined) retries = 5;
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to subscribe.');
|
console.warn('Failed to subscribe.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,30 +31,33 @@ function subscribe(retries = 5) {
|
||||||
subscribe_button.innerHTML = '<b>' + subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
subscribe_button.innerHTML = '<b>' + subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
subscribe_button.onclick = subscribe;
|
subscribe_button.onclick = subscribe;
|
||||||
subscribe_button.innerHTML = fallback;
|
subscribe_button.innerHTML = fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
console.log('Subscribing failed... ' + retries + '/5');
|
console.warn('Subscribing failed... ' + retries + '/5');
|
||||||
setTimeout(function () { subscribe(retries - 1) }, 1000);
|
setTimeout(function () { subscribe(retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Subscribing failed... ' + retries + '/5');
|
console.warn('Subscribing failed... ' + retries + '/5');
|
||||||
subscribe(retries - 1);
|
subscribe(retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + subscribe_data.csrf_token);
|
xhr.send('csrf_token=' + subscribe_data.csrf_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unsubscribe(retries = 5) {
|
function unsubscribe(retries) {
|
||||||
|
if (retries === undefined)
|
||||||
|
retries = 5;
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to subscribe');
|
console.warn('Failed to subscribe');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,23 +74,23 @@ function unsubscribe(retries = 5) {
|
||||||
subscribe_button.innerHTML = '<b>' + subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
subscribe_button.innerHTML = '<b>' + subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
subscribe_button.onclick = unsubscribe;
|
subscribe_button.onclick = unsubscribe;
|
||||||
subscribe_button.innerHTML = fallback;
|
subscribe_button.innerHTML = fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
console.log('Unsubscribing failed... ' + retries + '/5');
|
console.warn('Unsubscribing failed... ' + retries + '/5');
|
||||||
setTimeout(function () { unsubscribe(retries - 1) }, 1000);
|
setTimeout(function () { unsubscribe(retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Unsubscribing failed... ' + retries + '/5');
|
console.warn('Unsubscribing failed... ' + retries + '/5');
|
||||||
unsubscribe(retries - 1);
|
unsubscribe(retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + subscribe_data.csrf_token);
|
xhr.send('csrf_token=' + subscribe_data.csrf_token);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
'use strict';
|
||||||
var toggle_theme = document.getElementById('toggle_theme');
|
var toggle_theme = document.getElementById('toggle_theme');
|
||||||
toggle_theme.href = 'javascript:void(0);';
|
toggle_theme.href = 'javascript:void(0);';
|
||||||
|
|
||||||
toggle_theme.addEventListener('click', function () {
|
toggle_theme.addEventListener('click', function () {
|
||||||
var dark_mode = document.body.classList.contains("light-theme");
|
var dark_mode = document.body.classList.contains('light-theme');
|
||||||
|
|
||||||
var url = '/toggle_theme?redirect=false';
|
var url = '/toggle_theme?redirect=false';
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
|
@ -13,7 +14,7 @@ toggle_theme.addEventListener('click', function () {
|
||||||
set_mode(dark_mode);
|
set_mode(dark_mode);
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem('dark_mode', dark_mode ? 'dark' : 'light');
|
window.localStorage.setItem('dark_mode', dark_mode ? 'dark' : 'light');
|
||||||
} catch {}
|
} catch (e) {}
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
});
|
});
|
||||||
|
@ -29,7 +30,7 @@ window.addEventListener('DOMContentLoaded', function () {
|
||||||
try {
|
try {
|
||||||
// Update localStorage if dark mode preference changed on preferences page
|
// Update localStorage if dark mode preference changed on preferences page
|
||||||
window.localStorage.setItem('dark_mode', dark_mode);
|
window.localStorage.setItem('dark_mode', dark_mode);
|
||||||
} catch {}
|
} catch (e) {}
|
||||||
update_mode(dark_mode);
|
update_mode(dark_mode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -46,11 +47,11 @@ function scheme_switch (e) {
|
||||||
if (localStorage.getItem('dark_mode')) {
|
if (localStorage.getItem('dark_mode')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (exception) {}
|
||||||
if (e.matches) {
|
if (e.matches) {
|
||||||
if (e.media.includes("dark")) {
|
if (e.media.includes('dark')) {
|
||||||
set_mode(true);
|
set_mode(true);
|
||||||
} else if (e.media.includes("light")) {
|
} else if (e.media.includes('light')) {
|
||||||
set_mode(false);
|
set_mode(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,5 +88,3 @@ function update_mode (mode) {
|
||||||
}
|
}
|
||||||
// else do nothing, falling back to the mode defined by the `dark_mode` preference on the preferences page (backend)
|
// else do nothing, falling back to the mode defined by the `dark_mode` preference on the preferences page (backend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,32 @@
|
||||||
var video_data = JSON.parse(document.getElementById('video_data').innerHTML);
|
'use strict';
|
||||||
|
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||||
|
|
||||||
String.prototype.supplant = function (o) {
|
String.prototype.supplant = function (o) {
|
||||||
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
||||||
var r = o[b];
|
var r = o[b];
|
||||||
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function toggle_parent(target) {
|
function toggle_parent(target) {
|
||||||
body = target.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.children[1];
|
||||||
if (body.style.display === null || body.style.display === '') {
|
if (body.style.display === null || body.style.display === '') {
|
||||||
target.innerHTML = '[ + ]';
|
target.textContent = '[ + ]';
|
||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
target.innerHTML = '[ - ]';
|
target.textContent = '[ − ]';
|
||||||
body.style.display = '';
|
body.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle_comments(event) {
|
function toggle_comments(event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
body = target.parentNode.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.parentNode.children[1];
|
||||||
if (body.style.display === null || body.style.display === '') {
|
if (body.style.display === null || body.style.display === '') {
|
||||||
target.innerHTML = '[ + ]';
|
target.textContent = '[ + ]';
|
||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
} else {
|
} else {
|
||||||
target.innerHTML = '[ - ]';
|
target.textContent = '[ − ]';
|
||||||
body.style.display = '';
|
body.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,13 +44,13 @@ function swap_comments(event) {
|
||||||
function hide_youtube_replies(event) {
|
function hide_youtube_replies(event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
|
|
||||||
sub_text = target.getAttribute('data-inner-text');
|
var sub_text = target.getAttribute('data-inner-text');
|
||||||
inner_text = target.getAttribute('data-sub-text');
|
var inner_text = target.getAttribute('data-sub-text');
|
||||||
|
|
||||||
body = target.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.children[1];
|
||||||
body.style.display = 'none';
|
body.style.display = 'none';
|
||||||
|
|
||||||
target.innerHTML = sub_text;
|
target.textContent = sub_text;
|
||||||
target.onclick = show_youtube_replies;
|
target.onclick = show_youtube_replies;
|
||||||
target.setAttribute('data-inner-text', inner_text);
|
target.setAttribute('data-inner-text', inner_text);
|
||||||
target.setAttribute('data-sub-text', sub_text);
|
target.setAttribute('data-sub-text', sub_text);
|
||||||
|
@ -58,13 +59,13 @@ function hide_youtube_replies(event) {
|
||||||
function show_youtube_replies(event) {
|
function show_youtube_replies(event) {
|
||||||
var target = event.target;
|
var target = event.target;
|
||||||
|
|
||||||
sub_text = target.getAttribute('data-inner-text');
|
var sub_text = target.getAttribute('data-inner-text');
|
||||||
inner_text = target.getAttribute('data-sub-text');
|
var inner_text = target.getAttribute('data-sub-text');
|
||||||
|
|
||||||
body = target.parentNode.parentNode.children[1];
|
var body = target.parentNode.parentNode.children[1];
|
||||||
body.style.display = '';
|
body.style.display = '';
|
||||||
|
|
||||||
target.innerHTML = sub_text;
|
target.textContent = sub_text;
|
||||||
target.onclick = hide_youtube_replies;
|
target.onclick = hide_youtube_replies;
|
||||||
target.setAttribute('data-inner-text', inner_text);
|
target.setAttribute('data-inner-text', inner_text);
|
||||||
target.setAttribute('data-sub-text', sub_text);
|
target.setAttribute('data-sub-text', sub_text);
|
||||||
|
@ -116,25 +117,26 @@ function number_with_separator(val) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_playlist(plid, retries) {
|
function get_playlist(plid, retries) {
|
||||||
if (retries == undefined) retries = 5;
|
if (retries === undefined) retries = 5;
|
||||||
playlist = document.getElementById('playlist');
|
var playlist = document.getElementById('playlist');
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to pull playlist');
|
console.warn('Failed to pull playlist');
|
||||||
playlist.innerHTML = '';
|
playlist.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist.innerHTML = ' \
|
playlist.innerHTML = ' \
|
||||||
<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3> \
|
<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3> \
|
||||||
<hr>'
|
<hr>';
|
||||||
|
|
||||||
|
var plid_url;
|
||||||
if (plid.startsWith('RD')) {
|
if (plid.startsWith('RD')) {
|
||||||
var plid_url = '/api/v1/mixes/' + plid +
|
plid_url = '/api/v1/mixes/' + plid +
|
||||||
'?continuation=' + video_data.id +
|
'?continuation=' + video_data.id +
|
||||||
'&format=html&hl=' + video_data.preferences.locale;
|
'&format=html&hl=' + video_data.preferences.locale;
|
||||||
} else {
|
} else {
|
||||||
var plid_url = '/api/v1/playlists/' + plid +
|
plid_url = '/api/v1/playlists/' + plid +
|
||||||
'?index=' + video_data.index +
|
'?index=' + video_data.index +
|
||||||
'&continuation=' + video_data.id +
|
'&continuation=' + video_data.id +
|
||||||
'&format=html&hl=' + video_data.preferences.locale;
|
'&format=html&hl=' + video_data.preferences.locale;
|
||||||
|
@ -146,8 +148,8 @@ function get_playlist(plid, retries) {
|
||||||
xhr.open('GET', plid_url, true);
|
xhr.open('GET', plid_url, true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
playlist.innerHTML = xhr.response.playlistHtml;
|
playlist.innerHTML = xhr.response.playlistHtml;
|
||||||
var nextVideo = document.getElementById(xhr.response.nextVideo);
|
var nextVideo = document.getElementById(xhr.response.nextVideo);
|
||||||
nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop;
|
nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop;
|
||||||
|
@ -185,35 +187,35 @@ function get_playlist(plid, retries) {
|
||||||
document.getElementById('continue').style.display = '';
|
document.getElementById('continue').style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
playlist = document.getElementById('playlist');
|
playlist = document.getElementById('playlist');
|
||||||
playlist.innerHTML =
|
playlist.innerHTML =
|
||||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
|
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
|
||||||
|
|
||||||
console.log('Pulling playlist timed out... ' + retries + '/5');
|
console.warn('Pulling playlist timed out... ' + retries + '/5');
|
||||||
setTimeout(function () { get_playlist(plid, retries - 1) }, 1000);
|
setTimeout(function () { get_playlist(plid, retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
playlist = document.getElementById('playlist');
|
playlist = document.getElementById('playlist');
|
||||||
playlist.innerHTML =
|
playlist.innerHTML =
|
||||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
|
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3><hr>';
|
||||||
|
|
||||||
console.log('Pulling playlist timed out... ' + retries + '/5');
|
console.warn('Pulling playlist timed out... ' + retries + '/5');
|
||||||
get_playlist(plid, retries - 1);
|
get_playlist(plid, retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_reddit_comments(retries) {
|
function get_reddit_comments(retries) {
|
||||||
if (retries == undefined) retries = 5;
|
if (retries === undefined) retries = 5;
|
||||||
comments = document.getElementById('comments');
|
var comments = document.getElementById('comments');
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to pull comments');
|
console.warn('Failed to pull comments');
|
||||||
comments.innerHTML = '';
|
comments.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -231,12 +233,12 @@ function get_reddit_comments(retries) {
|
||||||
xhr.open('GET', url, true);
|
xhr.open('GET', url, true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
comments.innerHTML = ' \
|
comments.innerHTML = ' \
|
||||||
<div> \
|
<div> \
|
||||||
<h3> \
|
<h3> \
|
||||||
<a href="javascript:void(0)">[ - ]</a> \
|
<a href="javascript:void(0)">[ − ]</a> \
|
||||||
{title} \
|
{title} \
|
||||||
</h3> \
|
</h3> \
|
||||||
<p> \
|
<p> \
|
||||||
|
@ -263,34 +265,34 @@ function get_reddit_comments(retries) {
|
||||||
comments.children[0].children[1].children[0].onclick = swap_comments;
|
comments.children[0].children[1].children[0].onclick = swap_comments;
|
||||||
} else {
|
} else {
|
||||||
if (video_data.params.comments[1] === 'youtube') {
|
if (video_data.params.comments[1] === 'youtube') {
|
||||||
console.log('Pulling comments failed... ' + retries + '/5');
|
console.warn('Pulling comments failed... ' + retries + '/5');
|
||||||
setTimeout(function () { get_youtube_comments(retries - 1) }, 1000);
|
setTimeout(function () { get_youtube_comments(retries - 1); }, 1000);
|
||||||
} else {
|
} else {
|
||||||
comments.innerHTML = fallback;
|
comments.innerHTML = fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
console.log('Pulling comments failed... ' + retries + '/5');
|
console.warn('Pulling comments failed... ' + retries + '/5');
|
||||||
setTimeout(function () { get_reddit_comments(retries - 1) }, 1000);
|
setTimeout(function () { get_reddit_comments(retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Pulling comments failed... ' + retries + '/5');
|
console.warn('Pulling comments failed... ' + retries + '/5');
|
||||||
get_reddit_comments(retries - 1);
|
get_reddit_comments(retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_youtube_comments(retries) {
|
function get_youtube_comments(retries) {
|
||||||
if (retries == undefined) retries = 5;
|
if (retries === undefined) retries = 5;
|
||||||
comments = document.getElementById('comments');
|
var comments = document.getElementById('comments');
|
||||||
|
|
||||||
if (retries <= 0) {
|
if (retries <= 0) {
|
||||||
console.log('Failed to pull comments');
|
console.warn('Failed to pull comments');
|
||||||
comments.innerHTML = '';
|
comments.innerHTML = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -309,12 +311,12 @@ function get_youtube_comments(retries) {
|
||||||
xhr.open('GET', url, true);
|
xhr.open('GET', url, true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
comments.innerHTML = ' \
|
comments.innerHTML = ' \
|
||||||
<div> \
|
<div> \
|
||||||
<h3> \
|
<h3> \
|
||||||
<a href="javascript:void(0)">[ - ]</a> \
|
<a href="javascript:void(0)">[ − ]</a> \
|
||||||
{commentsText} \
|
{commentsText} \
|
||||||
</h3> \
|
</h3> \
|
||||||
<b> \
|
<b> \
|
||||||
|
@ -336,27 +338,27 @@ function get_youtube_comments(retries) {
|
||||||
comments.children[0].children[1].children[0].onclick = swap_comments;
|
comments.children[0].children[1].children[0].onclick = swap_comments;
|
||||||
} else {
|
} else {
|
||||||
if (video_data.params.comments[1] === 'youtube') {
|
if (video_data.params.comments[1] === 'youtube') {
|
||||||
setTimeout(function () { get_youtube_comments(retries - 1) }, 1000);
|
setTimeout(function () { get_youtube_comments(retries - 1); }, 1000);
|
||||||
} else {
|
} else {
|
||||||
comments.innerHTML = '';
|
comments.innerHTML = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
comments.innerHTML =
|
comments.innerHTML =
|
||||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
||||||
console.log('Pulling comments failed... ' + retries + '/5');
|
console.warn('Pulling comments failed... ' + retries + '/5');
|
||||||
setTimeout(function () { get_youtube_comments(retries - 1) }, 1000);
|
setTimeout(function () { get_youtube_comments(retries - 1); }, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
comments.innerHTML =
|
comments.innerHTML =
|
||||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
||||||
console.log('Pulling comments failed... ' + retries + '/5');
|
console.warn('Pulling comments failed... ' + retries + '/5');
|
||||||
get_youtube_comments(retries - 1);
|
get_youtube_comments(retries - 1);
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
@ -373,7 +375,7 @@ function get_youtube_replies(target, load_more, load_replies) {
|
||||||
'?format=html' +
|
'?format=html' +
|
||||||
'&hl=' + video_data.preferences.locale +
|
'&hl=' + video_data.preferences.locale +
|
||||||
'&thin_mode=' + video_data.preferences.thin_mode +
|
'&thin_mode=' + video_data.preferences.thin_mode +
|
||||||
'&continuation=' + continuation
|
'&continuation=' + continuation;
|
||||||
if (load_replies) {
|
if (load_replies) {
|
||||||
url += '&action=action_get_comment_replies';
|
url += '&action=action_get_comment_replies';
|
||||||
}
|
}
|
||||||
|
@ -383,8 +385,8 @@ function get_youtube_replies(target, load_more, load_replies) {
|
||||||
xhr.open('GET', url, true);
|
xhr.open('GET', url, true);
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status == 200) {
|
if (xhr.status === 200) {
|
||||||
if (load_more) {
|
if (load_more) {
|
||||||
body = body.parentNode.parentNode;
|
body = body.parentNode.parentNode;
|
||||||
body.removeChild(body.lastElementChild);
|
body.removeChild(body.lastElementChild);
|
||||||
|
@ -412,12 +414,12 @@ function get_youtube_replies(target, load_more, load_replies) {
|
||||||
body.innerHTML = fallback;
|
body.innerHTML = fallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.ontimeout = function () {
|
xhr.ontimeout = function () {
|
||||||
console.log('Pulling comments failed.');
|
console.warn('Pulling comments failed.');
|
||||||
body.innerHTML = fallback;
|
body.innerHTML = fallback;
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
@ -461,7 +463,7 @@ window.addEventListener('load', function (e) {
|
||||||
} else if (video_data.params.comments[1] === 'reddit') {
|
} else if (video_data.params.comments[1] === 'reddit') {
|
||||||
get_reddit_comments();
|
get_reddit_comments();
|
||||||
} else {
|
} else {
|
||||||
comments = document.getElementById('comments');
|
var comments = document.getElementById('comments');
|
||||||
comments.innerHTML = '';
|
comments.innerHTML = '';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var watched_data = JSON.parse(document.getElementById('watched_data').innerHTML);
|
'use strict';
|
||||||
|
var watched_data = JSON.parse(document.getElementById('watched_data').textContent);
|
||||||
|
|
||||||
function mark_watched(target) {
|
function mark_watched(target) {
|
||||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||||
|
@ -13,12 +14,12 @@ function mark_watched(target) {
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
tile.style.display = '';
|
tile.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + watched_data.csrf_token);
|
xhr.send('csrf_token=' + watched_data.csrf_token);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +27,7 @@ function mark_watched(target) {
|
||||||
function mark_unwatched(target) {
|
function mark_unwatched(target) {
|
||||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||||
tile.style.display = 'none';
|
tile.style.display = 'none';
|
||||||
var count = document.getElementById('count')
|
var count = document.getElementById('count');
|
||||||
count.innerText = count.innerText - 1;
|
count.innerText = count.innerText - 1;
|
||||||
|
|
||||||
var url = '/watch_ajax?action_mark_unwatched=1&redirect=false' +
|
var url = '/watch_ajax?action_mark_unwatched=1&redirect=false' +
|
||||||
|
@ -38,13 +39,13 @@ function mark_unwatched(target) {
|
||||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||||
|
|
||||||
xhr.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (xhr.readyState == 4) {
|
if (xhr.readyState === 4) {
|
||||||
if (xhr.status != 200) {
|
if (xhr.status !== 200) {
|
||||||
count.innerText = count.innerText - 1 + 2;
|
count.innerText = count.innerText - 1 + 2;
|
||||||
tile.style.display = '';
|
tile.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
xhr.send('csrf_token=' + watched_data.csrf_token);
|
xhr.send('csrf_token=' + watched_data.csrf_token);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
FROM crystallang/crystal:1.4.0-alpine AS builder
|
FROM crystallang/crystal:1.4.1-alpine AS builder
|
||||||
RUN apk add --no-cache sqlite-static yaml-static
|
RUN apk add --no-cache sqlite-static yaml-static
|
||||||
|
|
||||||
ARG release
|
ARG release
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
FROM alpine:edge AS builder
|
FROM alpine:edge AS builder
|
||||||
RUN apk add --no-cache 'crystal=1.4.0-r0' shards sqlite-static yaml-static yaml-dev libxml2-dev zlib-static openssl-libs-static openssl-dev musl-dev
|
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
|
||||||
|
|
||||||
ARG release
|
ARG release
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
"preferences_watch_history_label": "Enable watch history: ",
|
"preferences_watch_history_label": "Enable watch history: ",
|
||||||
"preferences_speed_label": "Default speed: ",
|
"preferences_speed_label": "Default speed: ",
|
||||||
"preferences_quality_label": "Preferred video quality: ",
|
"preferences_quality_label": "Preferred video quality: ",
|
||||||
"preferences_quality_option_dash": "DASH (adaptative quality)",
|
"preferences_quality_option_dash": "DASH (adaptive quality)",
|
||||||
"preferences_quality_option_hd720": "HD720",
|
"preferences_quality_option_hd720": "HD720",
|
||||||
"preferences_quality_option_medium": "Medium",
|
"preferences_quality_option_medium": "Medium",
|
||||||
"preferences_quality_option_small": "Small",
|
"preferences_quality_option_small": "Small",
|
||||||
|
|
|
@ -0,0 +1,474 @@
|
||||||
|
{
|
||||||
|
"last": "आखिरी",
|
||||||
|
"Yes": "हाँ",
|
||||||
|
"No": "नहीं",
|
||||||
|
"Export subscriptions as OPML (for NewPipe & FreeTube)": "OPML के रूप में सदस्यताएँ निर्यात करें (NewPipe और FreeTube के लिए)",
|
||||||
|
"Log in/register": "लॉग-इन/पंजीकृत करें",
|
||||||
|
"Log in with Google": "Google के साथ लॉग-इन करें",
|
||||||
|
"preferences_autoplay_label": "अपने आप चलाने की सुविधा: ",
|
||||||
|
"preferences_dark_mode_label": "थीम: ",
|
||||||
|
"preferences_default_home_label": "डिफ़ॉल्ट मुखपृष्ठ: ",
|
||||||
|
"Could not fetch comments": "टिप्पणियाँ प्राप्त न की जा सकीं",
|
||||||
|
"comments_points_count": "{{count}} पॉइंट",
|
||||||
|
"comments_points_count_plural": "{{count}} पॉइंट्स",
|
||||||
|
"Subscription manager": "सदस्यता प्रबंधन",
|
||||||
|
"License: ": "लाइसेंस: ",
|
||||||
|
"Wilson score: ": "Wilson स्कोर: ",
|
||||||
|
"Wrong answer": "गलत जवाब",
|
||||||
|
"Erroneous CAPTCHA": "गलत CAPTCHA",
|
||||||
|
"Please log in": "कृपया लॉग-इन करें",
|
||||||
|
"Bosnian": "बोस्नियाई",
|
||||||
|
"Bulgarian": "बुल्गारियाई",
|
||||||
|
"Burmese": "बर्मी",
|
||||||
|
"Chinese (Traditional)": "चीनी (पारंपरिक)",
|
||||||
|
"Kurdish": "कुर्द",
|
||||||
|
"Punjabi": "पंजाबी",
|
||||||
|
"Sinhala": "सिंहली",
|
||||||
|
"Slovak": "स्लोवाक",
|
||||||
|
"generic_count_days": "{{count}} दिन",
|
||||||
|
"generic_count_days_plural": "{{count}} दिन",
|
||||||
|
"generic_count_hours": "{{count}} घंटे",
|
||||||
|
"generic_count_hours_plural": "{{count}} घंटे",
|
||||||
|
"generic_count_minutes": "{{count}} मिनट",
|
||||||
|
"generic_count_minutes_plural": "{{count}} मिनट",
|
||||||
|
"generic_count_seconds": "{{count}} सेकंड",
|
||||||
|
"generic_count_seconds_plural": "{{count}} सेकंड",
|
||||||
|
"generic_playlists_count": "{{count}} प्लेलिस्ट",
|
||||||
|
"generic_playlists_count_plural": "{{count}} प्लेलिस्ट्स",
|
||||||
|
"crash_page_report_issue": "अगर इनमें से कुछ भी काम नहीं करता, कृपया <a href=\"`x`\">GitHub पर एक नया मुद्दा खोल दें</a> (अंग्रेज़ी में) और अपने संदेश में यह टेक्स्ट दर्ज करें (इसे अनुवादित न करें!):",
|
||||||
|
"generic_views_count": "{{count}} बार देखा गया",
|
||||||
|
"generic_views_count_plural": "{{count}} बार देखा गया",
|
||||||
|
"generic_videos_count": "{{count}} वीडियो",
|
||||||
|
"generic_videos_count_plural": "{{count}} वीडियो",
|
||||||
|
"generic_subscribers_count": "{{count}} सदस्य",
|
||||||
|
"generic_subscribers_count_plural": "{{count}} सदस्य",
|
||||||
|
"generic_subscriptions_count": "{{count}} सदस्यता",
|
||||||
|
"generic_subscriptions_count_plural": "{{count}} सदस्यताएँ",
|
||||||
|
"LIVE": "लाइव",
|
||||||
|
"Shared `x` ago": "`x` पहले बाँटा गया",
|
||||||
|
"Unsubscribe": "सदस्यता छोड़ें",
|
||||||
|
"Subscribe": "सदस्यता लें",
|
||||||
|
"View channel on YouTube": "चैनल YouTube पर देखें",
|
||||||
|
"View playlist on YouTube": "प्लेलिस्ट YouTube पर देखें",
|
||||||
|
"newest": "सबसे नया",
|
||||||
|
"oldest": "सबसे पुराना",
|
||||||
|
"popular": "सर्वाधिक लोकप्रिय",
|
||||||
|
"Next page": "अगला पृष्ठ",
|
||||||
|
"Previous page": "पिछला पृष्ठ",
|
||||||
|
"Clear watch history?": "देखने का इतिहास मिटाएँ?",
|
||||||
|
"New password": "नया पासवर्ड",
|
||||||
|
"New passwords must match": "पासवर्ड्स को मेल खाना होगा",
|
||||||
|
"Cannot change password for Google accounts": "Google खातों के लिए पासवर्ड नहीं बदल सकते",
|
||||||
|
"Authorize token?": "टोकन को प्रमाणित करें?",
|
||||||
|
"Authorize token for `x`?": "`x` के लिए टोकन को प्रमाणित करें?",
|
||||||
|
"Import and Export Data": "डेटा को आयात और निर्यात करें",
|
||||||
|
"Import": "आयात करें",
|
||||||
|
"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": "OPML के रूप में सदस्यताएँ निर्यात करें",
|
||||||
|
"Export data as JSON": "Invidious डेटा को JSON के रूप में निर्यात करें",
|
||||||
|
"Delete account?": "खाता हटाएँ?",
|
||||||
|
"History": "देखे गए वीडियो",
|
||||||
|
"An alternative front-end to YouTube": "YouTube का एक वैकल्पिक फ्रंट-एंड",
|
||||||
|
"JavaScript license information": "जावास्क्रिप्ट लाइसेंस की जानकारी",
|
||||||
|
"source": "स्रोत",
|
||||||
|
"Log in": "लॉग-इन करें",
|
||||||
|
"User ID": "सदस्य ID",
|
||||||
|
"Password": "पासवर्ड",
|
||||||
|
"Register": "पंजीकृत करें",
|
||||||
|
"E-mail": "ईमेल",
|
||||||
|
"Google verification code": "Google प्रमाणीकरण कोड",
|
||||||
|
"Time (h:mm:ss):": "समय (घं:मिमि:सेसे):",
|
||||||
|
"Text CAPTCHA": "टेक्स्ट CAPTCHA",
|
||||||
|
"Image CAPTCHA": "चित्र CAPTCHA",
|
||||||
|
"Sign In": "साइन इन करें",
|
||||||
|
"Preferences": "प्राथमिकताएँ",
|
||||||
|
"preferences_category_player": "प्लेयर की प्राथमिकताएँ",
|
||||||
|
"preferences_video_loop_label": "हमेशा लूप करें: ",
|
||||||
|
"preferences_continue_label": "डिफ़ॉल्ट से अगला चलाएँ: ",
|
||||||
|
"preferences_continue_autoplay_label": "अगला वीडियो अपने आप चलाएँ: ",
|
||||||
|
"preferences_listen_label": "डिफ़ॉल्ट से सुनें: ",
|
||||||
|
"preferences_local_label": "प्रॉक्सी वीडियो: ",
|
||||||
|
"preferences_watch_history_label": "देखने का इतिहास सक्षम करें: ",
|
||||||
|
"preferences_speed_label": "वीडियो चलाने की डिफ़ॉल्ट रफ़्तार: ",
|
||||||
|
"preferences_quality_label": "वीडियो की प्राथमिक क्वालिटी: ",
|
||||||
|
"preferences_quality_option_dash": "DASH (अनुकूली गुणवत्ता)",
|
||||||
|
"preferences_quality_option_hd720": "HD720",
|
||||||
|
"preferences_quality_option_medium": "मध्यम",
|
||||||
|
"preferences_quality_option_small": "छोटा",
|
||||||
|
"preferences_quality_dash_label": "प्राथमिक DASH वीडियो क्वालिटी: ",
|
||||||
|
"preferences_quality_dash_option_720p": "720p",
|
||||||
|
"preferences_quality_dash_option_auto": "अपने-आप",
|
||||||
|
"preferences_quality_dash_option_best": "सबसे अच्छा",
|
||||||
|
"preferences_quality_dash_option_worst": "सबसे खराब",
|
||||||
|
"preferences_quality_dash_option_4320p": "4320p",
|
||||||
|
"preferences_quality_dash_option_2160p": "2160p",
|
||||||
|
"preferences_quality_dash_option_1440p": "1440p",
|
||||||
|
"preferences_quality_dash_option_1080p": "1080p",
|
||||||
|
"preferences_quality_dash_option_480p": "480p",
|
||||||
|
"preferences_quality_dash_option_360p": "360p",
|
||||||
|
"preferences_quality_dash_option_240p": "240p",
|
||||||
|
"preferences_quality_dash_option_144p": "144p",
|
||||||
|
"preferences_comments_label": "डिफ़ॉल्ट टिप्पणियाँ: ",
|
||||||
|
"preferences_volume_label": "प्लेयर का वॉल्यूम: ",
|
||||||
|
"youtube": "YouTube",
|
||||||
|
"reddit": "Reddit",
|
||||||
|
"invidious": "Invidious",
|
||||||
|
"preferences_captions_label": "डिफ़ॉल्ट कैप्शन: ",
|
||||||
|
"Fallback captions: ": "वैकल्पिक कैप्शन: ",
|
||||||
|
"preferences_related_videos_label": "संबंधित वीडियो दिखाएँ: ",
|
||||||
|
"preferences_annotations_label": "डिफ़ॉल्ट से टिप्पणियाँ दिखाएँ: ",
|
||||||
|
"preferences_extend_desc_label": "अपने आप वीडियो के विवरण का विस्तार करें: ",
|
||||||
|
"preferences_vr_mode_label": "उत्तरदायी 360 डिग्री वीडियो (WebGL की ज़रूरत है): ",
|
||||||
|
"preferences_category_visual": "यथादृश्य प्राथमिकताएँ",
|
||||||
|
"preferences_region_label": "सामग्री का राष्ट्र: ",
|
||||||
|
"preferences_player_style_label": "प्लेयर का स्टाइल: ",
|
||||||
|
"Dark mode: ": "डार्क मोड: ",
|
||||||
|
"dark": "डार्क",
|
||||||
|
"light": "लाइट",
|
||||||
|
"preferences_thin_mode_label": "हल्का मोड: ",
|
||||||
|
"preferences_category_misc": "विविध प्राथमिकताएँ",
|
||||||
|
"preferences_automatic_instance_redirect_label": "अपने आप अनुप्रेषित करें (redirect.invidious.io पर फ़ॉलबैक करें): ",
|
||||||
|
"preferences_category_subscription": "सदस्यताओं की प्राथमिकताएँ",
|
||||||
|
"preferences_annotations_subscribed_label": "सदस्यता लिए गए चैनलों पर डिफ़ॉल्ट से टिप्पणियाँ दिखाएँ? ",
|
||||||
|
"Redirect homepage to feed: ": "फ़ीड पर मुखपृष्ठ को अनुप्रेषित करें: ",
|
||||||
|
"preferences_max_results_label": "फ़ीड में दिखाए जाने वाले वीडियों की संख्या: ",
|
||||||
|
"preferences_sort_label": "वीडियों को इस मानदंड पर छाँटें: ",
|
||||||
|
"published": "प्रकाशित",
|
||||||
|
"published - reverse": "प्रकाशित - उल्टा",
|
||||||
|
"Only show latest video from channel: ": "चैनल से सिर्फ नवीनतम वीडियो ही दिखाएँ: ",
|
||||||
|
"alphabetically": "वर्णक्रमानुसार",
|
||||||
|
"Only show latest unwatched video from channel: ": "चैनल से सिर्फ न देखा गया नवीनतम वीडियो ही दिखाएँ: ",
|
||||||
|
"alphabetically - reverse": "वर्णक्रमानुसार - उल्टा",
|
||||||
|
"channel name": "चैनल का नाम",
|
||||||
|
"channel name - reverse": "चैनल का नाम - उल्टा",
|
||||||
|
"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": "देखने का इतिहास साफ़ करें",
|
||||||
|
"Import/export data": "डेटा को आयात/निर्यात करें",
|
||||||
|
"Change password": "पासवर्ड बदलें",
|
||||||
|
"Manage subscriptions": "सदस्यताएँ प्रबंधित करें",
|
||||||
|
"Manage tokens": "टोकन प्रबंधित करें",
|
||||||
|
"Watch history": "देखने का इतिहास",
|
||||||
|
"Delete account": "खाता हटाएँ",
|
||||||
|
"preferences_category_admin": "प्रबंधक प्राथमिकताएँ",
|
||||||
|
"preferences_feed_menu_label": "फ़ीड मेन्यू: ",
|
||||||
|
"preferences_show_nick_label": "ऊपर उपनाम दिखाएँ: ",
|
||||||
|
"Top enabled: ": "ऊपर का हिस्सा सक्षम है: ",
|
||||||
|
"CAPTCHA enabled: ": "CAPTCHA सक्षम है: ",
|
||||||
|
"Login enabled: ": "लॉग-इन सक्षम है: ",
|
||||||
|
"Registration enabled: ": "पंजीकरण सक्षम है: ",
|
||||||
|
"Report statistics: ": "सांख्यिकी रिपोर्ट करें: ",
|
||||||
|
"Released under the AGPLv3 on Github.": "GitHub पर AGPLv3 के अंतर्गत प्रकाशित।",
|
||||||
|
"Save preferences": "प्राथमिकताएँ सहेजें",
|
||||||
|
"Token manager": "टोकन प्रबंधन",
|
||||||
|
"Token": "टोकन",
|
||||||
|
"tokens_count": "{{count}} टोकन",
|
||||||
|
"tokens_count_plural": "{{count}} टोकन",
|
||||||
|
"Import/export": "आयात/निर्यात करें",
|
||||||
|
"unsubscribe": "सदस्यता छोड़ें",
|
||||||
|
"revoke": "हटाएँ",
|
||||||
|
"Subscriptions": "सदस्यताएँ",
|
||||||
|
"subscriptions_unseen_notifs_count": "{{count}} अपठित सूचना",
|
||||||
|
"subscriptions_unseen_notifs_count_plural": "{{count}} अपठित सूचना",
|
||||||
|
"search": "खोजें",
|
||||||
|
"Log out": "लॉग-आउट करें",
|
||||||
|
"Source available here.": "स्रोत यहाँ उपलब्ध है।",
|
||||||
|
"View JavaScript license information.": "जावास्क्रिप्ट लाइसेंस की जानकारी देखें।",
|
||||||
|
"View privacy policy.": "निजता नीति देखें।",
|
||||||
|
"Trending": "रुझान में",
|
||||||
|
"Public": "सार्वजनिक",
|
||||||
|
"Unlisted": "सबके लिए उपलब्ध नहीं",
|
||||||
|
"Private": "निजी",
|
||||||
|
"View all playlists": "सभी प्लेलिस्ट देखें",
|
||||||
|
"Create playlist": "प्लेलिस्ट बनाएँ",
|
||||||
|
"Updated `x` ago": "`x` पहले अपडेट किया गया",
|
||||||
|
"Delete playlist `x`?": "प्लेलिस्ट `x` हटाएँ?",
|
||||||
|
"Delete playlist": "प्लेलिस्ट हटाएँ",
|
||||||
|
"Title": "शीर्षक",
|
||||||
|
"Playlist privacy": "प्लेलिस्ट की निजता",
|
||||||
|
"Editing playlist `x`": "प्लेलिस्ट `x` को संपादित किया जा रहा है",
|
||||||
|
"Show more": "अधिक देखें",
|
||||||
|
"Show less": "कम देखें",
|
||||||
|
"Watch on YouTube": "YouTube पर देखें",
|
||||||
|
"Switch Invidious Instance": "Invidious उदाहरण बदलें",
|
||||||
|
"search_message_no_results": "कोई परिणाम नहीं मिला।",
|
||||||
|
"search_message_change_filters_or_query": "अपने खोज क्वेरी को और चौड़ा करें और/या फ़िल्टर बदलें।",
|
||||||
|
"search_message_use_another_instance": " आप <a href=\"`x`\">दूसरे उदाहरण पर भी खोज सकते हैं</a>।",
|
||||||
|
"Hide annotations": "टिप्पणियाँ छिपाएँ",
|
||||||
|
"Show annotations": "टिप्पणियाँ दिखाएँ",
|
||||||
|
"Genre: ": "श्रेणी: ",
|
||||||
|
"Family friendly? ": "परिवार के लिए ठीक है? ",
|
||||||
|
"Engagement: ": "सगाई: ",
|
||||||
|
"Whitelisted regions: ": "स्वीकृत क्षेत्र: ",
|
||||||
|
"Blacklisted regions: ": "अस्वीकृत क्षेत्र: ",
|
||||||
|
"Shared `x`": "`x` बाँटा गया",
|
||||||
|
"Premieres in `x`": "`x` बाद प्रीमियर होगा",
|
||||||
|
"Premieres `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.": "नमस्कार! ऐसा लगता है कि आपका जावास्क्रिप्ट अक्षम है। टिप्पणियाँ देखने के लिए यहाँ क्लिक करें, लेकिन याद रखें कि इन्हें लोड होने में थोड़ा ज़्यादा समय लग सकता है।",
|
||||||
|
"View YouTube comments": "YouTube टिप्पणियाँ देखें",
|
||||||
|
"View more comments on Reddit": "Reddit पर अधिक टिप्पणियाँ देखें",
|
||||||
|
"View `x` comments": {
|
||||||
|
"([^.,0-9]|^)1([^.,0-9]|$)": "`x` टिप्पणी देखें",
|
||||||
|
"": "`x` टिप्पणियाँ देखें"
|
||||||
|
},
|
||||||
|
"View Reddit comments": "Reddit पर टिप्पणियाँ",
|
||||||
|
"Hide replies": "जवाब छिपाएँ",
|
||||||
|
"Show replies": "जवाब दिखाएँ",
|
||||||
|
"Incorrect password": "गलत पासवर्ड",
|
||||||
|
"Unable to log in, make sure two-factor authentication (Authenticator or SMS) is turned on.": "लॉग-इन नहीं किया जा सका, सुनिश्चित करें कि दो-कारक प्रमाणीकरण (Authenticator या SMS) सक्षम है।",
|
||||||
|
"Invalid TFA code": "अमान्य TFA कोड",
|
||||||
|
"Login failed. This may be because two-factor authentication is not turned on for your account.": "लॉग-इन नाकाम रहा। ऐसा इसलिए हो सकता है कि दो-कारक प्रमाणीकरण आपके खाते पर सक्षम नहीं है।",
|
||||||
|
"Quota exceeded, try again in a few hours": "कोटा पार हो चुका है, कृपया कुछ घंटों में फिर कोशिश करें",
|
||||||
|
"CAPTCHA is a required field": "CAPTCHA एक ज़रूरी फ़ील्ड है",
|
||||||
|
"User ID is a required field": "सदस्य ID एक ज़रूरी फ़ील्ड है",
|
||||||
|
"Password is a required field": "पासवर्ड एक ज़रूरी फ़ील्ड है",
|
||||||
|
"Wrong username or password": "गलत सदस्यनाम या पासवर्ड",
|
||||||
|
"Please sign in using 'Log in with Google'": "कृपया 'Google के साथ लॉग-इन करें' के साथ साइन-इन करें",
|
||||||
|
"Password cannot be empty": "पासवर्ड खाली नहीं हो सकता",
|
||||||
|
"Password cannot be longer than 55 characters": "पासवर्ड में अधिकतम 55 अक्षर हो सकते हैं",
|
||||||
|
"Invidious Private Feed for `x`": "`x` के लिए Invidious निजी फ़ीड",
|
||||||
|
"channel:`x`": "चैनल:`x`",
|
||||||
|
"Deleted or invalid channel": "हटाया गया या अमान्य चैनल",
|
||||||
|
"This channel does not exist.": "यह चैनल मौजूद नहीं है।",
|
||||||
|
"Could not get channel info.": "चैनल की जानकारी प्राप्त न की जा सकी।",
|
||||||
|
"comments_view_x_replies": "{{count}} टिप्पणी देखें",
|
||||||
|
"comments_view_x_replies_plural": "{{count}} टिप्पणियाँ देखें",
|
||||||
|
"`x` ago": "`x` पहले",
|
||||||
|
"Load more": "अधिक लोड करें",
|
||||||
|
"Could not create mix.": "मिक्स न बनाया जा सका।",
|
||||||
|
"Empty playlist": "खाली प्लेलिस्ट",
|
||||||
|
"Not a playlist.": "यह प्लेलिस्ट नहीं है।",
|
||||||
|
"Playlist does not exist.": "प्लेलिस्ट मौजूद नहीं है।",
|
||||||
|
"Could not pull trending pages.": "रुझान के पृष्ठ प्राप्त न किए जा सके।",
|
||||||
|
"Hidden field \"challenge\" is a required field": "छिपाया गया फ़ील्ड \"चुनौती\" एक आवश्यक फ़ील्ड है",
|
||||||
|
"Hidden field \"token\" is a required field": "छिपाया गया फ़ील्ड \"टोकन\" एक आवश्यक फ़ील्ड है",
|
||||||
|
"Erroneous challenge": "त्रुटिपूर्ण चुनौती",
|
||||||
|
"Erroneous token": "त्रुटिपूर्ण टोकन",
|
||||||
|
"No such user": "यह सदस्य मौजूद नहीं हैं",
|
||||||
|
"Token is expired, please try again": "टोकन की समय-सीमा समाप्त हो चुकी है, कृपया दोबारा कोशिश करें",
|
||||||
|
"English": "अंग्रेज़ी",
|
||||||
|
"English (United Kingdom)": "अंग्रेज़ी (यूनाइटेड किंग्डम)",
|
||||||
|
"English (United States)": "अंग्रेज़ी (संयुक्त राष्ट्र)",
|
||||||
|
"English (auto-generated)": "अंग्रेज़ी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Afrikaans": "अफ़्रीकी",
|
||||||
|
"Albanian": "अल्बानियाई",
|
||||||
|
"Amharic": "अम्हेरी",
|
||||||
|
"Arabic": "अरबी",
|
||||||
|
"Armenian": "आर्मेनियाई",
|
||||||
|
"Belarusian": "बेलारूसी",
|
||||||
|
"Azerbaijani": "अज़रबैजानी",
|
||||||
|
"Bangla": "बंगाली",
|
||||||
|
"Basque": "बास्क",
|
||||||
|
"Cantonese (Hong Kong)": "कैंटोनीज़ (हाँग काँग)",
|
||||||
|
"Catalan": "कातालान",
|
||||||
|
"Cebuano": "सेबुआनो",
|
||||||
|
"Chinese": "चीनी",
|
||||||
|
"Chinese (China)": "चीनी (चीन)",
|
||||||
|
"Chinese (Hong Kong)": "चीनी (हाँग काँग)",
|
||||||
|
"Chinese (Simplified)": "चीनी (सरलीकृत)",
|
||||||
|
"Chinese (Taiwan)": "चीनी (ताइवान)",
|
||||||
|
"Corsican": "कोर्सिकन",
|
||||||
|
"Croatian": "क्रोएशियाई",
|
||||||
|
"Czech": "चेक",
|
||||||
|
"Danish": "डेनिश",
|
||||||
|
"Dutch": "डच",
|
||||||
|
"Dutch (auto-generated)": "डच (अपने-आप जनरेट हुआ)",
|
||||||
|
"Esperanto": "एस्पेरांतो",
|
||||||
|
"Estonian": "एस्टोनियाई",
|
||||||
|
"Filipino": "फ़िलिपीनो",
|
||||||
|
"Finnish": "फ़िनिश",
|
||||||
|
"French": "फ़्रेंच",
|
||||||
|
"French (auto-generated)": "फ़्रेंच (अपने-आप जनरेट हुआ)",
|
||||||
|
"Galician": "गैलिशियन",
|
||||||
|
"Georgian": "जॉर्जियाई",
|
||||||
|
"German": "जर्मन",
|
||||||
|
"German (auto-generated)": "जर्मन (अपने-आप जनरेट हुआ)",
|
||||||
|
"Greek": "यूनानी",
|
||||||
|
"Gujarati": "गुजराती",
|
||||||
|
"Haitian Creole": "हैती क्रियोल",
|
||||||
|
"Hausa": "हौसा",
|
||||||
|
"Hawaiian": "हवाई",
|
||||||
|
"Hebrew": "हीब्रू",
|
||||||
|
"Hindi": "हिन्दी",
|
||||||
|
"Hmong": "हमोंग",
|
||||||
|
"Hungarian": "हंगेरी",
|
||||||
|
"Icelandic": "आइसलैंडिक",
|
||||||
|
"Igbo": "इग्बो",
|
||||||
|
"Indonesian": "इंडोनेशियाई",
|
||||||
|
"Indonesian (auto-generated)": "इंडोनेशियाई (अपने-आप जनरेट हुआ)",
|
||||||
|
"Interlingue": "इंटरलिंगुआ",
|
||||||
|
"Irish": "आयरिश",
|
||||||
|
"Italian": "इतालवी",
|
||||||
|
"Italian (auto-generated)": "इतालवी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Japanese": "जापानी",
|
||||||
|
"Japanese (auto-generated)": "जापानी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Javanese": "जावानीज़",
|
||||||
|
"Kannada": "कन्नड़",
|
||||||
|
"Kazakh": "कज़ाख़",
|
||||||
|
"Khmer": "खमेर",
|
||||||
|
"Korean": "कोरियाई",
|
||||||
|
"Korean (auto-generated)": "कोरियाई (अपने-आप जनरेट हुआ)",
|
||||||
|
"Kyrgyz": "किर्गीज़",
|
||||||
|
"Lao": "लाओ",
|
||||||
|
"Latin": "लैटिन",
|
||||||
|
"Latvian": "लातवियाई",
|
||||||
|
"Lithuanian": "लिथुएनियाई",
|
||||||
|
"Luxembourgish": "लग्ज़मबर्गी",
|
||||||
|
"Macedonian": "मकादूनियाई",
|
||||||
|
"Malagasy": "मालागासी",
|
||||||
|
"Malay": "मलय",
|
||||||
|
"Malayalam": "मलयालम",
|
||||||
|
"Maltese": "माल्टीज़",
|
||||||
|
"Maori": "माओरी",
|
||||||
|
"Marathi": "मराठी",
|
||||||
|
"Mongolian": "मंगोलियाई",
|
||||||
|
"Nepali": "नेपाली",
|
||||||
|
"Norwegian Bokmål": "नॉर्वेजियाई",
|
||||||
|
"Nyanja": "न्यानजा",
|
||||||
|
"Pashto": "पश्तो",
|
||||||
|
"Persian": "फ़ारसी",
|
||||||
|
"Polish": "पोलिश",
|
||||||
|
"Portuguese": "पुर्तगाली",
|
||||||
|
"Portuguese (auto-generated)": "पुर्तगाली (अपने-आप जनरेट हुआ)",
|
||||||
|
"Portuguese (Brazil)": "पुर्तगाली (ब्राज़ील)",
|
||||||
|
"Romanian": "रोमेनियाई",
|
||||||
|
"Russian": "रूसी",
|
||||||
|
"Russian (auto-generated)": "रूसी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Samoan": "सामोन",
|
||||||
|
"Scottish Gaelic": "स्कॉटिश गाएलिक",
|
||||||
|
"Serbian": "सर्बियाई",
|
||||||
|
"Shona": "शोणा",
|
||||||
|
"Sindhi": "सिंधी",
|
||||||
|
"Slovenian": "स्लोवेनियाई",
|
||||||
|
"Somali": "सोमाली",
|
||||||
|
"Southern Sotho": "दक्षिणी सोथो",
|
||||||
|
"Spanish": "स्पेनी",
|
||||||
|
"Spanish (auto-generated)": "स्पेनी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Spanish (Latin America)": "स्पेनी (लातिन अमेरिकी)",
|
||||||
|
"Spanish (Mexico)": "स्पेनी (मेक्सिको)",
|
||||||
|
"Spanish (Spain)": "स्पेनी (स्पेन)",
|
||||||
|
"Sundanese": "सुंडानी",
|
||||||
|
"Swahili": "स्वाहिली",
|
||||||
|
"Swedish": "स्वीडिश",
|
||||||
|
"Tajik": "ताजीक",
|
||||||
|
"Tamil": "तमिल",
|
||||||
|
"Telugu": "तेलुगु",
|
||||||
|
"Thai": "थाई",
|
||||||
|
"Turkish": "तुर्की",
|
||||||
|
"Turkish (auto-generated)": "तुर्की (अपने-आप जनरेट हुआ)",
|
||||||
|
"Ukrainian": "यूक्रेनी",
|
||||||
|
"Urdu": "उर्दू",
|
||||||
|
"Uzbek": "उज़्बेक",
|
||||||
|
"Vietnamese": "वियतनामी",
|
||||||
|
"Vietnamese (auto-generated)": "वियतनामी (अपने-आप जनरेट हुआ)",
|
||||||
|
"Welsh": "Welsh",
|
||||||
|
"Western Frisian": "पश्चिमी फ़्रिसियाई",
|
||||||
|
"Xhosa": "खोसा",
|
||||||
|
"Yiddish": "यहूदी",
|
||||||
|
"generic_count_years": "{{count}} वर्ष",
|
||||||
|
"generic_count_years_plural": "{{count}} वर्ष",
|
||||||
|
"Yoruba": "योरुबा",
|
||||||
|
"generic_count_months": "{{count}} महीने",
|
||||||
|
"generic_count_months_plural": "{{count}} महीने",
|
||||||
|
"Zulu": "ज़ूलू",
|
||||||
|
"generic_count_weeks": "{{count}} हफ़्ते",
|
||||||
|
"generic_count_weeks_plural": "{{count}} हफ़्ते",
|
||||||
|
"Fallback comments: ": "फ़ॉलबैक टिप्पणियाँ: ",
|
||||||
|
"Popular": "प्रसिद्ध",
|
||||||
|
"Search": "खोजें",
|
||||||
|
"Top": "ऊपर",
|
||||||
|
"About": "जानकारी",
|
||||||
|
"Rating: ": "रेटिंग: ",
|
||||||
|
"preferences_locale_label": "भाषा: ",
|
||||||
|
"View as playlist": "प्लेलिस्ट के रूप में देखें",
|
||||||
|
"Default": "डिफ़ॉल्ट",
|
||||||
|
"Download": "डाउनलोड करें",
|
||||||
|
"Download as: ": "इस रूप में डाउनलोड करें: ",
|
||||||
|
"%A %B %-d, %Y": "%A %B %-d, %Y",
|
||||||
|
"Music": "संगीत",
|
||||||
|
"Gaming": "गेमिंग",
|
||||||
|
"News": "समाचार",
|
||||||
|
"Movies": "फ़िल्में",
|
||||||
|
"(edited)": "(संपादित)",
|
||||||
|
"YouTube comment permalink": "YouTube पर टिप्पणी की स्थायी कड़ी",
|
||||||
|
"permalink": "स्थायी कड़ी",
|
||||||
|
"Videos": "वीडियो",
|
||||||
|
"`x` marked it with a ❤": "`x` ने इसे एक ❤ से चिह्नित किया",
|
||||||
|
"Audio mode": "ऑडियो मोड",
|
||||||
|
"Playlists": "प्लेलिस्ट्स",
|
||||||
|
"Video mode": "वीडियो मोड",
|
||||||
|
"Community": "समुदाय",
|
||||||
|
"search_filters_title": "फ़िल्टर",
|
||||||
|
"search_filters_date_label": "अपलोड करने का समय",
|
||||||
|
"search_filters_date_option_none": "कोई भी समय",
|
||||||
|
"search_filters_date_option_week": "इस हफ़्ते",
|
||||||
|
"search_filters_date_option_month": "इस महीने",
|
||||||
|
"search_filters_date_option_hour": "पिछला घंटा",
|
||||||
|
"search_filters_date_option_today": "आज",
|
||||||
|
"search_filters_date_option_year": "इस साल",
|
||||||
|
"search_filters_type_label": "प्रकार",
|
||||||
|
"search_filters_type_option_all": "कोई भी प्रकार",
|
||||||
|
"search_filters_type_option_video": "वीडियो",
|
||||||
|
"search_filters_type_option_channel": "चैनल",
|
||||||
|
"search_filters_sort_option_relevance": "प्रासंगिकता",
|
||||||
|
"search_filters_type_option_playlist": "प्लेलिस्ट",
|
||||||
|
"search_filters_type_option_movie": "फ़िल्म",
|
||||||
|
"search_filters_type_option_show": "शो",
|
||||||
|
"search_filters_duration_label": "अवधि",
|
||||||
|
"search_filters_duration_option_none": "कोई भी अवधि",
|
||||||
|
"search_filters_duration_option_short": "4 मिनट से कम",
|
||||||
|
"search_filters_duration_option_medium": "4 से 20 मिनट तक",
|
||||||
|
"search_filters_duration_option_long": "20 मिनट से ज़्यादा",
|
||||||
|
"search_filters_features_label": "सुविधाएँ",
|
||||||
|
"search_filters_features_option_live": "लाइव",
|
||||||
|
"search_filters_sort_option_rating": "रेटिंग",
|
||||||
|
"search_filters_features_option_four_k": "4K",
|
||||||
|
"search_filters_features_option_hd": "HD",
|
||||||
|
"search_filters_features_option_subtitles": "उपशीर्षक/कैप्शन",
|
||||||
|
"search_filters_features_option_c_commons": "क्रिएटिव कॉमन्स",
|
||||||
|
"search_filters_features_option_three_sixty": "360°",
|
||||||
|
"search_filters_features_option_vr180": "VR180",
|
||||||
|
"search_filters_features_option_three_d": "3D",
|
||||||
|
"search_filters_features_option_hdr": "HDR",
|
||||||
|
"search_filters_features_option_location": "जगह",
|
||||||
|
"search_filters_features_option_purchased": "खरीदा गया",
|
||||||
|
"search_filters_sort_label": "इस क्रम से लगाएँ",
|
||||||
|
"search_filters_sort_option_date": "अपलोड की ताऱीख",
|
||||||
|
"search_filters_sort_option_views": "देखे जाने की संख्या",
|
||||||
|
"search_filters_apply_button": "चयनित फ़िल्टर लागू करें",
|
||||||
|
"footer_documentation": "प्रलेख",
|
||||||
|
"footer_source_code": "स्रोत कोड",
|
||||||
|
"footer_original_source_code": "मूल स्रोत कोड",
|
||||||
|
"footer_modfied_source_code": "बदला गया स्रोत कोड",
|
||||||
|
"Current version: ": "वर्तमान संस्करण: ",
|
||||||
|
"next_steps_error_message": "इसके बाद आपके ये आज़माने चाहिए: ",
|
||||||
|
"next_steps_error_message_refresh": "साफ़ करें",
|
||||||
|
"next_steps_error_message_go_to_youtube": "YouTube पर जाएँ",
|
||||||
|
"footer_donate_page": "दान करें",
|
||||||
|
"adminprefs_modified_source_code_url_label": "बदले गए स्रोत कोड के रिपॉज़िटरी का URL",
|
||||||
|
"none": "कुछ नहीं",
|
||||||
|
"videoinfo_started_streaming_x_ago": "`x` पहले स्ट्रीम करना शुरू किया",
|
||||||
|
"videoinfo_watch_on_youTube": "YouTube पर देखें",
|
||||||
|
"Video unavailable": "वीडियो उपलब्ध नहीं है",
|
||||||
|
"preferences_save_player_pos_label": "यहाँ से चलाना शुरू करें: ",
|
||||||
|
"crash_page_you_found_a_bug": "शायद आपको Invidious में कोई बग नज़र आ गया है!",
|
||||||
|
"videoinfo_youTube_embed_link": "एम्बेड करें",
|
||||||
|
"videoinfo_invidious_embed_link": "एम्बोड करने की कड़ी",
|
||||||
|
"download_subtitles": "उपशीर्षक - `x` (.vtt)",
|
||||||
|
"user_created_playlists": "बनाए गए `x` प्लेलिस्ट्स",
|
||||||
|
"user_saved_playlists": "सहेजे गए `x` प्लेलिस्ट्स",
|
||||||
|
"crash_page_before_reporting": "बग रिपोर्ट करने से पहले:",
|
||||||
|
"crash_page_switch_instance": "<a href=\"`x`\">किसी दूसरे उदाहरण का इस्तेमाल करें</a>",
|
||||||
|
"crash_page_read_the_faq": "<a href=\"`x`\">अक्सर पूछे जाने वाले प्रश्न (FAQ)</a> पढ़ें",
|
||||||
|
"crash_page_refresh": "<a href=\"`x`\">पृष्ठ को एक बार साफ़ करें</a>",
|
||||||
|
"crash_page_search_issue": "<a href=\"`x`\">GitHub पर मौजूदा मुद्दे</a> ढूँढ़ें"
|
||||||
|
}
|
|
@ -31,15 +31,15 @@
|
||||||
"No": "Nem",
|
"No": "Nem",
|
||||||
"Import and Export Data": "Adatok importálása és exportálása",
|
"Import and Export Data": "Adatok importálása és exportálása",
|
||||||
"Import": "Importálás",
|
"Import": "Importálás",
|
||||||
"Import Invidious data": "Az Invidious adatainak importálása",
|
"Import Invidious data": "Az Invidious JSON-adatainak importálása",
|
||||||
"Import YouTube subscriptions": "YouTube-feliratkozások importálása",
|
"Import YouTube subscriptions": "YouTube- vagy OPML-feliratkozások importálása",
|
||||||
"Import FreeTube subscriptions (.db)": "FreeTube-feliratkozások importálása (.db)",
|
"Import FreeTube subscriptions (.db)": "FreeTube-feliratkozások importálása (.db)",
|
||||||
"Import NewPipe subscriptions (.json)": "NewPipe-feliratkozások importálása (.json)",
|
"Import NewPipe subscriptions (.json)": "NewPipe-feliratkozások importálása (.json)",
|
||||||
"Import NewPipe data (.zip)": "NewPipe adatainak importálása (.zip)",
|
"Import NewPipe data (.zip)": "NewPipe adatainak importálása (.zip)",
|
||||||
"Export": "Exportálás",
|
"Export": "Exportálás",
|
||||||
"Export subscriptions as OPML": "Feliratkozások exportálása OPML-ként",
|
"Export subscriptions as OPML": "Feliratkozások exportálása OPML-ként",
|
||||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Feliratkozások exportálása OPML-ként (NewPipe-hoz és FreeTube-hoz)",
|
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Feliratkozások exportálása OPML-ként (NewPipe-hoz és FreeTube-hoz)",
|
||||||
"Export data as JSON": "Adat exportálása JSON-ként",
|
"Export data as JSON": "Az Invidious JSON-adatainak exportálása",
|
||||||
"Delete account?": "Törlésre kerüljön a fiók?",
|
"Delete account?": "Törlésre kerüljön a fiók?",
|
||||||
"History": "Megnézett videók naplója",
|
"History": "Megnézett videók naplója",
|
||||||
"An alternative front-end to YouTube": "Ez az oldal egyike a YouTube alternatív kezelőfelületeinek",
|
"An alternative front-end to YouTube": "Ez az oldal egyike a YouTube alternatív kezelőfelületeinek",
|
||||||
|
@ -159,7 +159,7 @@
|
||||||
"Engagement: ": "Visszajelzési mutató: ",
|
"Engagement: ": "Visszajelzési mutató: ",
|
||||||
"Whitelisted regions: ": "Engedélyezett régiók: ",
|
"Whitelisted regions: ": "Engedélyezett régiók: ",
|
||||||
"Blacklisted regions: ": "Tiltott régiók: ",
|
"Blacklisted regions: ": "Tiltott régiók: ",
|
||||||
"Shared `x`": "`x` napon osztották meg",
|
"Shared `x`": "`x` dátummal osztották meg",
|
||||||
"Premieres in `x`": "`x` később lesz a premierje",
|
"Premieres in `x`": "`x` később lesz a premierje",
|
||||||
"Premieres `x`": "`x` lesz a premierje",
|
"Premieres `x`": "`x` lesz a premierje",
|
||||||
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Helló! Úgy tűnik a JavaScript ki van kapcsolva a böngészőben. Ide kattintva lehet olvasni a hozzászólásokat, de a betöltésük így kicsit több időbe telik.",
|
"Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.": "Helló! Úgy tűnik a JavaScript ki van kapcsolva a böngészőben. Ide kattintva lehet olvasni a hozzászólásokat, de a betöltésük így kicsit több időbe telik.",
|
||||||
|
@ -366,13 +366,13 @@
|
||||||
"invidious": "Invidious",
|
"invidious": "Invidious",
|
||||||
"videoinfo_started_streaming_x_ago": "`x` ezelőtt kezdte streamelni",
|
"videoinfo_started_streaming_x_ago": "`x` ezelőtt kezdte streamelni",
|
||||||
"search_filters_sort_option_views": "Mennyien látták",
|
"search_filters_sort_option_views": "Mennyien látták",
|
||||||
"search_filters_features_option_purchased": "Megvásárolva",
|
"search_filters_features_option_purchased": "Megvásárolt",
|
||||||
"search_filters_features_option_three_sixty": "360°-os",
|
"search_filters_features_option_three_sixty": "360°-os virtuális valóság",
|
||||||
"footer_original_source_code": "Eredeti forráskód",
|
"footer_original_source_code": "Eredeti forráskód",
|
||||||
"none": "egyik sem",
|
"none": "egyik sem",
|
||||||
"videoinfo_watch_on_youTube": "YouTube-on megnézni",
|
"videoinfo_watch_on_youTube": "YouTube-on megnézni",
|
||||||
"videoinfo_youTube_embed_link": "beágyazva",
|
"videoinfo_youTube_embed_link": "beágyazva",
|
||||||
"videoinfo_invidious_embed_link": "Beágyazás linkje",
|
"videoinfo_invidious_embed_link": "Beágyazott hivatkozás",
|
||||||
"download_subtitles": "Felirat – `x` (.vtt)",
|
"download_subtitles": "Felirat – `x` (.vtt)",
|
||||||
"user_created_playlists": "`x` létrehozott lejátszási lista",
|
"user_created_playlists": "`x` létrehozott lejátszási lista",
|
||||||
"user_saved_playlists": "`x` mentett lejátszási lista",
|
"user_saved_playlists": "`x` mentett lejátszási lista",
|
||||||
|
@ -459,5 +459,16 @@
|
||||||
"Dutch (auto-generated)": "holland (automatikusan generált)",
|
"Dutch (auto-generated)": "holland (automatikusan generált)",
|
||||||
"French (auto-generated)": "francia (automatikusan generált)",
|
"French (auto-generated)": "francia (automatikusan generált)",
|
||||||
"Vietnamese (auto-generated)": "vietnámi (automatikusan generált)",
|
"Vietnamese (auto-generated)": "vietnámi (automatikusan generált)",
|
||||||
"search_filters_title": "Szűrők"
|
"search_filters_title": "Szűrők",
|
||||||
|
"preferences_watch_history_label": "Megnézett videók naplózása: ",
|
||||||
|
"search_message_no_results": "Nincs találat.",
|
||||||
|
"search_message_change_filters_or_query": "Próbálj meg bővebben rákeresni vagy a szűrőkön állítani.",
|
||||||
|
"search_message_use_another_instance": " Megpróbálhatod <a href=\"`x`\">egy másik</a> Invidious-oldalon is a keresést.",
|
||||||
|
"search_filters_date_label": "Feltöltés ideje",
|
||||||
|
"search_filters_date_option_none": "Mindegy mikor",
|
||||||
|
"search_filters_type_option_all": "Bármilyen",
|
||||||
|
"search_filters_duration_option_none": "Mindegy",
|
||||||
|
"search_filters_duration_option_medium": "Átlagos (4 és 20 perc között)",
|
||||||
|
"search_filters_features_option_vr180": "180°-os virtuális valóság",
|
||||||
|
"search_filters_apply_button": "Keresés a megadott szűrőkkel"
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,15 @@
|
||||||
"No": "Não",
|
"No": "Não",
|
||||||
"Import and Export Data": "Importar e Exportar Dados",
|
"Import and Export Data": "Importar e Exportar Dados",
|
||||||
"Import": "Importar",
|
"Import": "Importar",
|
||||||
"Import Invidious data": "Importar dados do Invidious",
|
"Import Invidious data": "Importar dados em JSON do Invidious",
|
||||||
"Import YouTube subscriptions": "Importar inscrições do YouTube",
|
"Import YouTube subscriptions": "Importar inscrições do YouTube/OPML",
|
||||||
"Import FreeTube subscriptions (.db)": "Importar inscrições do FreeTube (.db)",
|
"Import FreeTube subscriptions (.db)": "Importar inscrições do FreeTube (.db)",
|
||||||
"Import NewPipe subscriptions (.json)": "Importar inscrições do NewPipe (.json)",
|
"Import NewPipe subscriptions (.json)": "Importar inscrições do NewPipe (.json)",
|
||||||
"Import NewPipe data (.zip)": "Importar dados do NewPipe (.zip)",
|
"Import NewPipe data (.zip)": "Importar dados do NewPipe (.zip)",
|
||||||
"Export": "Exportar",
|
"Export": "Exportar",
|
||||||
"Export subscriptions as OPML": "Exportar inscrições como OPML",
|
"Export subscriptions as OPML": "Exportar inscrições como OPML",
|
||||||
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exportar inscrições como OPML (para NewPipe e FreeTube)",
|
"Export subscriptions as OPML (for NewPipe & FreeTube)": "Exportar inscrições como OPML (para NewPipe e FreeTube)",
|
||||||
"Export data as JSON": "Exportar dados como JSON",
|
"Export data as JSON": "Exportar dados Invidious como JSON",
|
||||||
"Delete account?": "Excluir conta?",
|
"Delete account?": "Excluir conta?",
|
||||||
"History": "Histórico",
|
"History": "Histórico",
|
||||||
"An alternative front-end to YouTube": "Uma interface alternativa para o YouTube",
|
"An alternative front-end to YouTube": "Uma interface alternativa para o YouTube",
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
"preferences_related_videos_label": "Mostrar vídeos relacionados: ",
|
"preferences_related_videos_label": "Mostrar vídeos relacionados: ",
|
||||||
"preferences_annotations_label": "Sempre mostrar anotações: ",
|
"preferences_annotations_label": "Sempre mostrar anotações: ",
|
||||||
"preferences_extend_desc_label": "Estenda automaticamente a descrição do vídeo: ",
|
"preferences_extend_desc_label": "Estenda automaticamente a descrição do vídeo: ",
|
||||||
"preferences_vr_mode_label": "Vídeos interativos de 360 graus: ",
|
"preferences_vr_mode_label": "Vídeos interativos de 360 graus (requer WebGL): ",
|
||||||
"preferences_category_visual": "Preferências visuais",
|
"preferences_category_visual": "Preferências visuais",
|
||||||
"preferences_player_style_label": "Estilo do tocador: ",
|
"preferences_player_style_label": "Estilo do tocador: ",
|
||||||
"Dark mode: ": "Modo escuro: ",
|
"Dark mode: ": "Modo escuro: ",
|
||||||
|
@ -410,7 +410,7 @@
|
||||||
"crash_page_read_the_faq": "leu as <a href=\"`x`\">Perguntas Frequentes (FAQ)</a>",
|
"crash_page_read_the_faq": "leu as <a href=\"`x`\">Perguntas Frequentes (FAQ)</a>",
|
||||||
"generic_views_count": "{{count}} visualização",
|
"generic_views_count": "{{count}} visualização",
|
||||||
"generic_views_count_plural": "{{count}} visualizações",
|
"generic_views_count_plural": "{{count}} visualizações",
|
||||||
"preferences_quality_option_dash": "DASH (qualidade adaptiva)",
|
"preferences_quality_option_dash": "DASH (qualidade adaptável)",
|
||||||
"preferences_quality_option_hd720": "HD720",
|
"preferences_quality_option_hd720": "HD720",
|
||||||
"preferences_quality_option_small": "Pequeno",
|
"preferences_quality_option_small": "Pequeno",
|
||||||
"preferences_quality_dash_option_auto": "Auto",
|
"preferences_quality_dash_option_auto": "Auto",
|
||||||
|
@ -436,5 +436,10 @@
|
||||||
"user_saved_playlists": "`x` listas de reprodução salvas",
|
"user_saved_playlists": "`x` listas de reprodução salvas",
|
||||||
"Video unavailable": "Vídeo indisponível",
|
"Video unavailable": "Vídeo indisponível",
|
||||||
"videoinfo_started_streaming_x_ago": "Iniciou a transmissão a `x`",
|
"videoinfo_started_streaming_x_ago": "Iniciou a transmissão a `x`",
|
||||||
"search_filters_title": "Filtro"
|
"search_filters_title": "Filtro",
|
||||||
|
"preferences_watch_history_label": "Ative o histórico de exibição: ",
|
||||||
|
"search_message_no_results": "Nenhum resultado encontrado.",
|
||||||
|
"search_message_change_filters_or_query": "Tente ampliar sua consulta de pesquisa e/ou alterar os filtros.",
|
||||||
|
"English (United Kingdom)": "Inglês (Reino Unido)",
|
||||||
|
"English (United States)": "Inglês (Estados Unidos)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
"Subscribe": "Подписаться",
|
"Subscribe": "Подписаться",
|
||||||
"View channel on YouTube": "Смотреть канал на YouTube",
|
"View channel on YouTube": "Смотреть канал на YouTube",
|
||||||
"View playlist on YouTube": "Посмотреть плейлист на YouTube",
|
"View playlist on YouTube": "Посмотреть плейлист на YouTube",
|
||||||
"newest": "самые свежие",
|
"newest": "сначала новые",
|
||||||
"oldest": "самые старые",
|
"oldest": "сначала старые",
|
||||||
"popular": "популярные",
|
"popular": "популярные",
|
||||||
"last": "недавние",
|
"last": "недавние",
|
||||||
"Next page": "Следующая страница",
|
"Next page": "Следующая страница",
|
||||||
|
@ -74,8 +74,8 @@
|
||||||
"dark": "темная",
|
"dark": "темная",
|
||||||
"light": "светлая",
|
"light": "светлая",
|
||||||
"preferences_thin_mode_label": "Облегчённое оформление: ",
|
"preferences_thin_mode_label": "Облегчённое оформление: ",
|
||||||
"preferences_category_misc": "Прочие предпочтения",
|
"preferences_category_misc": "Прочие настройки",
|
||||||
"preferences_automatic_instance_redirect_label": "Автоматическое перенаправление на зеркало сайта (резервный вариант redirect.invidious.io): ",
|
"preferences_automatic_instance_redirect_label": "Автоматическое перенаправление на зеркало сайта (переход на redirect.invidious.io): ",
|
||||||
"preferences_category_subscription": "Настройки подписок",
|
"preferences_category_subscription": "Настройки подписок",
|
||||||
"preferences_annotations_subscribed_label": "Всегда показывать аннотации в видео каналов, на которые вы подписаны? ",
|
"preferences_annotations_subscribed_label": "Всегда показывать аннотации в видео каналов, на которые вы подписаны? ",
|
||||||
"Redirect homepage to feed: ": "Отображать видео с каналов, на которые вы подписаны, как главную страницу: ",
|
"Redirect homepage to feed: ": "Отображать видео с каналов, на которые вы подписаны, как главную страницу: ",
|
||||||
|
@ -476,5 +476,15 @@
|
||||||
"preferences_save_player_pos_label": "Запоминать позицию: ",
|
"preferences_save_player_pos_label": "Запоминать позицию: ",
|
||||||
"preferences_region_label": "Страна: ",
|
"preferences_region_label": "Страна: ",
|
||||||
"preferences_watch_history_label": "Включить историю просмотров ",
|
"preferences_watch_history_label": "Включить историю просмотров ",
|
||||||
"search_filters_title": "Фильтр"
|
"search_filters_title": "Фильтр",
|
||||||
|
"search_filters_duration_option_none": "Любой длины",
|
||||||
|
"search_filters_type_option_all": "Любого типа",
|
||||||
|
"search_filters_date_option_none": "Любой даты",
|
||||||
|
"search_filters_date_label": "Дата загрузки",
|
||||||
|
"search_message_no_results": "Ничего не найдено.",
|
||||||
|
"search_message_use_another_instance": " Дополнительно вы можете <a href=\"`x`\">поискать на других зеркалах</a>.",
|
||||||
|
"search_filters_features_option_vr180": "VR180",
|
||||||
|
"search_message_change_filters_or_query": "Попробуйте расширить поисковый запрос и изменить фильтры.",
|
||||||
|
"search_filters_duration_option_medium": "Средние (4 - 20 минут)",
|
||||||
|
"search_filters_apply_button": "Применить фильтры"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ record AboutChannel,
|
||||||
joined : Time,
|
joined : Time,
|
||||||
is_family_friendly : Bool,
|
is_family_friendly : Bool,
|
||||||
allowed_regions : Array(String),
|
allowed_regions : Array(String),
|
||||||
tabs : Array(String)
|
tabs : Array(String),
|
||||||
|
verified : Bool
|
||||||
|
|
||||||
record AboutRelatedChannel,
|
record AboutRelatedChannel,
|
||||||
ucid : String,
|
ucid : String,
|
||||||
|
@ -70,6 +71,9 @@ def get_about_info(ucid, locale) : AboutChannel
|
||||||
# if banner.includes? "channels/c4/default_banner"
|
# if banner.includes? "channels/c4/default_banner"
|
||||||
# banner = nil
|
# banner = nil
|
||||||
# end
|
# end
|
||||||
|
# author_verified_badges = initdata["header"]?.try &.["c4TabbedHeaderRenderer"]?.try &.["badges"]?
|
||||||
|
author_verified_badge = initdata["header"].dig?("c4TabbedHeaderRenderer", "badges", 0, "metadataBadgeRenderer", "tooltip")
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge == "Verified")
|
||||||
|
|
||||||
description = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?.try &.as_s? || ""
|
description = initdata["metadata"]["channelMetadataRenderer"]?.try &.["description"]?.try &.as_s? || ""
|
||||||
description_html = HTML.escape(description)
|
description_html = HTML.escape(description)
|
||||||
|
@ -128,6 +132,7 @@ def get_about_info(ucid, locale) : AboutChannel
|
||||||
is_family_friendly: is_family_friendly,
|
is_family_friendly: is_family_friendly,
|
||||||
allowed_regions: allowed_regions,
|
allowed_regions: allowed_regions,
|
||||||
tabs: tabs,
|
tabs: tabs,
|
||||||
|
verified: author_verified || false,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,8 @@ def fetch_youtube_comments(id, cursor, format, locale, thin_mode, region, sort_b
|
||||||
content_html = node_comment["contentText"]?.try { |t| parse_content(t) } || ""
|
content_html = node_comment["contentText"]?.try { |t| parse_content(t) } || ""
|
||||||
author = node_comment["authorText"]?.try &.["simpleText"]? || ""
|
author = node_comment["authorText"]?.try &.["simpleText"]? || ""
|
||||||
|
|
||||||
|
json.field "verified", (node_comment["authorCommentBadge"]? != nil)
|
||||||
|
|
||||||
json.field "author", author
|
json.field "author", author
|
||||||
json.field "authorThumbnails" do
|
json.field "authorThumbnails" do
|
||||||
json.array do
|
json.array do
|
||||||
|
@ -329,7 +331,11 @@ def template_youtube_comments(comments, locale, thin_mode, is_replies = false)
|
||||||
end
|
end
|
||||||
|
|
||||||
author_name = HTML.escape(child["author"].as_s)
|
author_name = HTML.escape(child["author"].as_s)
|
||||||
|
if child["verified"]?.try &.as_bool && child["authorIsChannelOwner"]?.try &.as_bool
|
||||||
|
author_name += " <i class=\"icon ion ion-md-checkmark-circle\"></i>"
|
||||||
|
elsif child["verified"]?.try &.as_bool
|
||||||
|
author_name += " <i class=\"icon ion ion-md-checkmark\"></i>"
|
||||||
|
end
|
||||||
html << <<-END_HTML
|
html << <<-END_HTML
|
||||||
<div class="pure-g" style="width:100%">
|
<div class="pure-g" style="width:100%">
|
||||||
<div class="channel-profile pure-u-4-24 pure-u-md-2-24">
|
<div class="channel-profile pure-u-4-24 pure-u-md-2-24">
|
||||||
|
|
|
@ -46,7 +46,7 @@ def error_template_helper(env : HTTP::Server::Context, status_code : Int32, exce
|
||||||
|
|
||||||
TEXT
|
TEXT
|
||||||
|
|
||||||
issue_template += github_details("Backtrace", HTML.escape(exception.inspect_with_backtrace))
|
issue_template += github_details("Backtrace", exception.inspect_with_backtrace)
|
||||||
|
|
||||||
# URLs for the error message below
|
# URLs for the error message below
|
||||||
url_faq = "https://github.com/iv-org/documentation/blob/master/docs/faq.md"
|
url_faq = "https://github.com/iv-org/documentation/blob/master/docs/faq.md"
|
||||||
|
|
|
@ -14,6 +14,7 @@ LOCALES_LIST = {
|
||||||
"fi" => "Suomi", # Finnish
|
"fi" => "Suomi", # Finnish
|
||||||
"fr" => "Français", # French
|
"fr" => "Français", # French
|
||||||
"he" => "עברית", # Hebrew
|
"he" => "עברית", # Hebrew
|
||||||
|
"hi" => "हिन्दी", # Hindi
|
||||||
"hr" => "Hrvatski", # Croatian
|
"hr" => "Hrvatski", # Croatian
|
||||||
"hu-HU" => "Magyar Nyelv", # Hungarian
|
"hu-HU" => "Magyar Nyelv", # Hungarian
|
||||||
"id" => "Bahasa Indonesia", # Indonesian
|
"id" => "Bahasa Indonesia", # Indonesian
|
||||||
|
|
|
@ -12,6 +12,7 @@ struct SearchVideo
|
||||||
property live_now : Bool
|
property live_now : Bool
|
||||||
property premium : Bool
|
property premium : Bool
|
||||||
property premiere_timestamp : Time?
|
property premiere_timestamp : Time?
|
||||||
|
property author_verified : Bool
|
||||||
|
|
||||||
def to_xml(auto_generated, query_params, xml : XML::Builder)
|
def to_xml(auto_generated, query_params, xml : XML::Builder)
|
||||||
query_params["v"] = self.id
|
query_params["v"] = self.id
|
||||||
|
@ -129,6 +130,7 @@ struct SearchPlaylist
|
||||||
property video_count : Int32
|
property video_count : Int32
|
||||||
property videos : Array(SearchPlaylistVideo)
|
property videos : Array(SearchPlaylistVideo)
|
||||||
property thumbnail : String?
|
property thumbnail : String?
|
||||||
|
property author_verified : Bool
|
||||||
|
|
||||||
def to_json(locale : String?, json : JSON::Builder)
|
def to_json(locale : String?, json : JSON::Builder)
|
||||||
json.object do
|
json.object do
|
||||||
|
@ -141,6 +143,8 @@ struct SearchPlaylist
|
||||||
json.field "authorId", self.ucid
|
json.field "authorId", self.ucid
|
||||||
json.field "authorUrl", "/channel/#{self.ucid}"
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
|
||||||
|
json.field "authorVerified", self.author_verified
|
||||||
|
|
||||||
json.field "videoCount", self.video_count
|
json.field "videoCount", self.video_count
|
||||||
json.field "videos" do
|
json.field "videos" do
|
||||||
json.array do
|
json.array do
|
||||||
|
@ -182,6 +186,7 @@ struct SearchChannel
|
||||||
property video_count : Int32
|
property video_count : Int32
|
||||||
property description_html : String
|
property description_html : String
|
||||||
property auto_generated : Bool
|
property auto_generated : Bool
|
||||||
|
property author_verified : Bool
|
||||||
|
|
||||||
def to_json(locale : String?, json : JSON::Builder)
|
def to_json(locale : String?, json : JSON::Builder)
|
||||||
json.object do
|
json.object do
|
||||||
|
@ -189,7 +194,7 @@ struct SearchChannel
|
||||||
json.field "author", self.author
|
json.field "author", self.author
|
||||||
json.field "authorId", self.ucid
|
json.field "authorId", self.ucid
|
||||||
json.field "authorUrl", "/channel/#{self.ucid}"
|
json.field "authorUrl", "/channel/#{self.ucid}"
|
||||||
|
json.field "authorVerified", self.author_verified
|
||||||
json.field "authorThumbnails" do
|
json.field "authorThumbnails" do
|
||||||
json.array do
|
json.array do
|
||||||
qualities = {32, 48, 76, 100, 176, 512}
|
qualities = {32, 48, 76, 100, 176, 512}
|
||||||
|
|
|
@ -62,6 +62,9 @@ module Invidious::Routes::API::Manifest
|
||||||
|
|
||||||
xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true) do
|
xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true) do
|
||||||
mime_streams.each do |fmt|
|
mime_streams.each do |fmt|
|
||||||
|
# OTF streams aren't supported yet (See https://github.com/TeamNewPipe/NewPipe/issues/2415)
|
||||||
|
next if !(fmt.has_key?("indexRange") && fmt.has_key?("initRange"))
|
||||||
|
|
||||||
codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
|
codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
|
||||||
bandwidth = fmt["bitrate"].as_i
|
bandwidth = fmt["bitrate"].as_i
|
||||||
itag = fmt["itag"].as_i
|
itag = fmt["itag"].as_i
|
||||||
|
@ -90,6 +93,9 @@ module Invidious::Routes::API::Manifest
|
||||||
heights = [] of Int32
|
heights = [] of Int32
|
||||||
xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, scanType: "progressive") do
|
xml.element("AdaptationSet", id: i, mimeType: mime_type, startWithSAP: 1, subsegmentAlignment: true, scanType: "progressive") do
|
||||||
mime_streams.each do |fmt|
|
mime_streams.each do |fmt|
|
||||||
|
# OTF streams aren't supported yet (See https://github.com/TeamNewPipe/NewPipe/issues/2415)
|
||||||
|
next if !(fmt.has_key?("indexRange") && fmt.has_key?("initRange"))
|
||||||
|
|
||||||
codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
|
codecs = fmt["mimeType"].as_s.split("codecs=")[1].strip('"')
|
||||||
bandwidth = fmt["bitrate"].as_i
|
bandwidth = fmt["bitrate"].as_i
|
||||||
itag = fmt["itag"].as_i
|
itag = fmt["itag"].as_i
|
||||||
|
|
|
@ -182,6 +182,7 @@ module Invidious::Routes::Feeds
|
||||||
paid: false,
|
paid: false,
|
||||||
premium: false,
|
premium: false,
|
||||||
premiere_timestamp: nil,
|
premiere_timestamp: nil,
|
||||||
|
author_verified: false, # ¯\_(ツ)_/¯
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -374,18 +374,25 @@ struct Video
|
||||||
json.array do
|
json.array do
|
||||||
self.adaptive_fmts.each do |fmt|
|
self.adaptive_fmts.each do |fmt|
|
||||||
json.object do
|
json.object do
|
||||||
json.field "index", "#{fmt["indexRange"]["start"]}-#{fmt["indexRange"]["end"]}"
|
# Only available on regular videos, not livestreams/OTF streams
|
||||||
json.field "bitrate", fmt["bitrate"].as_i.to_s
|
if init_range = fmt["initRange"]?
|
||||||
json.field "init", "#{fmt["initRange"]["start"]}-#{fmt["initRange"]["end"]}"
|
json.field "init", "#{init_range["start"]}-#{init_range["end"]}"
|
||||||
|
end
|
||||||
|
if index_range = fmt["indexRange"]?
|
||||||
|
json.field "index", "#{index_range["start"]}-#{index_range["end"]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Not available on MPEG-4 Timed Text (`text/mp4`) streams (livestreams only)
|
||||||
|
json.field "bitrate", fmt["bitrate"].as_i.to_s if fmt["bitrate"]?
|
||||||
|
|
||||||
json.field "url", fmt["url"]
|
json.field "url", fmt["url"]
|
||||||
json.field "itag", fmt["itag"].as_i.to_s
|
json.field "itag", fmt["itag"].as_i.to_s
|
||||||
json.field "type", fmt["mimeType"]
|
json.field "type", fmt["mimeType"]
|
||||||
json.field "clen", fmt["contentLength"]
|
json.field "clen", fmt["contentLength"]? || "-1"
|
||||||
json.field "lmt", fmt["lastModified"]
|
json.field "lmt", fmt["lastModified"]
|
||||||
json.field "projectionType", fmt["projectionType"]
|
json.field "projectionType", fmt["projectionType"]
|
||||||
|
|
||||||
fmt_info = itag_to_metadata?(fmt["itag"])
|
if fmt_info = itag_to_metadata?(fmt["itag"])
|
||||||
if fmt_info
|
|
||||||
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.as_i || 30
|
fps = fmt_info["fps"]?.try &.to_i || fmt["fps"]?.try &.as_i || 30
|
||||||
json.field "fps", fps
|
json.field "fps", fps
|
||||||
json.field "container", fmt_info["ext"]
|
json.field "container", fmt_info["ext"]
|
||||||
|
@ -405,6 +412,19 @@ struct Video
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Livestream chunk infos
|
||||||
|
json.field "targetDurationSec", fmt["targetDurationSec"].as_i if fmt.has_key?("targetDurationSec")
|
||||||
|
json.field "maxDvrDurationSec", fmt["maxDvrDurationSec"].as_i if fmt.has_key?("maxDvrDurationSec")
|
||||||
|
|
||||||
|
# Audio-related data
|
||||||
|
json.field "audioQuality", fmt["audioQuality"] if fmt.has_key?("audioQuality")
|
||||||
|
json.field "audioSampleRate", fmt["audioSampleRate"].as_s.to_i if fmt.has_key?("audioSampleRate")
|
||||||
|
json.field "audioChannels", fmt["audioChannels"] if fmt.has_key?("audioChannels")
|
||||||
|
|
||||||
|
# Extra misc stuff
|
||||||
|
json.field "colorInfo", fmt["colorInfo"] if fmt.has_key?("colorInfo")
|
||||||
|
json.field "captionTrack", fmt["captionTrack"] if fmt.has_key?("captionTrack")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -593,6 +613,10 @@ struct Video
|
||||||
info["authorThumbnail"]?.try &.as_s || ""
|
info["authorThumbnail"]?.try &.as_s || ""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def author_verified : Bool
|
||||||
|
info["authorVerified"]?.try &.as_bool || false
|
||||||
|
end
|
||||||
|
|
||||||
def sub_count_text : String
|
def sub_count_text : String
|
||||||
info["subCountText"]?.try &.as_s || "-"
|
info["subCountText"]?.try &.as_s || "-"
|
||||||
end
|
end
|
||||||
|
@ -612,6 +636,7 @@ struct Video
|
||||||
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
|
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
|
||||||
fmt["url"] = JSON::Any.new("#{fmt["url"]}®ion=#{self.info["region"]}") if self.info["region"]?
|
fmt["url"] = JSON::Any.new("#{fmt["url"]}®ion=#{self.info["region"]}") if self.info["region"]?
|
||||||
end
|
end
|
||||||
|
|
||||||
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
|
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
|
||||||
@fmt_stream = fmt_stream
|
@fmt_stream = fmt_stream
|
||||||
return @fmt_stream.as(Array(Hash(String, JSON::Any)))
|
return @fmt_stream.as(Array(Hash(String, JSON::Any)))
|
||||||
|
@ -631,9 +656,7 @@ struct Video
|
||||||
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
|
fmt["url"] = JSON::Any.new("#{fmt["url"]}&host=#{URI.parse(fmt["url"].as_s).host}")
|
||||||
fmt["url"] = JSON::Any.new("#{fmt["url"]}®ion=#{self.info["region"]}") if self.info["region"]?
|
fmt["url"] = JSON::Any.new("#{fmt["url"]}®ion=#{self.info["region"]}") if self.info["region"]?
|
||||||
end
|
end
|
||||||
# See https://github.com/TeamNewPipe/NewPipe/issues/2415
|
|
||||||
# Some streams are segmented by URL `sq/` rather than index, for now we just filter them out
|
|
||||||
fmt_stream.reject! { |f| !f["indexRange"]? }
|
|
||||||
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
|
fmt_stream.sort_by! { |f| f["width"]?.try &.as_i || 0 }
|
||||||
@adaptive_fmts = fmt_stream
|
@adaptive_fmts = fmt_stream
|
||||||
return @adaptive_fmts.as(Array(Hash(String, JSON::Any)))
|
return @adaptive_fmts.as(Array(Hash(String, JSON::Any)))
|
||||||
|
@ -845,6 +868,12 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
|
||||||
.try &.dig?("runs", 0)
|
.try &.dig?("runs", 0)
|
||||||
|
|
||||||
author = channel_info.try &.dig?("text")
|
author = channel_info.try &.dig?("text")
|
||||||
|
author_verified_badge = related["ownerBadges"]?.try do |badges_array|
|
||||||
|
badges_array.as_a.find(&.dig("metadataBadgeRenderer", "tooltip").as_s.== "Verified")
|
||||||
|
end
|
||||||
|
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge.size > 0).to_s
|
||||||
|
|
||||||
ucid = channel_info.try { |ci| HelperExtractors.get_browse_id(ci) }
|
ucid = channel_info.try { |ci| HelperExtractors.get_browse_id(ci) }
|
||||||
|
|
||||||
# "4,088,033 views", only available on compact renderer
|
# "4,088,033 views", only available on compact renderer
|
||||||
|
@ -868,6 +897,7 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
|
||||||
"length_seconds" => JSON::Any.new(length || "0"),
|
"length_seconds" => JSON::Any.new(length || "0"),
|
||||||
"view_count" => JSON::Any.new(view_count || "0"),
|
"view_count" => JSON::Any.new(view_count || "0"),
|
||||||
"short_view_count" => JSON::Any.new(short_view_count || "0"),
|
"short_view_count" => JSON::Any.new(short_view_count || "0"),
|
||||||
|
"author_verified" => JSON::Any.new(author_verified),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1062,6 +1092,10 @@ def extract_video_info(video_id : String, proxy_region : String? = nil, context_
|
||||||
author_info = video_secondary_renderer.try &.dig?("owner", "videoOwnerRenderer")
|
author_info = video_secondary_renderer.try &.dig?("owner", "videoOwnerRenderer")
|
||||||
author_thumbnail = author_info.try &.dig?("thumbnail", "thumbnails", 0, "url")
|
author_thumbnail = author_info.try &.dig?("thumbnail", "thumbnails", 0, "url")
|
||||||
|
|
||||||
|
author_verified_badge = author_info.try &.dig?("badges", 0, "metadataBadgeRenderer", "tooltip")
|
||||||
|
author_verified = (!author_verified_badge.nil? && author_verified_badge == "Verified")
|
||||||
|
params["authorVerified"] = JSON::Any.new(author_verified)
|
||||||
|
|
||||||
params["authorThumbnail"] = JSON::Any.new(author_thumbnail.try &.as_s || "")
|
params["authorThumbnail"] = JSON::Any.new(author_thumbnail.try &.as_s || "")
|
||||||
|
|
||||||
params["subCountText"] = JSON::Any.new(author_info.try &.["subscriberCountText"]?
|
params["subCountText"] = JSON::Any.new(author_info.try &.["subscriberCountText"]?
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
<div class="pure-u-2-3">
|
<div class="pure-u-2-3">
|
||||||
<div class="channel-profile">
|
<div class="channel-profile">
|
||||||
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
||||||
<span><%= author %></span>
|
<span><%= author %></span><% if !channel.verified.nil? && channel.verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1-3">
|
<div class="pure-u-1-3">
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="pure-u-2-3">
|
<div class="pure-u-2-3">
|
||||||
<div class="channel-profile">
|
<div class="channel-profile">
|
||||||
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
||||||
<span><%= author %></span>
|
<span><%= author %></span><% if !channel.verified.nil? && channel.verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1-3" style="text-align:right">
|
<div class="pure-u-1-3" style="text-align:right">
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<img loading="lazy" style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>"/>
|
<img loading="lazy" style="width:56.25%" src="/ggpht<%= URI.parse(item.author_thumbnail).request_target.gsub(/=s\d+/, "=s176") %>"/>
|
||||||
</center>
|
</center>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p dir="auto"><%= HTML.escape(item.author) %></p>
|
<p dir="auto"><%= HTML.escape(item.author) %><% if !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></p>
|
||||||
</a>
|
</a>
|
||||||
<p><%= translate_count(locale, "generic_subscribers_count", item.subscriber_count, NumberFormatting::Separator) %></p>
|
<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 %><p><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p><% end %>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
<p dir="auto"><%= HTML.escape(item.title) %></p>
|
<p dir="auto"><%= HTML.escape(item.title) %></p>
|
||||||
</a>
|
</a>
|
||||||
<a href="/channel/<%= item.ucid %>">
|
<a href="/channel/<%= item.ucid %>">
|
||||||
<p dir="auto"><b><%= HTML.escape(item.author) %></b></p>
|
<p dir="auto"><b><%= HTML.escape(item.author) %><% if !item.is_a?(InvidiousPlaylist) && !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></b></p>
|
||||||
</a>
|
</a>
|
||||||
<% when MixVideo %>
|
<% when MixVideo %>
|
||||||
<a href="/watch?v=<%= item.id %>&list=<%= item.rdid %>">
|
<a href="/watch?v=<%= item.id %>&list=<%= item.rdid %>">
|
||||||
|
@ -142,7 +142,7 @@
|
||||||
|
|
||||||
<div class="video-card-row flexible">
|
<div class="video-card-row flexible">
|
||||||
<div class="flex-left"><a href="/channel/<%= item.ucid %>">
|
<div class="flex-left"><a href="/channel/<%= item.ucid %>">
|
||||||
<p class="channel-name" dir="auto"><%= HTML.escape(item.author) %></p>
|
<p class="channel-name" dir="auto"><%= HTML.escape(item.author) %><% if !item.is_a?(ChannelVideo) && !item.author_verified.nil? && item.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></p>
|
||||||
</a></div>
|
</a></div>
|
||||||
|
|
||||||
<% endpoint_params = "?v=#{item.id}" %>
|
<% endpoint_params = "?v=#{item.id}" %>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<div class="pure-u-2-3">
|
<div class="pure-u-2-3">
|
||||||
<div class="channel-profile">
|
<div class="channel-profile">
|
||||||
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
<img src="/ggpht<%= URI.parse(channel.author_thumbnail).request_target %>">
|
||||||
<span><%= author %></span>
|
<span><%= author %></span><% if !channel.verified.nil? && channel.verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="pure-u-1-3" style="text-align:right">
|
<div class="pure-u-1-3" style="text-align:right">
|
||||||
|
|
|
@ -207,7 +207,7 @@ we're going to need to do it here in order to allow for translations.
|
||||||
<% if !video.author_thumbnail.empty? %>
|
<% if !video.author_thumbnail.empty? %>
|
||||||
<img src="/ggpht<%= URI.parse(video.author_thumbnail).request_target %>">
|
<img src="/ggpht<%= URI.parse(video.author_thumbnail).request_target %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
<span id="channel-name"><%= author %></span>
|
<span id="channel-name"><%= author %><% if !video.author_verified.nil? && video.author_verified %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
@ -281,9 +281,9 @@ we're going to need to do it here in order to allow for translations.
|
||||||
<h5 class="pure-g">
|
<h5 class="pure-g">
|
||||||
<div class="pure-u-14-24">
|
<div class="pure-u-14-24">
|
||||||
<% if rv["ucid"]? %>
|
<% if rv["ucid"]? %>
|
||||||
<b style="width:100%"><a href="/channel/<%= rv["ucid"] %>"><%= rv["author"]? %></a></b>
|
<b style="width:100%"><a href="/channel/<%= rv["ucid"] %>"><%= rv["author"]? %><% if rv["author_verified"]? == "true" %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></a></b>
|
||||||
<% else %>
|
<% else %>
|
||||||
<b style="width:100%"><%= rv["author"]? %></b>
|
<b style="width:100%"><%= rv["author"]? %><% if rv["author_verified"]? == "true" %> <i class="icon ion ion-md-checkmark-circle"></i><% end %></b>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,11 @@ private module Parsers
|
||||||
premium = false
|
premium = false
|
||||||
|
|
||||||
premiere_timestamp = item_contents.dig?("upcomingEventData", "startTime").try { |t| Time.unix(t.as_s.to_i64) }
|
premiere_timestamp = item_contents.dig?("upcomingEventData", "startTime").try { |t| Time.unix(t.as_s.to_i64) }
|
||||||
|
author_verified_badge = item_contents["ownerBadges"]?.try do |badges_array|
|
||||||
|
badges_array.as_a.find(&.dig("metadataBadgeRenderer", "tooltip").as_s.== "Verified")
|
||||||
|
end
|
||||||
|
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge.size > 0)
|
||||||
item_contents["badges"]?.try &.as_a.each do |badge|
|
item_contents["badges"]?.try &.as_a.each do |badge|
|
||||||
b = badge["metadataBadgeRenderer"]
|
b = badge["metadataBadgeRenderer"]
|
||||||
case b["label"].as_s
|
case b["label"].as_s
|
||||||
|
@ -129,6 +133,7 @@ private module Parsers
|
||||||
live_now: live_now,
|
live_now: live_now,
|
||||||
premium: premium,
|
premium: premium,
|
||||||
premiere_timestamp: premiere_timestamp,
|
premiere_timestamp: premiere_timestamp,
|
||||||
|
author_verified: author_verified || false,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,7 +161,11 @@ private module Parsers
|
||||||
private def self.parse(item_contents, author_fallback)
|
private def self.parse(item_contents, author_fallback)
|
||||||
author = extract_text(item_contents["title"]) || author_fallback.name
|
author = extract_text(item_contents["title"]) || author_fallback.name
|
||||||
author_id = item_contents["channelId"]?.try &.as_s || author_fallback.id
|
author_id = item_contents["channelId"]?.try &.as_s || author_fallback.id
|
||||||
|
author_verified_badge = item_contents["ownerBadges"]?.try do |badges_array|
|
||||||
|
badges_array.as_a.find(&.dig("metadataBadgeRenderer", "tooltip").as_s.== "Verified")
|
||||||
|
end
|
||||||
|
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge.size > 0)
|
||||||
author_thumbnail = HelperExtractors.get_thumbnails(item_contents)
|
author_thumbnail = HelperExtractors.get_thumbnails(item_contents)
|
||||||
# When public subscriber count is disabled, the subscriberCountText isn't sent by InnerTube.
|
# When public subscriber count is disabled, the subscriberCountText isn't sent by InnerTube.
|
||||||
# Always simpleText
|
# Always simpleText
|
||||||
|
@ -179,6 +188,7 @@ private module Parsers
|
||||||
video_count: video_count,
|
video_count: video_count,
|
||||||
description_html: description_html,
|
description_html: description_html,
|
||||||
auto_generated: auto_generated,
|
auto_generated: auto_generated,
|
||||||
|
author_verified: author_verified || false,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -206,7 +216,11 @@ private module Parsers
|
||||||
private def self.parse(item_contents, author_fallback)
|
private def self.parse(item_contents, author_fallback)
|
||||||
title = extract_text(item_contents["title"]) || ""
|
title = extract_text(item_contents["title"]) || ""
|
||||||
plid = item_contents["playlistId"]?.try &.as_s || ""
|
plid = item_contents["playlistId"]?.try &.as_s || ""
|
||||||
|
author_verified_badge = item_contents["ownerBadges"]?.try do |badges_array|
|
||||||
|
badges_array.as_a.find(&.dig("metadataBadgeRenderer", "tooltip").as_s.== "Verified")
|
||||||
|
end
|
||||||
|
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge.size > 0)
|
||||||
video_count = HelperExtractors.get_video_count(item_contents)
|
video_count = HelperExtractors.get_video_count(item_contents)
|
||||||
playlist_thumbnail = HelperExtractors.get_thumbnails(item_contents)
|
playlist_thumbnail = HelperExtractors.get_thumbnails(item_contents)
|
||||||
|
|
||||||
|
@ -218,6 +232,7 @@ private module Parsers
|
||||||
video_count: video_count,
|
video_count: video_count,
|
||||||
videos: [] of SearchPlaylistVideo,
|
videos: [] of SearchPlaylistVideo,
|
||||||
thumbnail: playlist_thumbnail,
|
thumbnail: playlist_thumbnail,
|
||||||
|
author_verified: author_verified || false,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -251,7 +266,11 @@ private module Parsers
|
||||||
author_info = item_contents.dig?("shortBylineText", "runs", 0)
|
author_info = item_contents.dig?("shortBylineText", "runs", 0)
|
||||||
author = author_info.try &.["text"].as_s || author_fallback.name
|
author = author_info.try &.["text"].as_s || author_fallback.name
|
||||||
author_id = author_info.try { |x| HelperExtractors.get_browse_id(x) } || author_fallback.id
|
author_id = author_info.try { |x| HelperExtractors.get_browse_id(x) } || author_fallback.id
|
||||||
|
author_verified_badge = item_contents["ownerBadges"]?.try do |badges_array|
|
||||||
|
badges_array.as_a.find(&.dig("metadataBadgeRenderer", "tooltip").as_s.== "Verified")
|
||||||
|
end
|
||||||
|
|
||||||
|
author_verified = (author_verified_badge && author_verified_badge.size > 0)
|
||||||
videos = item_contents["videos"]?.try &.as_a.map do |v|
|
videos = item_contents["videos"]?.try &.as_a.map do |v|
|
||||||
v = v["childVideoRenderer"]
|
v = v["childVideoRenderer"]
|
||||||
v_title = v.dig?("title", "simpleText").try &.as_s || ""
|
v_title = v.dig?("title", "simpleText").try &.as_s || ""
|
||||||
|
@ -274,6 +293,7 @@ private module Parsers
|
||||||
video_count: video_count,
|
video_count: video_count,
|
||||||
videos: videos,
|
videos: videos,
|
||||||
thumbnail: playlist_thumbnail,
|
thumbnail: playlist_thumbnail,
|
||||||
|
author_verified: author_verified || false,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
読み込み中…
新しいイシューから参照