mirror of
https://github.com/iv-org/invidious.git
synced 2025-06-27 17:18:29 +00:00
Formatting
This commit is contained in:
parent
1f7ce1890a
commit
70b36ed1a1
@ -1,254 +1,273 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
// Contains only auxiliary methods
|
||||
// May be included and executed unlimited number of times without any consequences
|
||||
|
||||
// Polyfills for IE11
|
||||
Array.prototype.find = Array.prototype.find || function (condition) {
|
||||
Array.prototype.find =
|
||||
Array.prototype.find ||
|
||||
function (condition) {
|
||||
return this.filter(condition)[0];
|
||||
};
|
||||
};
|
||||
|
||||
Array.from = Array.from || function (source) {
|
||||
Array.from =
|
||||
Array.from ||
|
||||
function (source) {
|
||||
return Array.prototype.slice.call(source);
|
||||
};
|
||||
NodeList.prototype.forEach = NodeList.prototype.forEach || function (callback) {
|
||||
};
|
||||
NodeList.prototype.forEach =
|
||||
NodeList.prototype.forEach ||
|
||||
function (callback) {
|
||||
Array.from(this).forEach(callback);
|
||||
};
|
||||
String.prototype.includes = String.prototype.includes || function (searchString) {
|
||||
};
|
||||
String.prototype.includes =
|
||||
String.prototype.includes ||
|
||||
function (searchString) {
|
||||
return this.indexOf(searchString) >= 0;
|
||||
};
|
||||
String.prototype.startsWith = String.prototype.startsWith || function (prefix) {
|
||||
};
|
||||
String.prototype.startsWith =
|
||||
String.prototype.startsWith ||
|
||||
function (prefix) {
|
||||
return this.substr(0, prefix.length) === prefix;
|
||||
};
|
||||
Math.sign = Math.sign || function(x) {
|
||||
};
|
||||
Math.sign =
|
||||
Math.sign ||
|
||||
function (x) {
|
||||
x = +x;
|
||||
if (!x) return x; // 0 and NaN
|
||||
return x > 0 ? 1 : -1;
|
||||
};
|
||||
if (!window.hasOwnProperty('HTMLDetailsElement') && !window.hasOwnProperty('mockHTMLDetailsElement')) {
|
||||
window.mockHTMLDetailsElement = true;
|
||||
const style = 'details:not([open]) > :not(summary) {display: none}';
|
||||
document.head.appendChild(document.createElement('style')).textContent = style;
|
||||
};
|
||||
if (
|
||||
!window.hasOwnProperty("HTMLDetailsElement") &&
|
||||
!window.hasOwnProperty("mockHTMLDetailsElement")
|
||||
) {
|
||||
window.mockHTMLDetailsElement = true;
|
||||
const style = "details:not([open]) > :not(summary) {display: none}";
|
||||
document.head.appendChild(document.createElement("style")).textContent =
|
||||
style;
|
||||
|
||||
addEventListener('click', function (e) {
|
||||
if (e.target.nodeName !== 'SUMMARY') return;
|
||||
const details = e.target.parentElement;
|
||||
if (details.hasAttribute('open'))
|
||||
details.removeAttribute('open');
|
||||
else
|
||||
details.setAttribute('open', '');
|
||||
});
|
||||
addEventListener("click", function (e) {
|
||||
if (e.target.nodeName !== "SUMMARY") return;
|
||||
const details = e.target.parentElement;
|
||||
if (details.hasAttribute("open")) details.removeAttribute("open");
|
||||
else details.setAttribute("open", "");
|
||||
});
|
||||
}
|
||||
|
||||
// Monstrous global variable for handy code
|
||||
// Includes: clamp, xhr, storage.{get,set,remove}
|
||||
window.helpers = window.helpers || {
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Clamping_(graphics)
|
||||
* @param {Number} num Source number
|
||||
* @param {Number} min Low border
|
||||
* @param {Number} max High border
|
||||
* @returns {Number} Clamped value
|
||||
*/
|
||||
clamp: function (num, min, max) {
|
||||
if (max < min) {
|
||||
var t = max; max = min; min = t; // swap max and min
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Clamping_(graphics)
|
||||
* @param {Number} num Source number
|
||||
* @param {Number} min Low border
|
||||
* @param {Number} max High border
|
||||
* @returns {Number} Clamped value
|
||||
*/
|
||||
clamp: function (num, min, max) {
|
||||
if (max < min) {
|
||||
var t = max;
|
||||
max = min;
|
||||
min = t; // swap max and min
|
||||
}
|
||||
|
||||
if (max < num) return max;
|
||||
if (min > num) return min;
|
||||
return num;
|
||||
},
|
||||
|
||||
/** @private */
|
||||
_xhr: function (method, url, options, callbacks) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, url);
|
||||
|
||||
// Default options
|
||||
xhr.responseType = "json";
|
||||
xhr.timeout = 10000;
|
||||
// Default options redefining
|
||||
if (options.responseType) xhr.responseType = options.responseType;
|
||||
if (options.timeout) xhr.timeout = options.timeout;
|
||||
|
||||
if (method === "POST")
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
// better than onreadystatechange because of 404 codes https://stackoverflow.com/a/36182963
|
||||
xhr.onloadend = function () {
|
||||
if (xhr.status === 200) {
|
||||
if (callbacks.on200) {
|
||||
// fix for IE11. It doesn't convert response to JSON
|
||||
if (xhr.responseType === "" && typeof xhr.response === "string")
|
||||
callbacks.on200(JSON.parse(xhr.response));
|
||||
else callbacks.on200(xhr.response);
|
||||
}
|
||||
} else {
|
||||
// handled by onerror
|
||||
if (xhr.status === 0) return;
|
||||
|
||||
if (max < num)
|
||||
return max;
|
||||
if (min > num)
|
||||
return min;
|
||||
return num;
|
||||
},
|
||||
if (callbacks.onNon200) callbacks.onNon200(xhr);
|
||||
}
|
||||
};
|
||||
|
||||
/** @private */
|
||||
_xhr: function (method, url, options, callbacks) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open(method, url);
|
||||
xhr.ontimeout = function () {
|
||||
if (callbacks.onTimeout) callbacks.onTimeout(xhr);
|
||||
};
|
||||
|
||||
// Default options
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 10000;
|
||||
// Default options redefining
|
||||
if (options.responseType)
|
||||
xhr.responseType = options.responseType;
|
||||
if (options.timeout)
|
||||
xhr.timeout = options.timeout;
|
||||
xhr.onerror = function () {
|
||||
if (callbacks.onError) callbacks.onError(xhr);
|
||||
};
|
||||
|
||||
if (method === 'POST')
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
|
||||
if (options.payload) xhr.send(options.payload);
|
||||
else xhr.send();
|
||||
},
|
||||
/** @private */
|
||||
_xhrRetry: function (method, url, options, callbacks) {
|
||||
if (options.retries <= 0) {
|
||||
console.warn("Failed to pull", options.entity_name);
|
||||
if (callbacks.onTotalFail) callbacks.onTotalFail();
|
||||
return;
|
||||
}
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
},
|
||||
/**
|
||||
* @callback callbackXhrOn200
|
||||
* @param {Object} response - xhr.response
|
||||
*/
|
||||
/**
|
||||
* @callback callbackXhrError
|
||||
* @param {XMLHttpRequest} xhr
|
||||
*/
|
||||
/**
|
||||
* @param {'GET'|'POST'} method - 'GET' or 'POST'
|
||||
* @param {String} url - URL to send request to
|
||||
* @param {Object} options - other XHR options
|
||||
* @param {XMLHttpRequestBodyInit} [options.payload=null] - payload for POST-requests
|
||||
* @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [options.responseType=json]
|
||||
* @param {Number} [options.timeout=10000]
|
||||
* @param {Number} [options.retries=1]
|
||||
* @param {String} [options.entity_name='unknown'] - string to log
|
||||
* @param {Number} [options.retry_timeout=1000]
|
||||
* @param {Object} callbacks - functions to execute on events fired
|
||||
* @param {callbackXhrOn200} [callbacks.on200]
|
||||
* @param {callbackXhrError} [callbacks.onNon200]
|
||||
* @param {callbackXhrError} [callbacks.onTimeout]
|
||||
* @param {callbackXhrError} [callbacks.onError]
|
||||
* @param {callbackXhrError} [callbacks.onTotalFail] - if failed after all retries
|
||||
*/
|
||||
xhr: function (method, url, options, callbacks) {
|
||||
if (!options.retries || options.retries <= 1) {
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
return;
|
||||
}
|
||||
|
||||
// better than onreadystatechange because of 404 codes https://stackoverflow.com/a/36182963
|
||||
xhr.onloadend = function () {
|
||||
if (xhr.status === 200) {
|
||||
if (callbacks.on200) {
|
||||
// fix for IE11. It doesn't convert response to JSON
|
||||
if (xhr.responseType === '' && typeof(xhr.response) === 'string')
|
||||
callbacks.on200(JSON.parse(xhr.response));
|
||||
else
|
||||
callbacks.on200(xhr.response);
|
||||
}
|
||||
} else {
|
||||
// handled by onerror
|
||||
if (xhr.status === 0) return;
|
||||
|
||||
if (callbacks.onNon200)
|
||||
callbacks.onNon200(xhr);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.ontimeout = function () {
|
||||
if (callbacks.onTimeout)
|
||||
callbacks.onTimeout(xhr);
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
if (callbacks.onError)
|
||||
callbacks.onError(xhr);
|
||||
};
|
||||
|
||||
if (options.payload)
|
||||
xhr.send(options.payload);
|
||||
else
|
||||
xhr.send();
|
||||
},
|
||||
/** @private */
|
||||
_xhrRetry: function(method, url, options, callbacks) {
|
||||
if (options.retries <= 0) {
|
||||
console.warn('Failed to pull', options.entity_name);
|
||||
if (callbacks.onTotalFail)
|
||||
callbacks.onTotalFail();
|
||||
return;
|
||||
}
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
},
|
||||
/**
|
||||
* @callback callbackXhrOn200
|
||||
* @param {Object} response - xhr.response
|
||||
*/
|
||||
/**
|
||||
* @callback callbackXhrError
|
||||
* @param {XMLHttpRequest} xhr
|
||||
*/
|
||||
/**
|
||||
* @param {'GET'|'POST'} method - 'GET' or 'POST'
|
||||
* @param {String} url - URL to send request to
|
||||
* @param {Object} options - other XHR options
|
||||
* @param {XMLHttpRequestBodyInit} [options.payload=null] - payload for POST-requests
|
||||
* @param {'arraybuffer'|'blob'|'document'|'json'|'text'} [options.responseType=json]
|
||||
* @param {Number} [options.timeout=10000]
|
||||
* @param {Number} [options.retries=1]
|
||||
* @param {String} [options.entity_name='unknown'] - string to log
|
||||
* @param {Number} [options.retry_timeout=1000]
|
||||
* @param {Object} callbacks - functions to execute on events fired
|
||||
* @param {callbackXhrOn200} [callbacks.on200]
|
||||
* @param {callbackXhrError} [callbacks.onNon200]
|
||||
* @param {callbackXhrError} [callbacks.onTimeout]
|
||||
* @param {callbackXhrError} [callbacks.onError]
|
||||
* @param {callbackXhrError} [callbacks.onTotalFail] - if failed after all retries
|
||||
*/
|
||||
xhr: function(method, url, options, callbacks) {
|
||||
if (!options.retries || options.retries <= 1) {
|
||||
helpers._xhr(method, url, options, callbacks);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.entity_name) options.entity_name = 'unknown';
|
||||
if (!options.retry_timeout) options.retry_timeout = 1000;
|
||||
const retries_total = options.retries;
|
||||
let currentTry = 1;
|
||||
|
||||
const retry = function () {
|
||||
console.warn('Pulling ' + options.entity_name + ' failed... ' + (currentTry++) + '/' + retries_total);
|
||||
setTimeout(function () {
|
||||
options.retries--;
|
||||
helpers._xhrRetry(method, url, options, callbacks);
|
||||
}, options.retry_timeout);
|
||||
};
|
||||
|
||||
// Pack retry() call into error handlers
|
||||
callbacks._onError = callbacks.onError;
|
||||
callbacks.onError = function (xhr) {
|
||||
if (callbacks._onError)
|
||||
callbacks._onError(xhr);
|
||||
retry();
|
||||
};
|
||||
callbacks._onTimeout = callbacks.onTimeout;
|
||||
callbacks.onTimeout = function (xhr) {
|
||||
if (callbacks._onTimeout)
|
||||
callbacks._onTimeout(xhr);
|
||||
retry();
|
||||
};
|
||||
if (!options.entity_name) options.entity_name = "unknown";
|
||||
if (!options.retry_timeout) options.retry_timeout = 1000;
|
||||
const retries_total = options.retries;
|
||||
let currentTry = 1;
|
||||
|
||||
const retry = function () {
|
||||
console.warn(
|
||||
"Pulling " +
|
||||
options.entity_name +
|
||||
" failed... " +
|
||||
currentTry++ +
|
||||
"/" +
|
||||
retries_total,
|
||||
);
|
||||
setTimeout(function () {
|
||||
options.retries--;
|
||||
helpers._xhrRetry(method, url, options, callbacks);
|
||||
},
|
||||
}, options.retry_timeout);
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {Object} invidiousStorage
|
||||
* @property {(key:String) => Object} get
|
||||
* @property {(key:String, value:Object)} set
|
||||
* @property {(key:String)} remove
|
||||
*/
|
||||
// Pack retry() call into error handlers
|
||||
callbacks._onError = callbacks.onError;
|
||||
callbacks.onError = function (xhr) {
|
||||
if (callbacks._onError) callbacks._onError(xhr);
|
||||
retry();
|
||||
};
|
||||
callbacks._onTimeout = callbacks.onTimeout;
|
||||
callbacks.onTimeout = function (xhr) {
|
||||
if (callbacks._onTimeout) callbacks._onTimeout(xhr);
|
||||
retry();
|
||||
};
|
||||
|
||||
/**
|
||||
* Universal storage, stores and returns JS objects. Uses inside localStorage or cookies
|
||||
* @type {invidiousStorage}
|
||||
*/
|
||||
storage: (function () {
|
||||
// access to localStorage throws exception in Tor Browser, so try is needed
|
||||
let localStorageIsUsable = false;
|
||||
try{localStorageIsUsable = !!localStorage.setItem;}catch(e){}
|
||||
helpers._xhrRetry(method, url, options, callbacks);
|
||||
},
|
||||
|
||||
if (localStorageIsUsable) {
|
||||
return {
|
||||
get: function (key) {
|
||||
let storageItem = localStorage.getItem(key)
|
||||
if (!storageItem) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(storageItem));
|
||||
} catch(e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
let encoded_value = encodeURIComponent(JSON.stringify(value))
|
||||
localStorage.setItem(key, encoded_value);
|
||||
},
|
||||
remove: function (key) { localStorage.removeItem(key); }
|
||||
};
|
||||
/**
|
||||
* @typedef {Object} invidiousStorage
|
||||
* @property {(key:String) => Object} get
|
||||
* @property {(key:String, value:Object)} set
|
||||
* @property {(key:String)} remove
|
||||
*/
|
||||
|
||||
/**
|
||||
* Universal storage, stores and returns JS objects. Uses inside localStorage or cookies
|
||||
* @type {invidiousStorage}
|
||||
*/
|
||||
storage: (function () {
|
||||
// access to localStorage throws exception in Tor Browser, so try is needed
|
||||
let localStorageIsUsable = false;
|
||||
try {
|
||||
localStorageIsUsable = !!localStorage.setItem;
|
||||
} catch (e) {}
|
||||
|
||||
if (localStorageIsUsable) {
|
||||
return {
|
||||
get: function (key) {
|
||||
let storageItem = localStorage.getItem(key);
|
||||
if (!storageItem) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(storageItem));
|
||||
} catch (e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
let encoded_value = encodeURIComponent(JSON.stringify(value));
|
||||
localStorage.setItem(key, encoded_value);
|
||||
},
|
||||
remove: function (key) {
|
||||
localStorage.removeItem(key);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: fire 'storage' event for cookies
|
||||
console.info(
|
||||
"Storage: localStorage is disabled or unaccessible. Cookies used as fallback",
|
||||
);
|
||||
return {
|
||||
get: function (key) {
|
||||
const cookiePrefix = key + "=";
|
||||
function findCallback(cookie) {
|
||||
return cookie.startsWith(cookiePrefix);
|
||||
}
|
||||
const matchedCookie = document.cookie.split("; ").find(findCallback);
|
||||
if (matchedCookie) {
|
||||
const cookieBody = matchedCookie.replace(cookiePrefix, "");
|
||||
if (cookieBody.length === 0) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(cookieBody));
|
||||
} catch (e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
const cookie_data = encodeURIComponent(JSON.stringify(value));
|
||||
|
||||
// TODO: fire 'storage' event for cookies
|
||||
console.info('Storage: localStorage is disabled or unaccessible. Cookies used as fallback');
|
||||
return {
|
||||
get: function (key) {
|
||||
const cookiePrefix = key + '=';
|
||||
function findCallback(cookie) {return cookie.startsWith(cookiePrefix);}
|
||||
const matchedCookie = document.cookie.split('; ').find(findCallback);
|
||||
if (matchedCookie) {
|
||||
const cookieBody = matchedCookie.replace(cookiePrefix, '');
|
||||
if (cookieBody.length === 0) return;
|
||||
try {
|
||||
return JSON.parse(decodeURIComponent(cookieBody));
|
||||
} catch(e) {
|
||||
// Erase non parsable value
|
||||
helpers.storage.remove(key);
|
||||
}
|
||||
}
|
||||
},
|
||||
set: function (key, value) {
|
||||
const cookie_data = encodeURIComponent(JSON.stringify(value));
|
||||
// Set expiration in 2 year
|
||||
const date = new Date();
|
||||
date.setFullYear(date.getFullYear() + 2);
|
||||
|
||||
// Set expiration in 2 year
|
||||
const date = new Date();
|
||||
date.setFullYear(date.getFullYear()+2);
|
||||
|
||||
document.cookie = key + '=' + cookie_data + '; expires=' + date.toGMTString();
|
||||
},
|
||||
remove: function (key) {
|
||||
document.cookie = key + '=; Max-Age=0';
|
||||
}
|
||||
};
|
||||
})()
|
||||
document.cookie =
|
||||
key + "=" + cookie_data + "; expires=" + date.toGMTString();
|
||||
},
|
||||
remove: function (key) {
|
||||
document.cookie = key + "=; Max-Age=0";
|
||||
},
|
||||
};
|
||||
})(),
|
||||
};
|
||||
|
@ -1,81 +1,91 @@
|
||||
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||
var video_data = JSON.parse(document.getElementById("video_data").textContent);
|
||||
|
||||
var spinnerHTML = '<div class="loading"><i class="icon ion-ios-refresh"></i></div>';
|
||||
var spinnerHTMLwithHR = spinnerHTML + '<hr>';
|
||||
var spinnerHTML =
|
||||
'<div class="loading"><i class="icon ion-ios-refresh"></i></div>';
|
||||
var spinnerHTMLwithHR = spinnerHTML + "<hr>";
|
||||
|
||||
String.prototype.supplant = function (o) {
|
||||
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
||||
var r = o[b];
|
||||
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
||||
});
|
||||
return this.replace(/{([^{}]*)}/g, function (a, b) {
|
||||
var r = o[b];
|
||||
return typeof r === "string" || typeof r === "number" ? r : a;
|
||||
});
|
||||
};
|
||||
|
||||
function toggle_comments(event) {
|
||||
const target = event.target;
|
||||
const comments = document.querySelector(".comments");
|
||||
if (comments.style.display === 'none') {
|
||||
target.textContent = '−';
|
||||
comments.style.display = '';
|
||||
} else {
|
||||
target.textContent = '+';
|
||||
comments.style.display = 'none';
|
||||
}
|
||||
const target = event.target;
|
||||
const comments = document.querySelector(".comments");
|
||||
if (comments.style.display === "none") {
|
||||
target.textContent = "−";
|
||||
comments.style.display = "";
|
||||
} else {
|
||||
target.textContent = "+";
|
||||
comments.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function hide_youtube_replies(event) {
|
||||
var target = event.target;
|
||||
var target = event.target;
|
||||
|
||||
var sub_text = target.getAttribute('data-inner-text');
|
||||
var inner_text = target.getAttribute('data-sub-text');
|
||||
var sub_text = target.getAttribute("data-inner-text");
|
||||
var inner_text = target.getAttribute("data-sub-text");
|
||||
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = 'none';
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = "none";
|
||||
|
||||
target.textContent = sub_text;
|
||||
target.onclick = show_youtube_replies;
|
||||
target.setAttribute('data-inner-text', inner_text);
|
||||
target.setAttribute('data-sub-text', sub_text);
|
||||
target.textContent = sub_text;
|
||||
target.onclick = show_youtube_replies;
|
||||
target.setAttribute("data-inner-text", inner_text);
|
||||
target.setAttribute("data-sub-text", sub_text);
|
||||
}
|
||||
|
||||
function show_youtube_replies(event) {
|
||||
var target = event.target;
|
||||
console.log(target);
|
||||
var target = event.target;
|
||||
console.log(target);
|
||||
|
||||
var sub_text = target.getAttribute('data-inner-text');
|
||||
var inner_text = target.getAttribute('data-sub-text');
|
||||
var sub_text = target.getAttribute("data-inner-text");
|
||||
var inner_text = target.getAttribute("data-sub-text");
|
||||
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = '';
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = "";
|
||||
|
||||
target.textContent = sub_text;
|
||||
target.onclick = hide_youtube_replies;
|
||||
target.setAttribute('data-inner-text', inner_text);
|
||||
target.setAttribute('data-sub-text', sub_text);
|
||||
target.textContent = sub_text;
|
||||
target.onclick = hide_youtube_replies;
|
||||
target.setAttribute("data-inner-text", inner_text);
|
||||
target.setAttribute("data-sub-text", sub_text);
|
||||
}
|
||||
|
||||
function get_youtube_comments() {
|
||||
var comments = document.getElementById('comments');
|
||||
var comments = document.getElementById("comments");
|
||||
|
||||
var fallback = comments.innerHTML;
|
||||
comments.innerHTML = spinnerHTML;
|
||||
var fallback = comments.innerHTML;
|
||||
comments.innerHTML = spinnerHTML;
|
||||
|
||||
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
|
||||
var url = baseUrl +
|
||||
'?format=html' +
|
||||
'&hl=' + video_data.preferences.locale +
|
||||
'&thin_mode=' + video_data.preferences.thin_mode;
|
||||
var baseUrl = video_data.base_url || "/api/v1/comments/" + video_data.id;
|
||||
var url =
|
||||
baseUrl +
|
||||
"?format=html" +
|
||||
"&hl=" +
|
||||
video_data.preferences.locale +
|
||||
"&thin_mode=" +
|
||||
video_data.preferences.thin_mode;
|
||||
|
||||
if (video_data.ucid) {
|
||||
url += '&ucid=' + video_data.ucid
|
||||
}
|
||||
if (video_data.ucid) {
|
||||
url += "&ucid=" + video_data.ucid;
|
||||
}
|
||||
|
||||
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
|
||||
if (video_data.params.comments[1] === 'youtube')
|
||||
onNon200 = function (xhr) {};
|
||||
var onNon200 = function (xhr) {
|
||||
comments.innerHTML = fallback;
|
||||
};
|
||||
if (video_data.params.comments[1] === "youtube") onNon200 = function (xhr) {};
|
||||
|
||||
helpers.xhr('GET', url, {retries: 5, entity_name: 'comments'}, {
|
||||
on200: function (response) {
|
||||
var commentInnerHtml = ' \
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
url,
|
||||
{ retries: 5, entity_name: "comments" },
|
||||
{
|
||||
on200: function (response) {
|
||||
var commentInnerHtml =
|
||||
' \
|
||||
<nav class="comments-header"> \
|
||||
<ul> \
|
||||
<li> \
|
||||
@ -83,92 +93,104 @@ function get_youtube_comments() {
|
||||
{commentsText} \
|
||||
</li> \
|
||||
\
|
||||
<li>'
|
||||
if (video_data.support_reddit) {
|
||||
commentInnerHtml += ' <button data-comments="reddit"> \
|
||||
<li>';
|
||||
if (video_data.support_reddit) {
|
||||
commentInnerHtml +=
|
||||
' <button data-comments="reddit"> \
|
||||
{redditComments} \
|
||||
</button> \
|
||||
'
|
||||
}
|
||||
commentInnerHtml += ' </li> \
|
||||
';
|
||||
}
|
||||
commentInnerHtml +=
|
||||
' </li> \
|
||||
</ul> \
|
||||
</nav> \
|
||||
<div class="comments">{contentHtml}</div>'
|
||||
commentInnerHtml = commentInnerHtml.supplant({
|
||||
contentHtml: response.contentHtml,
|
||||
redditComments: video_data.reddit_comments_text,
|
||||
commentsText: video_data.comments_text.supplant({
|
||||
// toLocaleString correctly splits number with local thousands separator. e.g.:
|
||||
// '1,234,567.89' for user with English locale
|
||||
// '1 234 567,89' for user with Russian locale
|
||||
// '1.234.567,89' for user with Portuguese locale
|
||||
commentCount: response.commentCount.toLocaleString()
|
||||
})
|
||||
});
|
||||
comments.innerHTML = commentInnerHtml;
|
||||
document.getElementById("toggle-comments").onclick = toggle_comments;
|
||||
if (video_data.support_reddit) {
|
||||
comments.children[1].children[1].onclick = swap_comments;
|
||||
}
|
||||
},
|
||||
onNon200: onNon200, // declared above
|
||||
onError: function (xhr) {
|
||||
comments.innerHTML = spinnerHTML;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
comments.innerHTML = spinnerHTML;
|
||||
<div class="comments">{contentHtml}</div>';
|
||||
commentInnerHtml = commentInnerHtml.supplant({
|
||||
contentHtml: response.contentHtml,
|
||||
redditComments: video_data.reddit_comments_text,
|
||||
commentsText: video_data.comments_text.supplant({
|
||||
// toLocaleString correctly splits number with local thousands separator. e.g.:
|
||||
// '1,234,567.89' for user with English locale
|
||||
// '1 234 567,89' for user with Russian locale
|
||||
// '1.234.567,89' for user with Portuguese locale
|
||||
commentCount: response.commentCount.toLocaleString(),
|
||||
}),
|
||||
});
|
||||
comments.innerHTML = commentInnerHtml;
|
||||
document.getElementById("toggle-comments").onclick = toggle_comments;
|
||||
if (video_data.support_reddit) {
|
||||
comments.children[1].children[1].onclick = swap_comments;
|
||||
}
|
||||
});
|
||||
},
|
||||
onNon200: onNon200, // declared above
|
||||
onError: function (xhr) {
|
||||
comments.innerHTML = spinnerHTML;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
comments.innerHTML = spinnerHTML;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function get_youtube_replies(target, load_more, load_replies) {
|
||||
var continuation = target.getAttribute('data-continuation');
|
||||
var continuation = target.getAttribute("data-continuation");
|
||||
|
||||
var body = target.parentNode;
|
||||
var fallback = body.innerHTML;
|
||||
body.innerHTML = spinnerHTML;
|
||||
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
|
||||
var url = baseUrl +
|
||||
'?format=html' +
|
||||
'&hl=' + video_data.preferences.locale +
|
||||
'&thin_mode=' + video_data.preferences.thin_mode +
|
||||
'&continuation=' + continuation;
|
||||
var body = target.parentNode;
|
||||
var fallback = body.innerHTML;
|
||||
body.innerHTML = spinnerHTML;
|
||||
var baseUrl = video_data.base_url || "/api/v1/comments/" + video_data.id;
|
||||
var url =
|
||||
baseUrl +
|
||||
"?format=html" +
|
||||
"&hl=" +
|
||||
video_data.preferences.locale +
|
||||
"&thin_mode=" +
|
||||
video_data.preferences.thin_mode +
|
||||
"&continuation=" +
|
||||
continuation;
|
||||
|
||||
if (video_data.ucid) {
|
||||
url += '&ucid=' + video_data.ucid
|
||||
}
|
||||
if (load_replies) url += '&action=action_get_comment_replies';
|
||||
if (video_data.ucid) {
|
||||
url += "&ucid=" + video_data.ucid;
|
||||
}
|
||||
if (load_replies) url += "&action=action_get_comment_replies";
|
||||
|
||||
helpers.xhr('GET', url, {}, {
|
||||
on200: function (response) {
|
||||
if (load_more) {
|
||||
body = body.parentNode;
|
||||
body.removeChild(body.lastElementChild);
|
||||
body.insertAdjacentHTML('beforeend', response.contentHtml);
|
||||
} else {
|
||||
body.removeChild(body.lastElementChild);
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
url,
|
||||
{},
|
||||
{
|
||||
on200: function (response) {
|
||||
if (load_more) {
|
||||
body = body.parentNode;
|
||||
body.removeChild(body.lastElementChild);
|
||||
body.insertAdjacentHTML("beforeend", response.contentHtml);
|
||||
} else {
|
||||
body.removeChild(body.lastElementChild);
|
||||
|
||||
var div = document.createElement('div');
|
||||
var button = document.createElement('button');
|
||||
div.appendChild(button);
|
||||
var div = document.createElement("div");
|
||||
var button = document.createElement("button");
|
||||
div.appendChild(button);
|
||||
|
||||
button.onclick = hide_youtube_replies;
|
||||
button.setAttribute('data-sub-text', video_data.hide_replies_text);
|
||||
button.setAttribute('data-inner-text', video_data.show_replies_text);
|
||||
button.textContent = video_data.hide_replies_text;
|
||||
button.onclick = hide_youtube_replies;
|
||||
button.setAttribute("data-sub-text", video_data.hide_replies_text);
|
||||
button.setAttribute("data-inner-text", video_data.show_replies_text);
|
||||
button.textContent = video_data.hide_replies_text;
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = response.contentHtml;
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = response.contentHtml;
|
||||
|
||||
body.appendChild(div);
|
||||
}
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
console.warn('Pulling comments failed');
|
||||
body.innerHTML = fallback;
|
||||
body.appendChild(div);
|
||||
}
|
||||
});
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
console.warn("Pulling comments failed");
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,82 +1,94 @@
|
||||
'use strict';
|
||||
var community_data = JSON.parse(document.getElementById('community_data').textContent);
|
||||
"use strict";
|
||||
var community_data = JSON.parse(
|
||||
document.getElementById("community_data").textContent,
|
||||
);
|
||||
|
||||
function hide_youtube_replies(event) {
|
||||
var target = event.target;
|
||||
var target = event.target;
|
||||
|
||||
var sub_text = target.getAttribute('data-inner-text');
|
||||
var inner_text = target.getAttribute('data-sub-text');
|
||||
var sub_text = target.getAttribute("data-inner-text");
|
||||
var inner_text = target.getAttribute("data-sub-text");
|
||||
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = 'none';
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = "none";
|
||||
|
||||
target.innerHTML = sub_text;
|
||||
target.onclick = show_youtube_replies;
|
||||
target.setAttribute('data-inner-text', inner_text);
|
||||
target.setAttribute('data-sub-text', sub_text);
|
||||
target.innerHTML = sub_text;
|
||||
target.onclick = show_youtube_replies;
|
||||
target.setAttribute("data-inner-text", inner_text);
|
||||
target.setAttribute("data-sub-text", sub_text);
|
||||
}
|
||||
|
||||
function show_youtube_replies(event) {
|
||||
var target = event.target;
|
||||
var target = event.target;
|
||||
|
||||
var sub_text = target.getAttribute('data-inner-text');
|
||||
var inner_text = target.getAttribute('data-sub-text');
|
||||
var sub_text = target.getAttribute("data-inner-text");
|
||||
var inner_text = target.getAttribute("data-sub-text");
|
||||
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = '';
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
body.style.display = "";
|
||||
|
||||
target.innerHTML = sub_text;
|
||||
target.onclick = hide_youtube_replies;
|
||||
target.setAttribute('data-inner-text', inner_text);
|
||||
target.setAttribute('data-sub-text', sub_text);
|
||||
target.innerHTML = sub_text;
|
||||
target.onclick = hide_youtube_replies;
|
||||
target.setAttribute("data-inner-text", inner_text);
|
||||
target.setAttribute("data-sub-text", sub_text);
|
||||
}
|
||||
|
||||
function get_youtube_replies(target, load_more) {
|
||||
var continuation = target.getAttribute('data-continuation');
|
||||
var continuation = target.getAttribute("data-continuation");
|
||||
|
||||
var body = target.parentNode.parentNode;
|
||||
var fallback = body.innerHTML;
|
||||
body.innerHTML =
|
||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
||||
var body = target.parentNode.parentNode;
|
||||
var fallback = body.innerHTML;
|
||||
body.innerHTML =
|
||||
'<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
||||
|
||||
var url = '/api/v1/channels/comments/' + community_data.ucid +
|
||||
'?format=html' +
|
||||
'&hl=' + community_data.preferences.locale +
|
||||
'&thin_mode=' + community_data.preferences.thin_mode +
|
||||
'&continuation=' + continuation;
|
||||
var url =
|
||||
"/api/v1/channels/comments/" +
|
||||
community_data.ucid +
|
||||
"?format=html" +
|
||||
"&hl=" +
|
||||
community_data.preferences.locale +
|
||||
"&thin_mode=" +
|
||||
community_data.preferences.thin_mode +
|
||||
"&continuation=" +
|
||||
continuation;
|
||||
|
||||
helpers.xhr('GET', url, {}, {
|
||||
on200: function (response) {
|
||||
if (load_more) {
|
||||
body = body.parentNode.parentNode;
|
||||
body.removeChild(body.lastElementChild);
|
||||
body.innerHTML += response.contentHtml;
|
||||
} else {
|
||||
body.removeChild(body.lastElementChild);
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
url,
|
||||
{},
|
||||
{
|
||||
on200: function (response) {
|
||||
if (load_more) {
|
||||
body = body.parentNode.parentNode;
|
||||
body.removeChild(body.lastElementChild);
|
||||
body.innerHTML += response.contentHtml;
|
||||
} else {
|
||||
body.removeChild(body.lastElementChild);
|
||||
|
||||
var p = document.createElement('p');
|
||||
var a = document.createElement('a');
|
||||
p.appendChild(a);
|
||||
var p = document.createElement("p");
|
||||
var a = document.createElement("a");
|
||||
p.appendChild(a);
|
||||
|
||||
a.href = 'javascript:void(0)';
|
||||
a.onclick = hide_youtube_replies;
|
||||
a.setAttribute('data-sub-text', community_data.hide_replies_text);
|
||||
a.setAttribute('data-inner-text', community_data.show_replies_text);
|
||||
a.textContent = community_data.hide_replies_text;
|
||||
a.href = "javascript:void(0)";
|
||||
a.onclick = hide_youtube_replies;
|
||||
a.setAttribute("data-sub-text", community_data.hide_replies_text);
|
||||
a.setAttribute("data-inner-text", community_data.show_replies_text);
|
||||
a.textContent = community_data.hide_replies_text;
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = response.contentHtml;
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = response.contentHtml;
|
||||
|
||||
body.appendChild(p);
|
||||
body.appendChild(div);
|
||||
}
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
console.warn('Pulling comments failed');
|
||||
body.innerHTML = fallback;
|
||||
body.appendChild(p);
|
||||
body.appendChild(div);
|
||||
}
|
||||
});
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
console.warn("Pulling comments failed");
|
||||
body.innerHTML = fallback;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,64 +1,79 @@
|
||||
'use strict';
|
||||
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||
"use strict";
|
||||
var video_data = JSON.parse(document.getElementById("video_data").textContent);
|
||||
|
||||
function get_playlist(plid) {
|
||||
var plid_url;
|
||||
if (plid.startsWith('RD')) {
|
||||
plid_url = '/api/v1/mixes/' + plid +
|
||||
'?continuation=' + video_data.id +
|
||||
'&format=html&hl=' + video_data.preferences.locale;
|
||||
} else {
|
||||
plid_url = '/api/v1/playlists/' + plid +
|
||||
'?index=' + video_data.index +
|
||||
'&continuation' + video_data.id +
|
||||
'&format=html&hl=' + video_data.preferences.locale;
|
||||
}
|
||||
var plid_url;
|
||||
if (plid.startsWith("RD")) {
|
||||
plid_url =
|
||||
"/api/v1/mixes/" +
|
||||
plid +
|
||||
"?continuation=" +
|
||||
video_data.id +
|
||||
"&format=html&hl=" +
|
||||
video_data.preferences.locale;
|
||||
} else {
|
||||
plid_url =
|
||||
"/api/v1/playlists/" +
|
||||
plid +
|
||||
"?index=" +
|
||||
video_data.index +
|
||||
"&continuation" +
|
||||
video_data.id +
|
||||
"&format=html&hl=" +
|
||||
video_data.preferences.locale;
|
||||
}
|
||||
|
||||
helpers.xhr('GET', plid_url, {retries: 5, entity_name: 'playlist'}, {
|
||||
on200: function (response) {
|
||||
if (!response.nextVideo)
|
||||
return;
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
plid_url,
|
||||
{ retries: 5, entity_name: "playlist" },
|
||||
{
|
||||
on200: function (response) {
|
||||
if (!response.nextVideo) return;
|
||||
|
||||
player.on('ended', function () {
|
||||
var url = new URL('https://example.com/embed/' + response.nextVideo);
|
||||
player.on("ended", function () {
|
||||
var url = new URL("https://example.com/embed/" + response.nextVideo);
|
||||
|
||||
url.searchParams.set('list', plid);
|
||||
if (!plid.startsWith('RD'))
|
||||
url.searchParams.set('index', response.index);
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set('autoplay', '1');
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set('listen', video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set('speed', video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set('local', video_data.params.local);
|
||||
url.searchParams.set("list", plid);
|
||||
if (!plid.startsWith("RD"))
|
||||
url.searchParams.set("index", response.index);
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set("autoplay", "1");
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set("listen", video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set("speed", video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set("local", video_data.params.local);
|
||||
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
}
|
||||
});
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
addEventListener('load', function (e) {
|
||||
if (video_data.plid) {
|
||||
get_playlist(video_data.plid);
|
||||
} else if (video_data.video_series) {
|
||||
player.on('ended', function () {
|
||||
var url = new URL('https://example.com/embed/' + video_data.video_series.shift());
|
||||
addEventListener("load", function (e) {
|
||||
if (video_data.plid) {
|
||||
get_playlist(video_data.plid);
|
||||
} else if (video_data.video_series) {
|
||||
player.on("ended", function () {
|
||||
var url = new URL(
|
||||
"https://example.com/embed/" + video_data.video_series.shift(),
|
||||
);
|
||||
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set('autoplay', '1');
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set('listen', video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set('speed', video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set('local', video_data.params.local);
|
||||
if (video_data.video_series.length !== 0)
|
||||
url.searchParams.set('playlist', video_data.video_series.join(','));
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set("autoplay", "1");
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set("listen", video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set("speed", video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set("local", video_data.params.local);
|
||||
if (video_data.video_series.length !== 0)
|
||||
url.searchParams.set("playlist", video_data.video_series.join(","));
|
||||
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
}
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,149 +1,220 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
var video_player = document.getElementById('player_html5_api');
|
||||
if (video_player) {
|
||||
video_player.onmouseenter = function () { video_player['data-title'] = video_player['title']; video_player['title'] = ''; };
|
||||
video_player.onmouseleave = function () { video_player['title'] = video_player['data-title']; video_player['data-title'] = ''; };
|
||||
video_player.oncontextmenu = function () { video_player['title'] = video_player['data-title']; };
|
||||
var video_player = document.getElementById("player_html5_api");
|
||||
if (video_player) {
|
||||
video_player.onmouseenter = function () {
|
||||
video_player["data-title"] = video_player["title"];
|
||||
video_player["title"] = "";
|
||||
};
|
||||
video_player.onmouseleave = function () {
|
||||
video_player["title"] = video_player["data-title"];
|
||||
video_player["data-title"] = "";
|
||||
};
|
||||
video_player.oncontextmenu = function () {
|
||||
video_player["title"] = video_player["data-title"];
|
||||
};
|
||||
}
|
||||
|
||||
// For dynamically inserted elements
|
||||
addEventListener("click", function (e) {
|
||||
if (!e || !e.target) return;
|
||||
|
||||
var t = e.target;
|
||||
var handler_name = t.getAttribute("data-onclick");
|
||||
|
||||
switch (handler_name) {
|
||||
case "jump_to_time":
|
||||
e.preventDefault();
|
||||
var time = t.getAttribute("data-jump-time");
|
||||
player.currentTime(time);
|
||||
break;
|
||||
case "get_youtube_replies":
|
||||
var load_more = t.getAttribute("data-load-more") !== null;
|
||||
var load_replies = t.getAttribute("data-load-replies") !== null;
|
||||
get_youtube_replies(t, load_more, load_replies);
|
||||
break;
|
||||
case "toggle_parent":
|
||||
e.preventDefault();
|
||||
toggle_parent(t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-mouse="switch_classes"]')
|
||||
.forEach(function (el) {
|
||||
var classes = el.getAttribute("data-switch-classes").split(",");
|
||||
var classOnEnter = classes[0];
|
||||
var classOnLeave = classes[1];
|
||||
function toggle_classes(toAdd, toRemove) {
|
||||
el.classList.add(toAdd);
|
||||
el.classList.remove(toRemove);
|
||||
}
|
||||
el.onmouseenter = function () {
|
||||
toggle_classes(classOnEnter, classOnLeave);
|
||||
};
|
||||
el.onmouseleave = function () {
|
||||
toggle_classes(classOnLeave, classOnEnter);
|
||||
};
|
||||
});
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-onsubmit="return_false"]')
|
||||
.forEach(function (el) {
|
||||
el.onsubmit = function () {
|
||||
return false;
|
||||
};
|
||||
});
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-onclick="mark_watched"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function () {
|
||||
mark_watched(el);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="mark_unwatched"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function () {
|
||||
mark_unwatched(el);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="add_playlist_video"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function (e) {
|
||||
add_playlist_video(e);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="add_playlist_item"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function (e) {
|
||||
add_playlist_item(e);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="remove_playlist_item"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function (e) {
|
||||
remove_playlist_item(e);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="revoke_token"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function () {
|
||||
revoke_token(el);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="remove_subscription"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function () {
|
||||
remove_subscription(el);
|
||||
};
|
||||
});
|
||||
document
|
||||
.querySelectorAll('[data-onclick="notification_requestPermission"]')
|
||||
.forEach(function (el) {
|
||||
el.onclick = function () {
|
||||
Notification.requestPermission();
|
||||
};
|
||||
});
|
||||
|
||||
document
|
||||
.querySelectorAll('[data-onrange="update_volume_value"]')
|
||||
.forEach(function (el) {
|
||||
function update_volume_value() {
|
||||
document.getElementById("volume-value").textContent = el.value;
|
||||
}
|
||||
el.oninput = update_volume_value;
|
||||
el.onchange = update_volume_value;
|
||||
});
|
||||
|
||||
function revoke_token(target) {
|
||||
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
row.style.display = "none";
|
||||
var count = document.getElementById("count");
|
||||
count.textContent--;
|
||||
|
||||
var url =
|
||||
"/token_ajax?action=revoke_token&redirect=false" +
|
||||
"&referer=" +
|
||||
encodeURIComponent(location.href) +
|
||||
"&session=" +
|
||||
target.getAttribute("data-session");
|
||||
|
||||
var payload =
|
||||
"csrf_token=" +
|
||||
target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
row.style.display = "";
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function remove_subscription(target) {
|
||||
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
row.style.display = "none";
|
||||
var count = document.getElementById("count");
|
||||
count.textContent--;
|
||||
|
||||
var url =
|
||||
"/subscription_ajax?action=remove_subscriptions&redirect=false" +
|
||||
"&referer=" +
|
||||
encodeURIComponent(location.href) +
|
||||
"&c=" +
|
||||
target.getAttribute("data-ucid");
|
||||
|
||||
var payload =
|
||||
"csrf_token=" +
|
||||
target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
row.style.display = "";
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Handle keypresses
|
||||
addEventListener("keydown", function (event) {
|
||||
// Ignore modifier keys
|
||||
if (event.ctrlKey || event.metaKey) return;
|
||||
|
||||
// Ignore shortcuts if any text input is focused
|
||||
let focused_tag = document.activeElement.tagName.toLowerCase();
|
||||
const allowed = /^(button|checkbox|file|radio|submit)$/;
|
||||
|
||||
if (focused_tag === "textarea") return;
|
||||
if (focused_tag === "input") {
|
||||
let focused_type = document.activeElement.type.toLowerCase();
|
||||
if (!allowed.test(focused_type)) return;
|
||||
}
|
||||
|
||||
// For dynamically inserted elements
|
||||
addEventListener('click', function (e) {
|
||||
if (!e || !e.target) return;
|
||||
|
||||
var t = e.target;
|
||||
var handler_name = t.getAttribute('data-onclick');
|
||||
|
||||
switch (handler_name) {
|
||||
case 'jump_to_time':
|
||||
e.preventDefault();
|
||||
var time = t.getAttribute('data-jump-time');
|
||||
player.currentTime(time);
|
||||
break;
|
||||
case 'get_youtube_replies':
|
||||
var load_more = t.getAttribute('data-load-more') !== null;
|
||||
var load_replies = t.getAttribute('data-load-replies') !== null;
|
||||
get_youtube_replies(t, load_more, load_replies);
|
||||
break;
|
||||
case 'toggle_parent':
|
||||
e.preventDefault();
|
||||
toggle_parent(t);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-mouse="switch_classes"]').forEach(function (el) {
|
||||
var classes = el.getAttribute('data-switch-classes').split(',');
|
||||
var classOnEnter = classes[0];
|
||||
var classOnLeave = classes[1];
|
||||
function toggle_classes(toAdd, toRemove) {
|
||||
el.classList.add(toAdd);
|
||||
el.classList.remove(toRemove);
|
||||
}
|
||||
el.onmouseenter = function () { toggle_classes(classOnEnter, classOnLeave); };
|
||||
el.onmouseleave = function () { toggle_classes(classOnLeave, classOnEnter); };
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-onsubmit="return_false"]').forEach(function (el) {
|
||||
el.onsubmit = function () { return false; };
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-onclick="mark_watched"]').forEach(function (el) {
|
||||
el.onclick = function () { mark_watched(el); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="mark_unwatched"]').forEach(function (el) {
|
||||
el.onclick = function () { mark_unwatched(el); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="add_playlist_video"]').forEach(function (el) {
|
||||
el.onclick = function (e) { add_playlist_video(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="add_playlist_item"]').forEach(function (el) {
|
||||
el.onclick = function (e) { add_playlist_item(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="remove_playlist_item"]').forEach(function (el) {
|
||||
el.onclick = function (e) { remove_playlist_item(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="revoke_token"]').forEach(function (el) {
|
||||
el.onclick = function () { revoke_token(el); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="remove_subscription"]').forEach(function (el) {
|
||||
el.onclick = function () { remove_subscription(el); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="notification_requestPermission"]').forEach(function (el) {
|
||||
el.onclick = function () { Notification.requestPermission(); };
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-onrange="update_volume_value"]').forEach(function (el) {
|
||||
function update_volume_value() {
|
||||
document.getElementById('volume-value').textContent = el.value;
|
||||
}
|
||||
el.oninput = update_volume_value;
|
||||
el.onchange = update_volume_value;
|
||||
});
|
||||
|
||||
|
||||
function revoke_token(target) {
|
||||
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
row.style.display = 'none';
|
||||
var count = document.getElementById('count');
|
||||
count.textContent--;
|
||||
|
||||
var url = '/token_ajax?action=revoke_token&redirect=false' +
|
||||
'&referer=' + encodeURIComponent(location.href) +
|
||||
'&session=' + target.getAttribute('data-session');
|
||||
|
||||
var payload = 'csrf_token=' + target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
row.style.display = '';
|
||||
}
|
||||
});
|
||||
// Focus search bar on '/'
|
||||
if (event.key === "/") {
|
||||
document.getElementById("searchbox").focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function remove_subscription(target) {
|
||||
var row = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
row.style.display = 'none';
|
||||
var count = document.getElementById('count');
|
||||
count.textContent--;
|
||||
|
||||
var url = '/subscription_ajax?action=remove_subscriptions&redirect=false' +
|
||||
'&referer=' + encodeURIComponent(location.href) +
|
||||
'&c=' + target.getAttribute('data-ucid');
|
||||
|
||||
var payload = 'csrf_token=' + target.parentNode.querySelector('input[name="csrf_token"]').value;
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
row.style.display = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Handle keypresses
|
||||
addEventListener('keydown', function (event) {
|
||||
// Ignore modifier keys
|
||||
if (event.ctrlKey || event.metaKey) return;
|
||||
|
||||
// Ignore shortcuts if any text input is focused
|
||||
let focused_tag = document.activeElement.tagName.toLowerCase();
|
||||
const allowed = /^(button|checkbox|file|radio|submit)$/;
|
||||
|
||||
if (focused_tag === 'textarea') return;
|
||||
if (focused_tag === 'input') {
|
||||
let focused_type = document.activeElement.type.toLowerCase();
|
||||
if (!allowed.test(focused_type)) return;
|
||||
}
|
||||
|
||||
// Focus search bar on '/'
|
||||
if (event.key === '/') {
|
||||
document.getElementById('searchbox').focus();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
@ -31,7 +31,11 @@ async function get_subscriptions_call() {
|
||||
}
|
||||
|
||||
// Start the retry mechanism
|
||||
const get_subscriptions = exponential_backoff(get_subscriptions_call, 100, 1000);
|
||||
const get_subscriptions = exponential_backoff(
|
||||
get_subscriptions_call,
|
||||
100,
|
||||
1000,
|
||||
);
|
||||
|
||||
function create_notification_stream(subscriptions) {
|
||||
// sse.js can't be replaced to EventSource in place as it lack support of payload and headers
|
||||
@ -96,7 +100,6 @@ function create_notification_stream(subscriptions) {
|
||||
"Something went wrong with notifications, trying to reconnect...",
|
||||
);
|
||||
notifications = notifications_mock;
|
||||
|
||||
});
|
||||
|
||||
notifications.stream();
|
||||
@ -177,7 +180,7 @@ function exponential_backoff(
|
||||
return function tryFunction() {
|
||||
fn()
|
||||
.then((response) => {
|
||||
attempt = 0;
|
||||
attempt = 0;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (attempt < maxRetries) {
|
||||
@ -193,5 +196,5 @@ function exponential_backoff(
|
||||
console.log("Max retries reached. Operation failed:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,93 +1,103 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const CURRENT_CONTINUATION = (new URL(document.location)).searchParams.get("continuation");
|
||||
const CURRENT_CONTINUATION = new URL(document.location).searchParams.get(
|
||||
"continuation",
|
||||
);
|
||||
const CONT_CACHE_KEY = `continuation_cache_${encodeURIComponent(window.location.pathname)}`;
|
||||
|
||||
function get_data(){
|
||||
return JSON.parse(sessionStorage.getItem(CONT_CACHE_KEY)) || [];
|
||||
function get_data() {
|
||||
return JSON.parse(sessionStorage.getItem(CONT_CACHE_KEY)) || [];
|
||||
}
|
||||
|
||||
function save_data(){
|
||||
const prev_data = get_data();
|
||||
prev_data.push(CURRENT_CONTINUATION);
|
||||
function save_data() {
|
||||
const prev_data = get_data();
|
||||
prev_data.push(CURRENT_CONTINUATION);
|
||||
|
||||
sessionStorage.setItem(CONT_CACHE_KEY, JSON.stringify(prev_data));
|
||||
sessionStorage.setItem(CONT_CACHE_KEY, JSON.stringify(prev_data));
|
||||
}
|
||||
|
||||
function button_press(){
|
||||
let prev_data = get_data();
|
||||
if (!prev_data.length) return null;
|
||||
function button_press() {
|
||||
let prev_data = get_data();
|
||||
if (!prev_data.length) return null;
|
||||
|
||||
// Sanity check. Nowhere should the current continuation token exist in the cache
|
||||
// but it can happen when using the browser's back feature. As such we'd need to travel
|
||||
// back to the point where the current continuation token first appears in order to
|
||||
// account for the rewind.
|
||||
const conflict_at = prev_data.indexOf(CURRENT_CONTINUATION);
|
||||
if (conflict_at != -1) {
|
||||
prev_data.length = conflict_at;
|
||||
}
|
||||
// Sanity check. Nowhere should the current continuation token exist in the cache
|
||||
// but it can happen when using the browser's back feature. As such we'd need to travel
|
||||
// back to the point where the current continuation token first appears in order to
|
||||
// account for the rewind.
|
||||
const conflict_at = prev_data.indexOf(CURRENT_CONTINUATION);
|
||||
if (conflict_at != -1) {
|
||||
prev_data.length = conflict_at;
|
||||
}
|
||||
|
||||
const prev_ctoken = prev_data.pop();
|
||||
|
||||
// On the first page, the stored continuation token is null.
|
||||
if (prev_ctoken === null) {
|
||||
sessionStorage.removeItem(CONT_CACHE_KEY);
|
||||
let url = set_continuation();
|
||||
window.location.href = url;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem(CONT_CACHE_KEY, JSON.stringify(prev_data));
|
||||
let url = set_continuation(prev_ctoken);
|
||||
const prev_ctoken = prev_data.pop();
|
||||
|
||||
// On the first page, the stored continuation token is null.
|
||||
if (prev_ctoken === null) {
|
||||
sessionStorage.removeItem(CONT_CACHE_KEY);
|
||||
let url = set_continuation();
|
||||
window.location.href = url;
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sessionStorage.setItem(CONT_CACHE_KEY, JSON.stringify(prev_data));
|
||||
let url = set_continuation(prev_ctoken);
|
||||
|
||||
window.location.href = url;
|
||||
}
|
||||
|
||||
// Method to set the current page's continuation token
|
||||
// Removes the continuation parameter when a continuation token is not given
|
||||
function set_continuation(prev_ctoken = null){
|
||||
let url = window.location.href.split('?')[0];
|
||||
let params = window.location.href.split('?')[1];
|
||||
let url_params = new URLSearchParams(params);
|
||||
function set_continuation(prev_ctoken = null) {
|
||||
let url = window.location.href.split("?")[0];
|
||||
let params = window.location.href.split("?")[1];
|
||||
let url_params = new URLSearchParams(params);
|
||||
|
||||
if (prev_ctoken) {
|
||||
url_params.set("continuation", prev_ctoken);
|
||||
} else {
|
||||
url_params.delete('continuation');
|
||||
};
|
||||
if (prev_ctoken) {
|
||||
url_params.set("continuation", prev_ctoken);
|
||||
} else {
|
||||
url_params.delete("continuation");
|
||||
}
|
||||
|
||||
if(Array.from(url_params).length > 0){
|
||||
return `${url}?${url_params.toString()}`;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
if (Array.from(url_params).length > 0) {
|
||||
return `${url}?${url_params.toString()}`;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener('DOMContentLoaded', function(){
|
||||
const pagination_data = JSON.parse(document.getElementById('pagination-data').textContent);
|
||||
const next_page_containers = document.getElementsByClassName("page-next-container");
|
||||
addEventListener("DOMContentLoaded", function () {
|
||||
const pagination_data = JSON.parse(
|
||||
document.getElementById("pagination-data").textContent,
|
||||
);
|
||||
const next_page_containers = document.getElementsByClassName(
|
||||
"page-next-container",
|
||||
);
|
||||
|
||||
for (let container of next_page_containers){
|
||||
const next_page_button = container.getElementsByClassName("pure-button")
|
||||
for (let container of next_page_containers) {
|
||||
const next_page_button = container.getElementsByClassName("pure-button");
|
||||
|
||||
// exists?
|
||||
if (next_page_button.length > 0){
|
||||
next_page_button[0].addEventListener("click", save_data);
|
||||
}
|
||||
// exists?
|
||||
if (next_page_button.length > 0) {
|
||||
next_page_button[0].addEventListener("click", save_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add previous page buttons when not on the first page
|
||||
if (CURRENT_CONTINUATION) {
|
||||
const prev_page_containers = document.getElementsByClassName("page-prev-container")
|
||||
// Only add previous page buttons when not on the first page
|
||||
if (CURRENT_CONTINUATION) {
|
||||
const prev_page_containers = document.getElementsByClassName(
|
||||
"page-prev-container",
|
||||
);
|
||||
|
||||
for (let container of prev_page_containers) {
|
||||
if (pagination_data.is_rtl) {
|
||||
container.innerHTML = `<button class="pure-button pure-button-secondary">${pagination_data.prev_page} <i class="icon ion-ios-arrow-forward"></i></button>`
|
||||
} else {
|
||||
container.innerHTML = `<button class="pure-button pure-button-secondary"><i class="icon ion-ios-arrow-back"></i> ${pagination_data.prev_page}</button>`
|
||||
}
|
||||
container.getElementsByClassName("pure-button")[0].addEventListener("click", button_press);
|
||||
}
|
||||
for (let container of prev_page_containers) {
|
||||
if (pagination_data.is_rtl) {
|
||||
container.innerHTML = `<button class="pure-button pure-button-secondary">${pagination_data.prev_page} <i class="icon ion-ios-arrow-forward"></i></button>`;
|
||||
} else {
|
||||
container.innerHTML = `<button class="pure-button pure-button-secondary"><i class="icon ion-ios-arrow-back"></i> ${pagination_data.prev_page}</button>`;
|
||||
}
|
||||
container
|
||||
.getElementsByClassName("pure-button")[0]
|
||||
.addEventListener("click", button_press);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
1224
assets/js/player.js
1224
assets/js/player.js
File diff suppressed because it is too large
Load Diff
@ -1,55 +1,83 @@
|
||||
'use strict';
|
||||
var playlist_data = JSON.parse(document.getElementById('playlist_data').textContent);
|
||||
var payload = 'csrf_token=' + playlist_data.csrf_token;
|
||||
"use strict";
|
||||
var playlist_data = JSON.parse(
|
||||
document.getElementById("playlist_data").textContent,
|
||||
);
|
||||
var payload = "csrf_token=" + playlist_data.csrf_token;
|
||||
|
||||
function add_playlist_video(event) {
|
||||
const target = event.target;
|
||||
var select = document.querySelector("#playlists");
|
||||
var option = select.children[select.selectedIndex];
|
||||
const target = event.target;
|
||||
var select = document.querySelector("#playlists");
|
||||
var option = select.children[select.selectedIndex];
|
||||
|
||||
var url = '/playlist_ajax?action=add_video&redirect=false' +
|
||||
'&video_id=' + target.getAttribute('data-id') +
|
||||
'&playlist_id=' + option.getAttribute('data-plid');
|
||||
var url =
|
||||
"/playlist_ajax?action=add_video&redirect=false" +
|
||||
"&video_id=" +
|
||||
target.getAttribute("data-id") +
|
||||
"&playlist_id=" +
|
||||
option.getAttribute("data-plid");
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
on200: function (response) {
|
||||
option.textContent = '✓ ' + option.textContent;
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
on200: function (response) {
|
||||
option.textContent = "✓ " + option.textContent;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function add_playlist_item(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_id = target.getAttribute('data-id');
|
||||
var card = document.querySelector(`#video-card-${video_id}`);
|
||||
card.classList.add("hide");
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_id = target.getAttribute("data-id");
|
||||
var card = document.querySelector(`#video-card-${video_id}`);
|
||||
card.classList.add("hide");
|
||||
|
||||
var url = '/playlist_ajax?action=add_video&redirect=false' +
|
||||
'&video_id=' + target.getAttribute('data-id') +
|
||||
'&playlist_id=' + target.getAttribute('data-plid');
|
||||
var url =
|
||||
"/playlist_ajax?action=add_video&redirect=false" +
|
||||
"&video_id=" +
|
||||
target.getAttribute("data-id") +
|
||||
"&playlist_id=" +
|
||||
target.getAttribute("data-plid");
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
card.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
card.classList.remove("hide");
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function remove_playlist_item(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_index = target.getAttribute('data-index');
|
||||
const card = document.querySelector(`.video-card [data-index="${video_index}"]`)
|
||||
card.classList.add("hide");
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_index = target.getAttribute("data-index");
|
||||
const card = document.querySelector(
|
||||
`.video-card [data-index="${video_index}"]`,
|
||||
);
|
||||
card.classList.add("hide");
|
||||
|
||||
var url = '/playlist_ajax?action=remove_video&redirect=false' +
|
||||
'&set_video_id=' + target.getAttribute('data-index') +
|
||||
'&playlist_id=' + target.getAttribute('data-plid');
|
||||
var url =
|
||||
"/playlist_ajax?action=remove_video&redirect=false" +
|
||||
"&set_video_id=" +
|
||||
target.getAttribute("data-index") +
|
||||
"&playlist_id=" +
|
||||
target.getAttribute("data-plid");
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
card.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
card.classList.remove("hide");
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
addEventListener('load', function (e) {
|
||||
get_youtube_comments();
|
||||
addEventListener("load", function (e) {
|
||||
get_youtube_comments();
|
||||
});
|
||||
|
1549
assets/js/silvermine-videojs-quality-selector.min.js
vendored
1549
assets/js/silvermine-videojs-quality-selector.min.js
vendored
File diff suppressed because one or more lines are too long
119
assets/js/sse.js
119
assets/js/sse.js
@ -17,18 +17,18 @@ var SSE = function (url, options) {
|
||||
|
||||
options = options || {};
|
||||
this.headers = options.headers || {};
|
||||
this.payload = options.payload !== undefined ? options.payload : '';
|
||||
this.method = options.method || (this.payload && 'POST' || 'GET');
|
||||
this.payload = options.payload !== undefined ? options.payload : "";
|
||||
this.method = options.method || (this.payload && "POST") || "GET";
|
||||
|
||||
this.FIELD_SEPARATOR = ':';
|
||||
this.FIELD_SEPARATOR = ":";
|
||||
this.listeners = {};
|
||||
|
||||
this.xhr = null;
|
||||
this.readyState = this.INITIALIZING;
|
||||
this.progress = 0;
|
||||
this.chunk = '';
|
||||
this.chunk = "";
|
||||
|
||||
this.addEventListener = function(type, listener) {
|
||||
this.addEventListener = function (type, listener) {
|
||||
if (this.listeners[type] === undefined) {
|
||||
this.listeners[type] = [];
|
||||
}
|
||||
@ -38,13 +38,13 @@ var SSE = function (url, options) {
|
||||
}
|
||||
};
|
||||
|
||||
this.removeEventListener = function(type, listener) {
|
||||
this.removeEventListener = function (type, listener) {
|
||||
if (this.listeners[type] === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var filtered = [];
|
||||
this.listeners[type].forEach(function(element) {
|
||||
this.listeners[type].forEach(function (element) {
|
||||
if (element !== listener) {
|
||||
filtered.push(element);
|
||||
}
|
||||
@ -56,14 +56,14 @@ var SSE = function (url, options) {
|
||||
}
|
||||
};
|
||||
|
||||
this.dispatchEvent = function(e) {
|
||||
this.dispatchEvent = function (e) {
|
||||
if (!e) {
|
||||
return true;
|
||||
}
|
||||
|
||||
e.source = this;
|
||||
|
||||
var onHandler = 'on' + e.type;
|
||||
var onHandler = "on" + e.type;
|
||||
if (this.hasOwnProperty(onHandler)) {
|
||||
this[onHandler].call(this, e);
|
||||
if (e.defaultPrevented) {
|
||||
@ -72,7 +72,7 @@ var SSE = function (url, options) {
|
||||
}
|
||||
|
||||
if (this.listeners[e.type]) {
|
||||
return this.listeners[e.type].every(function(callback) {
|
||||
return this.listeners[e.type].every(function (callback) {
|
||||
callback(e);
|
||||
return !e.defaultPrevented;
|
||||
});
|
||||
@ -82,78 +82,82 @@ var SSE = function (url, options) {
|
||||
};
|
||||
|
||||
this._setReadyState = function (state) {
|
||||
var event = new CustomEvent('readystatechange');
|
||||
var event = new CustomEvent("readystatechange");
|
||||
event.readyState = state;
|
||||
this.readyState = state;
|
||||
this.dispatchEvent(event);
|
||||
};
|
||||
|
||||
this._onStreamFailure = function(e) {
|
||||
this.dispatchEvent(new CustomEvent('error'));
|
||||
this._onStreamFailure = function (e) {
|
||||
this.dispatchEvent(new CustomEvent("error"));
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
|
||||
this._onStreamProgress = function(e) {
|
||||
this._onStreamProgress = function (e) {
|
||||
if (this.xhr.status !== 200 && this.readyState !== this.CLOSED) {
|
||||
this._onStreamFailure(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.readyState == this.CONNECTING) {
|
||||
this.dispatchEvent(new CustomEvent('open'));
|
||||
this.dispatchEvent(new CustomEvent("open"));
|
||||
this._setReadyState(this.OPEN);
|
||||
}
|
||||
|
||||
var data = this.xhr.responseText.substring(this.progress);
|
||||
this.progress += data.length;
|
||||
data.split(/(\r\n|\r|\n){2}/g).forEach(function(part) {
|
||||
if (part.trim().length === 0) {
|
||||
this.dispatchEvent(this._parseEventChunk(this.chunk.trim()));
|
||||
this.chunk = '';
|
||||
} else {
|
||||
this.chunk += part;
|
||||
}
|
||||
}.bind(this));
|
||||
data.split(/(\r\n|\r|\n){2}/g).forEach(
|
||||
function (part) {
|
||||
if (part.trim().length === 0) {
|
||||
this.dispatchEvent(this._parseEventChunk(this.chunk.trim()));
|
||||
this.chunk = "";
|
||||
} else {
|
||||
this.chunk += part;
|
||||
}
|
||||
}.bind(this),
|
||||
);
|
||||
};
|
||||
|
||||
this._onStreamLoaded = function(e) {
|
||||
this._onStreamLoaded = function (e) {
|
||||
this._onStreamProgress(e);
|
||||
|
||||
// Parse the last chunk.
|
||||
this.dispatchEvent(this._parseEventChunk(this.chunk));
|
||||
this.chunk = '';
|
||||
this.chunk = "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a received SSE event chunk into a constructed event object.
|
||||
*/
|
||||
this._parseEventChunk = function(chunk) {
|
||||
this._parseEventChunk = function (chunk) {
|
||||
if (!chunk || chunk.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var e = {'id': null, 'retry': null, 'data': '', 'event': 'message'};
|
||||
chunk.split(/\n|\r\n|\r/).forEach(function(line) {
|
||||
line = line.trimRight();
|
||||
var index = line.indexOf(this.FIELD_SEPARATOR);
|
||||
if (index <= 0) {
|
||||
// Line was either empty, or started with a separator and is a comment.
|
||||
// Either way, ignore.
|
||||
return;
|
||||
}
|
||||
var e = { id: null, retry: null, data: "", event: "message" };
|
||||
chunk.split(/\n|\r\n|\r/).forEach(
|
||||
function (line) {
|
||||
line = line.trimRight();
|
||||
var index = line.indexOf(this.FIELD_SEPARATOR);
|
||||
if (index <= 0) {
|
||||
// Line was either empty, or started with a separator and is a comment.
|
||||
// Either way, ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
var field = line.substring(0, index);
|
||||
if (!(field in e)) {
|
||||
return;
|
||||
}
|
||||
var field = line.substring(0, index);
|
||||
if (!(field in e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value = line.substring(index + 1).trimLeft();
|
||||
if (field === 'data') {
|
||||
e[field] += value;
|
||||
} else {
|
||||
e[field] = value;
|
||||
}
|
||||
}.bind(this));
|
||||
var value = line.substring(index + 1).trimLeft();
|
||||
if (field === "data") {
|
||||
e[field] += value;
|
||||
} else {
|
||||
e[field] = value;
|
||||
}
|
||||
}.bind(this),
|
||||
);
|
||||
|
||||
var event = new CustomEvent(e.event);
|
||||
event.data = e.data;
|
||||
@ -161,21 +165,24 @@ var SSE = function (url, options) {
|
||||
return event;
|
||||
};
|
||||
|
||||
this._checkStreamClosed = function() {
|
||||
this._checkStreamClosed = function () {
|
||||
if (this.xhr.readyState === XMLHttpRequest.DONE) {
|
||||
this._setReadyState(this.CLOSED);
|
||||
}
|
||||
};
|
||||
|
||||
this.stream = function() {
|
||||
this.stream = function () {
|
||||
this._setReadyState(this.CONNECTING);
|
||||
|
||||
this.xhr = new XMLHttpRequest();
|
||||
this.xhr.addEventListener('progress', this._onStreamProgress.bind(this));
|
||||
this.xhr.addEventListener('load', this._onStreamLoaded.bind(this));
|
||||
this.xhr.addEventListener('readystatechange', this._checkStreamClosed.bind(this));
|
||||
this.xhr.addEventListener('error', this._onStreamFailure.bind(this));
|
||||
this.xhr.addEventListener('abort', this._onStreamFailure.bind(this));
|
||||
this.xhr.addEventListener("progress", this._onStreamProgress.bind(this));
|
||||
this.xhr.addEventListener("load", this._onStreamLoaded.bind(this));
|
||||
this.xhr.addEventListener(
|
||||
"readystatechange",
|
||||
this._checkStreamClosed.bind(this),
|
||||
);
|
||||
this.xhr.addEventListener("error", this._onStreamFailure.bind(this));
|
||||
this.xhr.addEventListener("abort", this._onStreamFailure.bind(this));
|
||||
this.xhr.open(this.method, this.url);
|
||||
for (var header in this.headers) {
|
||||
this.xhr.setRequestHeader(header, this.headers[header]);
|
||||
@ -183,7 +190,7 @@ var SSE = function (url, options) {
|
||||
this.xhr.send(this.payload);
|
||||
};
|
||||
|
||||
this.close = function() {
|
||||
this.close = function () {
|
||||
if (this.readyState === this.CLOSED) {
|
||||
return;
|
||||
}
|
||||
@ -195,6 +202,6 @@ var SSE = function (url, options) {
|
||||
};
|
||||
|
||||
// Export our SSE module for npm.js
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof exports !== "undefined") {
|
||||
exports.SSE = SSE;
|
||||
}
|
||||
|
@ -1,62 +1,80 @@
|
||||
'use strict';
|
||||
var subscribe_data = JSON.parse(document.getElementById('subscribe_data').textContent);
|
||||
var payload = 'csrf_token=' + subscribe_data.csrf_token;
|
||||
"use strict";
|
||||
var subscribe_data = JSON.parse(
|
||||
document.getElementById("subscribe_data").textContent,
|
||||
);
|
||||
var payload = "csrf_token=" + subscribe_data.csrf_token;
|
||||
|
||||
var subscribe_button = document.getElementById('subscribe');
|
||||
var subscribe_button = document.getElementById("subscribe");
|
||||
|
||||
if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||
subscribe_button.onclick = subscribe;
|
||||
if (subscribe_button.getAttribute("data-type") === "subscribe") {
|
||||
subscribe_button.onclick = subscribe;
|
||||
} else {
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
}
|
||||
|
||||
function toggleSubscribeButton() {
|
||||
subscribe_button.classList.remove("primary");
|
||||
subscribe_button.classList.remove("secondary");
|
||||
subscribe_button.classList.remove("unsubscribe");
|
||||
subscribe_button.classList.remove("subscribe");
|
||||
subscribe_button.classList.remove("primary");
|
||||
subscribe_button.classList.remove("secondary");
|
||||
subscribe_button.classList.remove("unsubscribe");
|
||||
subscribe_button.classList.remove("subscribe");
|
||||
|
||||
if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||
subscribe_button.textContent = subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.classList.add("secondary");
|
||||
subscribe_button.classList.add("unsubscribe");
|
||||
} else {
|
||||
subscribe_button.textContent = subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.classList.add("primary");
|
||||
subscribe_button.classList.add("subscribe");
|
||||
}
|
||||
if (subscribe_button.getAttribute("data-type") === "subscribe") {
|
||||
subscribe_button.textContent =
|
||||
subscribe_data.unsubscribe_text + " | " + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.classList.add("secondary");
|
||||
subscribe_button.classList.add("unsubscribe");
|
||||
} else {
|
||||
subscribe_button.textContent =
|
||||
subscribe_data.subscribe_text + " | " + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.classList.add("primary");
|
||||
subscribe_button.classList.add("subscribe");
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe(e) {
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
|
||||
var url = '/subscription_ajax?action=create_subscription_to_channel&redirect=false' +
|
||||
'&c=' + subscribe_data.ucid;
|
||||
var url =
|
||||
"/subscription_ajax?action=create_subscription_to_channel&redirect=false" +
|
||||
"&c=" +
|
||||
subscribe_data.ucid;
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'subscribe request'}, {
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.textContent = fallback;
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload, retries: 5, entity_name: "subscribe request" },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.textContent = fallback;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function unsubscribe(e) {
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
|
||||
var url = '/subscription_ajax?action=remove_subscriptions&redirect=false' +
|
||||
'&c=' + subscribe_data.ucid;
|
||||
var url =
|
||||
"/subscription_ajax?action=remove_subscriptions&redirect=false" +
|
||||
"&c=" +
|
||||
subscribe_data.ucid;
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'unsubscribe request'}, {
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.textContent = fallback;
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload, retries: 5, entity_name: "unsubscribe request" },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.textContent = fallback;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -1,46 +1,46 @@
|
||||
'use strict';
|
||||
var toggle_theme = document.getElementById('toggle_theme');
|
||||
"use strict";
|
||||
var toggle_theme = document.getElementById("toggle_theme");
|
||||
|
||||
const STORAGE_KEY_THEME = 'dark_mode';
|
||||
const THEME_DARK = 'dark';
|
||||
const THEME_LIGHT = 'light';
|
||||
const STORAGE_KEY_THEME = "dark_mode";
|
||||
const THEME_DARK = "dark";
|
||||
const THEME_LIGHT = "light";
|
||||
|
||||
// TODO: theme state controlled by system
|
||||
toggle_theme.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const isDarkTheme = helpers.storage.get(STORAGE_KEY_THEME) === THEME_DARK;
|
||||
const newTheme = isDarkTheme ? THEME_LIGHT : THEME_DARK;
|
||||
setTheme(newTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, newTheme);
|
||||
helpers.xhr('GET', '/toggle_theme?redirect=false', {}, {});
|
||||
toggle_theme.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
const isDarkTheme = helpers.storage.get(STORAGE_KEY_THEME) === THEME_DARK;
|
||||
const newTheme = isDarkTheme ? THEME_LIGHT : THEME_DARK;
|
||||
setTheme(newTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, newTheme);
|
||||
helpers.xhr("GET", "/toggle_theme?redirect=false", {}, {});
|
||||
});
|
||||
|
||||
/** @param {THEME_DARK|THEME_LIGHT} theme */
|
||||
function setTheme(theme) {
|
||||
// By default body element has .no-theme class that uses OS theme via CSS @media rules
|
||||
// It rewrites using hard className below
|
||||
if (theme === THEME_DARK) {
|
||||
toggle_theme.children[0].className = 'icon ion-ios-sunny';
|
||||
document.body.className = 'dark-theme';
|
||||
} else if (theme === THEME_LIGHT) {
|
||||
toggle_theme.children[0].className = 'icon ion-ios-moon';
|
||||
document.body.className = 'light-theme';
|
||||
} else {
|
||||
document.body.className = 'no-theme';
|
||||
}
|
||||
// By default body element has .no-theme class that uses OS theme via CSS @media rules
|
||||
// It rewrites using hard className below
|
||||
if (theme === THEME_DARK) {
|
||||
toggle_theme.children[0].className = "icon ion-ios-sunny";
|
||||
document.body.className = "dark-theme";
|
||||
} else if (theme === THEME_LIGHT) {
|
||||
toggle_theme.children[0].className = "icon ion-ios-moon";
|
||||
document.body.className = "light-theme";
|
||||
} else {
|
||||
document.body.className = "no-theme";
|
||||
}
|
||||
}
|
||||
|
||||
// Handles theme change event caused by other tab
|
||||
addEventListener('storage', function (e) {
|
||||
if (e.key === STORAGE_KEY_THEME)
|
||||
setTheme(helpers.storage.get(STORAGE_KEY_THEME));
|
||||
addEventListener("storage", function (e) {
|
||||
if (e.key === STORAGE_KEY_THEME)
|
||||
setTheme(helpers.storage.get(STORAGE_KEY_THEME));
|
||||
});
|
||||
|
||||
// Set theme from preferences on page load
|
||||
addEventListener('DOMContentLoaded', function () {
|
||||
const prefTheme = document.getElementById('dark_mode_pref').textContent;
|
||||
if (prefTheme) {
|
||||
setTheme(prefTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, prefTheme);
|
||||
}
|
||||
addEventListener("DOMContentLoaded", function () {
|
||||
const prefTheme = document.getElementById("dark_mode_pref").textContent;
|
||||
if (prefTheme) {
|
||||
setTheme(prefTheme);
|
||||
helpers.storage.set(STORAGE_KEY_THEME, prefTheme);
|
||||
}
|
||||
});
|
||||
|
937
assets/js/videojs-youtube-annotations.min.js
vendored
937
assets/js/videojs-youtube-annotations.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,135 +1,159 @@
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
function toggle_parent(target) {
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
if (body.style.display === 'none') {
|
||||
target.textContent = '[ − ]';
|
||||
body.style.display = '';
|
||||
} else {
|
||||
target.textContent = '[ + ]';
|
||||
body.style.display = 'none';
|
||||
}
|
||||
var body = target.parentNode.parentNode.children[1];
|
||||
if (body.style.display === "none") {
|
||||
target.textContent = "[ − ]";
|
||||
body.style.display = "";
|
||||
} else {
|
||||
target.textContent = "[ + ]";
|
||||
body.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function swap_comments(event) {
|
||||
var source = event.target.getAttribute('data-comments');
|
||||
var source = event.target.getAttribute("data-comments");
|
||||
|
||||
if (source === 'youtube') {
|
||||
get_youtube_comments();
|
||||
} else if (source === 'reddit') {
|
||||
get_reddit_comments();
|
||||
}
|
||||
if (source === "youtube") {
|
||||
get_youtube_comments();
|
||||
} else if (source === "reddit") {
|
||||
get_reddit_comments();
|
||||
}
|
||||
}
|
||||
|
||||
var continue_button = document.getElementById('continue');
|
||||
var continue_button = document.getElementById("continue");
|
||||
if (continue_button) {
|
||||
continue_button.onclick = continue_autoplay;
|
||||
continue_button.onclick = continue_autoplay;
|
||||
}
|
||||
|
||||
function next_video() {
|
||||
var url = new URL('https://example.com/watch?v=' + video_data.next_video);
|
||||
var url = new URL("https://example.com/watch?v=" + video_data.next_video);
|
||||
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set('autoplay', '1');
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set('listen', video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set('speed', video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set('local', video_data.params.local);
|
||||
url.searchParams.set('continue', '1');
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set("autoplay", "1");
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set("listen", video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set("speed", video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set("local", video_data.params.local);
|
||||
url.searchParams.set("continue", "1");
|
||||
|
||||
location.assign(url.pathname + url.search);
|
||||
location.assign(url.pathname + url.search);
|
||||
}
|
||||
|
||||
function continue_autoplay(event) {
|
||||
if (event.target.checked) {
|
||||
player.on('ended', next_video);
|
||||
} else {
|
||||
player.off('ended');
|
||||
}
|
||||
if (event.target.checked) {
|
||||
player.on("ended", next_video);
|
||||
} else {
|
||||
player.off("ended");
|
||||
}
|
||||
}
|
||||
|
||||
function get_playlist(plid) {
|
||||
var playlist = document.getElementById('playlist');
|
||||
var playlist = document.getElementById("playlist");
|
||||
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
|
||||
var plid_url;
|
||||
if (plid.startsWith('RD')) {
|
||||
plid_url = '/api/v1/mixes/' + plid +
|
||||
'?continuation=' + video_data.id +
|
||||
'&format=html&hl=' + video_data.preferences.locale;
|
||||
} else {
|
||||
plid_url = '/api/v1/playlists/' + plid +
|
||||
'?index=' + video_data.index +
|
||||
'&continuation=' + video_data.id +
|
||||
'&format=html&hl=' + video_data.preferences.locale;
|
||||
}
|
||||
var plid_url;
|
||||
if (plid.startsWith("RD")) {
|
||||
plid_url =
|
||||
"/api/v1/mixes/" +
|
||||
plid +
|
||||
"?continuation=" +
|
||||
video_data.id +
|
||||
"&format=html&hl=" +
|
||||
video_data.preferences.locale;
|
||||
} else {
|
||||
plid_url =
|
||||
"/api/v1/playlists/" +
|
||||
plid +
|
||||
"?index=" +
|
||||
video_data.index +
|
||||
"&continuation=" +
|
||||
video_data.id +
|
||||
"&format=html&hl=" +
|
||||
video_data.preferences.locale;
|
||||
}
|
||||
|
||||
if (video_data.params.listen) {
|
||||
plid_url += '&listen=1'
|
||||
}
|
||||
if (video_data.params.listen) {
|
||||
plid_url += "&listen=1";
|
||||
}
|
||||
|
||||
helpers.xhr('GET', plid_url, {retries: 5, entity_name: 'playlist'}, {
|
||||
on200: function (response) {
|
||||
if (response === null) return;
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
plid_url,
|
||||
{ retries: 5, entity_name: "playlist" },
|
||||
{
|
||||
on200: function (response) {
|
||||
if (response === null) return;
|
||||
|
||||
playlist.innerHTML = response.playlistHtml;
|
||||
playlist.innerHTML = response.playlistHtml;
|
||||
|
||||
if (!response.nextVideo) return;
|
||||
if (!response.nextVideo) return;
|
||||
|
||||
var nextVideo = document.getElementById(response.nextVideo);
|
||||
nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop;
|
||||
var nextVideo = document.getElementById(response.nextVideo);
|
||||
nextVideo.parentNode.parentNode.scrollTop = nextVideo.offsetTop;
|
||||
|
||||
player.on('ended', function () {
|
||||
var url = new URL('https://example.com/watch?v=' + response.nextVideo);
|
||||
player.on("ended", function () {
|
||||
var url = new URL(
|
||||
"https://example.com/watch?v=" + response.nextVideo,
|
||||
);
|
||||
|
||||
url.searchParams.set('list', plid);
|
||||
if (!plid.startsWith('RD'))
|
||||
url.searchParams.set('index', response.index);
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set('autoplay', '1');
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set('listen', video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set('speed', video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set('local', video_data.params.local);
|
||||
url.searchParams.set("list", plid);
|
||||
if (!plid.startsWith("RD"))
|
||||
url.searchParams.set("index", response.index);
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set("autoplay", "1");
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set("listen", video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set("speed", video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set("local", video_data.params.local);
|
||||
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
playlist.innerHTML = '';
|
||||
document.getElementById('continue').style.display = '';
|
||||
},
|
||||
onError: function (xhr) {
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
}
|
||||
});
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
},
|
||||
onNon200: function (xhr) {
|
||||
playlist.innerHTML = "";
|
||||
document.getElementById("continue").style.display = "";
|
||||
},
|
||||
onError: function (xhr) {
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
},
|
||||
onTimeout: function (xhr) {
|
||||
playlist.innerHTML = spinnerHTMLwithHR;
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function get_reddit_comments() {
|
||||
var comments = document.getElementById('comments');
|
||||
var comments = document.getElementById("comments");
|
||||
|
||||
var fallback = comments.innerHTML;
|
||||
comments.innerHTML = spinnerHTML;
|
||||
var fallback = comments.innerHTML;
|
||||
comments.innerHTML = spinnerHTML;
|
||||
|
||||
var url = '/api/v1/comments/' + video_data.id +
|
||||
'?source=reddit&format=html' +
|
||||
'&hl=' + video_data.preferences.locale;
|
||||
var url =
|
||||
"/api/v1/comments/" +
|
||||
video_data.id +
|
||||
"?source=reddit&format=html" +
|
||||
"&hl=" +
|
||||
video_data.preferences.locale;
|
||||
|
||||
var onNon200 = function (xhr) { comments.innerHTML = fallback; };
|
||||
if (video_data.params.comments[1] === 'youtube')
|
||||
onNon200 = function (xhr) {};
|
||||
var onNon200 = function (xhr) {
|
||||
comments.innerHTML = fallback;
|
||||
};
|
||||
if (video_data.params.comments[1] === "youtube") onNon200 = function (xhr) {};
|
||||
|
||||
helpers.xhr('GET', url, {retries: 5, entity_name: ''}, {
|
||||
on200: function (response) {
|
||||
comments.innerHTML = ' \
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
url,
|
||||
{ retries: 5, entity_name: "" },
|
||||
{
|
||||
on200: function (response) {
|
||||
comments.innerHTML = ' \
|
||||
<div> \
|
||||
<h3> \
|
||||
<a href="javascript:void(0)">[ − ]</a> \
|
||||
@ -148,52 +172,52 @@ function get_reddit_comments() {
|
||||
</div> \
|
||||
<div>{contentHtml}</div> \
|
||||
<hr>'.supplant({
|
||||
title: response.title,
|
||||
youtubeCommentsText: video_data.youtube_comments_text,
|
||||
redditPermalinkText: video_data.reddit_permalink_text,
|
||||
permalink: response.permalink,
|
||||
contentHtml: response.contentHtml
|
||||
});
|
||||
title: response.title,
|
||||
youtubeCommentsText: video_data.youtube_comments_text,
|
||||
redditPermalinkText: video_data.reddit_permalink_text,
|
||||
permalink: response.permalink,
|
||||
contentHtml: response.contentHtml,
|
||||
});
|
||||
|
||||
comments.children[0].children[0].children[0].onclick = toggle_comments;
|
||||
comments.children[0].children[1].children[0].onclick = swap_comments;
|
||||
},
|
||||
onNon200: onNon200, // declared above
|
||||
});
|
||||
comments.children[0].children[0].children[0].onclick = toggle_comments;
|
||||
comments.children[0].children[1].children[0].onclick = swap_comments;
|
||||
},
|
||||
onNon200: onNon200, // declared above
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (video_data.play_next) {
|
||||
player.on('ended', function () {
|
||||
var url = new URL('https://example.com/watch?v=' + video_data.next_video);
|
||||
player.on("ended", function () {
|
||||
var url = new URL("https://example.com/watch?v=" + video_data.next_video);
|
||||
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set('autoplay', '1');
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set('listen', video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set('speed', video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set('local', video_data.params.local);
|
||||
url.searchParams.set('continue', '1');
|
||||
if (video_data.params.autoplay || video_data.params.continue_autoplay)
|
||||
url.searchParams.set("autoplay", "1");
|
||||
if (video_data.params.listen !== video_data.preferences.listen)
|
||||
url.searchParams.set("listen", video_data.params.listen);
|
||||
if (video_data.params.speed !== video_data.preferences.speed)
|
||||
url.searchParams.set("speed", video_data.params.speed);
|
||||
if (video_data.params.local !== video_data.preferences.local)
|
||||
url.searchParams.set("local", video_data.params.local);
|
||||
url.searchParams.set("continue", "1");
|
||||
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
location.assign(url.pathname + url.search);
|
||||
});
|
||||
}
|
||||
|
||||
addEventListener('load', function (e) {
|
||||
if (video_data.plid)
|
||||
get_playlist(video_data.plid);
|
||||
addEventListener("load", function (e) {
|
||||
if (video_data.plid) get_playlist(video_data.plid);
|
||||
|
||||
if (video_data.params.comments[0] === 'youtube') {
|
||||
get_youtube_comments();
|
||||
} else if (video_data.params.comments[0] === 'reddit') {
|
||||
get_reddit_comments();
|
||||
} else if (video_data.params.comments[1] === 'youtube') {
|
||||
get_youtube_comments();
|
||||
} else if (video_data.params.comments[1] === 'reddit') {
|
||||
get_reddit_comments();
|
||||
} else {
|
||||
var comments = document.getElementById('comments');
|
||||
comments.innerHTML = '';
|
||||
}
|
||||
if (video_data.params.comments[0] === "youtube") {
|
||||
get_youtube_comments();
|
||||
} else if (video_data.params.comments[0] === "reddit") {
|
||||
get_reddit_comments();
|
||||
} else if (video_data.params.comments[1] === "youtube") {
|
||||
get_youtube_comments();
|
||||
} else if (video_data.params.comments[1] === "reddit") {
|
||||
get_reddit_comments();
|
||||
} else {
|
||||
var comments = document.getElementById("comments");
|
||||
comments.innerHTML = "";
|
||||
}
|
||||
});
|
||||
|
@ -1,24 +1,24 @@
|
||||
'use strict';
|
||||
var save_player_pos_key = 'save_player_pos';
|
||||
"use strict";
|
||||
var save_player_pos_key = "save_player_pos";
|
||||
|
||||
function get_all_video_times() {
|
||||
return helpers.storage.get(save_player_pos_key) || {};
|
||||
return helpers.storage.get(save_player_pos_key) || {};
|
||||
}
|
||||
|
||||
document.querySelectorAll('.watched-indicator').forEach(function (indicator) {
|
||||
var watched_part = get_all_video_times()[indicator.dataset.id];
|
||||
var total = parseInt(indicator.dataset.length, 10);
|
||||
if (watched_part === undefined) {
|
||||
watched_part = total;
|
||||
}
|
||||
var percentage = Math.round((watched_part / total) * 100);
|
||||
document.querySelectorAll(".watched-indicator").forEach(function (indicator) {
|
||||
var watched_part = get_all_video_times()[indicator.dataset.id];
|
||||
var total = parseInt(indicator.dataset.length, 10);
|
||||
if (watched_part === undefined) {
|
||||
watched_part = total;
|
||||
}
|
||||
var percentage = Math.round((watched_part / total) * 100);
|
||||
|
||||
if (percentage < 5) {
|
||||
percentage = 5;
|
||||
}
|
||||
if (percentage > 90) {
|
||||
percentage = 100;
|
||||
}
|
||||
if (percentage < 5) {
|
||||
percentage = 5;
|
||||
}
|
||||
if (percentage > 90) {
|
||||
percentage = 100;
|
||||
}
|
||||
|
||||
indicator.style.width = percentage + '%';
|
||||
indicator.style.width = percentage + "%";
|
||||
});
|
||||
|
@ -1,34 +1,50 @@
|
||||
'use strict';
|
||||
var watched_data = JSON.parse(document.getElementById('watched_data').textContent);
|
||||
var payload = 'csrf_token=' + watched_data.csrf_token;
|
||||
"use strict";
|
||||
var watched_data = JSON.parse(
|
||||
document.getElementById("watched_data").textContent,
|
||||
);
|
||||
var payload = "csrf_token=" + watched_data.csrf_token;
|
||||
|
||||
function mark_watched(target) {
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = 'none';
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = "none";
|
||||
|
||||
var url = '/watch_ajax?action=mark_watched&redirect=false' +
|
||||
'&id=' + target.getAttribute('data-id');
|
||||
var url =
|
||||
"/watch_ajax?action=mark_watched&redirect=false" +
|
||||
"&id=" +
|
||||
target.getAttribute("data-id");
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
tile.style.display = '';
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
tile.style.display = "";
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function mark_unwatched(target) {
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = 'none';
|
||||
var count = document.getElementById('count');
|
||||
count.textContent--;
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = "none";
|
||||
var count = document.getElementById("count");
|
||||
count.textContent--;
|
||||
|
||||
var url = '/watch_ajax?action=mark_unwatched&redirect=false' +
|
||||
'&id=' + target.getAttribute('data-id');
|
||||
var url =
|
||||
"/watch_ajax?action=mark_unwatched&redirect=false" +
|
||||
"&id=" +
|
||||
target.getAttribute("data-id");
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
tile.style.display = '';
|
||||
}
|
||||
});
|
||||
helpers.xhr(
|
||||
"POST",
|
||||
url,
|
||||
{ payload: payload },
|
||||
{
|
||||
onNon200: function (xhr) {
|
||||
count.textContent++;
|
||||
tile.style.display = "";
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -89,13 +89,6 @@ module Invidious::Frontend::Pagination
|
||||
end
|
||||
|
||||
def nav_ctoken(locale : String?, *, base_url : String | URI, ctoken : String?, first_page : Bool, params : URI::Params)
|
||||
return String.build do |str|
|
||||
if !ctoken.nil?
|
||||
str << %(<nav class="pagination">\n<ul>\n)
|
||||
str << %(<li>)
|
||||
params_next = URI::Params{"continuation" => ctoken}
|
||||
url_next = HttpServer::Utils.add_params_to_url(base_url, params_next)
|
||||
|
||||
return String.build do |str|
|
||||
str << %(<nav class="pagination">\n<ul>\n)
|
||||
str << %(<li>)
|
||||
@ -106,13 +99,13 @@ module Invidious::Frontend::Pagination
|
||||
if !ctoken.nil?
|
||||
params["continuation"] = ctoken
|
||||
url_next = HttpServer::Utils.add_params_to_url(base_url, params)
|
||||
|
||||
self.next_page(str, locale, url_next.to_s)
|
||||
|
||||
str << %(</li>\n)
|
||||
|
||||
str << %(</ul>\n</nav>\n)
|
||||
end
|
||||
|
||||
self.next_page(str, locale, url_next.to_s)
|
||||
|
||||
str << %(</li>\n)
|
||||
|
||||
str << %(</ul>\n</nav>\n)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user