Compare commits

...

10 Commits

7 changed files with 275 additions and 79 deletions

View File

@@ -1,6 +1,7 @@
# Better Youtube + # Better Youtube +
Better YouTube + works to improve the YouTube experience by providing quick access to features we'd all like to have from the get-go. Better YouTube + works to improve the YouTube experience by providing quick access to features we'd all like to have from the get-go.
<br/> <br/>
* It defaults playback to 1080p if able to.
* It allows quick thumbnail access of the video. * It allows quick thumbnail access of the video.
* It allows setting the loop mode easily. * It allows setting the loop mode easily.
* It allows setting the loop mode to a ranged set. * It allows setting the loop mode to a ranged set.
@@ -11,8 +12,8 @@ Better YouTube + works to improve the YouTube experience by providing quick acce
* It shows volume level as you scroll. * It shows volume level as you scroll.
* It lets Unix, Linux, and MacOS systems have the ability to download the video using native app calls. * It lets Unix, Linux, and MacOS systems have the ability to download the video using native app calls.
# Version: 1.5.4 # Version: 1.6.1
* Fixed loop breakage * Fixing click dead zones; changesd dl icon.
# Download # Download
https://addons.mozilla.org/en-US/firefox/addon/better-youtube-plus/ https://addons.mozilla.org/en-US/firefox/addon/better-youtube-plus/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 11 KiB

149
src/inject.js Normal file
View File

@@ -0,0 +1,149 @@
'use strict';
// ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'auto']
const prefs = {
hd: true,
once: false,
higher: true,
quality: ["hd1080"],
log: false,
highFramerate: true
};
const script = document.createElement('script');
Object.assign(script.dataset, prefs);
script.textContent = `
window.yttools = window.yttools || [];
{
const isTypeSupported = MediaSource.isTypeSupported;
MediaSource.isTypeSupported = function(videoType) {
const prefs = resolutionChangeListener.prefs;
// Block all queries regarding high-framerate support.
if (prefs.highFramerate === 'false') {
const matches = videoType.match(/framerate=(\\d+)/);
if (matches && (matches[1] > 30)) {
return false;
}
}
return isTypeSupported(videoType);
}
}
function resolutionChangeListener(e) {
const prefs = resolutionChangeListener.prefs;
const player = resolutionChangeListener.player;
const log = (...args) => prefs.log === 'true' && console.log('Better-Youtube-Plus: ', ...args);
try {
if (e === 1 && player) {
const levels = player.getAvailableQualityLevels();
if (levels.length === 0) {
return log("Returned empty quality levels...");
}
// ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'auto']
const qualities = player.getAvailableQualityLevels();
const q = player.getPlaybackQuality();
// if ((q.startsWith('h') && prefs.quality.startsWith('h')) && prefs.hd === 'true') {
// console.log("Quality matches requested resolution...");
// return;
// }
const compare = (q1, q2) => {
if (q2 === 'auto') {
return false;
}
const i1 = qualities.indexOf(q1);
const i2 = qualities.indexOf(q2);
if (i1 === -1 || i2 === -1) {
return false;
}
return i1 - i2 <= 0;
};
if (prefs.higher === 'true' && compare(q, prefs.quality)) {
return log('Quality is higher than ' + prefs.quality + '... skipping quality change.');
}
if (q === prefs.quality) {
return log('Selected quality is okay...');
}
const find = increase => {
if (prefs.quality === 'highest') {
return levels[0];
}
else {
if (increase) {
prefs.quality = qualities[qualities.indexOf(prefs.quality) - 1] || levels[0];
}
const index = levels.indexOf(prefs.quality);
if (index !== -1) {
return prefs.quality;
}
return find(true);
}
};
const nq = find();
if (q === nq) {
return log('Requested quality is unavailable... skipping change.');
}
player.setPlaybackQuality(nq);
try {
player.setPlaybackQualityRange(nq, nq);
}
catch (e) {}
if (prefs.once === 'true') {
player.removeEventListener('onStateChange', 'resolutionChangeListener');
window.resolutionChangeListener = () => {};
log("Removing Listener...");
}
log('Quality was ' + q + ' and now is set to ' + nq);
}
}
catch (e) {
log(e);
}
}
resolutionChangeListener.prefs = document.currentScript.dataset;
window.yttools.push(e => {
resolutionChangeListener.player = e;
resolutionChangeListener(1);
e.addEventListener('onStateChange', resolutionChangeListener);
});
function onYouTubePlayerReady(player) {
if (yttools.resolved !== true) {
yttools.resolved = true;
yttools.forEach(c => {
try {
c(player);
}
catch (e) {}
});
}
}
window.addEventListener('spfready', () => {
if (typeof window.ytplayer === 'object' && window.ytplayer.config && yttools.resolved !== true) {
window.ytplayer.config.args.jsapicallback = 'onYouTubePlayerReady';
}
});
window.addEventListener('yt-navigate-finish', () => {
const player = document.querySelector('.html5-video-player');
if (player && yttools.resolved !== true) {
yttools.resolved = true;
yttools.forEach(c => c(player));
}
});
`;
document.documentElement.appendChild(script);
script.remove();

View File

@@ -1,10 +1,10 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Better Youtube +", "name": "Better Youtube +",
"version": "1.5.4", "version": "1.6.3",
"description": "Enhancements for Youtube to have a better experience.", "description": "Enhancements for Youtube to have a better experience.",
"applications": { "browser_specific_settings": {
"gecko": { "gecko": {
"id": "betterYoutube@itdominator.com" "id": "betterYoutube@itdominator.com"
} }
@@ -13,9 +13,16 @@
"permissions": [ "permissions": [
"nativeMessaging", "nativeMessaging",
"tabs", "tabs",
"*://*.youtube.com/*" "*://www.youtube.com/*"
], ],
"content_scripts": [{
"matches": ["*://www.youtube.com/*"],
"js": ["inject.js"],
"run_at": "document_start",
"all_frames": true
}],
"icons": { "icons": {
"48": "icons/betterYoutube_48.png", "48": "icons/betterYoutube_48.png",
"96": "icons/betterYoutube_96.png" "96": "icons/betterYoutube_96.png"

View File

@@ -1,11 +1,20 @@
(function() { (function() {
const menuTemplate = ` const menuTemplate = `
<div class="ytMenuStyle" id="enhancerMenuID" style="display: block;"> <ul class="ytMenuStyle" id="enhancerMenuID" style="display: block;">
<div id="ytThumbnailBttn" class="imageStyle" title="Video Thumbnails..."></div> <li>
<div id="ytLoopBttn" class="imageStyle" title="Start Loop..."/></div> <div id="ytThumbnailBttn" class="imageStyle" title="Video Thumbnails..."></div>
<div id="ytFloatBttn" class="imageStyle" title="Float Video Container"/></div> </li>
<div id="ytDownloadBttn" class="imageStyle" title="Download Video..."/></div> <li>
</div> <div id="ytLoopBttn" class="imageStyle" title="Start Loop..."/></div>
</li>
<li>
<div id="ytFloatBttn" class="imageStyle" title="Float Video Container"/></div>
</li>
<li>
<div id="ytDownloadBttn" class="imageStyle" title="Download Video..."/></div>
</li>
</ul>
` `
const slugTemplate = ` const slugTemplate = `
<div id="enhancerMenuID2"> <div id="enhancerMenuID2">
@@ -22,15 +31,23 @@
</div> </div>
` `
const thumbnailTemplate = ` const thumbnailTemplate = `
<div id="ytThumbMenuID" class="ytThumbMenuStyle" style="display: none;"> <ul id="ytThumbMenuID" class="ytThumbMenuStyle" style="display: none;">
<a id="ytAMaxDefaultImgID" target="_blank" href=""><img id="ytMaxDefaultImgID" class="thumbImageStyle" src="" title="Max Resolution Default"/></a> <li>
<a id="ytAHqDefaultImgID" target="_blank" href=""><img id="ytHqDefaultImgID" class="thumbImageStyle" src="" title="High Quality Default"/></a> <a id="ytAMaxDefaultImgID" target="_blank" href=""><img id="ytMaxDefaultImgID" class="thumbImageStyle" src="" title="Max Resolution Default"/></a>
<a id="ytAMedDefaultImgID" target="_blank" href=""><img id="ytMqDefaultImgID" class="thumbImageStyle" src="" title="Medium Quality Default"></a> </li>
<a id="ytASdDefaultImgID" target="_blank" href=""><img id="ytSdDefaultImgID" class="thumbImageStyle" src="" title="Standard Quality Default"/></a> <li>
</div> <a id="ytAHqDefaultImgID" target="_blank" href=""><img id="ytHqDefaultImgID" class="thumbImageStyle" src="" title="High Quality Default"/></a>
</li>
<li>
<a id="ytAMedDefaultImgID" target="_blank" href=""><img id="ytMqDefaultImgID" class="thumbImageStyle" src="" title="Medium Quality Default"></a>
</li>
<li>
<a id="ytASdDefaultImgID" target="_blank" href=""><img id="ytSdDefaultImgID" class="thumbImageStyle" src="" title="Standard Quality Default"/></a>
</li>
</ul>
` `
const popedContainerTemplate = ` const popedContainerTemplate = `
<div id="draggable" style="display:none; block; top: 114px; left: 408px;"> <div id="ytDraggable" style="display:none; bottom: 0px; right: 0px;">
<iframe id="popIframe" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" <iframe id="popIframe" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
autoplay="" allowfullscreen="true" width="650px" height="400px" frameborder="0" src="" /> autoplay="" allowfullscreen="true" width="650px" height="400px" frameborder="0" src="" />
</iframe> </iframe>
@@ -78,13 +95,27 @@
count++; count++;
} }
} }
}, 500); // check every 500ms }, 500);
const setupProcess = () => { const setupProcess = () => {
loadUI(); loadUI();
setupVariables(); setupVariables().then(() => {
fillUIAndSetupEvents(); let tid = -1;
setupObservers();
function timer() {
// Video Controler
video = document.getElementsByTagName("video")[0];
if (video) {
clearInterval(tid);
fillUIAndSetupEvents();
setupObservers();
}
}
tid = setInterval(timer, 1000);
});
} }
const loadUI = () => { const loadUI = () => {
@@ -115,7 +146,7 @@
} }
} }
const setupVariables = () => { const setupVariables = async () => {
ytEnhancerMenu2 = document.getElementById("enhancerMenuID2"); ytEnhancerMenu2 = document.getElementById("enhancerMenuID2");
ytThumbnailBttn = document.getElementById("ytThumbnailBttn"); ytThumbnailBttn = document.getElementById("ytThumbnailBttn");
ytLoopBttn = document.getElementById("ytLoopBttn"); ytLoopBttn = document.getElementById("ytLoopBttn");
@@ -137,23 +168,19 @@
ytMqDefaultImg = document.getElementById("ytMqDefaultImgID"); ytMqDefaultImg = document.getElementById("ytMqDefaultImgID");
ytSdDefaultImg = document.getElementById("ytSdDefaultImgID"); ytSdDefaultImg = document.getElementById("ytSdDefaultImgID");
poppedContainer = document.getElementById("draggable"); poppedContainer = document.getElementById("ytDraggable");
ytIfrm = document.getElementById("popIframe"); ytIfrm = document.getElementById("popIframe");
slugInputTag = document.getElementById("slugCopyZone"); slugInputTag = document.getElementById("slugCopyZone");
// Video Controler
video = document.getElementsByTagName("video")[0];
// Container of actual player (Used for floating window) // Container of actual player (Used for floating window)
containerOfPlyrWndow = document.getElementById("player-container"); containerOfPlyrWndow = document.getElementById("player-container");
part = "https://img.youtube.com/vi/";
part = "https://img.youtube.com/vi/";
} }
const fillUIAndSetupEvents = () => { const fillUIAndSetupEvents = () => {
slugInputTag.value = video.baseURI.slice(32, 32+11); slugInputTag.value = video.baseURI.slice(32, 32+11);
ytRangeStart.value = "0:00"; ytRangeStart.value = "0:00";
// We need to wait for info to load before getting full duration
setTimeout(function () { setTimeout(function () {
videoTimeLength = document.getElementsByClassName("ytp-time-duration")[0].innerText; videoTimeLength = document.getElementsByClassName("ytp-time-duration")[0].innerText;
ytRangeEnd.value = videoTimeLength; ytRangeEnd.value = videoTimeLength;
@@ -206,7 +233,10 @@
controlsShowHideToggle(mutation.target); controlsShowHideToggle(mutation.target);
} else if (mutation.type === 'childList') { } else if (mutation.type === 'childList') {
if (this.isEndlessWatch) { if (this.isEndlessWatch) {
let elm = document.querySelector(dialogElementQueryRef).parentElement; let target = document.querySelector(dialogElementQueryRef);
if (!target) continue
let elm = target.parentElement;
elmDisplayState = elm.style.display; elmDisplayState = elm.style.display;
if (elmDisplayState !== 'none' && modalHasBeenClosed == false) { if (elmDisplayState !== 'none' && modalHasBeenClosed == false) {
modalHasBeenClosed = true; modalHasBeenClosed = true;
@@ -221,7 +251,7 @@
}; };
const controlsShowHideToggle = (elm) => { const controlsShowHideToggle = (elm) => {
attrib = elm.getAttribute('masthead-hidden_'); attrib = elm.getAttribute('masthead-hidden');
if (attrib == null) { // if out of fullscreen if (attrib == null) { // if out of fullscreen
ytEnhancerMenu.style.display = "block"; ytEnhancerMenu.style.display = "block";
ytEnhancerMenu2.style.display = "block"; ytEnhancerMenu2.style.display = "block";
@@ -282,7 +312,7 @@
clearInterval(ytVideoIntervalLoop); clearInterval(ytVideoIntervalLoop);
loopingInterval = false; loopingInterval = false;
ytLoopBttn.title = "Start Loop..."; ytLoopBttn.title = "Start Loop...";
let ipath = browser.extension.getURL("/icons/loopFalse.png"); let ipath = browser.runtime.getURL("/icons/loopFalse.png");
setbuttonImage(ytLoopBttn, ipath); setbuttonImage(ytLoopBttn, ipath);
return ; return ;
} }
@@ -292,13 +322,13 @@
console.log("Setting default loop marker..."); console.log("Setting default loop marker...");
video.loop = true; video.loop = true;
ytLoopBttn.title = "Stop Loop..."; ytLoopBttn.title = "Stop Loop...";
let ipath = browser.extension.getURL("/icons/loopTrue.png"); let ipath = browser.runtime.getURL("/icons/loopTrue.png");
setbuttonImage(ytLoopBttn, ipath); setbuttonImage(ytLoopBttn, ipath);
} else { } else {
console.log("Unsetting default loop marker..."); console.log("Unsetting default loop marker...");
video.loop = false; video.loop = false;
ytLoopBttn.title = "Start Loop..."; ytLoopBttn.title = "Start Loop...";
let ipath = browser.extension.getURL("/icons/loopFalse.png"); let ipath = browser.runtime.getURL("/icons/loopFalse.png");
setbuttonImage(ytLoopBttn, ipath); setbuttonImage(ytLoopBttn, ipath);
} }
return ; return ;
@@ -339,7 +369,7 @@
// Setup interval check for 1 sec and compare value of current pos to end // Setup interval check for 1 sec and compare value of current pos to end
ytLoopBttn.title = "Stop Loop..."; ytLoopBttn.title = "Stop Loop...";
let ipath = browser.extension.getURL("/icons/loopTrue.png"); let ipath = browser.runtime.getURL("/icons/loopTrue.png");
setbuttonImage(ytLoopBttn, ipath); setbuttonImage(ytLoopBttn, ipath);
loopingInterval = true; loopingInterval = true;
@@ -449,7 +479,8 @@
if(e.preventDefault) e.preventDefault(); if(e.preventDefault) e.preventDefault();
e.cancelBubble = true; e.cancelBubble = true;
e.returnValue = false; e.returnValue = false;
return false;
return false;
} }
} }
@@ -459,6 +490,6 @@
} }
const setbuttonImage = (elm, path) => { const setbuttonImage = (elm, path) => {
elm.style.backgroundImage = "url('" + browser.extension.getURL(path); + "')"; elm.style.backgroundImage = "url('" + browser.runtime.getURL(path); + "')";
} }
}()); }());

View File

@@ -11,11 +11,11 @@ yt-formatted-string > a:hover {
/* ID CSS */ /* ID CSS */
#enhancerMenuID2, .ytThumbMenuStyle, .ytMenuStyle { #enhancerMenuID2, .ytThumbMenuStyle, .ytMenuStyle {
z-index: 100; z-index: 100;
position: fixed; position: fixed;
background: rgba(0,0,0,0.64); background: rgba(0,0,0,0.64);
margin: 0 auto; margin: 0 auto;
overflow: auto; overflow: auto;
} }
#enhancerMenuID2 { #enhancerMenuID2 {
@@ -25,8 +25,8 @@ yt-formatted-string > a:hover {
color: #ffffff; color: #ffffff;
} }
#enhancerMenuID, #enhancerMenuID2 { #enhancerMenuID, #enhancerMenuID2, #ytThumbMenuID {
z-index: 5; z-index: 9999;
} }
#volumeContainerID { #volumeContainerID {
@@ -36,17 +36,17 @@ yt-formatted-string > a:hover {
text-align: center; text-align: center;
} }
#draggable { #ytDraggable {
z-index: 9999; z-index: 9999;
position: fixed; position: fixed;
right: 0px; right: 0px;
bottom: 0px; bottom: 0px;
width: 650px; width: 650px;
height: 400px; height: 400px;
padding-top: 50px; padding-top: 50px;
border-style: solid; border-style: solid;
border-color: rgba(0, 232, 255, 0.64); border-color: rgba(0, 232, 255, 0.64);
background: rgba(64, 64, 64, 0.64) background: rgba(64, 64, 64, 0.64)
} }
#rangeEndID, #rangeStartID { #rangeEndID, #rangeStartID {
@@ -56,9 +56,9 @@ yt-formatted-string > a:hover {
} }
#slugCopyZone, #rangeEndID, #rangeStartID { #slugCopyZone, #rangeEndID, #rangeStartID {
text-align: center; text-align: center;
background: rgba(0,0,0,0.0); background: rgba(0,0,0,0.0);
color: #fff; color: #fff;
} }
@@ -66,34 +66,42 @@ yt-formatted-string > a:hover {
.ytMenuStyle { .ytMenuStyle {
top: 40%; top: 40%;
width: 42px; width: 42px;
overflow: hidden;
} }
.ytThumbMenuStyle { .ytThumbMenuStyle {
display: none; display: none;
bottom: 20px; bottom: 20px;
}
.ytThumbMenuStyle > ul,
.ytThumbMenuStyle > li {
list-style: none;
}
.ytThumbMenuStyle > li {
float: left;
} }
.imageStyle { .imageStyle {
width: 42px; width: 42px;
height: 42px; height: 42px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-color: rgba(0,0,0,.64); background-color: rgba(0,0,0,.64);
background-size: 42px 42px; background-size: 42px 42px;
} }
.imageStyle:hover { .imageStyle:hover {
background: rgba(12,160,193,.64); background: rgba(12,160,193,.64);
cursor: pointer; cursor: pointer;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: 28px 28px; background-size: 28px 28px;
} }
.thumbImageStyle { .thumbImageStyle {
width: 200px; width: 200px;
height: 100px; height: 100px;
margin: 0em 1em 0em 1em; margin: 0em 1em 0em 1em;
float: left; float: left;
} }