mirror of https://github.com/iv-org/invidious.git
improve feature
This commit is contained in:
parent
6a1beeb789
commit
1d67e13d9c
|
@ -75,7 +75,7 @@ function return_message(message, target_window) {
|
||||||
}
|
}
|
||||||
if (message.message_kind === 'event') {
|
if (message.message_kind === 'event') {
|
||||||
if (message.eventname === 'timeupdate' || message.eventname === 'loadedmetadata') {
|
if (message.eventname === 'timeupdate' || message.eventname === 'loadedmetadata') {
|
||||||
additional_info['value'] = { getvolume: player.volume(), getduration: player.duration(), getcurrenttime: player.currentTime(), getplaystatus: player.paused(), getplaybackrate: player.playbackRate(), getloopstatus: player.loop(), getmutestatus: player.muted(), getfullscreenstatus: player.isFullscreen(), getavailableplaybackrates: options.playbackRates, gettitle: player_data.title };
|
additional_info['value'] = { getvolume: player.volume(), getduration: player.duration(), getcurrenttime: player.currentTime(), getplaystatus: player.paused(), getplaybackrate: player.playbackRate(), getloopstatus: player.loop(), getmutestatus: player.muted(), getfullscreenstatus: player.isFullscreen(), getavailableplaybackrates: options.playbackRates, gettitle: player_data.title, getplaylistindex: video_data.index, getplaylistid: video_data.plid};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (message.eventname === 'error') {
|
if (message.eventname === 'error') {
|
||||||
|
@ -92,7 +92,7 @@ function control_embed_iframe(message) {
|
||||||
const origin_equal = origin === null || origin === message.origin;
|
const origin_equal = origin === null || origin === message.origin;
|
||||||
if (origin_equal) {
|
if (origin_equal) {
|
||||||
const widgetid = url_params.get('widgetid');
|
const widgetid = url_params.get('widgetid');
|
||||||
const widgetid_equal = (widgetid === null && message.data.widgetid === null) || widgetid === message.data.widgetid;
|
const widgetid_equal = widgetid === message.data.widgetid;
|
||||||
const target_name_equal = message.data.target === 'invidious_control';
|
const target_name_equal = message.data.target === 'invidious_control';
|
||||||
const eventname_string_check = typeof message.data.eventname === 'string';
|
const eventname_string_check = typeof message.data.eventname === 'string';
|
||||||
if (widgetid_equal && target_name_equal && eventname_string_check) {
|
if (widgetid_equal && target_name_equal && eventname_string_check) {
|
||||||
|
@ -159,6 +159,12 @@ function control_embed_iframe(message) {
|
||||||
case 'geterrorcode':
|
case 'geterrorcode':
|
||||||
message_return_value = player.error().code;
|
message_return_value = player.error().code;
|
||||||
break;
|
break;
|
||||||
|
case 'getplaylistindex':
|
||||||
|
message_return_value = video_data.index;
|
||||||
|
break;
|
||||||
|
case 'getplaylistid':
|
||||||
|
message_return_value = video_data.plid;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.info("Unhandled event name: " + message.data.eventname);
|
console.info("Unhandled event name: " + message.data.eventname);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,30 +1,147 @@
|
||||||
class invidious_embed {
|
class invidious_embed {
|
||||||
static widgetid = 0;
|
static widgetid = 0;
|
||||||
static eventname_table = { onPlaybackRateChange: 'ratechange', onStateChange: 'statechange', onerror: 'error' };
|
static eventname_table = { onPlaybackRateChange: 'ratechange', onStateChange: 'statechange', onError: 'error' ,onReady: 'ready'};
|
||||||
static available_event_name = ['ended', 'error', 'ratechange', 'volumechange', 'waiting', 'timeupdate', 'loadedmetadata', 'play', 'seeking', 'seeked', 'playerresize', 'pause'];
|
static available_event_name = ['ready', 'ended', 'error', 'ratechange', 'volumechange', 'waiting', 'timeupdate', 'loadedmetadata', 'play', 'seeking', 'seeked', 'playerresize', 'pause'];
|
||||||
static api_promise = false;
|
static api_promise = false;
|
||||||
static invidious_instance = '';
|
static invidious_instance = '';
|
||||||
|
static api_instance_list = [];
|
||||||
|
static instance_status_list = {};
|
||||||
|
|
||||||
addEventListener(eventname, func) {
|
addEventListener(eventname, func) {
|
||||||
if (eventname in invidious_embed.eventname_table) {
|
if (typeof func === 'function') {
|
||||||
this.eventobject[invidious_embed.eventname_table[eventname]].push(func);
|
if (eventname in invidious_embed.eventname_table) {
|
||||||
|
this.eventobject[invidious_embed.eventname_table[eventname]].push(func);
|
||||||
|
}
|
||||||
|
else if (invidious_embed.available_event_name.includes(eventname)) {
|
||||||
|
this.eventobject[eventname].push(func);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.warn('addEventListener cannot find such eventname : ' + eventname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.eventobject[eventname].push(func);
|
console.warn("addEventListner secound args must be function");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeEventListner(eventname, func) {
|
removeEventListener(eventname, func) {
|
||||||
let internal_eventname;
|
if (typeof func === 'function') {
|
||||||
if (eventname in invidious_embed.eventname_table) {
|
let internal_eventname;
|
||||||
internal_eventname = invidious_embed.eventname_table[eventname];
|
if (eventname in invidious_embed.eventname_table) {
|
||||||
|
internal_eventname = invidious_embed.eventname_table[eventname];
|
||||||
|
}
|
||||||
|
else if (invidious_embed.available_event_name.includes(eventname)) {
|
||||||
|
internal_eventname = eventname;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.warn('removeEventListner cannot find such eventname : ' + eventname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.eventobject[internal_eventname] = this.eventobject[internal_eventname].filter(x => {
|
||||||
|
const arrowFunctionDetected = x.toString()[0] === '(';
|
||||||
|
if (arrowFunctionDetected) {
|
||||||
|
x.toString() !== func.toString();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
x !== func;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (invidious_embed.available_event_name.includes(eventname)) {
|
else {
|
||||||
internal_eventname = eventname;
|
console.warn("removeEventListener secound args must be function");
|
||||||
}
|
}
|
||||||
this.eventobject[internal_eventname] = this.eventobject[internal_eventname].fillter(x => x !== func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player(element, options) {
|
async instance_access_check(instance_origin) {
|
||||||
|
let return_status;
|
||||||
|
const status_cahce_exist = instance_origin in invidious_embed.instance_status_list;
|
||||||
|
if (!status_cahce_exist) {
|
||||||
|
try{
|
||||||
|
const instance_stats = await fetch(instance_origin + '/api/v1/stats');
|
||||||
|
if (instance_stats.ok) {
|
||||||
|
const instance_stats_json = await instance_stats.json();
|
||||||
|
if (instance_stats_json.software.name === 'invidious') {
|
||||||
|
return_status = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return_status = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return_status = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch{
|
||||||
|
return_status = false;
|
||||||
|
}
|
||||||
|
invidious_embed.instance_status_list[instance_origin] = return_status;
|
||||||
|
return return_status;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return invidious_embed.instance_status_list[instance_origin];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async get_instance_list() {
|
||||||
|
invidious_embed.api_instance_list = [];
|
||||||
|
const instance_list_api = await (await fetch('https://api.invidious.io/instances.json?pretty=1&sort_by=type,users')).json();
|
||||||
|
instance_list_api.forEach(instance_data => {
|
||||||
|
const http_check = instance_data[1]['type'] === 'https';
|
||||||
|
let status_check_api_data;
|
||||||
|
if (instance_data[1]['monitor'] !== null) {
|
||||||
|
status_check_api_data = instance_data[1]['monitor']['statusClass'] === 'success';
|
||||||
|
}
|
||||||
|
const api_available = instance_data[1]['api'] && instance_data[1]['cors'];
|
||||||
|
if (http_check && status_check_api_data && api_available) {
|
||||||
|
invidious_embed.api_instance_list.push(instance_data[1]['uri']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async auto_instance_select(){
|
||||||
|
if (await this.instance_access_check(invidious_embed.invidious_instance)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (invidious_embed.api_instance_list.length === 0) {
|
||||||
|
await this.get_instance_list();
|
||||||
|
}
|
||||||
|
for (let x=0;x<invidious_embed.api_instance_list.length;x++) {
|
||||||
|
if(await this.instance_access_check(invidious_embed.api_instance_list[x])){
|
||||||
|
invidious_embed.invidious_instance = invidious_embed.api_instance_list[x];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
invidious_embed.api_instance_list.forEach(async (instance_origin) => {
|
||||||
|
if(await this.instance_access_check(instance_origin)){
|
||||||
|
invidious_embed.invidious_instance = instance_origin;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async videoid_accessable_check(videoid){
|
||||||
|
const video_api_response = await fetch(invidious_embed.invidious_instance + "/api/v1/videos/" + videoid);
|
||||||
|
return video_api_response.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPlaylistVideoids(playlistid) {
|
||||||
|
const playlist_api_response = await fetch(invidious_embed.invidious_instance + "/api/v1/playlists/" + playlistid);
|
||||||
|
if (playlist_api_response.ok){
|
||||||
|
const playlist_api_json = await playlist_api_response.json();
|
||||||
|
let tmp_videoid_list = [];
|
||||||
|
playlist_api_json.videos.forEach(videodata=>tmp_videoid_list.push(videodata.videoId));
|
||||||
|
return tmp_videoid_list;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Player(element, options) {
|
||||||
this.player_status = -1;
|
this.player_status = -1;
|
||||||
this.error_code = 0;
|
this.error_code = 0;
|
||||||
this.volume = 100;
|
this.volume = 100;
|
||||||
|
@ -46,14 +163,21 @@ class invidious_embed {
|
||||||
else if (invidious_embed.invidious_instance !== '') {
|
else if (invidious_embed.invidious_instance !== '') {
|
||||||
iframe_src = invidious_embed.invidious_instance;
|
iframe_src = invidious_embed.invidious_instance;
|
||||||
}
|
}
|
||||||
else {
|
if (!await this.instance_access_check(iframe_src)) {
|
||||||
iframe_src = 'https://vid.puffyan.us';//I set most hot instanse but this may need discuss or change ay to default instanse
|
await this.auto_instance_select();
|
||||||
|
iframe_src = invidious_embed.invidious_instance;
|
||||||
}
|
}
|
||||||
this.target_origin = iframe_src.slice();
|
invidious_embed.invidious_instance = iframe_src;
|
||||||
|
this.target_origin = iframe_src;
|
||||||
iframe_src += '/embed/';
|
iframe_src += '/embed/';
|
||||||
if (typeof options.videoId === 'string' && options.videoId.length === 11) {
|
if (typeof options.videoId === 'string' && options.videoId.length === 11) {
|
||||||
iframe_src += options.videoId;
|
iframe_src += options.videoId;
|
||||||
this.videoId = options.videoId;
|
this.videoId = options.videoId;
|
||||||
|
if (!await this.videoid_accessable_check(options.videoId)) {
|
||||||
|
this.error_code = 100;
|
||||||
|
this.event_executor('error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.error_code = 2;
|
this.error_code = 2;
|
||||||
|
@ -85,8 +209,9 @@ class invidious_embed {
|
||||||
}
|
}
|
||||||
this.player_iframe = document.createElement("iframe");
|
this.player_iframe = document.createElement("iframe");
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
this.addEventListener('loadedmetadata', () => { this.event_executor('ready'); this.loaded = true });
|
this.addEventListener('loadedmetadata', () => { this.event_executor('ready'); this.loaded = true; });
|
||||||
this.addEventListener('loadedmetadata', () => { this.setVolume(this.volume) });
|
this.addEventListener('loadedmetadata', () => { this.setVolume(this.volume); });
|
||||||
|
this.addEventListener('loadedmetadata', async () => { const plid = await this.promise_send_event('getplaylistid'); (plid === null || plid === undefined) ? this.playlistVideoIds = [] : this.playlistVideoIds = await this.getPlaylistVideoids(plid); })
|
||||||
this.player_iframe.src = iframe_src;
|
this.player_iframe.src = iframe_src;
|
||||||
if (typeof options.width === 'number') {
|
if (typeof options.width === 'number') {
|
||||||
this.player_iframe.width = options.width;
|
this.player_iframe.width = options.width;
|
||||||
|
@ -123,12 +248,14 @@ class invidious_embed {
|
||||||
if (eventname === 'statechange') {
|
if (eventname === 'statechange') {
|
||||||
return_data.data = this.getPlayerState();
|
return_data.data = this.getPlayerState();
|
||||||
}
|
}
|
||||||
for (let x = 0; x < execute_functions.length; x++) {
|
execute_functions.forEach(func => {
|
||||||
try {
|
try{
|
||||||
execute_functions[x](return_data);
|
func(return_data);
|
||||||
}
|
}
|
||||||
catch { }
|
catch(e){
|
||||||
}
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveMessage(message) {
|
receiveMessage(message) {
|
||||||
|
@ -239,15 +366,24 @@ class invidious_embed {
|
||||||
}
|
}
|
||||||
|
|
||||||
seekTo(seconds, allowSeekAhead) {//seconds must be a number and allowSeekAhead is ignore
|
seekTo(seconds, allowSeekAhead) {//seconds must be a number and allowSeekAhead is ignore
|
||||||
seconds = Number(seconds);
|
if (typeof seconds === 'number') {
|
||||||
if (seconds !== NaN && seconds !== undefined) {
|
if (seconds !== NaN && seconds !== undefined) {
|
||||||
this.postMessage({ eventname: 'seek', value: seconds });
|
this.postMessage({ eventname: 'seek', value: seconds });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.warn('seekTo first argument type must be number')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSize(width, height) {//width and height must be Number
|
setSize(width, height) {//width and height must be Number
|
||||||
this.player_iframe.width = Number(width);
|
if (typeof width === 'number' && typeof height === 'number'){
|
||||||
this.player_iframe.height = Number(height);
|
this.player_iframe.width = width;
|
||||||
|
this.player_iframe.height = height;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.warn('setSize first and secound argument type must be number');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaybackRate() {
|
getPlaybackRate() {
|
||||||
|
@ -255,9 +391,16 @@ class invidious_embed {
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlaybackRate(suggestedRate) {//suggestedRate must be number.this player allow not available playback rate such as 1.4
|
setPlaybackRate(suggestedRate) {//suggestedRate must be number.this player allow not available playback rate such as 1.4
|
||||||
suggestedRate = Number(suggestedRate);
|
if (typeof suggestedRate === 'number'){
|
||||||
if (suggestedRate !== NaN && suggestedRate !== undefined) {
|
if (suggestedRate !== NaN) {
|
||||||
this.postMessage({ eventname: 'setplaybackrate', value: suggestedRate });
|
this.postMessage({ eventname: 'setplaybackrate', value: suggestedRate });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.warn('setPlaybackRate first argument NaN is no valid');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
console.warn('setPlaybackRate first argument type must be number');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +408,7 @@ class invidious_embed {
|
||||||
return this.promise_send_event('getavailableplaybackrates');
|
return this.promise_send_event('getavailableplaybackrates');
|
||||||
}
|
}
|
||||||
|
|
||||||
playOtherVideoById(option, autoplay, startSeconds_arg) {//internal fuction
|
async playOtherVideoById(option, autoplay, startSeconds_arg) {//internal fuction
|
||||||
let videoId = '';
|
let videoId = '';
|
||||||
let startSeconds = 0;
|
let startSeconds = 0;
|
||||||
let endSeconds = -1;
|
let endSeconds = -1;
|
||||||
|
@ -308,27 +451,24 @@ class invidious_embed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mediaContetUrl.length > 0) {
|
if (mediaContetUrl.length > 0) {
|
||||||
var tmp_videoId = '';
|
const match_result = mediaContetUrl.match(/\/([A-Za-z0-9]{11})\//);
|
||||||
if (mediaContetUrl.indexOf('/v/') !== -1) {
|
if (match_result !== null && match_result.length === 2){
|
||||||
var end_pos = mediaContetUrl.length - 1;
|
videoId = match_result[1];
|
||||||
if (mediaContetUrl.indexOf('?') !== -1) {
|
|
||||||
end_pos = mediaContetUrl.indexOf('?');
|
|
||||||
}
|
|
||||||
tmp_videoId = mediaContetUrl.substring(mediaContetUrl.indexOf('/v/'), end_pos);
|
|
||||||
}
|
}
|
||||||
else {
|
else{
|
||||||
tmp_videoId = new URL(mediaContetUrl).searchParams.get('v');
|
|
||||||
}
|
|
||||||
if (tmp_videoId === null || tmp_videoId.length !== 11) {
|
|
||||||
this.error_code = 2;
|
this.error_code = 2;
|
||||||
this.event_executor('error');
|
this.event_executor('error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
videoId = tmp_videoId;
|
|
||||||
}
|
}
|
||||||
let iframe_sorce = this.target_origin.slice();
|
let iframe_sorce = this.target_origin.slice();
|
||||||
iframe_sorce += "/embed/" + videoId;
|
iframe_sorce += "/embed/" + videoId;
|
||||||
this.videoId = videoId;
|
this.videoId = videoId;
|
||||||
|
if (!await this.videoid_accessable_check(videoId)) {
|
||||||
|
this.error_code = 100;
|
||||||
|
this.event_executor('error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
let search_params = new URLSearchParams('');
|
let search_params = new URLSearchParams('');
|
||||||
search_params.append('origin', location.origin);
|
search_params.append('origin', location.origin);
|
||||||
search_params.append('enablejsapi', '1');
|
search_params.append('enablejsapi', '1');
|
||||||
|
@ -387,7 +527,7 @@ class invidious_embed {
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVideoEmbedCode() {
|
async getVideoEmbedCode() {
|
||||||
var title = await this.getVideoTitle();
|
const title = await this.getVideoTitle();
|
||||||
return '<iframe width="560" height="315" src="' + this.target_origin + '/embed/' + this.videoId + '" title="' + title.replace('"', "'") + '" frameborder="0" allow="autoplay;encrypted-media;picture-in-picture;web-share" allowfullscreen></iframe>';
|
return '<iframe width="560" height="315" src="' + this.target_origin + '/embed/' + this.videoId + '" title="' + title.replace('"', "'") + '" frameborder="0" allow="autoplay;encrypted-media;picture-in-picture;web-share" allowfullscreen></iframe>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,24 +535,36 @@ class invidious_embed {
|
||||||
return this.promise_send_event('getcurrenttime');
|
return this.promise_send_event('getcurrenttime');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getVideoData() {
|
||||||
|
return { video_id: this.videoId, title: await this.promise_send_event('gettitle'), list:this.promise_send_event('getplaylistid') };
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlaylistIndex() {
|
||||||
|
return this.promise_send_event('getplaylistindex');
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlaylist() {
|
||||||
|
return this.playlistVideoIds !== undefined ? this.playlistVideoIds : [];
|
||||||
|
}
|
||||||
|
|
||||||
constructor(element, options) {
|
constructor(element, options) {
|
||||||
this.Player(element, options);
|
this.Player(element, options);
|
||||||
window.addEventListener('message', (ms) => { this.receiveMessage(ms) });
|
window.addEventListener('message', (ms) => { this.receiveMessage(ms) });
|
||||||
this.message_wait = { getvolume: [], getmutestatus: [], getduration: [], getcurrenttime: [], getplaybackrate: [], getavailableplaybackrates: [], gettitle: [] };
|
this.message_wait = { getvolume: [], getmutestatus: [], getduration: [], getcurrenttime: [], getplaybackrate: [], getavailableplaybackrates: [], gettitle: [] };
|
||||||
}
|
}
|
||||||
|
|
||||||
async getVideoData() {
|
|
||||||
return { video_id: this.videoId, title: await this.promise_send_event('gettitle') };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function invidious_ready(func) {
|
function invidious_ready(func) {
|
||||||
if (typeof func === 'function') {
|
if (typeof func === 'function') {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
console.warn('invidious.ready first argument must be function');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
invidious_embed.invidious_instance = new URL(document.currentScript.src).origin;
|
invidious_embed.invidious_instance = new URL(document.currentScript.src).origin;
|
||||||
const invidious = { Player: invidious_embed, PlayerState: { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3, CUED: 5 }, ready: invidious_ready };
|
const invidious = { Player: invidious_embed, PlayerState: { ENDED: 0, PLAYING: 1, PAUSED: 2, BUFFERING: 3, CUED: 5 }, ready: invidious_ready };
|
||||||
try {
|
if (typeof onInvidiousIframeAPIReady === 'function'){
|
||||||
onInvidiousIframeAPIReady();
|
onInvidiousIframeAPIReady();
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
const YT = invidious;
|
||||||
|
|
Loading…
Reference in New Issue