diff --git a/bin/update.json b/bin/update.json index aae10df..983c315 100644 --- a/bin/update.json +++ b/bin/update.json @@ -2,7 +2,7 @@ "addons": { "unlisted-particle@particlecore.github.io": { "updates": [{ - "version": "1.7.3", + "version": "1.7.4", "update_link": "https://github.com/ParticleCore/Particle/raw/master/dist/YouTubePlus.xpi", "applications": { "gecko": { diff --git a/dist/YouTubePlus.xpi b/dist/YouTubePlus.xpi index d037020..df2fbdf 100644 Binary files a/dist/YouTubePlus.xpi and b/dist/YouTubePlus.xpi differ diff --git a/src/Userscript/YouTubePlus.user.js b/src/Userscript/YouTubePlus.user.js index acc7baf..da6d3cd 100644 --- a/src/Userscript/YouTubePlus.user.js +++ b/src/Userscript/YouTubePlus.user.js @@ -1,5 +1,5 @@ // ==UserScript== -// @version 1.7.3 +// @version 1.7.4 // @name YouTube + // @namespace https://github.com/ParticleCore // @description YouTube with more freedom @@ -19,10 +19,10 @@ // ==/UserScript== (function () { "use strict"; - var particle = { + let particle = { inject: function(is_userscript) { function setLocale(content) { - var i, j, list, temp, ytplabel; + let i, j, list, temp, ytplabel; ytplabel = content.querySelectorAll("[data-p]"); i = ytplabel.length; while (i--) { @@ -120,8 +120,7 @@ return next[Object.keys(next)[0]].localeCompare(previous[Object.keys(previous)[0]]); } function getBlacklist(blist) { - var i, obj, temp, lnk, keys, list, fragment, sortAlpha; - sortAlpha = []; + let i, obj, temp, lnk, keys, list, fragment, sortAlpha; list = user_settings.blacklist; fragment = document.createDocumentFragment(); sortAlpha = []; @@ -156,7 +155,7 @@ blist.appendChild(fragment); } function getValues(menu) { - var i, ytp, list; + let i, ytp, list; if (user_settings) { list = menu.querySelector("#blacklist"); if (list) { @@ -183,7 +182,7 @@ return menu; } function getMenu(section) { - var i, temp, svg, inputs; + let i, temp, svg, inputs; temp = document.createElement("template"); if (section === "MEN") { temp.innerHTML = // @@ -338,7 +337,7 @@

-
+

\n?
@@ -349,7 +348,7 @@
-

+
`; if (user_settings.GEN_LOCL_LANG && user_settings.localLang) { temp.content.querySelector(".P-implang").dataset.p = "ttl|GLB_LOCL_LANG&tnd|GLB_LOCL_LANG_CSTM"; @@ -360,7 +359,7 @@

-
+

Jeppe Rune Mortensen
Greasemonkey + Tampermonkey
@@ -374,14 +373,13 @@ inputs = temp.content.querySelectorAll("input[type='checkbox'] + label"); svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.innerHTML = ""; - i = inputs.length; - while (i--) { + for (i = 0; i < inputs.length; i++) { inputs[i].appendChild(svg.cloneNode(true)); } return setLocale(getValues(temp.content)); } function exportSettings(target) { - var expCont; + let expCont; if (target.classList.contains("P-impexp") || target.classList.contains("P-implang")) { expCont = document.getElementById("exp-cont"); if (expCont) { @@ -424,7 +422,7 @@ } } function delBlackList(event) { - var newKey = user_settings.blacklist; + let newKey = user_settings.blacklist; delete newKey[event.target.nextSibling.href.split("/channel/")[1]]; event.target.parentNode.outerHTML = ""; set("blacklist", newKey); @@ -433,7 +431,7 @@ document.body.classList.remove("show-guide-button-notification"); } function saveSettings(salt) { - var i, value, notification, navId, userSets, savedSets; + let i, value, notification, navId, userSets, savedSets; navId = document.querySelector(".selected").id; userSets = document.getElementById("P-content").querySelectorAll("[id^='" + navId + "']"); savedSets = user_settings; @@ -497,7 +495,7 @@ } } function settingsTemplate(event) { - var pWrapper; + let pWrapper; if (event.target.id === "P" && event.target.tagName !== "INPUT") { pWrapper = document.getElementById("P-settings"); if (pWrapper) { @@ -524,11 +522,11 @@ } } function settingsMenu() { - var notif_button, settings_button, welcome_message; + let notif_button, settings_button, welcome_message; if (settingsMenu.settingsButton) { return; } - notif_button = document.querySelector(".notifications-container"); + notif_button = document.querySelector("#yt-masthead-notifications, .notifications-container"); settings_button = document.querySelector("#yt-masthead-user, #yt-masthead-signin"); if (settings_button) { welcome_message = document.createElement("template"); @@ -542,9 +540,9 @@ @@ -566,7 +564,7 @@ } function modComment(original) { return function (a) { - var comments, is_live; + let comments, is_live; comments = document.getElementById("watch-discussion"); is_live = window.ytplayer && window.ytplayer.config && window.ytplayer.config.args && window.ytplayer.config.args.livestream; if (a.split("comments").length > 1 && !is_live && comments && !comments.lazyload && user_settings.VID_HIDE_COMS === "1" && !comments.classList.contains("show")) { @@ -591,12 +589,12 @@ } function modEmbed(original) { return function (a, b) { - var temp, player; + let temp, player; temp = a.id || a; if (temp !== "player-api" && temp !== "upsell-video") { return original.apply(this, arguments); } - b = modArgs(b); + /*b = */modArgs(b); temp = original.apply(this, arguments); player = document.getElementById("movie_player"); if (player) { @@ -614,7 +612,7 @@ } function modAutoplayFullscreen(original) { return function () { - var has_ended, next_button, next_clicked; + let has_ended, next_button, next_clicked; has_ended = api && api.getCurrentTime && Math.round(api.getCurrentTime()) >= Math.floor(api.getDuration()); next_clicked = document.activeElement.classList.contains("ytp-button-next") || document.activeElement.classList.contains("ytp-next-button"); if (!user_settings.plApl && !next_clicked && has_ended) { @@ -634,20 +632,14 @@ } }; } - function modArgsWatch(args) { - if (args && args.autoplay === "1" && !user_settings.VID_PLR_ATPL && window.location.hash === "") { - args.autoplay = "0"; - } - return modArgsWatch.original.apply(this, arguments); - } function modPlayerCreate(original) { return function (a, b) { - var i, temp, player; + let i, temp, player; temp = a.id || a; if (temp !== "player-api" && temp !== "upsell-video") { return original.apply(this, arguments); } - b = modArgs(b); + /*b = */modArgs(b); if (a.id === "upsell-video") { original.apply(this, arguments); } else if (typeof a === "object") { @@ -676,8 +668,14 @@ } }; } + function ModArgsWatch(args) { + if (args && args.autoplay === "1" && !user_settings.VID_PLR_ATPL && window.location.hash === "") { + args.autoplay = "0"; + } + return ModArgsWatch.Original.apply(this, arguments); + } function scriptExit(event) { - var i, j, key, temp; + let i, j, key, temp; if (event && event.target) { if (event.target.getAttribute("name") === "www/base") { window.yt.setConfig = modSetConfig(window.yt.setConfig); @@ -710,39 +708,40 @@ } if (event.target.getAttribute("name") === "spf/spf") { window.spf.load = modComment(window.spf.load); - window.spf.prefetch = function(){return;}; + window.spf.prefetch = function(){}; if (window.name === "popOut") { - window.spf.navigate = function(){return;}; + window.spf.navigate = function(){}; } } } - if ((event && event.target && event.target.getAttribute("name") === "player/base") || (!window.html5Patched && window.yt && window.yt.player && window.yt.player.Application && window.yt.player.Application.create)) { + if ( + (event && event.target && event.target.getAttribute("name") === "player/base") || + (!window.html5Patched && window.yt && window.yt.player && window.yt.player.Application && window.yt.player.Application.create) + ) { window.html5Patched = true; window.yt.player.Application.create = modPlayerCreate(window.yt.player.Application.create); if (window._yt_player) { temp = Object.keys(window._yt_player); - i = temp.length; - while (i--) { - if (typeof window._yt_player[temp[i]] === "function" && window._yt_player[temp[i]].toString().match("this.adaptiveFormats")) { + for (i = 0; i < temp.length; i++) { + if (typeof window._yt_player[temp[i]] === "function" && window._yt_player[temp[i]].toString().match(/this\.adaptiveFormats/)) { key = temp[i]; break; } } if (key) { - modArgsWatch.original = window._yt_player[key]; - modArgsWatch.prototype = modArgsWatch.original.prototype; - temp = Object.keys(modArgsWatch.original); - i = temp.length; - while (i--) { - modArgsWatch[temp[i]] = modArgsWatch.original[temp[i]]; + ModArgsWatch.Original = window._yt_player[key]; + ModArgsWatch.prototype = ModArgsWatch.Original.prototype; + temp = Object.keys(ModArgsWatch.Original); + for (i = 0; i < temp.length; i++) { + ModArgsWatch[temp[i]] = ModArgsWatch.Original[temp[i]]; } - window._yt_player[key] = modArgsWatch; + window._yt_player[key] = ModArgsWatch; } } } } function checkBounds(elm, X, Y) { - var snapX, snapY; + let snapX, snapY; if (X > -1 && X + elm.offsetWidth < document.documentElement.offsetWidth) { snapX = false; } else if (X < 1) { @@ -764,7 +763,7 @@ return {X: X + "px", Y: Y + "px", snapX: snapX, snapY: snapY}; } function updatePos() { - var x, y, height, player, bounds; + let x, y, height, player, bounds; player = document.getElementById("movie_player"); if (!document.documentElement.classList.contains("floater") || window.innerWidth < 657) { if (player) { @@ -798,7 +797,7 @@ document[(window.chrome && "body") || "documentElement"].scrollTop = 0; } function dragFloater(event) { - var excluded, isFScreen, isFloater, bounds, player; + let excluded, isFScreen, isFloater, bounds, player; isFScreen = document.querySelector(".ytp-fullscreen"); isFloater = document.documentElement.classList.contains("floater"); if (event && !isFScreen && isFloater) { @@ -816,7 +815,13 @@ orgX: event.clientX, orgY: event.clientY }; - } else if (event.type === "mousemove" && (dragFloater.hasMoved || Math.abs(event.clientX - dragFloater.oldPos.orgX) > 10 || Math.abs(event.clientY - dragFloater.oldPos.orgY) > 10)) { + } else if ( + event.type === "mousemove" && ( + dragFloater.hasMoved || + Math.abs(event.clientX - dragFloater.oldPos.orgX) > 10 || + Math.abs(event.clientY - dragFloater.oldPos.orgY) > 10 + ) + ) { bounds = checkBounds(player, event.clientX + dragFloater.oldPos.X, event.clientY + dragFloater.oldPos.Y); player.style.left = bounds.X; player.style.top = bounds.Y; @@ -843,7 +848,7 @@ } } function iniFloater() { - var player, plrApi, out_of_sight, isFloater, isFScreen, floaterUI, settings_open; + let player, plrApi, out_of_sight, isFloater, isFScreen, floaterUI, settings_open; player = document.getElementById("movie_player"); plrApi = document.getElementById("player-api").getBoundingClientRect(); settings_open = document.getElementById("P-settings"); @@ -887,9 +892,16 @@ } } function alwaysActive(event) { - var i, list, clear, length, eventClone; + let i, list, clear, length, eventClone; clear = window.location.pathname == "/watch" && api && api !== event.target && !api.contains(event.target) && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey && !event.target.isContentEditable; - if (clear && ((event.which > 47 && event.which < 58) || (event.which > 95 && event.which < 106) || [27, 32, 35, 36, 37, 38, 39, 40, 66, 67, 79, 87, 187, 189].indexOf(event.which) > -1) && ["EMBED", "INPUT", "OBJECT", "TEXTAREA", "IFRAME"].indexOf(document.activeElement.tagName) < 0) { + if ( + clear && ( + event.which > 47 && event.which < 58 || + event.which > 95 && event.which < 106 || + [27, 32, 35, 36, 37, 38, 39, 40, 66, 67, 79, 87, 187, 189].indexOf(event.which) > -1 + ) && + ["EMBED", "INPUT", "OBJECT", "TEXTAREA", "IFRAME"].indexOf(document.activeElement.tagName) < 0 + ) { eventClone = new Event("keydown"); list = Object.keys(Object.getPrototypeOf(event)); length = list.length; @@ -935,7 +947,7 @@ } } function getThumb() { - var args, base, thumb_url; + let args, base, thumb_url; args = window.ytplayer.config.args; base = (args.iurl_webp && "_webp") || ""; thumb_url = args["iurlmaxres" + base] || args["iurlsd" + base] || args["iurl" + base]; @@ -948,7 +960,7 @@ } } function getScreenshot() { - var width, height, aspectRatio, video, container, canvas, close, context; + let width, height, aspectRatio, video, container, canvas, close, context; video = document.querySelector("video"); container = document.getElementById("screenshot-result") || document.createElement("div"); canvas = container.querySelector("canvas") || document.createElement("canvas"); @@ -971,7 +983,15 @@ } } function exitFullBrowser(key) { - if (document.documentElement.classList.contains("part_fullbrowser") && (key.keyCode === 27 || key.key === "Escape" || (key.target.className && key.target.className.split("ytp-size").length > 1))) { + if ( + document.documentElement.classList.contains("part_fullbrowser") && ( + key.keyCode === 27 || + key.key === "Escape" || ( + key.target.className && + key.target.className.split("ytp-size").length > 1 + ) + ) + ) { toggleFullBrowser(key); if (key.type === "mousedown") { document.removeEventListener("keydown", exitFullBrowser); @@ -981,7 +1001,7 @@ } } function toggleFullBrowser(event) { - var plrState = api && api.getPlayerState && api.getPlayerState(); + let plrState = api && api.getPlayerState && api.getPlayerState(); plrState = plrState < 5 && plrState > 0; document[(window.chrome && "body") || "documentElement"].scrollTop = 0; document.addEventListener("keydown", exitFullBrowser); @@ -993,6 +1013,45 @@ window.dispatchEvent(new Event("resize")); } } + function toggleFrames(event) { + let i, pi, fps, temp; + advancedOptions.frame_step = document.getElementById("framestep-button"); + if (event && ["EMBED", "INPUT", "OBJECT", "TEXTAREA"].indexOf(document.activeElement.tagName) < 0 && event.target.tagName !== "IFRAME" && !event.target.getAttribute("contenteditable")) { + if ((event.keyCode === 37 || event.keyCode === 39) && event.shiftKey) { + pi = api.getVideoStats().fmt; + if (window.ytplayer && window.ytplayer.config && window.ytplayer.config.args && window.ytplayer.config.args.adaptive_fmts) { + temp = window.ytplayer.config.args.adaptive_fmts.split(","); + i = temp.length; + while (i--) { + if (temp[i].indexOf("itag=" + pi) > 0) { + advancedOptions.fps = parseInt(temp[i].match(/fps=([\d]+)/)[1]); + break; + } + } + } + if (!advancedOptions.fps || advancedOptions.fps === 1) { + advancedOptions.fps = 30; + } + fps = ((event.keyCode < 39 && -1) || 1) * ((advancedOptions.fps < 2 && 30) || advancedOptions.fps); + if (fps && api) { + if (!document.querySelector("video").paused) { + api.pauseVideo(); + } + api.seekBy(1 / fps); + } + event.preventDefault(); + event.stopImmediatePropagation(); + } else if (event.type === "click" && event.target.id === "framestep-button") { + set("frame_step", !user_settings.frame_step); + advancedOptions.frame_step.classList[(user_settings.frame_step && "add") || "remove"]("active"); + } + } + if (advancedOptions.frame_step && advancedOptions.frame_step.classList.contains("active")) { + document.addEventListener("keydown", toggleFrames, true); + } else if (!advancedOptions.frame_step || !advancedOptions.frame_step.classList.contains("active")) { + document.removeEventListener("keydown", toggleFrames, true); + } + } function toggleShortcuts() { window.open("https://github.com/ParticleCore/Particle/wiki/YouTube-shortcuts", "_blank"); } @@ -1009,7 +1068,7 @@ document.getElementById("autoplay-button").classList[(user_settings.VID_PLR_ATPL && "add") || "remove"]("active"); } function toggleLoop(event) { - var videoPlayer = document.querySelector("video"); + let videoPlayer = document.querySelector("video"); if (videoPlayer) { videoPlayer.loop = event ? !user_settings.loopVid : user_settings.loopVid; if (event) { @@ -1019,7 +1078,7 @@ set("loopVid", advancedOptions.loop_button.classList.contains("active")); } function toggleCinemaMode(event) { - var plrState = api && api.getPlayerState && api.getPlayerState() < 5 && api.getPlayerState() > 0; + let plrState = api && api.getPlayerState && api.getPlayerState() < 5 && api.getPlayerState() > 0; set("lightsOut", event ? !user_settings.lightsOut : true); advancedOptions.cinema_mode.classList[(user_settings.lightsOut && "add") || "remove"]("active"); if (event && plrState) { @@ -1036,6 +1095,7 @@ advancedOptions.full_browser = advancedOptions.controls.querySelector("#fullbrowser-button"); advancedOptions.cinema_mode = advancedOptions.controls.querySelector("#cinemamode-button"); advancedOptions.loop_button = advancedOptions.controls.querySelector("#loop-button"); + advancedOptions.frame_step = advancedOptions.controls.querySelector("#framestep-button"); advancedOptions.actions = { togglePlay: togglePlay, toggleLoop: toggleLoop, @@ -1044,6 +1104,7 @@ popPlayer: popPlayer, toggleFullBrowser: toggleFullBrowser, toggleCinemaMode: toggleCinemaMode, + toggleFrames: toggleFrames, toggleShortcuts: toggleShortcuts }; document.addEventListener("click", handleToggles); @@ -1059,9 +1120,13 @@ advancedOptions.cinema_mode.classList.add("active"); toggleCinemaMode(); } + if (user_settings.frame_step && !advancedOptions.frame_step.classList.contains("active")) { + advancedOptions.frame_step.classList.add("active"); + toggleFrames(); + } } function advancedOptions() { - var header, cnslBtn, cnslCont; + let header, cnslBtn, cnslCont; header = document.getElementById("watch-header"); cnslBtn = document.getElementById("console-button"); advancedOptions.controls = document.getElementById("player-console"); @@ -1098,6 +1163,7 @@
+
`; if (user_settings.VID_PLR_ATPL) { @@ -1113,7 +1179,7 @@ } } function iniAction(event) { - var observer, load_more, click_title; + let observer, load_more, click_title; load_more = document.querySelector("#watch-more-related, .load-more-button"); click_title = document.querySelector(".yt-uix-tile"); while (click_title) { @@ -1142,7 +1208,7 @@ } } function setButtons() { - var i, j, list, temp, thumb, button; + let i, j, list, temp, thumb, button; list = Object.keys(modThumbs.thumbs); i = list.length; while (i--) { @@ -1180,7 +1246,7 @@ } } function delVideos() { - var i, j, temp, parent, blacklist, has_upnext; + let i, j, temp, parent, blacklist, has_upnext; has_upnext = document.querySelector(".autoplay-bar"); blacklist = Object.keys(user_settings.blacklist); i = blacklist.length; @@ -1233,7 +1299,7 @@ } } function getVideos() { - var i, list, temp, channel_id; + let i, list, temp, channel_id; modThumbs.thumbs = {}; list = document.querySelectorAll(` .yt-lockup-byline > a, @@ -1271,7 +1337,7 @@ } } function setVideoCount() { - var span = document.createElement("span"); + let span = document.createElement("span"); span.textContent = " · "; enhancedDetails.username.appendChild(span); enhancedDetails.link.href = window.location.origin + "/channel/" + enhancedDetails.user.dataset.ytid + "/videos"; @@ -1301,7 +1367,7 @@ } } function getChannelInfo(details) { - var retry, isLive; + let retry, isLive; isLive = details.target.response.querySelector(".yt-badge-live"); if (!isLive) { retry = details.target.responseURL.split("/videos").length < 2; @@ -1331,7 +1397,7 @@ } } function reverseControl() { - var i, temp, prev, next, list, videos; + let i, temp, prev, next, list, videos; prev = document.querySelector(".prev-playlist-list-item"); next = document.querySelector(".next-playlist-list-item"); list = document.getElementById("playlist-autoscroll-list"); @@ -1362,7 +1428,7 @@ } } function createButton(type, label, bool, call) { - var button = document.createElement("template"); + let button = document.createElement("template"); button.innerHTML = // ` @@ -2023,12 +2115,11 @@ document.documentElement.appendChild(temp.content.firstChild); document.addEventListener("click", closeMigrationInstructions); } - var api, cid, events, language, user_settings, player_instance, default_settings; + let api, cid, language, user_settings, player_instance, default_settings; if (isMaterial()) { return; } cid = {}; - events = {}; user_settings = JSON.parse(document.documentElement.dataset.user_settings || null); if (document.documentElement.dataset.user_settings) { document.documentElement.removeAttribute("data-user_settings"); @@ -2077,6 +2168,7 @@ CNSL_PPOT : "Pop-out video", CNSL_FLBR : "Fullbrowser mode", CNSL_CINM_MD : "Cinema mode", + CNSL_FRME : "Frame by frame (Shift + ← or →)", CNSL_YTSC : "YouTube shortcuts list", PLST_AP : "Autoplay", PLST_RVRS : "Reverse", @@ -2217,7 +2309,7 @@ main(); }, contentScriptMessages: function() { - var key1, key2, gate, sets, locs, observer; + let key1, key2, gate, sets, locs, observer; key1 = "parsend"; key2 = "getlocale"; gate = document.documentElement; @@ -2250,7 +2342,7 @@ } }, main: function(event) { - var holder; + let holder; if (!event && particle.is_userscript) { event = JSON.parse(particle.GM_getValue(particle.id, "{}")); } @@ -2261,7 +2353,7 @@ holder = document.createElement("link"); holder.rel = "stylesheet"; holder.type = "text/css"; - holder.href = "https://particlecore.github.io/Particle/stylesheets/YouTubePlus.css?v=1.7.3"; + holder.href = "https://particlecore.github.io/Particle/stylesheets/YouTubePlus.css?v=1.7.4"; document.documentElement.appendChild(holder); } holder = document.createElement("script"); @@ -2274,7 +2366,7 @@ }, ini: function() { particle.id = "particleSettings"; - particle.is_userscript = typeof GM_info === "object" ? true : false; + particle.is_userscript = typeof GM_info === "object"; if (particle.is_userscript) { particle.GM_getValue = GM_getValue; particle.GM_setValue = GM_setValue; diff --git a/src/Webextension/JS/YouTubePlus.user.js b/src/Webextension/JS/YouTubePlus.user.js index acc7baf..da6d3cd 100644 --- a/src/Webextension/JS/YouTubePlus.user.js +++ b/src/Webextension/JS/YouTubePlus.user.js @@ -1,5 +1,5 @@ // ==UserScript== -// @version 1.7.3 +// @version 1.7.4 // @name YouTube + // @namespace https://github.com/ParticleCore // @description YouTube with more freedom @@ -19,10 +19,10 @@ // ==/UserScript== (function () { "use strict"; - var particle = { + let particle = { inject: function(is_userscript) { function setLocale(content) { - var i, j, list, temp, ytplabel; + let i, j, list, temp, ytplabel; ytplabel = content.querySelectorAll("[data-p]"); i = ytplabel.length; while (i--) { @@ -120,8 +120,7 @@ return next[Object.keys(next)[0]].localeCompare(previous[Object.keys(previous)[0]]); } function getBlacklist(blist) { - var i, obj, temp, lnk, keys, list, fragment, sortAlpha; - sortAlpha = []; + let i, obj, temp, lnk, keys, list, fragment, sortAlpha; list = user_settings.blacklist; fragment = document.createDocumentFragment(); sortAlpha = []; @@ -156,7 +155,7 @@ blist.appendChild(fragment); } function getValues(menu) { - var i, ytp, list; + let i, ytp, list; if (user_settings) { list = menu.querySelector("#blacklist"); if (list) { @@ -183,7 +182,7 @@ return menu; } function getMenu(section) { - var i, temp, svg, inputs; + let i, temp, svg, inputs; temp = document.createElement("template"); if (section === "MEN") { temp.innerHTML = // @@ -338,7 +337,7 @@

-
+

\n?
@@ -349,7 +348,7 @@
-

+
`; if (user_settings.GEN_LOCL_LANG && user_settings.localLang) { temp.content.querySelector(".P-implang").dataset.p = "ttl|GLB_LOCL_LANG&tnd|GLB_LOCL_LANG_CSTM"; @@ -360,7 +359,7 @@

-
+

Jeppe Rune Mortensen
Greasemonkey + Tampermonkey
@@ -374,14 +373,13 @@ inputs = temp.content.querySelectorAll("input[type='checkbox'] + label"); svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.innerHTML = ""; - i = inputs.length; - while (i--) { + for (i = 0; i < inputs.length; i++) { inputs[i].appendChild(svg.cloneNode(true)); } return setLocale(getValues(temp.content)); } function exportSettings(target) { - var expCont; + let expCont; if (target.classList.contains("P-impexp") || target.classList.contains("P-implang")) { expCont = document.getElementById("exp-cont"); if (expCont) { @@ -424,7 +422,7 @@ } } function delBlackList(event) { - var newKey = user_settings.blacklist; + let newKey = user_settings.blacklist; delete newKey[event.target.nextSibling.href.split("/channel/")[1]]; event.target.parentNode.outerHTML = ""; set("blacklist", newKey); @@ -433,7 +431,7 @@ document.body.classList.remove("show-guide-button-notification"); } function saveSettings(salt) { - var i, value, notification, navId, userSets, savedSets; + let i, value, notification, navId, userSets, savedSets; navId = document.querySelector(".selected").id; userSets = document.getElementById("P-content").querySelectorAll("[id^='" + navId + "']"); savedSets = user_settings; @@ -497,7 +495,7 @@ } } function settingsTemplate(event) { - var pWrapper; + let pWrapper; if (event.target.id === "P" && event.target.tagName !== "INPUT") { pWrapper = document.getElementById("P-settings"); if (pWrapper) { @@ -524,11 +522,11 @@ } } function settingsMenu() { - var notif_button, settings_button, welcome_message; + let notif_button, settings_button, welcome_message; if (settingsMenu.settingsButton) { return; } - notif_button = document.querySelector(".notifications-container"); + notif_button = document.querySelector("#yt-masthead-notifications, .notifications-container"); settings_button = document.querySelector("#yt-masthead-user, #yt-masthead-signin"); if (settings_button) { welcome_message = document.createElement("template"); @@ -542,9 +540,9 @@ @@ -566,7 +564,7 @@ } function modComment(original) { return function (a) { - var comments, is_live; + let comments, is_live; comments = document.getElementById("watch-discussion"); is_live = window.ytplayer && window.ytplayer.config && window.ytplayer.config.args && window.ytplayer.config.args.livestream; if (a.split("comments").length > 1 && !is_live && comments && !comments.lazyload && user_settings.VID_HIDE_COMS === "1" && !comments.classList.contains("show")) { @@ -591,12 +589,12 @@ } function modEmbed(original) { return function (a, b) { - var temp, player; + let temp, player; temp = a.id || a; if (temp !== "player-api" && temp !== "upsell-video") { return original.apply(this, arguments); } - b = modArgs(b); + /*b = */modArgs(b); temp = original.apply(this, arguments); player = document.getElementById("movie_player"); if (player) { @@ -614,7 +612,7 @@ } function modAutoplayFullscreen(original) { return function () { - var has_ended, next_button, next_clicked; + let has_ended, next_button, next_clicked; has_ended = api && api.getCurrentTime && Math.round(api.getCurrentTime()) >= Math.floor(api.getDuration()); next_clicked = document.activeElement.classList.contains("ytp-button-next") || document.activeElement.classList.contains("ytp-next-button"); if (!user_settings.plApl && !next_clicked && has_ended) { @@ -634,20 +632,14 @@ } }; } - function modArgsWatch(args) { - if (args && args.autoplay === "1" && !user_settings.VID_PLR_ATPL && window.location.hash === "") { - args.autoplay = "0"; - } - return modArgsWatch.original.apply(this, arguments); - } function modPlayerCreate(original) { return function (a, b) { - var i, temp, player; + let i, temp, player; temp = a.id || a; if (temp !== "player-api" && temp !== "upsell-video") { return original.apply(this, arguments); } - b = modArgs(b); + /*b = */modArgs(b); if (a.id === "upsell-video") { original.apply(this, arguments); } else if (typeof a === "object") { @@ -676,8 +668,14 @@ } }; } + function ModArgsWatch(args) { + if (args && args.autoplay === "1" && !user_settings.VID_PLR_ATPL && window.location.hash === "") { + args.autoplay = "0"; + } + return ModArgsWatch.Original.apply(this, arguments); + } function scriptExit(event) { - var i, j, key, temp; + let i, j, key, temp; if (event && event.target) { if (event.target.getAttribute("name") === "www/base") { window.yt.setConfig = modSetConfig(window.yt.setConfig); @@ -710,39 +708,40 @@ } if (event.target.getAttribute("name") === "spf/spf") { window.spf.load = modComment(window.spf.load); - window.spf.prefetch = function(){return;}; + window.spf.prefetch = function(){}; if (window.name === "popOut") { - window.spf.navigate = function(){return;}; + window.spf.navigate = function(){}; } } } - if ((event && event.target && event.target.getAttribute("name") === "player/base") || (!window.html5Patched && window.yt && window.yt.player && window.yt.player.Application && window.yt.player.Application.create)) { + if ( + (event && event.target && event.target.getAttribute("name") === "player/base") || + (!window.html5Patched && window.yt && window.yt.player && window.yt.player.Application && window.yt.player.Application.create) + ) { window.html5Patched = true; window.yt.player.Application.create = modPlayerCreate(window.yt.player.Application.create); if (window._yt_player) { temp = Object.keys(window._yt_player); - i = temp.length; - while (i--) { - if (typeof window._yt_player[temp[i]] === "function" && window._yt_player[temp[i]].toString().match("this.adaptiveFormats")) { + for (i = 0; i < temp.length; i++) { + if (typeof window._yt_player[temp[i]] === "function" && window._yt_player[temp[i]].toString().match(/this\.adaptiveFormats/)) { key = temp[i]; break; } } if (key) { - modArgsWatch.original = window._yt_player[key]; - modArgsWatch.prototype = modArgsWatch.original.prototype; - temp = Object.keys(modArgsWatch.original); - i = temp.length; - while (i--) { - modArgsWatch[temp[i]] = modArgsWatch.original[temp[i]]; + ModArgsWatch.Original = window._yt_player[key]; + ModArgsWatch.prototype = ModArgsWatch.Original.prototype; + temp = Object.keys(ModArgsWatch.Original); + for (i = 0; i < temp.length; i++) { + ModArgsWatch[temp[i]] = ModArgsWatch.Original[temp[i]]; } - window._yt_player[key] = modArgsWatch; + window._yt_player[key] = ModArgsWatch; } } } } function checkBounds(elm, X, Y) { - var snapX, snapY; + let snapX, snapY; if (X > -1 && X + elm.offsetWidth < document.documentElement.offsetWidth) { snapX = false; } else if (X < 1) { @@ -764,7 +763,7 @@ return {X: X + "px", Y: Y + "px", snapX: snapX, snapY: snapY}; } function updatePos() { - var x, y, height, player, bounds; + let x, y, height, player, bounds; player = document.getElementById("movie_player"); if (!document.documentElement.classList.contains("floater") || window.innerWidth < 657) { if (player) { @@ -798,7 +797,7 @@ document[(window.chrome && "body") || "documentElement"].scrollTop = 0; } function dragFloater(event) { - var excluded, isFScreen, isFloater, bounds, player; + let excluded, isFScreen, isFloater, bounds, player; isFScreen = document.querySelector(".ytp-fullscreen"); isFloater = document.documentElement.classList.contains("floater"); if (event && !isFScreen && isFloater) { @@ -816,7 +815,13 @@ orgX: event.clientX, orgY: event.clientY }; - } else if (event.type === "mousemove" && (dragFloater.hasMoved || Math.abs(event.clientX - dragFloater.oldPos.orgX) > 10 || Math.abs(event.clientY - dragFloater.oldPos.orgY) > 10)) { + } else if ( + event.type === "mousemove" && ( + dragFloater.hasMoved || + Math.abs(event.clientX - dragFloater.oldPos.orgX) > 10 || + Math.abs(event.clientY - dragFloater.oldPos.orgY) > 10 + ) + ) { bounds = checkBounds(player, event.clientX + dragFloater.oldPos.X, event.clientY + dragFloater.oldPos.Y); player.style.left = bounds.X; player.style.top = bounds.Y; @@ -843,7 +848,7 @@ } } function iniFloater() { - var player, plrApi, out_of_sight, isFloater, isFScreen, floaterUI, settings_open; + let player, plrApi, out_of_sight, isFloater, isFScreen, floaterUI, settings_open; player = document.getElementById("movie_player"); plrApi = document.getElementById("player-api").getBoundingClientRect(); settings_open = document.getElementById("P-settings"); @@ -887,9 +892,16 @@ } } function alwaysActive(event) { - var i, list, clear, length, eventClone; + let i, list, clear, length, eventClone; clear = window.location.pathname == "/watch" && api && api !== event.target && !api.contains(event.target) && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey && !event.target.isContentEditable; - if (clear && ((event.which > 47 && event.which < 58) || (event.which > 95 && event.which < 106) || [27, 32, 35, 36, 37, 38, 39, 40, 66, 67, 79, 87, 187, 189].indexOf(event.which) > -1) && ["EMBED", "INPUT", "OBJECT", "TEXTAREA", "IFRAME"].indexOf(document.activeElement.tagName) < 0) { + if ( + clear && ( + event.which > 47 && event.which < 58 || + event.which > 95 && event.which < 106 || + [27, 32, 35, 36, 37, 38, 39, 40, 66, 67, 79, 87, 187, 189].indexOf(event.which) > -1 + ) && + ["EMBED", "INPUT", "OBJECT", "TEXTAREA", "IFRAME"].indexOf(document.activeElement.tagName) < 0 + ) { eventClone = new Event("keydown"); list = Object.keys(Object.getPrototypeOf(event)); length = list.length; @@ -935,7 +947,7 @@ } } function getThumb() { - var args, base, thumb_url; + let args, base, thumb_url; args = window.ytplayer.config.args; base = (args.iurl_webp && "_webp") || ""; thumb_url = args["iurlmaxres" + base] || args["iurlsd" + base] || args["iurl" + base]; @@ -948,7 +960,7 @@ } } function getScreenshot() { - var width, height, aspectRatio, video, container, canvas, close, context; + let width, height, aspectRatio, video, container, canvas, close, context; video = document.querySelector("video"); container = document.getElementById("screenshot-result") || document.createElement("div"); canvas = container.querySelector("canvas") || document.createElement("canvas"); @@ -971,7 +983,15 @@ } } function exitFullBrowser(key) { - if (document.documentElement.classList.contains("part_fullbrowser") && (key.keyCode === 27 || key.key === "Escape" || (key.target.className && key.target.className.split("ytp-size").length > 1))) { + if ( + document.documentElement.classList.contains("part_fullbrowser") && ( + key.keyCode === 27 || + key.key === "Escape" || ( + key.target.className && + key.target.className.split("ytp-size").length > 1 + ) + ) + ) { toggleFullBrowser(key); if (key.type === "mousedown") { document.removeEventListener("keydown", exitFullBrowser); @@ -981,7 +1001,7 @@ } } function toggleFullBrowser(event) { - var plrState = api && api.getPlayerState && api.getPlayerState(); + let plrState = api && api.getPlayerState && api.getPlayerState(); plrState = plrState < 5 && plrState > 0; document[(window.chrome && "body") || "documentElement"].scrollTop = 0; document.addEventListener("keydown", exitFullBrowser); @@ -993,6 +1013,45 @@ window.dispatchEvent(new Event("resize")); } } + function toggleFrames(event) { + let i, pi, fps, temp; + advancedOptions.frame_step = document.getElementById("framestep-button"); + if (event && ["EMBED", "INPUT", "OBJECT", "TEXTAREA"].indexOf(document.activeElement.tagName) < 0 && event.target.tagName !== "IFRAME" && !event.target.getAttribute("contenteditable")) { + if ((event.keyCode === 37 || event.keyCode === 39) && event.shiftKey) { + pi = api.getVideoStats().fmt; + if (window.ytplayer && window.ytplayer.config && window.ytplayer.config.args && window.ytplayer.config.args.adaptive_fmts) { + temp = window.ytplayer.config.args.adaptive_fmts.split(","); + i = temp.length; + while (i--) { + if (temp[i].indexOf("itag=" + pi) > 0) { + advancedOptions.fps = parseInt(temp[i].match(/fps=([\d]+)/)[1]); + break; + } + } + } + if (!advancedOptions.fps || advancedOptions.fps === 1) { + advancedOptions.fps = 30; + } + fps = ((event.keyCode < 39 && -1) || 1) * ((advancedOptions.fps < 2 && 30) || advancedOptions.fps); + if (fps && api) { + if (!document.querySelector("video").paused) { + api.pauseVideo(); + } + api.seekBy(1 / fps); + } + event.preventDefault(); + event.stopImmediatePropagation(); + } else if (event.type === "click" && event.target.id === "framestep-button") { + set("frame_step", !user_settings.frame_step); + advancedOptions.frame_step.classList[(user_settings.frame_step && "add") || "remove"]("active"); + } + } + if (advancedOptions.frame_step && advancedOptions.frame_step.classList.contains("active")) { + document.addEventListener("keydown", toggleFrames, true); + } else if (!advancedOptions.frame_step || !advancedOptions.frame_step.classList.contains("active")) { + document.removeEventListener("keydown", toggleFrames, true); + } + } function toggleShortcuts() { window.open("https://github.com/ParticleCore/Particle/wiki/YouTube-shortcuts", "_blank"); } @@ -1009,7 +1068,7 @@ document.getElementById("autoplay-button").classList[(user_settings.VID_PLR_ATPL && "add") || "remove"]("active"); } function toggleLoop(event) { - var videoPlayer = document.querySelector("video"); + let videoPlayer = document.querySelector("video"); if (videoPlayer) { videoPlayer.loop = event ? !user_settings.loopVid : user_settings.loopVid; if (event) { @@ -1019,7 +1078,7 @@ set("loopVid", advancedOptions.loop_button.classList.contains("active")); } function toggleCinemaMode(event) { - var plrState = api && api.getPlayerState && api.getPlayerState() < 5 && api.getPlayerState() > 0; + let plrState = api && api.getPlayerState && api.getPlayerState() < 5 && api.getPlayerState() > 0; set("lightsOut", event ? !user_settings.lightsOut : true); advancedOptions.cinema_mode.classList[(user_settings.lightsOut && "add") || "remove"]("active"); if (event && plrState) { @@ -1036,6 +1095,7 @@ advancedOptions.full_browser = advancedOptions.controls.querySelector("#fullbrowser-button"); advancedOptions.cinema_mode = advancedOptions.controls.querySelector("#cinemamode-button"); advancedOptions.loop_button = advancedOptions.controls.querySelector("#loop-button"); + advancedOptions.frame_step = advancedOptions.controls.querySelector("#framestep-button"); advancedOptions.actions = { togglePlay: togglePlay, toggleLoop: toggleLoop, @@ -1044,6 +1104,7 @@ popPlayer: popPlayer, toggleFullBrowser: toggleFullBrowser, toggleCinemaMode: toggleCinemaMode, + toggleFrames: toggleFrames, toggleShortcuts: toggleShortcuts }; document.addEventListener("click", handleToggles); @@ -1059,9 +1120,13 @@ advancedOptions.cinema_mode.classList.add("active"); toggleCinemaMode(); } + if (user_settings.frame_step && !advancedOptions.frame_step.classList.contains("active")) { + advancedOptions.frame_step.classList.add("active"); + toggleFrames(); + } } function advancedOptions() { - var header, cnslBtn, cnslCont; + let header, cnslBtn, cnslCont; header = document.getElementById("watch-header"); cnslBtn = document.getElementById("console-button"); advancedOptions.controls = document.getElementById("player-console"); @@ -1098,6 +1163,7 @@
+
`; if (user_settings.VID_PLR_ATPL) { @@ -1113,7 +1179,7 @@ } } function iniAction(event) { - var observer, load_more, click_title; + let observer, load_more, click_title; load_more = document.querySelector("#watch-more-related, .load-more-button"); click_title = document.querySelector(".yt-uix-tile"); while (click_title) { @@ -1142,7 +1208,7 @@ } } function setButtons() { - var i, j, list, temp, thumb, button; + let i, j, list, temp, thumb, button; list = Object.keys(modThumbs.thumbs); i = list.length; while (i--) { @@ -1180,7 +1246,7 @@ } } function delVideos() { - var i, j, temp, parent, blacklist, has_upnext; + let i, j, temp, parent, blacklist, has_upnext; has_upnext = document.querySelector(".autoplay-bar"); blacklist = Object.keys(user_settings.blacklist); i = blacklist.length; @@ -1233,7 +1299,7 @@ } } function getVideos() { - var i, list, temp, channel_id; + let i, list, temp, channel_id; modThumbs.thumbs = {}; list = document.querySelectorAll(` .yt-lockup-byline > a, @@ -1271,7 +1337,7 @@ } } function setVideoCount() { - var span = document.createElement("span"); + let span = document.createElement("span"); span.textContent = " · "; enhancedDetails.username.appendChild(span); enhancedDetails.link.href = window.location.origin + "/channel/" + enhancedDetails.user.dataset.ytid + "/videos"; @@ -1301,7 +1367,7 @@ } } function getChannelInfo(details) { - var retry, isLive; + let retry, isLive; isLive = details.target.response.querySelector(".yt-badge-live"); if (!isLive) { retry = details.target.responseURL.split("/videos").length < 2; @@ -1331,7 +1397,7 @@ } } function reverseControl() { - var i, temp, prev, next, list, videos; + let i, temp, prev, next, list, videos; prev = document.querySelector(".prev-playlist-list-item"); next = document.querySelector(".next-playlist-list-item"); list = document.getElementById("playlist-autoscroll-list"); @@ -1362,7 +1428,7 @@ } } function createButton(type, label, bool, call) { - var button = document.createElement("template"); + let button = document.createElement("template"); button.innerHTML = // ` @@ -2023,12 +2115,11 @@ document.documentElement.appendChild(temp.content.firstChild); document.addEventListener("click", closeMigrationInstructions); } - var api, cid, events, language, user_settings, player_instance, default_settings; + let api, cid, language, user_settings, player_instance, default_settings; if (isMaterial()) { return; } cid = {}; - events = {}; user_settings = JSON.parse(document.documentElement.dataset.user_settings || null); if (document.documentElement.dataset.user_settings) { document.documentElement.removeAttribute("data-user_settings"); @@ -2077,6 +2168,7 @@ CNSL_PPOT : "Pop-out video", CNSL_FLBR : "Fullbrowser mode", CNSL_CINM_MD : "Cinema mode", + CNSL_FRME : "Frame by frame (Shift + ← or →)", CNSL_YTSC : "YouTube shortcuts list", PLST_AP : "Autoplay", PLST_RVRS : "Reverse", @@ -2217,7 +2309,7 @@ main(); }, contentScriptMessages: function() { - var key1, key2, gate, sets, locs, observer; + let key1, key2, gate, sets, locs, observer; key1 = "parsend"; key2 = "getlocale"; gate = document.documentElement; @@ -2250,7 +2342,7 @@ } }, main: function(event) { - var holder; + let holder; if (!event && particle.is_userscript) { event = JSON.parse(particle.GM_getValue(particle.id, "{}")); } @@ -2261,7 +2353,7 @@ holder = document.createElement("link"); holder.rel = "stylesheet"; holder.type = "text/css"; - holder.href = "https://particlecore.github.io/Particle/stylesheets/YouTubePlus.css?v=1.7.3"; + holder.href = "https://particlecore.github.io/Particle/stylesheets/YouTubePlus.css?v=1.7.4"; document.documentElement.appendChild(holder); } holder = document.createElement("script"); @@ -2274,7 +2366,7 @@ }, ini: function() { particle.id = "particleSettings"; - particle.is_userscript = typeof GM_info === "object" ? true : false; + particle.is_userscript = typeof GM_info === "object"; if (particle.is_userscript) { particle.GM_getValue = GM_getValue; particle.GM_setValue = GM_setValue; diff --git a/src/Webextension/manifest.json b/src/Webextension/manifest.json index 2e986bf..27fa477 100644 --- a/src/Webextension/manifest.json +++ b/src/Webextension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "YouTube Plus", - "version": "1.7.3", + "version": "1.7.4", "description": "YouTube with more freedom", "default_locale": "en", "icons": {