aboutsummaryrefslogtreecommitdiffstats
path: root/youtube/static/js/watch.js
diff options
context:
space:
mode:
authorAstounds <kirito@disroot.org>2026-04-20 01:22:55 -0400
committerheckyel <heckyel@noreply.git.fridu.us>2026-04-20 01:22:55 -0400
commita0f315be51ef121618e73d5b450c8616c0d11d21 (patch)
treeb68f1268a901ded1a7afd2f12a16aed8d9f3d307 /youtube/static/js/watch.js
parent62a028968e6d9b4e821b6014d6658b8317328fcf (diff)
downloadyt-local-0.5.0.tar.lz
yt-local-0.5.0.tar.xz
yt-local-0.5.0.zip
feature/hls: Add HLS playback support, and refactors documentation for better usability and maintainability. (#1)HEADv0.5.0master
## Overview This PR introduces HLS playback support, improves the player experience, and refactors documentation for better usability and maintainability. ## Key Features ### HLS Playback Support - Add HLS integration via new JavaScript assets: - `hls.min.js` - `plyr.hls.start.js` - `watch.hls.js` - Separate DASH and HLS logic: - `plyr-start.js` → `plyr.dash.start.js` - `watch.js` → `watch.dash.js` - Update templates (`embed.html`, `watch.html`) for conditional player loading ### Native Storyboard Preview - Add `native_player_storyboard` setting in `settings.py` - Implement hover thumbnail preview for native player modes - Add `storyboard-preview.js` ### UI and Player Adjustments - Update templates and styles (`custom_plyr.css`) - Modify backend modules to support new player modes: - `watch.py`, `channel.py`, `util.py`, and related components ### Internationalization - Update translation files: - `messages.po` - `messages.pot` ### Testing and CI - Add and update tests: - `test_shorts.py` - `test_util.py` - Minor CI and release script improvements ## Documentation ### OpenRC Service Guide Rewrite - Restructure `docs/basic-script-openrc/README.md` into: - Prerequisites - Installation - Service Management - Verification - Troubleshooting - Add admonition blocks: - `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]` - Fix log inspection command: ```bash doas tail -f /var/log/ytlocal.log ```` * Add path placeholders and clarify permission requirements * Remove legacy and duplicate content Reviewed-on: https://git.fridu.us/heckyel/yt-local/pulls/1 Co-authored-by: Astounds <kirito@disroot.org> Co-committed-by: Astounds <kirito@disroot.org>
Diffstat (limited to 'youtube/static/js/watch.js')
-rw-r--r--youtube/static/js/watch.js200
1 files changed, 0 insertions, 200 deletions
diff --git a/youtube/static/js/watch.js b/youtube/static/js/watch.js
deleted file mode 100644
index 00803cf..0000000
--- a/youtube/static/js/watch.js
+++ /dev/null
@@ -1,200 +0,0 @@
-const video = document.getElementById('js-video-player');
-
-function changeQuality(selection) {
- let currentVideoTime = video.currentTime;
- let videoPaused = video.paused;
- let videoSpeed = video.playbackRate;
- let srcInfo;
- if (avMerge && typeof avMerge.close === 'function') {
- avMerge.close();
- }
- if (selection.type == 'uni'){
- srcInfo = data['uni_sources'][selection.index];
- video.src = srcInfo.url;
- } else {
- srcInfo = data['pair_sources'][selection.index];
- avMerge = new AVMerge(video, srcInfo, currentVideoTime);
- }
- video.currentTime = currentVideoTime;
- if (!videoPaused){
- video.play();
- }
- video.playbackRate = videoSpeed;
-}
-
-// Initialize av-merge
-let avMerge;
-if (data.using_pair_sources) {
- let srcPair = data['pair_sources'][data['pair_idx']];
- // Do it dynamically rather than as the default in jinja
- // in case javascript is disabled
- avMerge = new AVMerge(video, srcPair, 0);
-}
-
-// Quality selector
-const qs = document.getElementById('quality-select');
-if (qs) {
- qs.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
-let speedInput = document.getElementById('speed-control');
-speedInput.addEventListener('keyup', (event) => {
- if (event.key === 'Enter') {
- let 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
- let 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
- let 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);
- }
- }
-}