diff --git a/assets/js/embed.js b/assets/js/embed.js index 04b08ca5..3d56c4ff 100644 --- a/assets/js/embed.js +++ b/assets/js/embed.js @@ -6,12 +6,12 @@ function get_playlist(plid, timeouts = 0) { if (plid.startsWith('RD')) { var plid_url = '/api/v1/mixes/' + plid + - '?continuation=' + embed_data.id + - '&format=html&hl=' + embed_data.preferences.locale; + '?continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; } else { var plid_url = '/api/v1/playlists/' + plid + - '?continuation=' + embed_data.id + - '&format=html&hl=' + embed_data.preferences.locale; + '?continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; } var xhr = new XMLHttpRequest(); @@ -21,22 +21,22 @@ function get_playlist(plid, timeouts = 0) { xhr.send(); xhr.onreadystatechange = function () { - if (xhr.readyState == 4) { - if (xhr.status == 200) { + if (xhr.readyState === 4) { + if (xhr.status === 200) { if (xhr.response.nextVideo) { player.on('ended', function () { var url = new URL('https://example.com/embed/' + xhr.response.nextVideo); - if (embed_data.params.autoplay || embed_data.params.continue_autoplay) { + if (video_data.params.autoplay || video_data.params.continue_autoplay) { url.searchParams.set('autoplay', '1'); } - if (embed_data.params.listen !== embed_data.preferences.listen) { - url.searchParams.set('listen', embed_data.params.listen); + if (video_data.params.listen !== video_data.preferences.listen) { + url.searchParams.set('listen', video_data.params.listen); } - if (embed_data.params.speed !== embed_data.preferences.speed) { - url.searchParams.set('speed', embed_data.params.speed); + if (video_data.params.speed !== video_data.preferences.speed) { + url.searchParams.set('speed', video_data.params.speed); } url.searchParams.set('list', plid); @@ -53,26 +53,26 @@ function get_playlist(plid, timeouts = 0) { } } -if (embed_data.plid) { - get_playlist(embed_data.plid); -} else if (embed_data.video_series) { +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/' + embed_data.video_series.shift()); + var url = new URL('https://example.com/embed/' + video_data.video_series.shift()); - if (embed_data.params.autoplay || embed_data.params.continue_autoplay) { + if (video_data.params.autoplay || video_data.params.continue_autoplay) { url.searchParams.set('autoplay', '1'); } - if (embed_data.params.listen !== embed_data.preferences.listen) { - url.searchParams.set('listen', embed_data.params.listen); + if (video_data.params.listen !== video_data.preferences.listen) { + url.searchParams.set('listen', video_data.params.listen); } - if (embed_data.params.speed !== embed_data.preferences.speed) { - url.searchParams.set('speed', embed_data.params.speed); + if (video_data.params.speed !== video_data.preferences.speed) { + url.searchParams.set('speed', video_data.params.speed); } - if (embed_data.video_series.length !== 0) { - url.searchParams.set('playlist', embed_data.video_series.join(',')) + if (video_data.video_series.length !== 0) { + url.searchParams.set('playlist', video_data.video_series.join(',')) } location.assign(url.pathname + url.search); diff --git a/assets/js/player.js b/assets/js/player.js new file mode 100644 index 00000000..be76b674 --- /dev/null +++ b/assets/js/player.js @@ -0,0 +1,231 @@ +var options = { + preload: "auto", + playbackRates: [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 2.0], + controlBar: { + children: [ + "playToggle", + "volumePanel", + "currentTimeDisplay", + "timeDivider", + "durationDisplay", + "progressControl", + "remainingTimeDisplay", + "captionsButton", + "qualitySelector", + "playbackRateMenuButton", + "fullscreenToggle" + ] + } +} + +if (player_data.aspect_ratio) { + options.aspectRatio = player_data.aspect_ratio; +} + +var embed_url = new URL(location); +embed_url.searchParams.delete('v'); +embed_url = location.origin + '/embed/' + video_data.id + embed_url.search; + +var shareOptions = { + socials: ["fbFeed", "tw", "reddit", "email"], + + url: window.location.href, + title: player_data.title, + description: player_data.description, + image: player_data.thumbnail, + embedCode: "" +} + +var player = videojs("player", options, function () { + this.hotkeys({ + volumeStep: 0.1, + seekStep: 5, + enableModifiersForNumbers: false, + enableHoverScroll: true, + customKeys: { + // Toggle play with K Key + play: { + key: function (e) { + return e.which === 75; + }, + handler: function (player, options, e) { + if (player.paused()) { + player.play(); + } else { + player.pause(); + } + } + }, + // Go backward 10 seconds + backward: { + key: function (e) { + return e.which === 74; + }, + handler: function (player, options, e) { + player.currentTime(player.currentTime() - 10); + } + }, + // Go forward 10 seconds + forward: { + key: function (e) { + return e.which === 76; + }, + handler: function (player, options, e) { + player.currentTime(player.currentTime() + 10); + } + }, + // Increase speed + increase_speed: { + key: function (e) { + return (e.which === 190 && e.shiftKey); + }, + handler: function (player, _, e) { + size = options.playbackRates.length; + index = options.playbackRates.indexOf(player.playbackRate()); + player.playbackRate(options.playbackRates[(index + 1) % size]); + } + }, + // Decrease speed + decrease_speed: { + key: function (e) { + return (e.which === 188 && e.shiftKey); + }, + handler: function (player, _, e) { + size = options.playbackRates.length; + index = options.playbackRates.indexOf(player.playbackRate()); + player.playbackRate(options.playbackRates[(size + index - 1) % size]); + } + } + } + }); +}); + +player.on('error', function (event) { + if (player.error().code === 2 || player.error().code === 4) { + setInterval(setTimeout(function (event) { + console.log('An error occured in the player, reloading...'); + + var currentTime = player.currentTime(); + var playbackRate = player.playbackRate(); + var paused = player.paused(); + + player.load(); + + if (currentTime > 0.5) { + currentTime -= 0.5; + } + + player.currentTime(currentTime); + player.playbackRate(playbackRate); + + if (!paused) { + player.play(); + } + }, 5000), 5000); + } +}); + +// Add markers +if (video_data.params.video_start > 0 || video_data.params.video_end > 0) { + var markers = [{ time: video_data.params.video_start, text: 'Start' }]; + + if (video_data.params.video_end < 0) { + markers.push({ time: video_data.length_seconds - 0.5, text: 'End' }); + } else { + markers.push({ time: video_data.params.video_end, text: 'End' }); + } + + player.markers({ + onMarkerReached: function (marker) { + if (marker.text === 'End') { + if (player.loop()) { + player.markers.prev('Start'); + } else { + player.pause(); + } + } + }, + markers: markers + }); + + player.currentTime(video_data.params.video_start); +} + +player.volume(video_data.params.volume / 100); +player.playbackRate(video_data.params.speed); + +if (video_data.params.autoplay) { + var bpb = player.getChild('bigPlayButton'); + + if (bpb) { + bpb.hide(); + + player.ready(function () { + new Promise(function (resolve, reject) { + setTimeout(() => resolve(1), 1); + }).then(function (result) { + var promise = player.play(); + + if (promise !== undefined) { + promise.then(_ => { + }).catch(error => { + bpb.show(); + }); + } + }); + }); + } +} + +if (!video_data.params.listen && video_data.params.quality === 'dash') { + player.httpSourceSelector(); +} + +player.vttThumbnails({ + src: location.origin + '/api/v1/storyboards/' + video_data.id + '?height=90' +}); + +// Enable annotations +if (video_data.params.listen && video_data.params.annotations) { + var video_container = document.getElementById('player'); + let xhr = new XMLHttpRequest(); + xhr.responseType = 'text'; + xhr.timeout = 60000; + xhr.open('GET', '/api/v1/annotations/' + video_data.id, true); + xhr.send(); + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + videojs.registerPlugin('youtubeAnnotationsPlugin', youtubeAnnotationsPlugin); + if (!player.paused()) { + player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container }); + } else { + player.one('play', function (event) { + player.youtubeAnnotationsPlugin({ annotationXml: xhr.response, videoContainer: video_container }); + }); + } + } + } + } + + window.addEventListener('__ar_annotation_click', e => { + const { url, target, seconds } = e.detail; + var path = new URL(url); + + if (path.href.startsWith('https://www.youtube.com/watch?') && seconds) { + path.search += '&t=' + seconds; + } + + path = path.pathname + path.search; + + if (target === 'current') { + window.location.href = path; + } else if (target === 'new') { + window.open(path, '_blank'); + } + }); +} + +// Since videojs-share can sometimes be blocked, we defer it until last +player.share(shareOptions); diff --git a/assets/js/watch.js b/assets/js/watch.js index c5a29313..4ce31014 100644 --- a/assets/js/watch.js +++ b/assets/js/watch.js @@ -51,21 +51,24 @@ function hide_youtube_replies(target, inner_text, sub_text) { target.setAttribute('onclick', "show_youtube_replies(this, \'" + inner_text + "\', \'" + sub_text + "\')"); } -function continue_autoplay(target) { - if (target.checked) { - player.on('ended', function () { - var url = new URL('https://example.com/watch?v=' + watch_data.next_video); +var continue_button = document.getElementById('continue'); +continue_button.onclick = continue_autoplay; - if (watch_data.params.autoplay || watch_data.params.continue_autoplay) { +function continue_autoplay(event) { + if (event.target.checked) { + 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 (watch_data.params.listen !== watch_data.preferences.listen) { - url.searchParams.set('listen', watch_data.params.listen); + if (video_data.params.listen !== video_data.preferences.listen) { + url.searchParams.set('listen', video_data.params.listen); } - if (watch_data.params.speed !== watch_data.preferences.speed) { - url.searchParams.set('speed', watch_data.params.speed); + if (video_data.params.speed !== video_data.preferences.speed) { + url.searchParams.set('speed', video_data.params.speed); } url.searchParams.set('continue', '1'); @@ -98,12 +101,12 @@ function get_playlist(plid, timeouts = 0) { if (plid.startsWith('RD')) { var plid_url = '/api/v1/mixes/' + plid + - '?continuation=' + watch_data.id + - '&format=html&hl=' + watch_data.preferences.locale; + '?continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; } else { var plid_url = '/api/v1/playlists/' + plid + - '?continuation=' + watch_data.id + - '&format=html&hl=' + watch_data.preferences.locale; + '?continuation=' + video_data.id + + '&format=html&hl=' + video_data.preferences.locale; } var xhr = new XMLHttpRequest(); @@ -119,18 +122,18 @@ function get_playlist(plid, timeouts = 0) { if (xhr.response.nextVideo) { player.on('ended', function () { - var url = new URL('https://example.com/watch?v=' + watch_data.next_video); + var url = new URL('https://example.com/watch?v=' + video_data.next_video); - if (watch_data.params.autoplay || watch_data.params.continue_autoplay) { + if (video_data.params.autoplay || video_data.params.continue_autoplay) { url.searchParams.set('autoplay', '1'); } - if (watch_data.params.listen !== watch_data.preferences.listen) { - url.searchParams.set('listen', watch_data.params.listen); + if (video_data.params.listen !== video_data.preferences.listen) { + url.searchParams.set('listen', video_data.params.listen); } - if (watch_data.params.speed !== watch_data.preferences.speed) { - url.searchParams.set('speed', watch_data.params.speed); + if (video_data.params.speed !== video_data.preferences.speed) { + url.searchParams.set('speed', video_data.params.speed); } url.searchParams.set('list', plid); @@ -166,9 +169,9 @@ function get_reddit_comments(timeouts = 0) { comments.innerHTML = '

'; - var url = '/api/v1/comments/' + watch_data.id + + var url = '/api/v1/comments/' + video_data.id + '?source=reddit&format=html' + - '&hl=' + watch_data.preferences.locale; + '&hl=' + video_data.preferences.locale; var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.timeout = 20000; @@ -198,13 +201,13 @@ function get_reddit_comments(timeouts = 0) {
{contentHtml}
\
'.supplant({ title: xhr.response.title, - youtubeCommentsText: watch_data.youtube_comments_text, - redditPermalinkText: watch_data.reddit_permalink_text, + youtubeCommentsText: video_data.youtube_comments_text, + redditPermalinkText: video_data.reddit_permalink_text, permalink: xhr.response.permalink, contentHtml: xhr.response.contentHtml }); } else { - if (watch_data.preferences.comments[1] === 'youtube') { + if (video_data.preferences.comments[1] === 'youtube') { get_youtube_comments(timeouts + 1); } else { comments.innerHTML = fallback; @@ -232,10 +235,10 @@ function get_youtube_comments(timeouts = 0) { comments.innerHTML = '

'; - var url = '/api/v1/comments/' + watch_data.id + + var url = '/api/v1/comments/' + video_data.id + '?format=html' + - '&hl=' + watch_data.preferences.locale + - '&thin_mode=' + watch_data.preferences.thin_mode; + '&hl=' + video_data.preferences.locale + + '&thin_mode=' + video_data.preferences.thin_mode; var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.timeout = 20000; @@ -261,8 +264,8 @@ function get_youtube_comments(timeouts = 0) {
{contentHtml}
\
'.supplant({ contentHtml: xhr.response.contentHtml, - redditComments: watch_data.reddit_comments_text, - commentsText: watch_data.comments_text.supplant( + redditComments: video_data.reddit_comments_text, + commentsText: video_data.comments_text.supplant( { commentCount: number_with_separator(xhr.response.commentCount) } ) }); @@ -270,7 +273,7 @@ function get_youtube_comments(timeouts = 0) { comments.innerHTML = ''; } } else { - if (watch_data.preferences[1] === 'youtube') { + if (video_data.preferences[1] === 'youtube') { get_youtube_comments(timeouts + 1); } else { comments.innerHTML = ''; @@ -295,10 +298,10 @@ function get_youtube_replies(target, load_more) { body.innerHTML = '

'; - var url = '/api/v1/comments/' + watch_data.id + + var url = '/api/v1/comments/' + video_data.id + '?format=html' + - '&hl=' + watch_data.preferences.locale + - '&thin_mode=' + watch_data.preferences.thin_mode + + '&hl=' + video_data.preferences.locale + + '&thin_mode=' + video_data.preferences.thin_mode + '&continuation=' + continuation; var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; @@ -319,8 +322,8 @@ function get_youtube_replies(target, load_more) { onclick="hide_youtube_replies(this, \'{hideRepliesText}\', \'{showRepliesText}\')">{hideRepliesText} \

\
{contentHtml}
'.supplant({ - hideRepliesText: watch_data.hide_replies_text, - showRepliesText: watch_data.show_replies_text, + hideRepliesText: video_data.hide_replies_text, + showRepliesText: video_data.show_replies_text, contentHtml: xhr.response.contentHtml }); } @@ -336,20 +339,20 @@ function get_youtube_replies(target, load_more) { } } -if (watch_data.play_next) { +if (video_data.play_next) { player.on('ended', function () { - var url = new URL('https://example.com/watch?v=' + watch_data.next_video); + var url = new URL('https://example.com/watch?v=' + video_data.next_video); - if (watch_data.params.autoplay || watch_data.params.continue_autoplay) { + if (video_data.params.autoplay || video_data.params.continue_autoplay) { url.searchParams.set('autoplay', '1'); } - if (watch_data.params.listen !== watch_data.preferences.listen) { - url.searchParams.set('listen', watch_data.params.listen); + if (video_data.params.listen !== video_data.preferences.listen) { + url.searchParams.set('listen', video_data.params.listen); } - if (watch_data.params.speed !== watch_data.preferences.speed) { - url.searchParams.set('speed', watch_data.params.speed); + if (video_data.params.speed !== video_data.preferences.speed) { + url.searchParams.set('speed', video_data.params.speed); } url.searchParams.set('continue', '1'); @@ -357,17 +360,17 @@ if (watch_data.play_next) { }); } -if (watch_data.plid) { - get_playlist(watch_data.plid); +if (video_data.plid) { + get_playlist(video_data.plid); } -if (watch_data.preferences.comments[0] === 'youtube') { +if (video_data.preferences.comments[0] === 'youtube') { get_youtube_comments(); -} else if (watch_data.preferences.comments[0] === 'reddit') { +} else if (video_data.preferences.comments[0] === 'reddit') { get_reddit_comments(); -} else if (watch_data.preferences.comments[1] === 'youtube') { +} else if (video_data.preferences.comments[1] === 'youtube') { get_youtube_comments(); -} else if (watch_data.preferences.comments[1] === 'reddit') { +} else if (video_data.preferences.comments[1] === 'reddit') { get_reddit_comments(); } else { comments = document.getElementById('comments'); diff --git a/src/invidious/views/components/player.ecr b/src/invidious/views/components/player.ecr index a9dfe896..c17b5464 100644 --- a/src/invidious/views/components/player.ecr +++ b/src/invidious/views/components/player.ecr @@ -40,228 +40,11 @@ + diff --git a/src/invidious/views/embed.ecr b/src/invidious/views/embed.ecr index 380a3806..5e0f2349 100644 --- a/src/invidious/views/embed.ecr +++ b/src/invidious/views/embed.ecr @@ -23,17 +23,18 @@ -<%= rendered "components/player" %> - + +<%= rendered "components/player" %> diff --git a/src/invidious/views/watch.ecr b/src/invidious/views/watch.ecr index 26f19e3d..796b8d01 100644 --- a/src/invidious/views/watch.ecr +++ b/src/invidious/views/watch.ecr @@ -26,6 +26,24 @@ <%= HTML.escape(video.title) %> - Invidious <% end %> + +
<%= rendered "components/player" %>
@@ -224,21 +242,4 @@ <% end %> - -