Yt6 -- Snarl's YouTube Video Player (bookmarklet)
Latest version: 2024-08-18-19:49
Features
On any YouTube video (watch) page, this bookmarklet will call an external player and load some extra functions, some of which can be used with YouTube's original player as well. Written in pure javascript with the aim to be as much platform-independent and backward-compatible as possible. There is no installation, it works on-demand. Only a working internet connection is needed. The program is able to- restrict on-site advertisement -- suppress endscreen cards, auto-skip or just auto-mute video ads (in case some may be interesting to you),
- resize, zoom, rotate and move around video picture arbitrarily,
- pick your favoured and supported video/audio codec and resolution for playback,
- select the desired media sequence to loop -- custom loop segments become active once the starting and ending time input fields disappear,
- change playback rate ("speed" or tempo) from 0 up to 1600%,
- replace soundtrack with any external audio (or video) file across the net
- grab media URLs directly from the "shorts" pages,
- download the video/audio content,
- occasionally extract video commercials as well, accessible through the alternative links,
- download subtitles/closed captions (CC)
-
On bookmarklet line, you can edit the value
of "add_subs" after the equal sign and between apostrophes (a comma separated list
of ISO 639-1 languge codes, such as
'en, de, fr, es, ja'
...) to add Google-Translated tracks of your choice, - facilitate background play while your mobile is in sleep mode,
- bypass age verification
- show videos in mobile view which are otherwise available only in desktop view mode
- Works only if you select a video-only format of the youtube video, and play it back with the progressive download method,
Keep in mind that this is not a browser extension. If anything it is an extension of the YouTube video page. Any event resulting in a browser page reload such as
-
- leaving the current YT subdomain,
- typing URLs directly to the address bar instead of following links,
- or even just navigating between two points in your browsing history where a full page refresh has already taken place
Please note:
Setup
- Right click (on mobile, hold your finger) on the Yt6 link above, and "Copy link address".
- Bookmark any web page (this one for example)
- Edit the created bookmark's Properties / Location:
- Save the changes if there is a Save button!
- If you have no such option, the code is written in plain text below, select and copy it manually.
- delete its URL-address entirely and paste this snippet of javascript code in its place.
(Optionally, you can give it a name of your choice.)
That's it, your bookmarklet is now ready to use.
Also, in many desktop browsers you can simply drag and drop the link to the Bookmarks Toolbar, or right click on it and select "Bookmark this link" -- however, some browsers may automatically replace the dragged / right-clicked link's address with a useless
about:blank#blocked
line. It is default precaution for any javascript code behind a link
as this programming language is easy to abuse. The copy-paste method is your best
choice.
CODE IN PLAIN TEXT
javascript:(function(){var v='2c7ae5f3cf051eeeaeeebeecbb0d4b997875a7c4/yt6.js',y='youtube.com/',w=window,d=w.document,h=d.location.href,yt6=w.yt6||{},yt6d=w.yt6d||{},t=w.trustedTypes;if(yt6d.loaded>=4)return void 0;if(h.split(y+'watch')[1]||h.split(y+'embed')[1]||h.split('playlist')[1]||h.split(y+'shorts')[1]||h.split('/base.j')[1]=='s'){var id='snarls_player',e='script',q,u=function(s){if(typeof s=='string')return s};try{t.createPolicy('default',{createHTML:u,createScriptURL:u,createScript:u,})}catch(f){};yt6.loaded=0;function s(x){x=x||id;return d.getElementById(x)};function c(e){return d.createElement(e)};function a(q){s().appendChild(q);s().add_subs='en,hu,de';s().version='2024-08-18-19:49';yt6d.src=q.src};function r(){if(s()){var x;try{x=s().querySelector('#'+id)}catch(e){x=s().firstChild};if(x)s().removeChild(x)}};function b(){var i,j,o,x;o=['rawcdn.githack','js','cdn.rawgit'];for(j,x,i=o.length;i;j=Math.floor(Math.random()*i),x=o[--i],o[i]=o[j],o[j]=x);q=c('div');q.id=id;if(q!=s())d.body.appendChild(q);var src='https://'+o[0]+'.com/snarly/yt6/'+v,src0='https://cdn.jsdelivr.net/gh/snarly/yt6@'+v;function oc(ox,oy,sr){return(oy!='js')?sr.replace(ox,oy):src0};q=c(e);q.id=id;q.src=(o[0]!='js')?src:src0; q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[1],src);q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[2],src);q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[3],src);q.onerror=function(){q=c(e);q.id=id;q.src=src.replace('https','http')};a(q);r();};a(q);r();};a(q);r();};try{a(q);}catch(f){a(q)};};function g(){try{deldiv()}catch(f){r()};b()};if(!s()){b()};setTimeout(function(){var t=w.yt6;if(t)t.loaded=t.loaded||window['status'];if(!t||(t&&(!t.body||(t.loaded<3))))g()},3000);}else{void 0};})()/*2024-08-18-19:49*/
How to use
On Desktop, just click on it on your bookmarks list whenever you enter a YouTube video you want to play around with, unless you have the code already running.On Mobile
- Tap the browser's address bar first (NOT the YouTube search bar!)
- The browser should suggest the bookmarklet as an available option
- Tapping on the correct entry shall initiate the call.
- this will select / highlight the whole address of the current YouTube video page.
Loading time depends on your internet connection and the current traffic on the storage servers, but it should be up and running within a few seconds. If it doesn't seem to work, it may be because of installed script blocker extensions. See the Important Notes section to learn how to resolve this.
Automatic playback depends on the state of YouTube's own "Repeat / Loop Playlist" (the circular arrows) button on user-created playlists.
Use the HTML5 emblem on the control panel to switch between the native and this alternative player.
It is possible to use the bookmarklet code as a userscript with the help of add-ons like
-
Greasemonkey (for Firefox),
Tampermonkey (for Firefox, Chrome, Edge and Opera) or
Violentmonkey (for Firefox, Chrome and Edge)
// ==UserScript== // @name Yt6 -- Snarl's YouTube Video Player (userscript) // @namespace yt6 // @version 2024-08-18-19:49 // @author Snarl // @description Auto-Load Yt6 script as soon as possible // @match https://*.youtube.com/watch* // @match https://*.youtube.com/embed/* // @match http://*.youtube.com/watch* // @match http://*.youtube.com/embed/* // @grant none // @run-at document-end // @icon https://yt3.ggpht.com/-afBnHVG_R6E/AAAAAAAAAAI/AAAAAAAAAAA/LtE5kbPkZvE/s27-c-k-no-mo-rj-c0xffffff/photo.jpg // ==/UserScript== (function(){ window['yt6'] = {}; window['yt6d'] = {}; window['yt6'].body = 1 var idle_time = 2000 // wait some time before running the bookmarklet part var onComplete = function(){setTimeout( //javascript:( function(){var v='2c7ae5f3cf051eeeaeeebeecbb0d4b997875a7c4/yt6.js',y='youtube.com/',w=window,d=w.document,h=d.location.href,yt6=w.yt6||{},yt6d=w.yt6d||{},t=w.trustedTypes;if(yt6d.loaded>=4)return void 0;if(h.split(y+'watch')[1]||h.split(y+'embed')[1]||h.split('playlist')[1]||h.split(y+'shorts')[1]||h.split('/base.j')[1]=='s'){var id='snarls_player',e='script',q,u=function(s){if(typeof s=='string')return s};try{t.createPolicy('default',{createHTML:u,createScriptURL:u,createScript:u,})}catch(f){};yt6.loaded=0;function s(x){x=x||id;return d.getElementById(x)};function c(e){return d.createElement(e)};function a(q){s().appendChild(q);s().add_subs='en,hu,de';s().version='2024-08-18-19:49';yt6d.src=q.src};function r(){if(s()){var x;try{x=s().querySelector('#'+id)}catch(e){x=s().firstChild};if(x)s().removeChild(x)}};function b(){var i,j,o,x;o=['rawcdn.githack','js','cdn.rawgit'];for(j,x,i=o.length;i;j=Math.floor(Math.random()*i),x=o[--i],o[i]=o[j],o[j]=x);q=c('div');q.id=id;if(q!=s())d.body.appendChild(q);var src='https://'+o[0]+'.com/snarly/yt6/'+v,src0='https://cdn.jsdelivr.net/gh/snarly/yt6@'+v;function oc(ox,oy,sr){return(oy!='js')?sr.replace(ox,oy):src0};q=c(e);q.id=id;q.src=(o[0]!='js')?src:src0; q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[1],src);q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[2],src);q.onerror=function(){q=c(e);q.id=id;q.src=oc(o[0],o[3],src);q.onerror=function(){q=c(e);q.id=id;q.src=src.replace('https','http')};a(q);r();};a(q);r();};a(q);r();};try{a(q);}catch(f){a(q)};};function g(){try{deldiv()}catch(f){r()};b()};if(!s()){b()};setTimeout(function(){var t=w.yt6;if(t)t.loaded=t.loaded||window['status'];if(!t||(t&&(!t.body||(t.loaded<3))))g()},3000);}else{void 0};} //)()/*2024-08-18-19:49*/ , idle_time) } var check = function(){ // conditions to meet before loading var x = window['performance']; if (x && x.timing && x.timing.loadEventEnd > 0 && x.timing.loadEventEnd >= x.timing.domComplete) return true } if (check()) { onComplete() return } var delay = 500, timeout = 8000 var timeoutPointer var intervalPointer = setInterval(function () { if (!check()) return clearInterval(intervalPointer) if (timeoutPointer) clearTimeout(timeoutPointer) if (typeof onComplete == 'function') onComplete() },delay) if (timeout) timeoutPointer=setTimeout(function () { clearInterval(intervalPointer) },timeout) })()
Note:
- These "monkey"-scripts only seem to work on normal, non-incognito tabs on mobile.
If the launched program appears dysfunctional in Desktop view mode, edit the userscript code through the manager's Dashboard* and try to set the idle_time variable to a higher value (the number is in milliseconds).
Background play on Mobile
You won't have to request YouTube's resource-hungry Desktop mode to be able to listen to videos over a locked screen -- the site's lightweight Mobile version will do just fine.I recommend to use the 48k Opus audio-only format for playback to save as much bandwidth as possible. (The drop in sound quality becomes noticeable only over high-end headphones or on loud sound recordings.) Picking a video format for background play is pretty much pointless anyway and would also raise the chance of playback failure significantly.
Whenever your device is either locked, the browser isn't the app in the foreground, the player's tab is not the active one, or for any god-forsaken reason commercial breaks are being attempted to be skipped, while navigation occurs, YouTube may severely restrict access to new media sources to a couple of formats only -- the ones currently loaded by the original YT player and possibly maybe one or two old-fashioned AV-formats which were kept for compatibility reasons.
And even these scarce sources may point to an advertisement since the ad-filtering is never quite 100% (and is getting worse and worse nowadays rapidly):
- sometimes background play stops because there is only video but no legit audio to play back, as the YT commercial happens to hog all the available audio formats
- other times, all playable formats are from a commercial, but the program still identifies them as advertisement, and rather chooses to repeat the audio track of the previous video
- and there are occasions when the program finds no clue suggesting that every bit of available video and audio are from a commercial, and plays them back as if it were the actual video.
Now that YouTube have upgraded to the newest version of its mobile UI, there is hope that maybe three years from now its bugs will be fixed too. Playlists are simplified to the point where no native skip forward or backward buttons exist, and the list itself appears to be floating over all the other elements on the page -- sometimes stupidly covering even the player itself.
The only way I found around this was to lower the playlist object's opacity a little bit. This may make the control panel re-appear on top of the list but also reduces the size of the area by which you can grab the list in order to scroll up or down. If you still can't see the control panel, there is a backup of the panel located at the lower end of the download box, use that as a last resort. You can also manually toggle between the opacity values of 1 (default) and 0.99 by either tapping on the "Used for playback" or the "Alternatives" button.
Another important change: programmatically we can only move to the next entry of a playlist if the playlist object is not minimized and the upcoming entry is within sight -- i.e. located in close proximity of the currently visible part of the playlist. Every time we "close" the playlist object, the stored links to other videos become invalid in the sense that using them would trigger a full page reload, thereby removing the Yt6 script from memory. Therefore the program first attempts to automatically open the playlist object when a video is getting within 10 seconds away from its end, then tries to scroll near the current video on the list to meet these prerequisites in time, and if they are not met, simply avoids attempting navigation. For now, this mechanism is in the test phase and only works if the "Remove ads" radio button is turned on.
Supported browsers
On Desktop, the script should work with almost any browser. The only criteria is that they must support the usage of bookmarklets or have userscript add-on capabilities, which most of them do.Below is a list of popular Mobile browsers. Ranking them is currently a hopeless venture as recent changes to the YouTube engine broke a lot of things, and now none of the browsers work particularly well with the script as far as energy-saving background play goes.
- Firefox
the uBlock Origin add-on was rendered almost useless on mobile
- Mull*
Firefox-based
- Firefox Nightly
- Brave
definitely the best choice for background play if you don't load the script at all
- Edge
slow video handling but currently the second best in eliminating YT ads
- Vivaldi
the builtin ad-filter has become useless in a mobile environment for some time now
- Kiwi
engulfed by ads
- Google Chrome
defined by ads
- Chromium*
available for older versions of the Android OS only
- Ecosia
seems to be a Brave-clone except much slower
- DuckDuckGo
not sure if it can block anything at all on YT
- Yandex
may only launch the code through a userscript manager
- Bromite*
available only for older versions of the Android OS
Unsupported
- Opera
the mobile version no longer supports bookmarklets -- one less reason to use it
- Firefox Focus, Samsung, Qwant, Mint ...
*Browsers available exclusively through F-Droid, an alternative app store for Android.
Legacy browsers
Till June/July of 2020 the bookmarklet was usable with really old browsers too that were dated back to around the IE7/8 era (with the help of the Adobe Flash plugin), but now that YouTube enforces its bug-filled new layout, they broke compatibility with them.Still, I found a way to make use of this script with outdated browsers anyway.
It's obviously discouraged to use them because of the myriad of security holes that can be found in such old sowftware, not to mention that the development of Adobe Flash also ended officially in 2020. It is possible to reactivate Flash, although only Firefox 84, Edge 87, Chrome 87 and older browsers will acknowledge the presence of the plugin now. But in case you have no other option, the possibility is there.
The trick is to visit the "embed" page which contains a stripped-down code normally used to create an embedded video on other websites. There is literally nothing on these pages beside the player itself, therefore it's super lightweight which makes it a legit choice even for modern browsers (if you just want to listen to a playlist in the background). It's clunky and inconvenient to use on mobile, not recommended there. On desktop, it's okay.
Regular video URL with playlist
https://www.youtube.com/watch?v=d020hcWA_Wg&list=PLNxOe-buLm6cz8UQ-hyG1nm3RTNBUBv3K&index=214
The "embed" variant to enter on the address bar
https://www.youtube.com/embed/d020hcWA_Wg?list=PLNxOe-buLm6cz8UQ-hyG1nm3RTNBUBv3K&index=214
Pro: the alternative player can play videos which are otherwise blocked from view in embedded frames.
Con: due to a YT limitation you can only navigate through the first 200 videos on an embedded playlist.
Stream capturing
The yt6 script can expose URLs in the sourcechooser / download box which doesn't seem to work -- there is no way to load them for playback, and trying to download the linked content would either result in a zero-length file or merely a short segment of a live stream.That's because there is no contiguous media file behind those links. Only fragments of media -- hardly usable in the old-fashioned way -- meant to be streamed by a player capable of streaming. You can recognize these URLs as video- or audio-only sources which have no file size displayed next to them. Since a recent update of the yt6 code, along with the stream URLs appears a link to a "DASH Manifest", and in case of live streams, a "HLS Manifest" too, which are XML documents containing info on the streamable bits.
Here is one example of the "yt_otf" type.
I wrote a small bash shell script called
yt_streamcat
which makes it possible to save
the media behind those type of URLs as well. It's a Command Line Interface (CLI) utility
which relies on a widely used binary program called wget to be installed on the system.
Having ffmpeg, "The swiss army knife of Internet Streaming" installed is a huge bonus,
and in case ffmpeg produces broken media, you may need an alternative tool capable of
media muxing, such as mencoder, to process the broken file and fix it for good.
The script is supplementary code to do the job which is not possible for the yt6 main program in a javascript environment. Save the program file (link below) to an accessible subfolder on your computer -- preferably a dedicated folder you don't mind getting filled up with temporary media file segments -- open a virtual terminal with the bash shell running and change working directory ("cd" in)to that folder.
Currently, the script has only a Linux version available, but it shouldn't be too hard to port it to Windows.
Under Linux, newly created or downloaded files cannot be run by default, regardless of whether they are meant to be executables or not. Technically speaking they are not marked as executable, for security reasons. In order to make a file executable for your own user only, you must run the following command at the shell prompt:
chmod u+x [path to file/]filename
The script command itself must be issued the following way:
./yt_streamcat target_file "stream_base_URL" start end "2nd_stream_URL"
where
./
means the program file is located in the current directory (in Windows, .\
would
mean the same thing)yt_streamcat
- is the script file we run as our command
target_file
(mandatory)
- is a user-specified file the media segments are going to be written into -- must not
exist yet, if it does, the script will abort to prevent an accidental overwrite
"stream_base_URL"
(mandatory)
- is a YT stream source URL originating from one of the two possible types of videos
mentioned above, extracted by the yt6 main program. Must be enclosed in quotation
marks to prevent bash from misinterpreting each URL-parameter (after each "&"
sign) as yet another command to run in the background.
start
(optional)
- is the number of the segment the media should begin download from. For live
streams, you should give this a value somewhere between the first and last
available "sq" (segment query?) parameter values which you can read on the DASH and HLS
Manifest URL lines. If you go over that range, the download will start with the
most recent live segment. If you go below it, the download will stall.
end
(optional)
- is the number of the ending segment, or if it's less than the previous number, it will
be interpreted as the number of segments to download
"2nd_stream_URL"
(optional)
- to save another track parallel to the first one (an audio stream, maybe?). Must be
between quotes as well. (You must specify the previous two options in order to be
able to specify this fifth one.)
#!/bin/bash ./yt_streamcat v \ "https://[...]googlevideo.com/videoplayback?[...]" \ 100 \ 150 \ "https://[...]googlevideo.com/videoplayback?[...]"
where the target file will be "v" (thus the secondary source will be saved to "vA"), number 100 is going to be the first segment to be saved and 150 will be the last. Notice the
\
character, which is the escape character in most programming languages.
It escapes a line break inside the wrapper for the lines before and after it which bash
is supposed to interpret as a single line of command. (No other character must be present
between the escape character and the following invisible newline character.) You can
name the wrapper file anything you want, just make it executable the same way as
above, then enter ./[wrapper_filename]
, and it will run the command(s) inside of it.
One way to abort a running bash script process is to hit Ctrl+C on the terminal. A temporary helper script is always generated automatically for such events to take care of the remaining minimum steps in the muxing procedure. Its default filename is
0[target_filename]-yt_streamcat-ffmpeg
, you just have to execute
it.
In my tests, live-streamed webm video content seemingly encoded as 30fps, had to be regularly remuxed to a framerate of anywhere between 36 and 36.25fps in the saved file, then also remove one segment from the beginning in order to get it synced up with the audio track. No idea why that is the case, but it is. For higher framerates, the difference should be even larger.
Remuxing commandline examples:
To fix a broken mp4mencoder v.mp4 -ovc copy -o v2.mp4To change the framerate of a webm from 30 to 36
mencoder v.webm -ovc copy -mc 0 -noskip -fps 30 -ofps 36 -o v2.webmTo cut the first video segment out, mencoder's seek option must be a bit less than each segment's duration, so if they are 5 seconds long, 4 seconds will do
mencoder v2.webm -ovc copy -ss 4 -o v3.webmFinally, to mux the video and audio into one matroska file
ffmpeg -i v3.webm -i vA.aac -c:v copy -c:a copy v.mkvCheck if the mkv is playable, then remove the intermediate files.
__
Credit should go to the authors of their respective open source code I had my own built around:
John Dyer - Mediaelementplayer - http://mediaelementjs.com/
Christian Heilmann - Transformvideo - http://github.com/codepo8/rotatezoomHTML5video
Steven Penny - Youtube download bookmarklet - (closed account)
This program is free to use for anyone.
__
Important Notes
-
If you use add-ons like NoScript (a recommended practice), make sure to
Whitelist / Trust these domains permanently:
githubusercontent.com - program code is stored on this site
jsdelivr.net - #1 cdn proxy to load the files
githack.com - #2 (does not always fix the Content-Type header...)
rawgit.com - #3 (now redirects to jsdelivr's cdn)
api.codetabs.com - (should not be necessary but it wouldn't hurt either)
youtube.com - won't even budge without its own javascript code running
googlevideo.com - youtube media is delivered through this domain
-
On videos with strong copyright protection, it is often the case that YouTube sends deliberately wrong signature decryption keys on the first try. I did not implement a fully automatic update of video signatures because of the high risk of infinite loop on repeated failure. You MUST switch over to the alternative player to manually initiate playback on multiple formats till enough errors occur for the updating procedure to fire. The video can be downloaded as soon as it becomes playable on the alt-player. The appearing blue gauge on its time rail shows that the video data has arrived and is buffering.
-
The alternative player of Yt6 uses the Progressive Download method to access video & audio instead of the Adaptive Streaming YouTube's own player had as the default since late 2013.
Both have their pros and cons. With the former, media is getting piled up in the browser's cache during playback, which means there must be enough free space for storage either in the system RAM or on the disk. While in the case of streaming, you only have tiny slices of the media buffered at all times, which in turn requires higher CPU-power and constantly fast network speeds.
Consequently, for live streams or Ultra-HD videos it is recommended to switch over to YouTube's native player, as it is much better suited for those.
To make sure your browser chooses memory over the much slower and/or fragile Hard Disk / Solid-state drive, use the program in an Incognito / In-private browser window or tab.