From 309ff409436a5a016c33f71f8b483d9ed226aaaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs?= Date: Sun, 29 Aug 2021 22:43:10 -0500 Subject: watch.html: Move loose inline javascript into watch.js The number of inline code blocks and the dependencies between them became unmanageable. From 9d96c07a3c2e68f1893634574c3be64e41a2c041 Mon Sep 17 00:00:00 2001 From: James Taylor --- youtube/static/js/av-merge.js | 7 -- youtube/static/js/speedyplay.js | 13 --- youtube/static/js/watch.js | 201 ++++++++++++++++++++++++++++++++++++ youtube/templates/watch.html | 219 +--------------------------------------- youtube/watch.py | 5 +- 5 files changed, 209 insertions(+), 236 deletions(-) delete mode 100644 youtube/static/js/speedyplay.js create mode 100644 youtube/static/js/watch.js diff --git a/youtube/static/js/av-merge.js b/youtube/static/js/av-merge.js index 3831bcc..f6ea007 100644 --- a/youtube/static/js/av-merge.js +++ b/youtube/static/js/av-merge.js @@ -19,13 +19,6 @@ // TODO: Call abort to cancel in-progress appends? - -var avMerge; - -function avInitialize(...args){ - avMerge = new AVMerge(...args); -} - function AVMerge(video, srcPair, startTime){ this.videoSource = srcPair[0]; this.audioSource = srcPair[1]; diff --git a/youtube/static/js/speedyplay.js b/youtube/static/js/speedyplay.js deleted file mode 100644 index 58b5d33..0000000 --- a/youtube/static/js/speedyplay.js +++ /dev/null @@ -1,13 +0,0 @@ -(function main() { - 'use strict'; - const video = document.getElementById('js-video-player'); - const speedInput = document.getElementById('speed-control'); - speedInput.addEventListener('keyup', (event) => { - if (event.key === 'Enter') { - let speed = parseFloat(speedInput.value); - if(!isNaN(speed)){ - video.playbackRate = speed; - } - } - }); -}()); diff --git a/youtube/static/js/watch.js b/youtube/static/js/watch.js new file mode 100644 index 0000000..38aab3f --- /dev/null +++ b/youtube/static/js/watch.js @@ -0,0 +1,201 @@ +var video = document.getElementById('js-video-player'); + +function changeQuality(selection) { + var currentVideoTime = video.currentTime; + var videoPaused = video.paused; + var videoSpeed = video.playbackRate; + var videoSource; + if (avMerge) + avMerge.close(); + if (selection.type == 'uni'){ + videoSource = data['uni_sources'][selection.index]; + video.src = videoSource.url; + } else { + let srcPair = data['pair_sources'][selection.index]; + videoSource = srcPair[0]; + avMerge = new AVMerge(video, srcPair, currentVideoTime); + } + video.currentTime = currentVideoTime; + if (!videoPaused){ + video.play(); + } + video.playbackRate = videoSpeed; +} + +// Initialize av-merge +var avMerge; +if (data.using_pair_sources) { + var srcPair = data['pair_sources'][data['pair_idx']]; + var videoSource = srcPair[0]; + // Do it dynamically rather than as the default in jinja + // in case javascript is disabled + avMerge = new AVMerge(video, srcPair, 0); +} + +// Quality selector +document.getElementById('quality-select').addEventListener( + 'change', function(e) { + changeQuality(JSON.parse(this.value)) + } +); + +// Set up video start time from &t parameter +if (data.time_start != 0 && video) + video.currentTime = data.time_start; + +// External video speed control +var speedInput = document.getElementById('speed-control'); +speedInput.addEventListener('keyup', (event) => { + if (event.key === 'Enter') { + var speed = parseFloat(speedInput.value); + if(!isNaN(speed)){ + video.playbackRate = speed; + } + } +}); + + +// Playlist lazy image loading +if (data.playlist && data.playlist['id'] !== null) { + // lazy load playlist images + // copied almost verbatim from + // https://css-tricks.com/tips-for-rolling-your-own-lazy-loading/ + // IntersectionObserver isn't supported in pre-quantum + // firefox versions, but the alternative of making it + // manually is a performance drain, so oh well + var observer = new IntersectionObserver(lazyLoad, { + + // where in relation to the edge of the viewport, we are observing + rootMargin: "100px", + + // how much of the element needs to have intersected + // in order to fire our loading function + threshold: 1.0 + + }); + + function lazyLoad(elements) { + elements.forEach(item => { + if (item.intersectionRatio > 0) { + + // set the src attribute to trigger a load + item.target.src = item.target.dataset.src; + + // stop observing this element. Our work here is done! + observer.unobserve(item.target); + }; + }); + }; + + // Tell our observer to observe all img elements with a "lazy" class + var lazyImages = document.querySelectorAll('img.lazy'); + lazyImages.forEach(img => { + observer.observe(img); + }); +} + + +// Autoplay +if (data.settings.related_videos_mode !== 0 || data.playlist !== null) { + let playability_error = !!data.playability_error; + let isPlaylist = false; + if (data.playlist !== null && data.playlist['current_index'] !== null) + isPlaylist = true; + + // read cookies on whether to autoplay + // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie + let cookieValue; + let playlist_id; + if (isPlaylist) { + // from https://stackoverflow.com/a/6969486 + function escapeRegExp(string) { + // $& means the whole matched string + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + playlist_id = data.playlist['id']; + playlist_id = escapeRegExp(playlist_id); + + cookieValue = document.cookie.replace(new RegExp( + '(?:(?:^|.*;\\s*)autoplay_' + + playlist_id + '\\s*\\=\\s*([^;]*).*$)|^.*$' + ), '$1'); + } else { + cookieValue = document.cookie.replace(new RegExp( + '(?:(?:^|.*;\\s*)autoplay\\s*\\=\\s*([^;]*).*$)|^.*$' + ),'$1'); + } + + let autoplayEnabled = 0; + if(cookieValue.length === 0){ + autoplayEnabled = 0; + } else { + autoplayEnabled = Number(cookieValue); + } + + // check the checkbox if autoplay is on + let checkbox = document.querySelector('.autoplay-toggle'); + if(autoplayEnabled){ + checkbox.checked = true; + } + + // listen for checkbox to turn autoplay on and off + let cookie = 'autoplay' + if (isPlaylist) + cookie += '_' + playlist_id; + + checkbox.addEventListener( 'change', function() { + if(this.checked) { + autoplayEnabled = 1; + document.cookie = cookie + '=1; SameSite=Strict'; + } else { + autoplayEnabled = 0; + document.cookie = cookie + '=0; SameSite=Strict'; + } + }); + + if(!playability_error){ + // play the video if autoplay is on + if(autoplayEnabled){ + video.play(); + } + } + + // determine next video url + let nextVideoUrl; + if (isPlaylist) { + let currentIndex = data.playlist['current_index']; + if (data.playlist['current_index']+1 == data.playlist['items'].length) + nextVideoUrl = null; + else + nextVideoUrl = data.playlist['items'][data.playlist['current_index']+1]['url']; + + // scroll playlist to proper position + // item height + gap == 100 + let pl = document.querySelector('.playlist-videos'); + pl.scrollTop = 100*currentIndex; + } else { + if (data.related.length === 0) + nextVideoUrl = null; + else + nextVideoUrl = data.related[0]['url']; + } + let nextVideoDelay = 1000; + + // go to next video when video ends + // https://stackoverflow.com/a/2880950 + if (nextVideoUrl) { + if(playability_error){ + videoEnded(); + } else { + video.addEventListener('ended', videoEnded, false); + } + function nextVideo(){ + if(autoplayEnabled){ + window.location.href = nextVideoUrl; + } + } + function videoEnded(e) { + window.setTimeout(nextVideo, nextVideoDelay); + } + } +} diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html index 4b2aa50..5b0fce5 100644 --- a/youtube/templates/watch.html +++ b/youtube/templates/watch.html @@ -54,49 +54,6 @@ {% endfor %} - - - - {% if using_pair_sources %} - - - {% endif %} - - {% if time_start != 0 %} - - {% endif %} {% endif %}
@@ -125,7 +82,6 @@
- -
@@ -212,7 +161,7 @@

{{ playlist['title'] }}

{% elif settings.related_videos_mode != 0 %} - - {% endif %} - - {% if settings.related_videos_mode != 0 or playlist %} - + {% endif %} - {% if subtitle_sources %}
@@ -448,6 +235,8 @@
+ + {% if settings.use_video_player == 2 %} diff --git a/youtube/watch.py b/youtube/watch.py index e397574..5bb3341 100644 --- a/youtube/watch.py +++ b/youtube/watch.py @@ -654,7 +654,6 @@ def get_watch_page(video_id=None): invidious_reload_button = info['invidious_reload_button'], video_url = util.URL_ORIGIN + '/watch?v=' + video_id, video_id = video_id, - time_start = time_start, js_data = { 'video_id': info['id'], @@ -663,6 +662,10 @@ def get_watch_page(video_id=None): 'has_manual_captions': any(s.get('on') for s in subtitle_sources), **source_info, 'using_pair_sources': using_pair_sources, + 'time_start': time_start, + 'playlist': info['playlist'], + 'related': info['related_videos'], + 'playability_error': info['playability_error'], }, font_family=youtube.font_choices[settings.font], **source_info, -- cgit v1.2.3