diff --git a/README.md b/README.md index fa7c0ab..471b534 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,13 @@ For best results with autodetection, please make sure the following requirements ## Installing -### Temporary install +### Permanent install / stable + +[v1.2.1 — Regular version — download from AMO](https://addons.mozilla.org/en/firefox/addon/ultrawidify/) + +[v1.2.1 — Regular version — download from Chrome store](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi) + +### Installing the current, github version 1. Clone this repo 2. Open up Firefox @@ -72,14 +78,7 @@ For best results with autodetection, please make sure the following requirements 4. Add temporary addon 5. Browse to wherever you saved it and select manifest.json -### Permanent install - -[v1.2.1 — Regular version — download from AMO](https://addons.mozilla.org/en/firefox/addon/ultrawidify/) - -[v1.2.1 — Regular version — download from Chrome store](https://chrome.google.com/webstore/detail/ultrawidify/dndehlekllfkaijdlokmmicgnlanfjbi) - - -## Known issues +## Known issues (in stable versions) 'More settings' button actually doesn't work at the moment. @@ -98,6 +97,12 @@ For best results with autodetection, please make sure the following requirements ## Changelog +###v1.3a1 (git/current version) + +* Adding ability to add custom sites (in progress) +* Most of the extension is being completely rewritten to accomodate that feature, which means there's a serious regression with Netflix support (no netflix at the moment) +* I'm also trying to break the 1500 line behemoth into smaller files. + ###v1.2.1 (AMO + Chrome) * Fixed the bugs which caused aspect ratio to not be calculated properly. diff --git a/buildext.sh b/buildext.sh new file mode 100755 index 0000000..c674bb5 --- /dev/null +++ b/buildext.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# Takes all the files from 'src' and compiles it intro a single content script. +# Also compiles background scripts and settings pages. +# +# I'm using this over something like requirejs so my extension doesn't need even more +# dependencies. +# +# How does this work? +# 0. You're supposed to run this in the root directory of the extension. + +# 1. see if file has any #include [filename] comments. If so, merge [filename] file +# into the current file (after checking if that file has any #include comments +# Compiled files are saved to /tmp. +# +# 2. After compiling file and its dependencies, check for presence of #location [directory] +# comments. [directory] is relative to the root directory of the extension +# 2.1 also check for #out, which defines filename. +# +# 3. Use '-nodebug' to remove all calls of console.log (to be implemented) + +function flattenFileName { + echo $1 | sed 's/\//_/g' +} + +fileList=""; + +function compileFile { + local file=$1 + local flatfile=$(flattenFileName $file); + + + if [ -f /tmp/$flatfile ] ; then + return 0 + fi; + + fileList="$fileList $flatfile" + + # let's take all the #included files and put them at the top + for f in $(grep "#include" $file | awk '{print $NF}') ; do + + local lf=$f + fflat=$(flattenFileName $lf); + + compileFile $lf + + printf "\n//BEGIN included from $lf\n" >> /tmp/$flatfile + grep -Ev "#include|#location|#out" /tmp/$fflat >> /tmp/$flatfile + printf "//END included from $lf\n\n" >> /tmp/$flatfile + + done + + grep -Ev "#include|#location|#out" $file >> /tmp/$flatfile +} + +cd src; + +for file in *.js ; do + echo "main loop, we're looking at this file: $file" + compileFile $file + echo "Files compiled. Moving to location (if specified)" + + outFile=$file + + if grep -q "#out" $file ; then + outFile=$( grep "#out" $file | awk '{print $NF}') + fi + + + + if grep -q "#location" $file ; then + location=$( grep "#location" $file | awk '{print $NF}') + echo "File will be saved to $location as $outFile" + cd .. + echo "// Autogenerated using buildext. This file should not be modified — modify source files instead." > $location/$outFile + grep -Ev "#location|#include|#out" /tmp/$(flattenFileName $file) >> $location/$outFile + cd src + fi +done + +# perform cleanup +for file in $fileList ; do + rm /tmp/$file +done diff --git a/js/uw.js b/js/uw.js index 544388a..9b685f7 100644 --- a/js/uw.js +++ b/js/uw.js @@ -1,215 +1,126 @@ -var usebrowser = "chrome"; -var browser_autodetect = true; +// Autogenerated using buildext. This file should not be modified — modify source files instead. -var debugmsg = true; -var debugmsg_click = false; -var debugmsg_message = false; -var debugmsg_autoar = false; -var debugmsg_periodic = false; -var debugmsg_ui = true; -var force_conf_reload = true; -if(debugmsg || debugmsg_click || debugmsg_message || debugmsg_autoar){ - console.log("\n\n\n\n\n\n\n\n\n\n\n\n\n\n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); - console.log("\nLoading ultrawidify (uw)\nIf you can see this, extension at least tried to load\n\nRandom number: ",Math.floor(Math.random() * 20) + 1,"\n"); - - if(debugmsg) - console.log("Logging all"); - - if(debugmsg_click) - console.log("Logging debugmsg_click"); - - if(debugmsg_message) - console.log("Logging debugmsg_message"); - - if(debugmsg_autoar) - console.log("Logging autoar"); - - console.log(". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); -} +//BEGIN included from conf/uiconf.js + var UW_UI_BUTTONS = { + fitw: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/fitw.png", + text: "Fit to width", + onclick: function(){ changeCSS("fit", "fitw") } + }, + fith: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/fith.png", + text: "Fit to height", + onclick: function(){ changeCSS("fit", "fith") } + }, + reset: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/reset.png", + text: "Reset", + onclick: function(){ changeCSS("reset", "reset") } + }, + zoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/zoom.png", + text: "Zoom", + onclick: function(){ changeCSS("fit", "zoom") } + }, + unzoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/unzoom.png", + text: "Unzoom", + onclick: function(){ changeCSS("fit", "unzoom") } + }, + zoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/zoom.png", + text: "Reset", + onclick: function(){ changeCSS("fit", "zoom") } + }, + autoar: { + native_bar: false, + has_submenu: false, + button: false, + text: "Detect aspect ratio via 3rd party", + onclick: function(){ manual_autoar()} + }, + settings: { + native_bar: true, + button: true, + icon: "/res/img/ytplayer-icons/settings.png", + text: "Settings", + has_submenu: true, + submenu: [ "fitw","fith","reset","zoom","unzoom","autoar","ar" ], + top_level: true, + submenu_id: "uw_settings_menu", + onclick: function(){ toggleMenu("uw_settings_menu") } + }, + ar: { + native_bar: false, + button: false, + text: "Force aspect ratio", + has_submenu: true, + submenu: [ "ar219", "ar169", "ar1610", "ar43" ], + submenu_id: "uw_force_ar_menu", + onclick: function(){ showMenu("uw_force_ar_menu") } + }, + ar219: { + native_bar: false, + button: false, + text: "21:9", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 21/9 )); } + }, + ar169: { + native_bar: false, + button: false, + text: "16:9", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 16/9 )); } + }, + ar1610: { + native_bar: false, + button: false, + text: "16:10", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 1.6 )); } + }, + ar43: { + native_bar: false, + button: false, + text: "4:3", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 4/3 )); } + } + } -var UW_UI_BUTTONS = { - fitw: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/fitw.png", - text: "Fit to width", - onclick: function(){ changeCSS("fit", "fitw") } - }, - fith: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/fith.png", - text: "Fit to height", - onclick: function(){ changeCSS("fit", "fith") } - }, - reset: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/reset.png", - text: "Reset", - onclick: function(){ changeCSS("reset", "reset") } - }, - zoom: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/zoom.png", - text: "Zoom", - onclick: function(){ changeCSS("fit", "zoom") } - }, - unzoom: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/unzoom.png", - text: "Unzoom", - onclick: function(){ changeCSS("fit", "unzoom") } - }, - zoom: { - native_bar: true, - has_submenu: false, - button: true, - icon: "/res/img/ytplayer-icons/zoom.png", - text: "Reset", - onclick: function(){ changeCSS("fit", "zoom") } - }, - autoar: { - native_bar: false, - has_submenu: false, - button: false, - text: "Detect aspect ratio via 3rd party", - onclick: function(){ manual_autoar()} - }, - settings: { - native_bar: true, - button: true, - icon: "/res/img/ytplayer-icons/settings.png", - text: "Settings", - has_submenu: true, - submenu: [ "fitw","fith","reset","zoom","unzoom","autoar","ar" ], - top_level: true, - submenu_id: "uw_settings_menu", - onclick: function(){ toggleMenu("uw_settings_menu") } - }, - ar: { - native_bar: false, - button: false, - text: "Force aspect ratio", - has_submenu: true, - submenu: [ "ar219", "ar169", "ar1610", "ar43" ], - submenu_id: "uw_force_ar_menu", - onclick: function(){ showMenu("uw_force_ar_menu") } - }, - ar219: { - native_bar: false, - button: false, - text: "21:9", - has_submenu: false, - onclick: function(){ changeCSS("char", ( 21/9 )); } - }, - ar169: { - native_bar: false, - button: false, - text: "16:9", - has_submenu: false, - onclick: function(){ changeCSS("char", ( 16/9 )); } - }, - ar1610: { - native_bar: false, - button: false, - text: "16:10", - has_submenu: false, - onclick: function(){ changeCSS("char", ( 1.6 )); } - }, - ar43: { - native_bar: false, - button: false, - text: "4:3", - has_submenu: false, - onclick: function(){ changeCSS("char", ( 4/3 )); } - } -} - -var UW_UI_BANLIST = { - youtube: { - autoar: "all" - }, - netflix: { - settings: "all" - } -} - -if(browser_autodetect){ - if(typeof browser === "undefined"){ // This means we're probably not on Firefox. - if(chrome){ - browser = chrome; - usebrowser = "chrome"; - } - } - else - usebrowser = "firefox"; -} + var UW_UI_BANLIST = { + youtube: { + autoar: "all" + }, + netflix: { + settings: "all" + } + } + + +//END included from conf/uiconf.js -const playercheck_recursion_depth_limit = 3; - -var uw_autoar_default = true; // true - autoar enabled. False - autoar disabled - -var extraClassAdded = false; -var inFullScreen = false; - -var cssmod = ""; -var zoomStep = 0.05; - -var whatdo_persistence = true; -var last_whatdo = {type: "autoar", what_do:"reset"}; -var page_url = window.location.toString(); // S pomočjo page_url določimo, na kateri spletni strani smo. -var SITE; - -var ctlbar_classnames = ["ytp-chrome-controls"]; -var serviceArray = [".video-stream"]; //Youtube - -var buttons = []; - -var IGNORE_STORAGE_CHANGES = false; - -//BEGIN determining which site we're on and the associated names - -var ui_anchor; -var player; -var vid_el; -var SAMPLE_BUTTON_CLASS; // Class of a sample button -var SAMPLE_BUTTON_INDEX = 0; // index of a sample button -var button_size_base = "x"; // Determines if size of extension buttons is defined by width or height of sample button - -var char_strat = "contain"; -var char_got_ar = false; -var char_arx; -var char_ary; -var autoar_enabled; - -var video_wrap; - - -// Here we store the window size, so we know when to trigger css change. -var winsize = {w: window.innerWidth, h: window.innerHeight}; - -// Video title for third party -var title = ""; - -// provider-specific variables - -var netflix_cltbar_visibility = -1; // -1 for invisible, anything non-negative for visible -var netflix_periodic_timer; - -// Stuff for other browsers -if(usebrowser == "chrome"){ - browser = chrome; -} - +//BEGIN included from conf/sitesconf.js var UW_SITES = { youtube: { enabled: true, @@ -282,206 +193,11 @@ var UW_SITES = { enabled: false } } -} -browser.storage.local.set({ultrawidify_siterules: UW_SITES}); - -//Na reloadu vselej odstrani vmesnik od prej -//Always remove previous UI on extension reload -var previousElements = document.getElementsByClassName("uw_element"); -if(previousElements){ - while (previousElements.length > 0){ - previousElements[0].parentNode.removeChild(previousElements[0]); - } -} +} +//END included from conf/sitesconf.js -function init(force_reload){ - - if(debugmsg) - console.log("uw::init | starting init"); - - - var el; - for (key in UW_UI_BUTTONS){ - el = UW_UI_BUTTONS[key]; - if(el.submenu_id){ - // We defined submenus. Now let's add parent info to each submenu. - for(var i = 0; i < el.submenu.length; i++){ - UW_UI_BUTTONS[el.submenu[i]].parent = key; - } - } - } - -// var marker = document.getElementById("uw_save_site"); - - if(debugmsg) - console.log("uw | %cpage_url: "+page_url,"color: #99F"); - - - /* Fun fact — če reloadamo razširitev v about:debugging, window.location vrne "javascript:". Fak - * // Fun fact — ivar previousElements = document.getElementsByClassName("uw_element"); - i *f(previousElements){ - while (previousElements.length > 0){ - previousElements[0].parentNode.removeChild(previousElements[0]); -} -}f we reload the extension from about:debugging, window.location returns "javascript:" (which - // obviously isn't the page we're on. Fak. - */ -// if(page_url.indexOf("javascript:") != -1){ -// if(marker){ -// if(debugmsg){ -// console.log("uw::init | %csomething went wrong, page_url is not properly defined. Trying to get URL from a marker","color: #000; background-color: #F00", "marker value:",marker.textContent); -// } -// page_url = marker.textContent; -// } -// else -// console.log("uw::init | %csomething went wrong, page_url is not properly defined. Marker wasn't found either.r","color: #000; background-color: #F00"); -// } -// else{ -// if(!marker && page_url.indexOf("javascript:") == -1){ -// var marker = document.createElement('div'); -// marker.id = "uw_save_site"; -// marker.textContent = page_url; -// } -// else{ -// if(page_url.indexOf("javascript:") == -1) -// marker.textContent = page_url; -// } -// } - - - - - //Youtube: - if(page_url.indexOf("youtu") != -1){ - if(debugmsg) - console.log("uw::init | we're on youtube. Page url:", page_url); - -// SAMPLE_BUTTON_CLASS = "ytp-button ytp-settings-button"; - -// if(inIframe()) -// player = document.getElementById("player") -// else -// player = document.getElementById("movie_player"); -// - video_wrap = "video-stream"; - return true; - } - - //Netflix: - if(page_url.indexOf("netflix.com") != -1){ - if(debugmsg) - console.log("uw::init | we're on netflix. Page url:", page_url); - - player = document.getElementById("playerContainer"); - var tmp = document.getElementsByClassName("player-status")[0]; - if(!tmp) - return false; - -// tmp.id = "uw_buttons_go_after_this"; - - - -// ui_anchor = document.getElementsByClassName("uw-button-row")[0]; - -// var container = document.getElementsByClassName("player-control-bar")[0]; -// if(! container || ! container.childNodes) -// return false; - -// for(var i = 1; i < container.childNodes.length; i++){ -// if(debugmsg || debugmsg_click){ -// console.log("child node",i,"has next sibling",container.childNodes[i].nextSibling); -// } -// if(container.childNodes[i].className == "player-status"){ -// console.log("a"); -// var nnode = container.childNodes[i].parentNode.insertBefore(ui_anchor, container.childNodes[i].nextSibling); -// console.log("b", nnode, container.childNodes[i].nextSibling.nodeValue); -// break; -// } -// -// } - -// if(!ui_anchor){ -// ui_anchor = document.createElement("div"); -// ui_anchor.className = "uw-button-row"; -// ui_anchor.id = "uw_anchor"; -// } -// -// -// if(debugmsg) -// console.log("uw::init | we're on netflix. ui anchor: ",ui_anchor, "; ui anchor parent:", tmp); -// -// tmp.appendChild(ui_anchor); - -// document.querySelector(".player-control-bar").appendChild(ui_anchor); -// console.log(document.querySelector(".player-control-bar")) -// console.log("trying insert-after trick", $("#uw_anchor"), $("uw_buttons_go_after_this"), tmp); -// $("#ui_anchor").insertAfter(".player-control-bar"); -// console.log( - - vid_el = document.getElementsByTagName("video")[0]; - - SAMPLE_BUTTON_CLASS = "player-control-button player-fill-screen"; - video_wrap = "player-video-wrapper"; - button_size_base = "y"; - - return true; - } - - return false; -} - - -//END - -//BEGIN ADDING CSS - -// Če ponovno naložimo dodatek, potem odstranimo star CSS. Lahko se zgodi, da je Tam spremenil CSS in hoče -// preveriti, če stvari zgledajo tako kot morajo. Če ima en razred/id več nasprotujoćih si definicij, potem -// nam to lahko povzroča težave. Za uporabnike je načeloma odstranjevanje obstoječega CSS brezpredmetno, ker -// uporabnik ponavadi ne bo reloadal razširitve. -// -// If we reload the extension, then we also remove our old CSS. It can easily happen that Tam changed CSS a bit -// and wants to see if things look roughly the way they should. We do this because if a class/id has multiple -// mutually exclusive definitions, we can get some problems with CSS not working the way it should. People who -// aren't Tam generally don't see the benefit as they won't reload the extension — let alone reload the extension -// after messing with CSS. -var ui_anchor = document.getElementById("uw_ui_anchor"); -// if(force_reload && ui_anchor) -// ui_anchor.parentNode.remove(ui_anchor); -var uwcss = document.getElementsByClassName("uw_css"); -while(uwcss && uwcss.length > 0) - uwcss[0].parentNode.removeChild(uwcss[0]); - -// funkcija pomagač za ustvarjanje css linkov -// helper function for creating css links -function addLink(css_url){ - var link = document.createElement("link"); - link.className = "uw_css"; - link.setAttribute("rel","stylesheet"); - link.setAttribute("type","text/css"); - link.setAttribute("href", resourceToUrl(css_url)); - $("head").append(link); -} - -// Vsaka stran dobi uw_common.css -// We add uw_common.css on every page - -addLink("res/css/uw_common.css"); - -// Če smo na Youtube/youtube popupu, dodamo css za youtube elemente -// If we're on youtube/youtube popup, we add css for youtube elements -if(page_url.indexOf("youtu") != -1){ - addLink("res/css/uw_yt.css"); -} -if(page_url.indexOf("netflix.com") != -1){ - addLink("res/css/uw_netflix.css"); -} - -//END ADDING CSS - - -//BEGIN keybind-related stuff +//BEGIN included from conf/keybinds.js // Yeah hi /r/badcode. // Anyway, because nazi localstorage flat out refuses to store arrays: var DEFAULT_KEYBINDINGS = { @@ -539,6 +255,258 @@ var DEFAULT_KEYBINDINGS = { modifiers: [] } }; +//END included from conf/keybinds.js + + +//BEGIN included from lib/libopts.js +// setopt in getopt. Shranita oz. dobita stvari iz skladišča +// setopt, getopt. They set/get stuff from the storage + +function setopt(item){ + browser.storage.local.set(item); +} +function getopt(prop, callback){ + if(usebrowser == "chrome") + browser.storage.local.get(prop, callback); + else + browser.storage.local.get(prop).then(callback); +} +//END included from lib/libopts.js + + +//BEGIN included from lib/browser_autodetect.js +usebrowser = "firefox"; + +if(typeof browser === "undefined"){ // This means we're probably not on Firefox. + if(chrome){ + browser = chrome; + usebrowser = "chrome"; + } +} +else{ + usebrowser = "firefox"; +} +//END included from lib/browser_autodetect.js + + +//BEGIN included from lib/optinit.js +IGNORE_STORAGE_CHANGES = true; + +// getopt( "ultrawidify_uiban", function (opt) { +// if(! opt || opt.ultrawidify_uiban === undefined){ +// if(debugmsg) +// console.log("uw::extsetup_uiban | ui ban missing from storage. Setting defaults."); +// browser.storage.local.set({ultrawidify_uiban: UW_UI_BANLIST}); +// } +// } + + +IGNORE_STORAGE_CHANGES = false; +//END included from lib/optinit.js + + +var usebrowser = "chrome"; +var browser_autodetect = true; + +var debugmsg = true; +var debugmsg_click = false; +var debugmsg_message = false; +var debugmsg_autoar = false; +var debugmsg_periodic = false; +var debugmsg_ui = true; +var force_conf_reload = true; +if(debugmsg || debugmsg_click || debugmsg_message || debugmsg_autoar){ + console.log("\n\n\n\n\n\n\n\n\n\n\n\n\n\n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); + console.log("\nLoading ultrawidify (uw)\nIf you can see this, extension at least tried to load\n\nRandom number: ",Math.floor(Math.random() * 20) + 1,"\n"); + + if(debugmsg) + console.log("Logging all"); + + if(debugmsg_click) + console.log("Logging debugmsg_click"); + + if(debugmsg_message) + console.log("Logging debugmsg_message"); + + if(debugmsg_autoar) + console.log("Logging autoar"); + + console.log(". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); +} + + + + + + + +const playercheck_recursion_depth_limit = 3; + +var uw_autoar_default = true; // true - autoar enabled. False - autoar disabled + +var extraClassAdded = false; +var inFullScreen = false; + +var cssmod = ""; +var zoomStep = 0.05; + +var whatdo_persistence = true; +var last_whatdo = {type: "autoar", what_do:"reset"}; +var page_url = window.location.toString(); // S pomočjo page_url določimo, na kateri spletni strani smo. +var SITE; + +var ctlbar_classnames = ["ytp-chrome-controls"]; +var serviceArray = [".video-stream"]; //Youtube + +var buttons = []; + +var IGNORE_STORAGE_CHANGES = false; + +//BEGIN determining which site we're on and the associated names + +var ui_anchor; +var player; +var vid_el; +var SAMPLE_BUTTON_CLASS; // Class of a sample button +var SAMPLE_BUTTON_INDEX = 0; // index of a sample button +var button_size_base = "x"; // Determines if size of extension buttons is defined by width or height of sample button + +var char_strat = "contain"; +var char_got_ar = false; +var char_arx; +var char_ary; +var autoar_enabled; + +var video_wrap; + + +// Here we store the window size, so we know when to trigger css change. +var winsize = {w: window.innerWidth, h: window.innerHeight}; + +// Video title for third party +var title = ""; + +// provider-specific variables + +var netflix_cltbar_visibility = -1; // -1 for invisible, anything non-negative for visible +var netflix_periodic_timer; + +// Stuff for other browsers +if(usebrowser == "chrome"){ + browser = chrome; +} + + +browser.storage.local.set({ultrawidify_siterules: UW_SITES}); + +//Na reloadu vselej odstrani vmesnik od prej +//Always remove previous UI on extension reload +var previousElements = document.getElementsByClassName("uw_element"); +if(previousElements){ + while (previousElements.length > 0){ + previousElements[0].parentNode.removeChild(previousElements[0]); + } +} + + +function init(force_reload){ + + if(debugmsg) + console.log("uw::init | starting init"); + + + var el; + for (key in UW_UI_BUTTONS){ + el = UW_UI_BUTTONS[key]; + if(el.submenu_id){ + // We defined submenus. Now let's add parent info to each submenu. + for(var i = 0; i < el.submenu.length; i++){ + UW_UI_BUTTONS[el.submenu[i]].parent = key; + } + } + } + + if(debugmsg) + console.log("uw::init | %cpage_url: "+page_url,"color: #99F"); + + //Youtube: + if(page_url.indexOf("youtu") != -1){ + if(debugmsg) + console.log("uw::init | we're on youtube. Page url:", page_url); + + video_wrap = "video-stream"; + return true; + } + + //Netflix: + if(page_url.indexOf("netflix.com") != -1){ + if(debugmsg) + console.log("uw::init | we're on netflix. Page url:", page_url); + + player = document.getElementById("playerContainer"); + var tmp = document.getElementsByClassName("player-status")[0]; + if(!tmp) + return false; + + vid_el = document.getElementsByTagName("video")[0]; + + SAMPLE_BUTTON_CLASS = "player-control-button player-fill-screen"; + video_wrap = "player-video-wrapper"; + button_size_base = "y"; + + return true; + } + + return false; +} + + +//END + +//BEGIN ADDING CSS + +// Če ponovno naložimo dodatek, potem odstranimo star CSS. Lahko se zgodi, da je Tam spremenil CSS in hoče +// preveriti, če stvari zgledajo tako kot morajo. Če ima en razred/id več nasprotujoćih si definicij, potem +// nam to lahko povzroča težave. Za uporabnike je načeloma odstranjevanje obstoječega CSS brezpredmetno, ker +// uporabnik ponavadi ne bo reloadal razširitve. +// +// If we reload the extension, then we also remove our old CSS. It can easily happen that Tam changed CSS a bit +// and wants to see if things look roughly the way they should. We do this because if a class/id has multiple +// mutually exclusive definitions, we can get some problems with CSS not working the way it should. People who +// aren't Tam generally don't see the benefit as they won't reload the extension — let alone reload the extension +// after messing with CSS. + +var ui_anchor = document.getElementById("uw_ui_anchor"); +var uwcss = document.getElementsByClassName("uw_css"); +while(uwcss && uwcss.length > 0) + uwcss[0].parentNode.removeChild(uwcss[0]); + +// funkcija pomagač za ustvarjanje css linkov +// helper function for creating css links +function addLink(css_url){ + var link = document.createElement("link"); + link.className = "uw_css"; + link.setAttribute("rel","stylesheet"); + link.setAttribute("type","text/css"); + link.setAttribute("href", resourceToUrl(css_url)); + $("head").append(link); +} + +// Vsaka stran dobi uw_common.css +// We add uw_common.css on every page + +addLink("res/css/uw_common.css"); + +// Če smo na Youtube/youtube popupu, dodamo css za youtube elemente +// If we're on youtube/youtube popup, we add css for youtube elements +if(page_url.indexOf("youtu") != -1){ + addLink("res/css/uw_yt.css"); +} +if(page_url.indexOf("netflix.com") != -1){ + addLink("res/css/uw_netflix.css"); +} + +//END ADDING CSS @@ -546,8 +514,6 @@ var last_location = ""; var KEYBINDS = {}; - - //END keybind-related stuff //BEGIN comms with uw-bg @@ -645,17 +611,7 @@ function periodic() { if(debugmsg_periodic) console.log("uw::periodic | we found controls!"); -// var ind = controls.className.indexOf("display-none"); -// if(debugmsg_periodic) -// console.log("uw::periodic | ind:",ind,"last ind:",netflix_cltbar_visibility); - // controls must be visible. We must have not called updateCtlButtonSize before. -// if( ind != netflix_cltbar_visibility ){ -// if(debugmsg) -// console.log("uw::periodic | toggled visibility"); -// netflix_cltbar_visibility = ind; -// if(ind == -1) -// updateUICSS(); -// } + } if( autoar_enabled ){ @@ -856,17 +812,6 @@ function uinit(){ console.log("uw::uinit | initializing elements from the webpage"); } -function getopt(prop, callback){ - if(usebrowser == "chrome") - browser.storage.local.get(prop, callback); - else - browser.storage.local.get(prop).then(function(prop){ - if(debugmsg) - console.log("uw::getopt [ff] | we received this from storage:", prop); - callback(prop[0]) - }); -} - function loadFromStorage(){ if(debugmsg || debugmsg_autoar) console.log("uw::loadFromStorage | loading stuff from storage."); @@ -1068,18 +1013,13 @@ function extsetup_uiban(opt){ if(debugmsg) console.log("%cuw::extsetup_uiban | setting uiban","color: #88f;"); -// if(usebrowser == "chrome") - var obj = opt; -// else -// var obj = opt[0]; - - if(! opt || obj.ultrawidify_uiban === undefined){ + if(! opt || opt.ultrawidify_uiban === undefined){ if(debugmsg) console.log("uw::extsetup_uiban | ui ban missing from storage. Setting defaults."); browser.storage.local.set({ultrawidify_uiban: UW_UI_BANLIST}); } else - UW_UI_BANLIST = obj.ultrawidify_uiban; + UW_UI_BANLIST = opt.ultrawidify_uiban; } @@ -1426,396 +1366,6 @@ function alignToBottom(){ return align_to == "bottom"; } -//BEGIN legacy - -// function addCtlButtons(recursion_depth){ -// return; -// if(debugmsg) -// console.log("uw::addCtlButtons | function started"); -// -// // Gumb za nastavitve je bolj kot ne vselej prisoten, zato širino tega gumba uporabimo kot širino naših gumbov -// // Settings button is more or less always there, so we use its width as width of our buttons -// try{ -// // Na različnih straneh širino gumba poberemo na različne načine. -// if(button_size_base == "y") -// var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollHeight; -// else -// var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollWidth; -// -// if(debugmsg) -// console.log("uw::addCtlButtons | width of the element is ", button_width , "and is based on the height of this element:", document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX], " ") -// } -// catch(e){ -// // Zato, ker predvajalnik ni vselej prisoten. Če predvajalnik ni prisoten, -// // potem tudi knofov ni. Kar pomeni problem. -// // -// // Because the player isn't always there, and when the player isn't there the buttons aren't, either. -// // In that case, the above statement craps out, throws an exception and trashes the extension. -// -// if(recursion_depth === undefined) -// recursion_depth = 0; -// -// if(debugmsg) -// console.log("uw::addCtlButtons | seems there was a fuckup and no buttons were found on this page. No player (and therefore no buttons) found. Recursion depth:",recursion_depth); -// -// // If buttons weren't found, we relaunch init() just in case -// init(); -// return recursion_depth < playercheck_recursion_depth_limit ? addCtlButtons(++recursion_depth) : false; -// -// return false; -// } -// var button_def = []; -// if(page_url.indexOf("netflix.com") != -1) -// button_def = [ "fitw", "fith", "reset", "zoom", "uzoom"/*, "settings" */]; // No settings button on netflix until further notice -// else -// button_def = [ "fitw", "fith", "reset", "zoom", "uzoom", "settings" ]; -// -// if(debugmsg) -// console.log("uw::addCtlButtons | trying to add buttons"); -// -// /* Če je ta dodatek že nameščen, potem odstranimo vse elemente. Vsi top-level elementi imajo definiran prazen razred -// // uw_element, prek katerega jih naberemo na kup. Ta del kode je tu bolj ali manj zaradi debugiranja. -// // -// // If this addon is already installed, we have to remove all prevously added elements (to avoid duplicating). -// // The easiest way to gather all of them is to tack an empty class, 'uw_element,' to each top-level element we add. -// // This is here mostly because debugging, but could also be useful in case of unforseen happenings. -// */ -// var previousElements = document.getElementsByClassName("uw_element"); -// -// /* Uporabimo while loop in vselej odstranimo prvi element. Tabela previousElements se z odstranjevanjem elementov -// // krajša. -// // -// // Da, to je bil bug. -// // -// // -------------------------------- -// // -// // As previousElements.length decreases as we remove elements, we use a while loop and remove the first element -// // for as long as the array contains elements. -// // -// // Yes, that used to be a bug. -// */ -// if(!debugmsg && !debugmsg_click){ -// /* Če je debugmsg false, potem verjetno ne dodajamo nobenih novih funkcionalnosti, zaradi katerih bi bilo potrebno -// // ponovno naložiti vmesnik. Zato tega ne storimo, temveč ohranimo stare gumbe. Ker so ok. -// // -// // If debugging is false, then we aren't adding any new features that would require us to reload UI. So we leave -// // the old UI in place, because it should be good enough. -// */ -// -// if(previousElements && previousElements.length > 0){ -// return; -// } -// } -// -// while (previousElements && previousElements.length > 0){ -// previousElements[0].parentNode.removeChild(previousElements[0]); -// } -// -// var check_width = false; -// -// // If we're on youtube: -// if(page_url.indexOf("youtu") != -1){ -// check_width = true; -// -// var rctl; -// var rctl_width; -// var lctl_width; -// var ctlbar_width; -// -// if(inIframe()) -// player = document.getElementById("player"); -// else -// player = document.getElementById("movie_player"); -// -// rctl = document.getElementsByClassName("ytp-right-controls")[0]; -// rctl_width = rctl.offsetWidth; -// lctl_width = document.getElementsByClassName("ytp-left-controls")[0].offsetWidth; -// ctlbar_width = document.getElementsByClassName("ytp-chrome-controls")[0].offsetWidth; -// -// } -// -// // Ker na različne strani knofe dodajamo na različne načine, določanje lastnosti in dodajanje gumbov na -// // vmesnik izvedemo posebej -// // Because different pages require adding buttons to the UI in a different order, we handle defining button -// // properties and adding buttons to the UI in different loops. -// -// var btns = button_def.length; -// var settings_menu_mid = document.createElement("div"); -// -// for(var i = 0; i < btns; i++){ -// buttons[i] = document.createElement('div'); -// buttons[i].style.backgroundImage = 'url(' + resourceToUrl("/res/img/ytplayer-icons/" + button_def[i] + ".png") + ')'; -// buttons[i].style.width = (button_width * 0.75) + "px"; -// buttons[i].style.height = (button_width) + "px"; -// buttons[i].style.width = 0; -// // buttons[i].style.marginLeft = (button_width * 0.3) + "px"; -// buttons[i].style.paddingLeft = (button_width *0.15 ) + "px"; -// buttons[i].style.paddingRight = (button_width * 0.15) + "px"; -// buttons[i].className += " uw-button uw_element"; -// } -// -// // Tukaj dodamo gumbe na stran -// // Here we add the buttons -// -// if(page_url.indexOf("netflix.com") != -1){ -// for( var i = 0; i < btns; i++){ -// ui_anchor.appendChild(buttons[i]); -// } -// } -// else{ -// for( var i = (btns - 1); i >= 0; i--){ -// $(rctl).prepend(buttons[i]); -// } -// } -// -// // Če na ctlbar ni prostora za vse knofe, potem skrijemo vse knofe razen tistega, ki ima popup z vsemi možnostmi -// // -// // If ctlbar doesn't have the space for all the buttons, we hide all except the one that contains the popup -// // with all the options -// -// if(check_width && (rctl_width + lctl_width) * 1.1 > ctlbar_width){ //TODO: don't hardcode that 4 -// for( var i = 4; i >= 0; i--){ -// buttons[i].classList.add("uw_hide"); -// } -// } -// -// buttons[0].onclick = function() { changeCSS("fit", "fitw") }; -// buttons[1].onclick = function() { changeCSS("fit", "fith") }; -// buttons[2].onclick = function() { changeCSS("reset", "reset") }; -// buttons[3].onclick = function() { changeCSS("fit", "zoom") }; -// buttons[4].onclick = function() { changeCSS("fit", "unzoom") }; -// -// // Knof za nastavitve ima še vgnezden meni, ki ga dodamo tu (privzeto je ta meni skrit) -// // Settings button contains a menu that's nested in the element. By default, that menu is -// // hidden. -// if(btns > 5){ -// buttons[5].onclick = function() { -// if(debugmsg || debugmsg_click) -// console.log("uw::kbm | we clicked the button 5 with id ‘uw-smenu’. Button:",document.getElementById("uw-smenu")); -// toggleMenu("uw-smenu"); -// }; -// buttons[5].id = "uw-settings-button"; -// } -// var settings_menu = document.createElement("div"); -// // settings_menu_mid.appendChild(settings_menu); -// var smenu_ar_menu = document.createElement("div"); -// -// var smenu_el = []; -// for(var i = 0; i < 7; i++){ -// smenu_el[i] = document.createElement("div"); -// } -// -// var smenu_ar_options = []; -// -// if(buttons[5]) -// buttons[5].appendChild(settings_menu); -// -// //Če rabimo skriti gumb za nastavitve, potem mora biti i=1 -// //If we need to hide settings button, then we should make i=1 -// -// //FIXME: knof za nastavitve ne radi (nastavitve se ne odprejo) -// //FIXME: 'settings' button on the player doesn't work -// -// for(var i = 1; i < smenu_el.length; i++){ -// settings_menu.appendChild(smenu_el[i]); -// smenu_el[i].className += "uw-setmenu-item uw_setmenu_main uw_element"; -// } -// -// -// for(var i = 0; i < 4; i++){ -// smenu_ar_options[i] = document.createElement("div"); -// smenu_ar_options[i].className = "uw-setmenu-item uw_setmenu_ar uw_element"; -// smenu_ar_menu.appendChild(smenu_ar_options[i]); -// } -// -// settings_menu.id = "uw-smenu"; -// // settings_menu_mid.className = "uw-setmenu uw_element"; -// settings_menu.className = "uw-setmenu uw_element"; -// // settings_menu.className = "uw_element"; -// -// -// smenu_el[0].id = "uw-smenu_settings"; -// smenu_el[6].id = "uw-smenu_ar"; -// -// -// smenu_ar_menu.id = "uw-armenu"; -// smenu_ar_menu.className = "uw-setmenu uw_element"; -// -// // Stvari, ki se spreminjajo, se določijo tukaj -// // -// // Things that can change are defined here. -// -// var smenu_item_width = (button_width * 7.5); -// var smenu_item_fontSize = (button_width * 0.5); -// var smenu_ar_item_width = (smenu_item_width / 3); -// var smenu_item_height = button_width; -// -// // Popup meni je lahko visok največ 75% višine predvajalnika -// // Popup menu can be at most 75% of the video player tall -// var smenu_max_h = player.clientHeight * 0.75; -// -// // Če je popup večji, kot 80% predvajalnika, potem ga pomanjšamo. Višina elementa na popupu je približno enaka -// // višini knofa. Gumbi so načeloma kvadratni, zato je višina enaka širini. -// // If the popup menu is taller than 80% of the player, we resize it. height of an element in the popup is roughly -// // equal to the height of a button. Buttons are generally squares, so width is equal to heigth. (And if it's not, -// // that's still close enough for us!) -// -// var smenu_default_h = button_width * smenu_el.length; -// -// -// if(smenu_max_h < smenu_default_h){ -// var scale_factor = smenu_max_h / smenu_default_h; -// -// smenu_item_width *= scale_factor; -// smenu_item_fontSize *= scale_factor; -// smenu_item_height = button_width * scale_factor; -// smenu_ar_item_width *= scale_factor; -// -// } -// -// settings_menu.style.bottom = (button_width * 1.5) + "px"; -// settings_menu.style.width = smenu_item_width + "px"; -// settings_menu.style.fontSize = smenu_item_fontSize + "px"; -// -// smenu_ar_menu.style.right = smenu_item_width + "px"; -// smenu_ar_menu.style.width = smenu_ar_item_width + "px"; -// smenu_ar_menu.style.bottom = "0px"; -// -// for(var i = 0; i < smenu_el.length; i++){ -// smenu_el[i].style.width = smenu_item_width + "px"; -// smenu_el[i].style.height = smenu_item_height + "px"; -// smenu_el[i].style.fontSize = smenu_item_fontSize + "px"; -// } -// for(var i = 0; i < smenu_ar_options.length; i++){ -// smenu_ar_options[i].height = smenu_item_height + "px"; -// smenu_ar_options[i].width = smenu_ar_item_width + "px"; -// } -// -// -// // Tukaj se določa notranji HTML knofov -// // Inner HTML of elements is defined here -// smenu_el[6].textContent = "Force aspect ratio"; -// smenu_el[6].appendChild(smenu_ar_menu); -// -// smenu_el[0].textContent = "Settings"; -// -// smenu_ar_options[0].textContent = "4:3"; -// smenu_ar_options[1].textContent = "16:10"; -// smenu_ar_options[2].textContent = "16:9"; -// smenu_ar_options[3].textContent = "21:9"; -// -// smenu_el[5].textContent = "Fit width"; -// smenu_el[4].textContent = "Fit height"; -// smenu_el[3].textContent = "Reset"; -// smenu_el[1].textContent = "Zoom in"; -// smenu_el[2].textContent = "Zoom out"; -// -// // Pritisneš gumb, nekej zakon se more narest. -// // — Bioware -// // ( https://www.youtube.com/watch?v=hMcVZQI6ybw | [NVZD] ) -// // -// // Press the button, something awesome has to happen. -// // — Bioware -// // ( https://www.youtube.com/watch?v=hMcVZQI6ybw | [NSFW] ) -// if(smenu_el[6]){ -// $(smenu_el[6]).on("mouseenter", function(){showMenu("uw-armenu")}); -// $(smenu_el[6]).on("mouseleave", function(){hideMenu("uw-armenu")}); -// smenu_el[6].onclick = function(event){event.stopPropagation(); showMenu("uw-armenu")}; -// } -// // event.stopPropagation, ker nočemo togglati še funkcij od knofa za popup z nastavitvami -// // event.stopPropagation, because we don't want to trigger onclick functions of the settings popup button in -// // the player bar -// -// smenu_ar_options[0].onclick = function(event) {event.stopPropagation(); changeCSS("char", ( 4/3 )); }; -// smenu_ar_options[1].onclick = function(event) {event.stopPropagation(); changeCSS("char", (16/10)); }; -// smenu_ar_options[2].onclick = function(event) {event.stopPropagation(); changeCSS("char", (16/9 )); }; -// smenu_ar_options[3].onclick = function(event) {event.stopPropagation(); changeCSS("char", (21/9 )); }; -// -// -// // smenu_el[0].onclick = function (event) {event.stopPropagation(); showSettings() }; -// -// smenu_el[5].onclick = function (event) {event.stopPropagation(); changeCSS("fit" ,"fitw" ) }; -// smenu_el[4].onclick = function (event) {event.stopPropagation(); changeCSS("fit" ,"fith" ) }; -// smenu_el[3].onclick = function (event) {event.stopPropagation(); changeCSS("reset","reset" ) }; -// smenu_el[1].onclick = function (event) {event.stopPropagation(); changeCSS("fit" ,"zoom" ) }; -// smenu_el[2].onclick = function (event) {event.stopPropagation(); changeCSS("fit" ,"unzoom") }; -// -// -// -// -// -// if(debugmsg) -// console.log("uw::addCtlButtons | buttons added"); -// -// return true; -// } - -// function updateCtlButtonSize(){ -// // Gumb za nastavitve je bolj kot ne vselej prisoten, zato širino tega gumba uporabimo kot širino naših gumbov -// // Settings button is more or less always there, so we use its width as width of our buttons -// try{ -// // Na različnih straneh širino gumba poberemo na različne načine. -// if(button_size_base == "y") -// var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollHeight; -// else -// var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollWidth; -// } -// catch(e){ -// // Zato, ker predvajalnik ni vselej prisoten. Če predvajalnik ni prisoten, -// // potem tudi knofov ni. Kar pomeni problem. -// // -// // Because the player isn't always there, and when the player isn't there the buttons aren't, either. -// // In that case, the above statement craps out, throws an exception and trashes the extension. -// if(debugmsg) -// console.log("uw::updateCtlButtonSize | seems there was a fuckup and no buttons were found on this page. No player (and therefore no buttons) found."); -// return; -// } -// var buttons = document.getElementsByClassName("uw-button"); -// -// for(var i = 0; i < buttons.length; i++){ -// buttons[i].style.width = (button_width * 0.75) + "px"; -// buttons[i].style.height = (button_width) + "px"; -// buttons[i].style.paddingLeft = (button_width *0.15 ) + "px"; -// buttons[i].style.paddingRight = (button_width * 0.15) + "px"; -// } -// -// var smenu_item_width = (button_width * 7.5); -// var smenu_item_fontSize = (button_width * 0.5); -// var smenu_ar_item_width = (smenu_item_width / 3); -// var smenu_item_height = button_width; -// -// if(debugmsg || debugmsg_click) -// console.log("uw::updateCtlButtonSize | changing css of menu items"); -// -// var settings_menu = document.getElementById("uw-smenu"); -// if(settings_menu != null){ -// settings_menu.style.bottom = (button_width * 1.5) + "px"; -// settings_menu.style.width = smenu_item_width + "px"; -// settings_menu.style.fontSize = smenu_item_fontSize + "px"; -// } -// // smenu_ar_menu.style.right = smenu_item_width + "px"; -// // smenu_ar_menu.style.width = smenu_ar_item_width + "px"; -// // smenu_ar_menu.style.bottom = "0px"; -// // smenu_ar_men -// -// document.getElementById("uw-smenu_ar").right = smenu_item_width; -// -// buttons = document.getElementsByClassName("uw_setmenu_main"); -// for(var i = 0; i < buttons.length; i++){ -// buttons[i].style.width = smenu_item_width + "px"; -// buttons[i].style.height = smenu_item_height + "px"; -// buttons[i].style.fontSize = smenu_item_fontSize + "px"; -// } -// buttons = document.getElementsByClassName("uw_setmenu_ar"); -// for(var i = 0; i < buttons.length; i++){ -// buttons[i].style.width = smenu_ar_item_width + "px"; -// buttons[i].style.height = smenu_item_height + "px"; -// buttons[i].style.fontSize = smenu_item_fontSize + "px"; -// buttons[i].style.right = smenu_item_width + "px"; -// } -// } - -//END legacy //END UI //END EXTENSION SETUP diff --git a/manifest.json b/manifest.json index 5981427..46486e7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, - "name": "Ultrawidify", - "version": "1.2.1.1", + "name": "Ultrawidify-git", + "version": "1.3a1", "icons": { "32":"res/icons/uw-32.png", diff --git a/src/conf/keybinds.js b/src/conf/keybinds.js new file mode 100644 index 0000000..c7e23d6 --- /dev/null +++ b/src/conf/keybinds.js @@ -0,0 +1,57 @@ +// Yeah hi /r/badcode. +// Anyway, because nazi localstorage flat out refuses to store arrays: +var DEFAULT_KEYBINDINGS = { + 0:{ action: "fitw", + key: 'w', + modifiers: [] + }, + 1:{ + action: "fith", + key: 'e', + modifiers: [] + }, + 2: { + action: "reset", + key: 'r', + modifiers: [] + }, + 3: { + action: "zoom", + key: "z", + modifiers: [] + }, + 4: { + action: "unzoom", + key: "u", + modifiers: [] + }, + 5: { + action: "char", + targetAR: (21/9), + key: "d", + modifiers: [] + }, + 6: { + action: "char", + targetAR: (16/9), + key: "s", + modifiers: [] + }, + 7: { + action: "char", + targetAR: (16/10), + key: "x", + modifiers: [] + }, + 8: { + action: "char", + targetAR: (4/3), + key: "c", + modifiers: [] + }, + 9: { + action: "autoar", + key: "a", + modifiers: [] + } +}; diff --git a/src/conf/sitesconf.js b/src/conf/sitesconf.js new file mode 100644 index 0000000..cebf113 --- /dev/null +++ b/src/conf/sitesconf.js @@ -0,0 +1,73 @@ +var UW_SITES = { + youtube: { + enabled: true, + type: "official", + urlRules: ["youtu"], + player: { + name: "movie_player", + isClass: false, + }, + iframe: { + name: "player", + isClass: false + }, + sampleButton: { + class: "ytp-button ytp-settings-button", + index: 0, + buttonSizeBase: "x", + }, + uiParent: { + name: "ytp-right-controls", + isClass: true, + insertStrat: "prepend", + }, + autoar_imdb:{ + enabled: false + } + }, + netflix: { + enabled: true, + type: "official", + urlRules: ["netflix"], + player: { + name: "placeholder", + isClass: true, + }, + sampleButton: { + class: "ytp-button ytp-settings-button", + index: 0, + buttonSizeBase: "x", + }, + uiParent: { + name: "player-controls-wrapper", + isClass: true, + insertStrat: "append" + }, + autoar_imdb:{ + enabled: true, + title: "player-status-main-title", + isClass: true + } + }, + dummy: { + type: "add new site", + urlRules: [""], + player: { + name: "", + isClass: false, + }, + sampleButton: { + class: "ytp-button ytp-settings-button", + index: 0, + buttonSizeBase: "x", + }, + uiParent: { + name: "", + isClass: false, + insertStrat: "prepend", + }, + autoar_imdb:{ + enabled: false + } + } +} diff --git a/src/conf/uiconf.js b/src/conf/uiconf.js new file mode 100644 index 0000000..6d8377a --- /dev/null +++ b/src/conf/uiconf.js @@ -0,0 +1,116 @@ + var UW_UI_BUTTONS = { + fitw: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/fitw.png", + text: "Fit to width", + onclick: function(){ changeCSS("fit", "fitw") } + }, + fith: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/fith.png", + text: "Fit to height", + onclick: function(){ changeCSS("fit", "fith") } + }, + reset: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/reset.png", + text: "Reset", + onclick: function(){ changeCSS("reset", "reset") } + }, + zoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/zoom.png", + text: "Zoom", + onclick: function(){ changeCSS("fit", "zoom") } + }, + unzoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/unzoom.png", + text: "Unzoom", + onclick: function(){ changeCSS("fit", "unzoom") } + }, + zoom: { + native_bar: true, + has_submenu: false, + button: true, + icon: "/res/img/ytplayer-icons/zoom.png", + text: "Reset", + onclick: function(){ changeCSS("fit", "zoom") } + }, + autoar: { + native_bar: false, + has_submenu: false, + button: false, + text: "Detect aspect ratio via 3rd party", + onclick: function(){ manual_autoar()} + }, + settings: { + native_bar: true, + button: true, + icon: "/res/img/ytplayer-icons/settings.png", + text: "Settings", + has_submenu: true, + submenu: [ "fitw","fith","reset","zoom","unzoom","autoar","ar" ], + top_level: true, + submenu_id: "uw_settings_menu", + onclick: function(){ toggleMenu("uw_settings_menu") } + }, + ar: { + native_bar: false, + button: false, + text: "Force aspect ratio", + has_submenu: true, + submenu: [ "ar219", "ar169", "ar1610", "ar43" ], + submenu_id: "uw_force_ar_menu", + onclick: function(){ showMenu("uw_force_ar_menu") } + }, + ar219: { + native_bar: false, + button: false, + text: "21:9", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 21/9 )); } + }, + ar169: { + native_bar: false, + button: false, + text: "16:9", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 16/9 )); } + }, + ar1610: { + native_bar: false, + button: false, + text: "16:10", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 1.6 )); } + }, + ar43: { + native_bar: false, + button: false, + text: "4:3", + has_submenu: false, + onclick: function(){ changeCSS("char", ( 4/3 )); } + } + } + + var UW_UI_BANLIST = { + youtube: { + autoar: "all" + }, + netflix: { + settings: "all" + } + } + + diff --git a/src/lib/browser_autodetect.js b/src/lib/browser_autodetect.js new file mode 100644 index 0000000..cba74c9 --- /dev/null +++ b/src/lib/browser_autodetect.js @@ -0,0 +1,11 @@ +usebrowser = "firefox"; + +if(typeof browser === "undefined"){ // This means we're probably not on Firefox. + if(chrome){ + browser = chrome; + usebrowser = "chrome"; + } +} +else{ + usebrowser = "firefox"; +} diff --git a/src/lib/libopts.js b/src/lib/libopts.js new file mode 100644 index 0000000..8622a20 --- /dev/null +++ b/src/lib/libopts.js @@ -0,0 +1,12 @@ +// setopt in getopt. Shranita oz. dobita stvari iz skladišča +// setopt, getopt. They set/get stuff from the storage + +function setopt(item){ + browser.storage.local.set(item); +} +function getopt(prop, callback){ + if(usebrowser == "chrome") + browser.storage.local.get(prop, callback); + else + browser.storage.local.get(prop).then(callback); +} diff --git a/src/lib/optinit.js b/src/lib/optinit.js new file mode 100644 index 0000000..d8a5224 --- /dev/null +++ b/src/lib/optinit.js @@ -0,0 +1,12 @@ +IGNORE_STORAGE_CHANGES = true; + +// getopt( "ultrawidify_uiban", function (opt) { +// if(! opt || opt.ultrawidify_uiban === undefined){ +// if(debugmsg) +// console.log("uw::extsetup_uiban | ui ban missing from storage. Setting defaults."); +// browser.storage.local.set({ultrawidify_uiban: UW_UI_BANLIST}); +// } +// } + + +IGNORE_STORAGE_CHANGES = false; diff --git a/src/uw.js b/src/uw.js new file mode 100644 index 0000000..fa80530 --- /dev/null +++ b/src/uw.js @@ -0,0 +1,1692 @@ +#location js +#include conf/uiconf.js +#include conf/sitesconf.js +#include conf/keybinds.js +#include lib/libopts.js +#include lib/browser_autodetect.js +#include lib/optinit.js + +var usebrowser = "chrome"; +var browser_autodetect = true; + +var debugmsg = true; +var debugmsg_click = false; +var debugmsg_message = false; +var debugmsg_autoar = false; +var debugmsg_periodic = false; +var debugmsg_ui = true; +var force_conf_reload = true; +if(debugmsg || debugmsg_click || debugmsg_message || debugmsg_autoar){ + console.log("\n\n\n\n\n\n\n\n\n\n\n\n\n\n. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); + console.log("\nLoading ultrawidify (uw)\nIf you can see this, extension at least tried to load\n\nRandom number: ",Math.floor(Math.random() * 20) + 1,"\n"); + + if(debugmsg) + console.log("Logging all"); + + if(debugmsg_click) + console.log("Logging debugmsg_click"); + + if(debugmsg_message) + console.log("Logging debugmsg_message"); + + if(debugmsg_autoar) + console.log("Logging autoar"); + + console.log(". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "); +} + + + + + + + +const playercheck_recursion_depth_limit = 3; + +var uw_autoar_default = true; // true - autoar enabled. False - autoar disabled + +var extraClassAdded = false; +var inFullScreen = false; + +var cssmod = ""; +var zoomStep = 0.05; + +var whatdo_persistence = true; +var last_whatdo = {type: "autoar", what_do:"reset"}; +var page_url = window.location.toString(); // S pomočjo page_url določimo, na kateri spletni strani smo. +var SITE; + +var ctlbar_classnames = ["ytp-chrome-controls"]; +var serviceArray = [".video-stream"]; //Youtube + +var buttons = []; + +var IGNORE_STORAGE_CHANGES = false; + +//BEGIN determining which site we're on and the associated names + +var ui_anchor; +var player; +var vid_el; +var SAMPLE_BUTTON_CLASS; // Class of a sample button +var SAMPLE_BUTTON_INDEX = 0; // index of a sample button +var button_size_base = "x"; // Determines if size of extension buttons is defined by width or height of sample button + +var char_strat = "contain"; +var char_got_ar = false; +var char_arx; +var char_ary; +var autoar_enabled; + +var video_wrap; + + +// Here we store the window size, so we know when to trigger css change. +var winsize = {w: window.innerWidth, h: window.innerHeight}; + +// Video title for third party +var title = ""; + +// provider-specific variables + +var netflix_cltbar_visibility = -1; // -1 for invisible, anything non-negative for visible +var netflix_periodic_timer; + +// Stuff for other browsers +if(usebrowser == "chrome"){ + browser = chrome; +} + + +browser.storage.local.set({ultrawidify_siterules: UW_SITES}); + +//Na reloadu vselej odstrani vmesnik od prej +//Always remove previous UI on extension reload +var previousElements = document.getElementsByClassName("uw_element"); +if(previousElements){ + while (previousElements.length > 0){ + previousElements[0].parentNode.removeChild(previousElements[0]); + } +} + + +function init(force_reload){ + + if(debugmsg) + console.log("uw::init | starting init"); + + + var el; + for (key in UW_UI_BUTTONS){ + el = UW_UI_BUTTONS[key]; + if(el.submenu_id){ + // We defined submenus. Now let's add parent info to each submenu. + for(var i = 0; i < el.submenu.length; i++){ + UW_UI_BUTTONS[el.submenu[i]].parent = key; + } + } + } + + if(debugmsg) + console.log("uw | %cpage_url: "+page_url,"color: #99F"); + + //Youtube: + if(page_url.indexOf("youtu") != -1){ + if(debugmsg) + console.log("uw::init | we're on youtube. Page url:", page_url); + + video_wrap = "video-stream"; + return true; + } + + //Netflix: + if(page_url.indexOf("netflix.com") != -1){ + if(debugmsg) + console.log("uw::init | we're on netflix. Page url:", page_url); + + player = document.getElementById("playerContainer"); + var tmp = document.getElementsByClassName("player-status")[0]; + if(!tmp) + return false; + + vid_el = document.getElementsByTagName("video")[0]; + + SAMPLE_BUTTON_CLASS = "player-control-button player-fill-screen"; + video_wrap = "player-video-wrapper"; + button_size_base = "y"; + + return true; + } + + return false; +} + + +//END + +//BEGIN ADDING CSS + +// Če ponovno naložimo dodatek, potem odstranimo star CSS. Lahko se zgodi, da je Tam spremenil CSS in hoče +// preveriti, če stvari zgledajo tako kot morajo. Če ima en razred/id več nasprotujoćih si definicij, potem +// nam to lahko povzroča težave. Za uporabnike je načeloma odstranjevanje obstoječega CSS brezpredmetno, ker +// uporabnik ponavadi ne bo reloadal razširitve. +// +// If we reload the extension, then we also remove our old CSS. It can easily happen that Tam changed CSS a bit +// and wants to see if things look roughly the way they should. We do this because if a class/id has multiple +// mutually exclusive definitions, we can get some problems with CSS not working the way it should. People who +// aren't Tam generally don't see the benefit as they won't reload the extension — let alone reload the extension +// after messing with CSS. + +var ui_anchor = document.getElementById("uw_ui_anchor"); +var uwcss = document.getElementsByClassName("uw_css"); +while(uwcss && uwcss.length > 0) + uwcss[0].parentNode.removeChild(uwcss[0]); + +// funkcija pomagač za ustvarjanje css linkov +// helper function for creating css links +function addLink(css_url){ + var link = document.createElement("link"); + link.className = "uw_css"; + link.setAttribute("rel","stylesheet"); + link.setAttribute("type","text/css"); + link.setAttribute("href", resourceToUrl(css_url)); + $("head").append(link); +} + +// Vsaka stran dobi uw_common.css +// We add uw_common.css on every page + +addLink("res/css/uw_common.css"); + +// Če smo na Youtube/youtube popupu, dodamo css za youtube elemente +// If we're on youtube/youtube popup, we add css for youtube elements +if(page_url.indexOf("youtu") != -1){ + addLink("res/css/uw_yt.css"); +} +if(page_url.indexOf("netflix.com") != -1){ + addLink("res/css/uw_netflix.css"); +} + +//END ADDING CSS + + + +var last_location = ""; + +var KEYBINDS = {}; + +//END keybind-related stuff + +//BEGIN comms with uw-bg +function extsetup_comms(){ + if(debugmsg) + console.log("uw | Setting up comms with background scripts"); + + var num_of_msg = 0; + browser.runtime.onMessage.addListener(function (message, sender, stuff ) { + if(debugmsg || debugmsg_message) + console.log("uw::onMessage | message number: ", num_of_msg++ , "; message:", message ); + + if(message.message && message.message == "page-change"){ + if(document.getElementsByClassName("uw_element").length === 0){ + if(debugmsg) + console.log("uw::onMessage | page was updated but control buttons aren't there. Trying to readd.") + + init(); + addCtlButtons(0); + } + + + // We don't do that if we zoomed or unzoomed + if(last_whatdo.what_do != "zoom" && last_whatdo.what_do != "unzoom") + changeCSS(last_whatdo.type, last_whatdo.what_do); + + // Velikost gumbov posodobimo v vsakem primeru + // We update the button size in any case + updateUICSS(); + + if(debugmsg) + console.log("uw::onMessage | message number:",num_of_msg," »» everything is done. Buttons: ", document.getElementsByClassName("uw-button")); + } + + if(message.type && message.type == "arInfo"){ + char_got_ar = true; + char_arx = message.arx; + char_ary = message.ary; + if(debugmsg || debugmsg_message || debugmsg_autoar) + console.log("uw::onMessage | got aspect ratio (",char_arx,"/",char_ary,"), launching autochar"); + autochar(); + } + + }); + + // browser.runtime.onMessage.addListener(request => { + // console.log("Message from the background script:"); + // console.log(request.greeting); + // return Promise.resolve({response: "Hi from content script"}); + // }); + + if(debugmsg) + console.log("uw | Comms with background scripts: done"); +} +//END comms with uw-bg + +//BEGIN periodic functions +//Because onUpdated event isn't reliable enough for what we're doing on netflix. +function periodic() { + + //NOTE: this entire function needs to be tested if it still works + + if(debugmsg_periodic) + console.log("uw::periodic started!"); + + if(document.getElementsByClassName("uw_element").length === 0){ + if(debugmsg) + console.log("uw::periodic | no buttons detected. Readding."); + + init(); + buildUInative(); + updateUICSS(); + } + var w = window.innerWidth; + var h = window.innerHeight; + if(winsize.w != w && winsize.h != h){ + if(debugmsg) + console.log("uw::periodic | detected change in window size. Triggering css change"); + + winsize.w = w; + winsize.h = h; + + // We don't do that if we zoomed or unzoomed + if(last_whatdo.what_do != "zoom" && last_whatdo.what_do != "unzoom"/* && last_whatdo.type != "autoar"*/){ + changeCSS(last_whatdo.type, last_whatdo.what_do); + } + + updateUICSS(); + } + if(SITE_PROPS.uiParent.isClass) + var controls = document.getElementsByClassName(SITE_PROPS.uiParent.name)[0]; + else + var controls = document.getElementById(SITE_PROPS.uiParent.name); + if(controls){ + if(debugmsg_periodic) + console.log("uw::periodic | we found controls!"); + + + } + + if( autoar_enabled ){ + + var titleElement; + + if(SITE_PROPS.autoar_imdb.isClass) + titleElement = document.querySelector("." + SITE_PROPS.autoar_imdb.title); + else + titleElement = document.querySelector("#" + SITE_PROPS.autoar_imdb.title); + var ntitle = ""; + + //querySelector lahko vrne null, zato moramo preveriti, kaj smo dobili — drugače se .textContent pritožuje. + //querySelector can return null, in which case .textContent will complain. + if(qntitle) + ntitle = titleElement.textContent; + else{ + char_got_ar = false; + return; + } + if(titleElement && ntitle && ntitle != title){ + if(debugmsg || debugmsg_message || debugmsg_autoar) + console.log("uw::periodic | title changed. New title:",ntitle,"Old title:",title); + + char_got_ar = false; + + title = ntitle; + var sending = browser.runtime.sendMessage({ + type: "gibAspectRatio", + title: title + }); +// sending.then( function(){}, function(err1, err2){console.log("uw::periodic: there was an error while sending a message", err1, err2)} ); + } + } + +} +//END periodic functions + + + +$(document).ready(function() { + if(debugmsg) + console.log("uw::document.ready | document is ready. Starting extension setup ..."); + extSetup(); +}); + +//BEGIN EXTENSION SETUP + +function extSetup(force_reload){ + if(debugmsg) + console.log("=============================================================================================="); + + last_location = window.location; + +// SITE = ""; + + if(force_reload){ + ui_anchor.parentNode.removeChild(ui_anchor); + ui_anchor = null; + } + + if(debugmsg){ + console.log("uw::extSetup | our current location is:", last_location, "(page_url says",page_url,")"); + console.log("uw::extSetup | initiating extension"); + } + var ini = init(); + + if(debugmsg){ + console.log("uw::extSetup | init exited with", ini); + console.log("uw::extSetup | removing existing keydown event from document (useful if extension was previously loaded and we navigated to a different video)"); + } + $(document).off("keydown"); + + if(debugmsg) + console.log("uw::extSetup | setting up keyboard shortcuts"); + + loadFromStorage(); + + //extsetup_stage2 gets called in loadFromStorage, on siterules +} + + +var EXTSETUP_STAGES = { + site: false, + uiban: false, + uimode: false, +} + +function stagetracker(op){ + if(op == "clear"){ + if(debugmsg) + console.log("uw::stagetracker | %cclearing progress (state)","color: #fff"); + for(key in EXTSETUP_STAGES) + EXTSETUP_STAGES[key] = false; + return; + } + EXTSETUP_STAGES[op] = true; + + var all_done = true; + var unfinished_stages = ""; + + for(key in EXTSETUP_STAGES){ + all_done &= EXTSETUP_STAGES[key]; + if(debugmsg && ! EXTSETUP_STAGES[key]){ + unfinished_stages += "<" + key + "> "; + } + } + + if(debugmsg) + console.log("uw::stagetracker | added stage",op, all_done ? " | all stages finished" : (" | missing stages: " + unfinished_stages)); + + return all_done; +} + +function extsetup_stage2(op){ + + if(debugmsg) + console.log("uw::extSetup (stage 2) | %cStarting the function. op=","color: #fff", op); + + if(! stagetracker(op) ){ + if(debugmsg) + console.log("uw::extSetup (stage 2) | %cSome stages are still uncompleted, doing nothing.","color: #fff"); + return false; + } + + extsetup_listener(); + + // SITE se nastavi v funkciji loadFromStorage. Če ni nastavljen, potem nismo na znani/podprti strani + // SITE is set in loadFromStorage. If SITE is still undefined at this point, then we aren't on a known page. + + if(debugmsg){ + console.log("uw::extSetup (stage 2) | --------- ENTERING STAGE 2 OF SETUP -----------"); + } + + if(SITE){ + uinit(); + keydownSetup(); + extsetup_comms(); + buildUInative(); + updateUICSS(); + + if(page_url.indexOf("netflix.com") != -1){ + console.log("uw::extSetup (stage 2) | starting netflix-specific setup steps"); + if(netflix_periodic_timer) + clearInterval(netflix_periodic_timer); + netflix_periodic_timer = setInterval(function(){ periodic(); }, 100); + } + } + else{ + if(debugmsg){ + console.log("uw::extSetup (stage 2) |%c SITE appears to be undefined. This means we aren't on a known/supported site. Ultrawidify shouldn't be loaded.",'background-color: #fa6607; color: #000;',"\n(note: this usually happens once after reloading this extension. If that's the case, chances are everything is fine, since this function runs twice — once with correct page_url and once with wrong one"); + debugger; + } + } + if(debugmsg) + console.log("======================================[ setup finished ]======================================\n\n\n\n\n"); +} + + +function uinit(){ + if(debugmsg) + console.log("uw::uinit | initializing elements from the webpage"); + + var site = UW_SITES[SITE]; +// var inIframe = inIframe(); + + if(debugmsg) + console.log("uw::uinit | site data:",site,"\n\n\nsite.player.name:", site.player.name,"\nsite.player.isClass:", site.player.isClass); + +// if(inIframe){ +// +// } +// else{ + SITE_ENABLED = site.enabled; + SITE_TYPE = site.type; + SITE_URL_RULES = site.urlRules; + SITE_PROPS = site; + + if(debugmsg) + console.log("uw::uinit | are we in iframe?", inIframe(), "does the site have a separate config for iframe?", site.iframe ? true : false ); + + if(inIframe() && site.iframe){ + console.log("uw::uinit | we're in iframe."); + PLAYER = site.iframe.isClass ? document.getElementsByClassName(site.iframe.name)[0] : document.getElementById(site.iframe.name); + } + else{ + PLAYER = site.player.isClass ? document.getElementsByClassName(site.player.name)[0] : document.getElementById(site.player.name); + } + + SAMPLE_BUTTON_CLASS = site.sampleButton.class; + SAMPLE_BUTTON_INDEX = site.sampleButton.index; + BUTTON_SIZE_BASE = site.sampleButton.buttonSizeBase; +// } + + IMDB_AUTOAR_ALLOWED = site.autoar_imdb.enabled; + + if(debugmsg) + console.log("uw::uinit | initializing elements from the webpage"); +} + +function loadFromStorage(){ + if(debugmsg || debugmsg_autoar) + console.log("uw::loadFromStorage | loading stuff from storage."); + + extsetup_stage2("clear"); + + getopt("ultrawidify_uiban", function(data){ + IGNORE_STORAGE_CHANGES = true; + extsetup_uiban(data); + extsetup_stage2("uiban"); + IGNORE_STORAGE_CHANGES = false; + }); + getopt("ultrawidify_siterules", function(data){ + IGNORE_STORAGE_CHANGES = true; + extsetup_siterules(data); + console.log("sss"); + extsetup_stage2("site"); + IGNORE_STORAGE_CHANGES = false; + }); + getopt("ultrawidify_ui", function(data){ + IGNORE_STORAGE_CHANGES = true; + extsetup_ui_mode(data); + console.log("sasa"); + extsetup_stage2("uimode"); + IGNORE_STORAGE_CHANGES = false; + }); + getopt("ultrawidify_autoar", function(data){ + IGNORE_STORAGE_CHANGES = true; + extsetup_autoar(data) + IGNORE_STORAGE_CHANGES = false; + }); + getopt("ultrawidify_keybinds", function(data){ + IGNORE_STORAGE_CHANGES = true; + extsetup_keybinds(data); + IGNORE_STORAGE_CHANGES = false; + }); + +} + +function keydownSetup(){ + if(debugmsg) + console.log("uw::keydownSetup | starting keybord shortcut setup"); + $(document).keydown(function (event) { // Tukaj ugotovimo, katero tipko smo pritisnili + + // Tipke upoštevamo samo, če smo v celozaslonskem načinu oz. če ne pišemo komentarja + // v nasprotnem primeru ne naredimo nič. + // We only take actions if we're in full screen or not writing a comment + if( !(inFullScreen || ( + (document.activeElement.getAttribute("role") != "textbox") && + (document.activeElement.getAttribute("type") != "text") + ))){ + if(debugmsg) + console.log("We're writing a comment or something. Doing nothing"); + return; + } + if(debugmsg || debugmsg_message){ +// console.log(KEYBINDS); + console.log("we pressed a key: ", event.key , " | keydown: ", event.keydown); + if(event.key == 'p'){ + console.log("uw/keydown: attempting to send message") + var sending = browser.runtime.sendMessage({ + type: "debug", + message: "Test message, please ignore" + }); + sending.then( function(){}, function(){console.log("uw/keydown: there was an error while sending a message")} ); + console.log("uw/keydown: test message sent! (probably)"); + return; + } + } + + for(i in KEYBINDS){ + if(debugmsg) + console.log("i: ", i, "keybinds[i]:", KEYBINDS[i]); + + if(event.key == KEYBINDS[i].key){ + if(debugmsg) + console.log("Key matches!"); + //Tipka se ujema. Preverimo še modifierje: + //Key matches. Let's check if modifiers match, too: + var mods = true; + for(var j = 0; j < KEYBINDS[i].modifiers.length; j++){ + if(KEYBINDS[i].modifiers[j] == "ctrl") + mods &= event.ctrlKey ; + else if(KEYBINDS[i].modifiers[j] == "alt") + mods &= event.altKey ; + else if(KEYBINDS[i].modifiers[j] == "shift") + mods &= event.shiftKey ; + } + if(debugmsg) + console.log("we pressed a key: ", event.key , " | mods match?", mods, "keybinding: ", KEYBINDS[i]); + if(mods){ + event.stopPropagation(); + + console.log("uw::keydown | keys match. Taking action."); + if(KEYBINDS[i].action == "char"){ + changeCSS("char", KEYBINDS[i].targetAR); + return; + } + if(KEYBINDS[i].action == "autoar"){ + manual_autoar(); + return; + } + changeCSS("anything goes", KEYBINDS[i].action); + return; + } + } + } + }); + + document.addEventListener("mozfullscreenchange", function( event ) { + onFullScreenChange(); + inFullScreen = ( window.innerHeight == window.screen.height && window.innerWidth == window.screen.width); + inFullScreen ? onFullscreenOn() : onFullscreenOff(); + }); +} + +function extsetup_siterules(opt){ + if(debugmsg) + console.log("%cuw::extsetup_siterules | setting up site rules settings","color: #88f;"); + +// if(usebrowser == "chrome") + var obj = opt; +// else +// var obj = opt[0]; + + if(!opt || obj.ultrawidify_siterules === undefined){ + if(debugmsg) + console.log("uw::extsetup_siterules | site url rules missing from storage. Setting defaults."); + browser.storage.local.set({ultrawidify_siterules: UW_SITES}); + } + else{ + UW_SITES = obj.ultrawidify_siterules; + } + + if(debugmsg) + console.log("uw::extsetup_siterules | UW_SITES:",UW_SITES,"current site:",SITE); + + var match; + for(key in UW_SITES){ + var el = UW_SITES[key]; + if(debugmsg){ + console.log("uw::extsetup_siterules | key:",key,"; el:",el, location); + } + match = false; + + for (var i = 0; i < el.urlRules.length; i++){ + if(debugmsg) + console.log("uw::extsetup_siterules | page_url:",page_url,"; el.urlRules["+i+"]:",el.urlRules[i],"; last_location.indexOf(el.urlRules["+i+"]):",page_url.indexOf(el.urlRules[i])); + match |= page_url.indexOf(el.urlRules[i]) != -1; + } + if(match){ + if(debugmsg) + console.log("uw::extsetup_siterules | we are on site", key); + + SITE = key; + return true; + } + } + if(debugmsg) + console.log("%cuw::extsetup_siterules | page_url is unknown or incorrect. Stalling extension setup","color:#fa6607","\n(NOTE: In some cases, stalling like that could be result of this extension script running twice)"); + debugging + return false; +} + +function extsetup_autoar(opt){ + if(debugmsg) + console.log("%cuw::extsetup_autoar | setting up autoar settings","color: #88f;"); + +// if(usebrowser == "chrome") + var obj = opt; +// else +// var obj = opt[0]; + + //Naslov resetiramo v vsakem primeru + //We always reset the title + title = ""; + if(obj === undefined) + return; + + + if(obj.ultrawidify_autoar === undefined){ + if(debugmsg || debugmsg_autoar) + console.log("uw::extsetup_autoar | autoar setting unavailavle in storage. Setting defaults."); + browser.storage.local.set({ultrawidify_autoar: uw_autoar_default}); + autoar_enabled = uw_autoar_default; + } + else + autoar_enabled = obj.ultrawidify_autoar; + + + if(debugmsg || debugmsg_autoar) + console.log("uw::extsetup_autoar | autoar",(autoar_enabled ? "enabled":"disabled"),"opt: ",opt); + + if(!autoar_enabled) + last_whatdo = {type: "reset", what_do:"reset"}; +} + +function extsetup_uiban(opt){ + if(debugmsg) + console.log("%cuw::extsetup_uiban | setting uiban","color: #88f;"); + + if(! opt || opt.ultrawidify_uiban === undefined){ + if(debugmsg) + console.log("uw::extsetup_uiban | ui ban missing from storage. Setting defaults."); + browser.storage.local.set({ultrawidify_uiban: UW_UI_BANLIST}); + } + else + UW_UI_BANLIST = opt.ultrawidify_uiban; + +} + +function extsetup_listener(){ + if(debugmsg) + console.log("uw::extsetup_listener | setting up listeners"); + + browser.storage.onChanged.addListener(function(){ + if(IGNORE_STORAGE_CHANGES){ + if(debugmsg) + console.log("uw:: | %c We are ignoring storage changes at the moment. Doing nothing.", "color: #fa6607") + return; + } + if(debugmsg){ + console.log("uw:: |%c calling extSetup from storage.onChanged","color:#99f"); + } + extSetup(true); + }); +} + +function extsetup_ui_mode(opt){ + if(!opt || opt.ultrawidify_ui === undefined) + UW_UI_MODE = "all"; + else + UW_UI_MODE = opt.ultrawidify_ui; + + console.log("uw::extsetup_ui_mode | ui mode:",UW_UI_MODE); +} + +function extsetup_keybinds(res){ + if(debugmsg) + console.log("%cuw::extsetup_keybinds | setting up autoar settings","color: #88f;"); + +// if(usebrowser == "chrome") + var obj = res; +// else +// var obj = res[0]; + + if(typeof uw_keybinds_storage_set === "undefined" && (jQuery.isEmptyObject(obj) || jQuery.isEmptyObject(obj.ultrawidify_keybinds)) ){ + if(debugmsg) + console.log("uw:: | No keybindings found. Loading default keybinds as keybinds"); + + browser.storage.local.set({ultrawidify_keybinds:DEFAULT_KEYBINDINGS}); + KEYBINDS = DEFAULT_KEYBINDINGS; + uw_keybinds_storage_set = true; + } + else{ + if(Object.keys(obj.ultrawidify_keybinds).length == Object.keys(DEFAULT_KEYBINDINGS).length) + KEYBINDS = obj.ultrawidify_keybinds; + else{ + KEYBINDS = obj.ultrawidify_keybinds; + + // remap 4:3 keybind from 'a' to 'c', but only if the keybind wasn't changed + var old_keybinds = Object.keys(obj.ultrawidify_keybinds); + if(KEYBINDS[old_keybinds-1].key == "a" && KEYBINDS[old_keybinds-1].modifiers == []){ + KEYBINDS[old_keybinds-1].key == "c"; + } + KEYBINDS[old_keybinds] = {action: "autoar", key: "a", modifiers: []}; + } + } + // console.log("res. ", obj.ultrawidify_keybinds); +} + + //BEGIN UI + +function check4player(recursion_depth){ + try{ + var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollWidth; + return true; + } + catch(e){ + // Zato, ker predvajalnik ni vselej prisoten. Če predvajalnik ni prisoten, + // potem tudi knofov ni. Kar pomeni problem. + // + // Because the player isn't always there, and when the player isn't there the buttons aren't, either. + // In that case, the above statement craps out, throws an exception and trashes the extension. + if(debugmsg) + console.log("uw::addCtlButtons | seems there was a fuckup and no buttons were found on this page. No player (and therefore no buttons) found."); + + if(!recursion_depth) + recursion_depth = 0; + + // If buttons weren't found, we relaunch init() just + init(); + return recursion_depth < playercheck_recursion_depth_limit ? check4player(++recursion_depth) : false; + } + return false; +} + +function mkanchor(){ + ui_anchor = document.createElement("div"); + ui_anchor.className = "uw_ui_anchor"; + ui_anchor.id = "uw_ui_anchor"; + + var site = UW_SITES[SITE]; + + if(site.uiParent.insertStrat == "prepend"){ + $(document.getElementsByClassName(site.uiParent.name)[0]).prepend(ui_anchor); + } + +} + +function buildUInative(){ + /** This function builds UI in the native bar. + * + */ + + + if(ui_anchor) + return; + + if(!ui_anchor) + mkanchor(); + + if(UW_UI_MODE == "none"){ + if(debugmsg || debugmsg_ui) + console.log("uw::buildUInative | usersettings say UI shouldn't be displayed. UI will not be built."); + return; + } + if(UW_UI_MODE == "compact"){ + if(debugmsg || debugmsg_ui) + console.log("uw::buildUInative | usersettings say UI should be compact if possible. Checking if possible."); + + if(UW_UI_BANLIST[SITE].settings !== undefined && UW_UI_BANLIST[SITE].settings != "noban"){ + if(debugmsg || debugmsg_ui) + console.log("uw::buildUInative | compact ui is not possible on this site. Reverting to full."); + UW_UI_MODE == "all"; + } + } + + if(debugmsg || debugmsg_ui ) + console.log("uw::buildUInative | starting to build UI"); + + var el; + + if(UW_UI_MODE == "compact"){ // no need for loop if all we add is the 'settings' buton + el = UW_UI_BUTTONS.settings; + uiel = mkbutton(el); + uiel.appendChild(mksubmenu(el)); + ui_anchor.appendChild(uiel); + } + else{ + for(key in UW_UI_BUTTONS){ + + el = UW_UI_BUTTONS[key]; + + if(UW_UI_BANLIST[SITE][key]){ + if(debugmsg) + console.log("uw::buildUInative | we don't show", key, "on site", SITE, ". Doing nothing."); + + continue; + } + + if(!el.native_bar) + continue; + + var uiel; //ui element + + if(el.button){ + uiel = mkbutton(el); + } + + if(!uiel) + continue; + + ui_anchor.appendChild(uiel); + + if(el.has_submenu){ + uiel.appendChild(mksubmenu(el)); + } + } + } + + if(debugmsg || debugmsg_ui ) + console.log("uw::buildUInative | ui finished"); +} + +function mksubmenu(el){ + var submenu = document.createElement("div"); + submenu.id = el.submenu_id; + submenu.className = "uw_element uw_submenu"; + + for(var i = 0; i < el.submenu.length; i++){ + if(UW_UI_BANLIST[SITE][el.submenu[i]]){ + if(debugmsg) + console.log("uw::mksubmenu | we don't show", el.submenu[i], "on site", SITE, ". Doing nothing."); + + continue; + } + submenu.appendChild(mkmenuitem(el.submenu[i])); + } + + return submenu; +} + +function mkmenuitem(key){ + var el = UW_UI_BUTTONS[key]; + var item = document.createElement("div"); + item.textContent = el.text; + item.className = "uw-setmenu-item uw_element"; + item.onclick = function(event){ event.stopPropagation(); el.onclick(); hideAllMenus(); }; + + if(el.has_submenu){ + item.appendChild(mksubmenu(el)); + + if(debugmsg){ + console.log("uw::mkmenuitem | we are:", el, "; do we have parent?",el.parent,"parent id:",UW_UI_BUTTONS[el.parent].submenu_id, UW_UI_BUTTONS[el.parent].submenu_id === "uw_settings_menu"); + } + + if(el.parent) + $(item).on("mouseenter", function(){ + // We determine where the submenu goes - to the left or to the right. showMenu handles position, + // this function gets sizes of all objects + var div = document.getElementById(UW_UI_BUTTONS[el.parent].submenu_id); + var supmenusize = div.getBoundingClientRect(); + div = document.getElementById(el.submenu_id); + var submenusize = div.getBoundingClientRect(); + var playersize = player.getBoundingClientRect(); + + if(debugmsg) + console.log("uw::mouseenter | parent menu size:",supmenusize,"submenu size:",submenusize,"player size:",playersize); + + showMenu(el.submenu_id, {parent:supmenusize, submenu:submenusize, player:playersize}); + }); + else + $(item).on("mouseenter", function(){showMenu(el.submenu_id)}); + + $(item).on("mouseleave", function(){hideMenu(el.submenu_id)}); + } + + return item; +} + + +function mkbutton(el){ + if(debugmsg | debugmsg_ui) + console.log("uw::mkbutton | trying to make a button", el.text); + + var button = document.createElement("div"); + button.style.backgroundImage = 'url(' + resourceToUrl(el.icon) + ')'; + button.className += " uw_button uw_element"; + button.onclick = function(event) {event.stopPropagation(); el.onclick() }; + + if(debugmsg | debugmsg_ui) + console.log("uw::mkbutton | button completed"); + + return button; +} + +function hideAllMenus(){ + var el; + for(key in UW_UI_BUTTONS){ + el = UW_UI_BUTTONS[key]; + if( el.submenu_id ) + hideMenu(el.submenu_id); + } +} + +function updateUICSS(){ + + //BEGIN INIT + var buttons = document.getElementsByClassName("uw_button"); + + var button_width = getBaseButtonWidth(); + + if(debugmsg) + console.log("uw::updateUICSS | resizing buttons. This are our buttons:",buttons," | a button is this wide:", button_width); + + if(button_width == -1 || buttons.length == 0){ //this means there's no ui + if(debugmsg) + console.log("uw::updateUICSS | UI wasn't detected, stopping"); + return; + } + + if(debugmsg){ + console.log("uw::updateUICSS | checks passed. Starting to resize ..."); + console.log("uw::updateUICSS | we have this many elements:",buttons.length, buttons); + } + //END INIT + //BEGIN update buttons + + for (var i = 0; i < buttons.length; i++){ + buttons[i].style.width = (button_width * 0.75) + "px"; + buttons[i].style.height = (button_width) + "px"; + buttons[i].style.marginLeft = (button_width * 0.3) + "px"; + buttons[i].style.paddingLeft = (button_width *0.15 ) + "px"; + buttons[i].style.paddingRight = (button_width * 0.15) + "px"; + } + + + //END update buttons + //BEGIN update menus + + var el; + var div; + for(key in UW_UI_BUTTONS){ + el = UW_UI_BUTTONS[key]; + if( el.submenu_id ){ + div = document.getElementById(el.submenu_id); + if( el.top_level) { + if( alignToBottom() ){ + div.style.bottom = button_width * 1.2 + "px"; + } + + + } + else{ + if( alignToBottom() ) { + div.style.bottom = "0px"; + } + + // this is tricky. We need to find the best place to put the (sub)menu. + } + } + } + + //END menus +} + +function getBaseButtonWidth(){ + try{ + // Na različnih straneh širino gumba poberemo na različne načine. + if(BUTTON_SIZE_BASE == "y") + return document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollHeight; + else + return document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollWidth; + } + catch(e){ + // Zato, ker predvajalnik ni vselej prisoten. Če predvajalnik ni prisoten, + // potem tudi knofov ni. Kar pomeni problem. + // + // Because the player isn't always there, and when the player isn't there the buttons aren't, either. + // In that case, the above statement craps out, throws an exception and trashes the extension. + if(debugmsg) + console.log("uw::getBaseButtonWidth | seems there was a fuckup and no buttons were found on this page. No player (and therefore no buttons) found."); + return -1; + } +} + + + +var align_to = "bottom"; //TODO — unhardcode +function alignToBottom(){ + return align_to == "bottom"; +} + + +//END UI +//END EXTENSION SETUP + +function onOpen(){ + if(debugmsg) + console.log("uw | Options page opened"); +} + +function onError(err){ + if(debugmsg){ + console.log(`Error: ${error}`); + console.log("uw | Error opening the page", err); + } +} + +function showSettings(){ + +} + +// Ta funkcija se proži, ko vstopimo ali izstopimo iz celozaslonskega načina +// This function gets triggered by full screen state change +function onFullScreenChange(){ + // Popravimo velikost gumbov + // Let's fix the button size: + var button_width = document.getElementsByClassName(SAMPLE_BUTTON_CLASS)[SAMPLE_BUTTON_INDEX].scrollWidth; + for( var i = 5; i >= 0; i--){ + buttons[i].style.width = (button_width * 0.75) + "px"; + buttons[i].style.paddingLeft = (button_width *0.15 ) + "px"; + buttons[i].style.paddingRight = (button_width * 0.15) + "px"; + } + + document.getElementById("uw-smenu").style.bottom = (button_width * 1.5) + "px"; + + //Sedaj poglejmo še, če lahko v nadzorno vrstico spravimo vse gumbe + //Let's see if we can get all the buttons in the control bar +// var rctl = document.getElementsByClassName("ytp-right-controls")[0]; + +} + + +// Ta funkcija se proži, ko gremo v celozaslonski način +// This function triggers when we enter fullscreen mode +function onFullscreenOn(){ + +} + +// Ta funkcija se proži, ko gremo ven iz celozaslonskega načina +// This function triggers when we leave fullscreen mode +function onFullscreenOff(){ + +} + +function manual_autoar(){ + if(! SITE_PROPS.autoar_imdb.enabled) + return; + + if(SITE_PROPS.autoar_imdb.isClass) + var ntitle = document.querySelector("."+ SITE_PROPS.autoar_imdb.title); // NOTE: needs to be tested + else + var ntitle = document.querySelector("#"+ SITE_PROPS.autoar_imdb.title); // NOTE: needs to be tested + + //querySelector lahko vrne null, zato moramo preveriti, kaj smo dobili — drugače se .textContent pritožuje. + //querySelector can return null, in which case .textContent will complain. + if(!ntitle) + return; + + var title = ntitle.textContent; + + char_got_ar = false; + last_whatdo = {type: "autoar", what_do:"autoar"}; + + var sending = browser.runtime.sendMessage({ + type: "gibAspectRatio", + title: title + }); +// sending.then( function(){}, function(err1, err2){console.log("uw::periodic: there was an error while sending a message", err1, err2)} ); + +} + +function changeCSS(type, what_do){ + if(debugmsg) + console.log("uw::changeCSS | starting function. type:", type, "; what_do:",what_do,"\nPlayer element is this:",PLAYER); +// hideMenu("uw-armenu"); +// hideMenu("uw-smenu"); + + + var evideo = $("video")[0]; + + if(!evideo){ + if(debugmsg) + console.log("uw::changeCSS | no video element found. Doing nothing."); + + return; + } + + var video = { width: evideo.videoWidth, height: evideo.videoHeight }; + + var nplayer = { width: PLAYER.clientWidth, height: PLAYER.clientHeight }; + + if(debugmsg) + console.log("uw::changeCSS | video dimensions:",video.width,"x",video.height,"; player:",nplayer.width,"x",nplayer.height); + + // Youtube predvajalnik privzeto resetira CSS ob prehodu v/iz fullscreen. Tukaj shranimo zadnje dejanje, + // da ga lahko onFullscreenOff/onFullscreenOn uveljavita. + // + // Youtube player resets CSS on fullscreen state change. Here we save the last action taken, so + // onFullscreenOff/onFullscreenOn are able to preserve it (if we want). + last_whatdo = {type:type, what_do:what_do}; + + // ----------------------------------------------------------------------------------------- + // Handlanje dejanj se zgodi pod to črto + // + // Handling actions happens below this line + // ----------------------------------------------------------------------------------------- + + if (type == "autoar"){ + autochar(); + return; + } + + if (type == "char"){ + + if(debugmsg) + console.log("uw::changeCSS | trying to change aspect ratio."); + + // char = CHange Aspect Ratio + char(what_do, video, nplayer); + return; + } + + if (what_do == "reset"){ + + if(debugmsg) + console.log("uw::changeCSS | issuing reset."); + + resetCSS(video, nplayer); + return; + } + + // Velikost videa spreminjamo samo, če smo v celozaslonskem načinu ALI če NE pišemo komentarja + // Videa ne spreminjamo tudi, če uporabljamo vrstico za iskanje. + // + // We only change video size when we're in full screen OR if we are NOT writing a comment. + // We also leave video alone if we're using the search bar + + if(inFullScreen || ( + (document.activeElement.getAttribute("role") != "textbox") && + (document.activeElement.getAttribute("type") != "text") + )){ + if(debugmsg) + console.log("uw::changeCSS | trying to fit width or height"); + + changeCSS_nofs(what_do, video, nplayer); + } + + +} + + +function char(new_ar, video, player){ + + // Kot vhodni argument dobimo razmerje stranic. Problem je, ker pri nekaterih ločljivostih lahko razmerje stranic + // videa/našega zaslona minimalno odstopa od idealnega razmerja — npr 2560x1080 ni natanko 21:9, 1920x1080 ni + // natanko 16:9. Zato ob podanem razmerju stranic izračunamo dejansko razmerje stranic. + // + // The aspect ratio we get as an argument is an ideal aspect ratio. Some (most) resolutions' aspect ratios differ + // from that ideal aspect ratio (by a minimal amount) — e.g. 2560x1080 isn't exactly 21:9, 1920x1080 isn't exactly + // 16:9. What is more, both 3440x1440 and 2560x1080 are considered "21:9", but their aspect ratios are slightly + // different. This has the potential to result in annoying black bars, so we correct the aspect ratio we're given + // to something that's slightly more correct. + + var ar; + var res_219 = [ [2560,1080], [3440,1440] ]; + var res_169 = [ [1920,1080], [1280,720], [1366,768] ]; + + if(new_ar == (21/9)){ + for (var i = 0; i < res_219.length; i++){ + if( player.height == res_219[i][1]){ + ar = res_219[i][0]/res_219[i][1]; + set_video_ar( ar, video, player); + return; + } + } + } + else if(new_ar == (16/9)){ + for (var i = 0; i < res_169.length; i++){ + if( player.height == res_169[i][1]){ + ar = res_169[i][0]/res_169[i][1]; + set_video_ar( ar, video, player); + return; + } + } + } + + set_video_ar(new_ar, video, player); +} + +function autochar(){ + + if(debugmsg || debugmsg_autoar) + console.log("uw::autochar | starting. Did we get ar?",char_got_ar,"What about arx and ary?",char_arx,char_ary); + + if(!char_got_ar) + return; + + if(!char_arx || !char_ary) + return; + + var ar = char_arx / char_ary; + if(ar){ + set_best_fit(ar); + last_whatdo = {type: "autoar", what_do: "autoar"}; + } +} + +/* Tukaj povemo, kakšno razmerje stranic ima video. +// Kaj to pomeni: +// Mi rečemo, da ima video razmerje stranic 16:9. Dejanski video +// ima razmerje 4:3. To pomeni, da ima video zgoraj in spodaj črno +// obrobo, ki je nočemo, zato video povečamo toliko, da se ta obroba odreže. +// +// OBROB TUKAJ NE DODAJAMO. +// +// With this function, we specify the aspect ratio of the video. +// What does this mean? +// If we specify that the aspect ratio of a video is 16:9 when video is +// actually 4:3, that means the video has black bars above and below. +// We zoom the video just enough for the black lines to disappear. +// +// WE DO NOT ADD ANY BLACK BORDERS. If we get to a scenario when we'd have to add +// black borders, we do nothing instead. +*/ +function set_video_ar(aspect_ratio, video, player){ + var video_ar = video.width / video.height; + var display_ar = player.width / player.height; + + if(debugmsg){ + console.log("uw::set_video_ar | aspect ratio: " + aspect_ratio + "; video_ar: " + video_ar + "; display_ar: " + display_ar); + console.log("uw::set_video_ar | player dimensions: " + player.width + "x" + player.height + "; video dimensions: " + video.width + "x" + video.height); + } + + if( aspect_ratio*1.1 > video_ar && video_ar > aspect_ratio*0.9 ){ + // Ta hack nas reši problema, ki ga predstavlja spodnji if stavek — če se legit 21:9 videu na 16:9 monitorju + // obreže na 16:9, potem ga s klicem te funkcije ne moremo spremeniti nazaj na 21:9. Vendar pa bi za tak primer + // radi imeli izjemo. + // + // This hack solves the problem that the bottom if statement presents. If we crop a 21:9 video on a 16:9 monitor, + // we can't change it back to 21:9 in this function, even though we kinda want that to happen — so we add an + // exception. + if( debugmsg) + console.log("uw::set_video_ar | ar matches our display ar. resetting"); + + resetCSS(video, player); + return; + } + + // Širina, višina, top, left za nov video + // Width, height, top and left for the new video + var nv = { "w":0, "h":0, "top":0, "left":0 }; + + /* + // Video hočemo pretvoriti v video z drugačnim razmerjem stranic. + // To storimo tako, da širino videa nastavimo relativno na višino prikazovalnika, torej: + // + // širina = višina_prikazovalnika * razmerje_stranic + // višina = širina / video_ar + // + // + // + // ---------------------------------------------------------------------------------------------- + // + // In this case, the video is narrower than we want (think 4:3, which we want to make into 16:9) + // We achieve this by setting video width relative to the display width, so: + // + // width = display_height * aspect_ratio + // height = width / video_ar + // + */ + + if( video_ar <= aspect_ratio ){ + if(debugmsg){ + console.log("uw::set_video_ar | reached pre-calc. Video is taller than ar. target ar: " + aspect_ratio ); + } + + nv.w = player.height * aspect_ratio; + nv.h = nv.w / video_ar; + + nv.top = (player.height - nv.h)/2; + nv.left = (player.width - nv.w)/2; + } + else{ + if(debugmsg){ + console.log("uw::set_video_ar | reached pre-calc. Video is wider than ar. target ar: " + aspect_ratio ); + } + nv.h = player.width / aspect_ratio; + nv.w = nv.h * video_ar; + + nv.top = (player.height - nv.h)/2; + nv.left = (player.width - nv.w)/2; + } + + if(nv.w > (player.width * 1.1) && nv.h > (player.height * 1.1)) + return; + + applyCSS(nv); +} + +// Ta funkcija ugotovi, kako se kvadrat s podanim razmerjem stranic najbolj prilega ekranu +// Predpostavimo, da so ćrne obrobe vselej zgoraj in spodaj, nikoli levo in desno. +// +// This function determines how a rectangle with a given aspect ratio best fits the monitor +// We assume letterbox is always letterbox, never pillarbox. +function set_best_fit(ar){ + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | got ar:",ar); + + var player = {width: PLAYER.clientWidth, height: PLAYER.clientHeight}; + var player_ar = player.width / player.height; + + var evideo = $("video")[0]; + var video = {width: evideo.videoWidth, height: evideo.videoHeight}; + var video_ar = video.width / video.height; + + // Ob predpostavki, da je argument 'ar' pravilen, naračunamo dimenzije videa glede na širino in višino predvajalnika + // Kot rezultat laho dobimo dve možnosti: + // A: naračunana širina je širša, kot naš zaslon —> za računanje uporabimo širino (letterbox zgoraj/spodaj, + // levo/desno pa ne) + // B: naračunana širina je ožja, kot naš zaslon —> za računanje uporabimo višino (letterbox levo/desno, + // zgoraj/spodaj pa ne) + + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | here's all we got. ar:",ar,"player:",player,"video:",video); + + var tru_width = player.height * ar; + var tru_height = player.width / ar; + + var nv = {w: "", h: "", top: "", left: ""}; + + if(ar >= video_ar){ + if(ar >= player_ar){ + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | aspect ratio is wider than player ar.") + nv.h = player.width / video_ar; + nv.w = nv.h * ar; + } + else{ + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | aspect ratio is narrower than player ar.", (player.height * ar), nv) + nv.w = player.height * ar; + nv.h = nv.w / video_ar; + } + } + else{ + if(ar >= player_ar){ + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | aspect ratio is wider than player ar.") + nv.h = player.width / ar; + nv.w = nv.h * video_ar; + } + else{ + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | aspect ratio is narrower than player ar.", (player.height * ar), nv) + nv.w = player.height * video_ar; + nv.h = nv.w / ar; + } + } + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | new video width and height processed. nv so far:", nv) + + nv.top = (player.height - nv.h)/2; + nv.left = (player.width - nv.w)/2; + + if(debugmsg || debugmsg_autoar) + console.log("uw::set_best_fit | tru width:",tru_width,"(player width:",player.width,"); new video size:",nv); + + applyCSS(nv); + console.log("uw::set_best_fit | css applied"); +} + +function resetCSS(video, player){ + if(debugmsg) + console.log("uw::resetCSS | resetting video size"); + + + var nv = {"w": 0, "h": 0, "top": 0, "left": 0}; + + var vidaspect = video.width / video.height; + var scraspect = player.width / player.height; + + if( vidaspect > scraspect ){ // Video je širši od okna | video is wider than window + nv.w = player.width; + nv.h = player.width / video.width * video.height; + + // Lahko se zgodi, da je prišlo do zaokroževalne napake ter da je dejanska višina videa le nekaj pikslov drugačna, + // kot višina predvajalnika. V tem primeru zavržemo prej dobljeni rezultat in namesto tega privzamemo, da je višina + // videa enaka višini predvajalnika. + // + // It's possible to have a rounding error where calculated height of the video is only a few pixels different from + // the player height. In such cases, we discard the calculated video height and use player height instead. + + if( player.height - 4 < nv.h && nv.h < player.height + 4 ) + nv.h = player.height; + + nv.top = (player.height - nv.h) / 2; + nv.left = 0; + } + else{ + nv.h = player.height; + nv.w = player.height / video.height * video.width; + + if( player.width - 4 < nv.w && nv.w < player.width + 4) + nv.w = player.width; + + nv.top = 0; //itak zasedemo 100% višine + nv.left = (player.width - nv.w) / 2; + } + + applyCSS(nv); +} + +function changeCSS_nofs(what_do, video, player){ + if(debugmsg){ + console.log("uw::changeCSS_nofs | arguments: what_do:",what_do,"; video:", video,"; player:", player); + } + + var w; + var h; + var top; + var left; + + var evideo = $("video")[0]; + var video = {width: evideo.videoWidth, height: evideo.videoHeight, scrollw: evideo.scrollWidth, scrollh: evideo.scrollWidth}; + + var ar = video.width / video.height; + + if(debugmsg){ + console.log("uw::changeCSS_nofs | video dimensions:", video.width, "x", video.height, "; ar:",ar); + } + + if(what_do == "fitw" || what_do == "fit-width"){ + // Ker bi bilo lepo, da atribut 'top' spremenimo hkrati z width in height, moramo najprej naračunati, + // za kakšen faktor se poviša višina. To potrebujemo, da se pravilno izračuna offset. + // + // 100vw = window.innerWidth + // window.innerWidth / videoWidth = x + // + // Če pomnožimo videoHeight z x, dobimo novo višino videa. Nova višina videa je lahko večja ali manjša + // kot višina ekrana. Če je višina videa manjša kot višina ekrana, bo top pozitiven, drugače negativen: + // + // nvideoh = x * videoWidth + // top = (window.innerHeight - nvideoh) / 2 + // + // Z 2 delimo, ker hočemo video vertikalno poravnati. + + w = player.width; + h = player.width / video.width * video.height; + + if(debugmsg) + console.log("uw::changeCSS_nofs | w:",w,"; h:",h); + + top = (player.height - h) / 2; + left = 0; // Ker zavzamemo vso širino | cos we take up all the width + } + + if(what_do == "fith" || what_do == "fit-height"){ + h = player.height; + w = player.height / video.height * video.width; + + top = 0; //itak zasedemo 100% višine + left = (player.width - w) / 2; + } + + if(what_do == "zoom"){ + // Video povečujemo na tak način, da sta zoom in unzoom povečata oz. zmanjšata video za enak korak + // We do this so zoom and unzoom steps change video sizes for the same amount + + h = video.scrollh + (player.height * zoomStep); + w = video.scrollw + (player.height * zoomStep * ar); + /* Zakaj računamo širino na tak način? + // + // Predstavljajte si, da imamo 2100:900 video v 1600:900 škatli, zoomStep = 0.1. Če bi širino računali po formuli: + // + // širina = širina_videa + (širina zaslona * zoomStep) + // + // Potem bi bila nova velikost videa 2260 x 990. Razmerje stranic: 2.28 (moglo bi biti 2.33 — video je popačen). + // Zaradi tega novo širino rajši povečamo za razliko_v_višini * razmerje_stranic + // + // 2100 + (900 * 0.1 * (2100/900)) = + // 2100 + (90 * 2.333) = 2310 + // + // Razmerje stranic (2310x990) je tako 2.333 — tako, kot bi moglo biti. + // + // + // ============================================================================================================ + // + // Why did we calculate width this way? + // + // Imagine we have a 2100x900 video in a 1600:900 container, zoomStep = 0.1. If we calculated width using this: + // + // width = video_width + (container_width * zoomStep) + // + // then the new size would be 2260 x 990. This gives us an aspect ratio of 2.28 instead of 2.33 (which is what it + // should be). Because of that we rather increase the width by delta_height * aspect_ratio: + // + // 2100 + (900 * 0.1 * (2100/900)) = + // 2100 + (90 * 2.333) = 2310 + // + // This gives us the correct aspect ratio and prevents video deformations. + */ + + top = (player.height - h)/2 + left = (player.width - w) / 2; + + if (h > player.height * 4){ + if(debugmsg){ + console.log("But this video is ... I mean, it's fucking huge. This is bigger than some rooms, this is bigger than some people's flats!"); + // Insert obligatory omnishambles & coffee machine quote here + console.log("(No really, mate, you took this way too far already. Can't let you do that, Dave.)"); + } + return; + } + } + + if(what_do == "unzoom"){ + // Video povečujemo na tak način, da sta zoom in unzoom povečata oz. zmanjšata video za enak korak + // We do this so zoom and unzoom steps change video sizes for the same amount + h = video.scrollh - (player.height * zoomStep); + w = video.scrollw - (player.height * zoomStep * ar); + + top = (player.height - h)/2 + left = (player.width - w) / 2; + + if (h < player.height * 0.25){ + if(debugmsg){ + console.log("don't you think this is small enough already? You don't need to resize the video all the way down to the size smaller than your penis."); + console.log("(if you're a woman, substitute 'penis' with whatever the female equivalent is.)"); + } + return; + } + } + var dimensions = { h: h, w: w, top: top, left: left }; + applyCSS(dimensions); +} + +function applyCSS(dimensions){ + dimensions.top = Math.round(dimensions.top) + "px"; + dimensions.left = Math.round(dimensions.left) + "px"; + dimensions.w = Math.round(dimensions.w) + "px"; + dimensions.h = Math.round(dimensions.h) + "px"; + + $("video").css({"width": dimensions.w,"height": dimensions.h,"top": dimensions.top, "left": dimensions.left}); + + if(debugmsg) + console.log("uw::applycss | css applied. Dimensions/pos: w:",dimensions.w,"; h:",dimensions.h,"; top:",dimensions.top,"; left:",dimensions.left); +} + +function inIframe(){ + if(debugmsg) + console.log("uw::inIframe | checking if we're in an iframe"); + try { + return window.self !== window.top; + } catch (e) { + return true; + } +} + +function resourceToUrl(img){ + return chrome.extension.getURL(img); +} + +function showMenu(id, sizes){ + if(debugmsg){ + console.log("uw::showMenu | showing menu with id ", id, "\n\n", document.getElementById(id)); + } + + var div = document.getElementById(id); + + console.log("showMenu | asasdas", sizes); + + div.classList.add("show"); + console.log("showMenu | asasdas"); + if(sizes){ + console.log("uw::showMenu",sizes); + var player_leftmost = sizes.player.left; + var parent_leftmost = sizes.parent.left; + var player_rightmost = sizes.player.left + sizes.player.width; + var parent_rightmost = sizes.parent.left + sizes.parent.width; + + if(debugmsg){ + console.log("uw::showMenu | space on left:", parent_leftmost - player_leftmost, "| space on right:", player_rightmost - parent_rightmost); + } + + // if: + // space left of the parent is bigger than space right of the parent + if( (parent_leftmost - player_leftmost) > (player_rightmost - parent_rightmost) ){ + //player goes to the left side + if(debugmsg){ + console.log("uw::showMenu | setting position on the submenu relative to the parent. left:", -div.getBoundingClientRect().width ) + } + div.style.left = (- div.getBoundingClientRect().width ) + "px"; + } + else{ + if(debugmsg) + alert("this wasn't defined yet. pls do this. ctrl+f rivianpoint"); + div.style.left = sizes.parent.width + "px"; + } + } +} + + +function toggleMenu(id){ + if(debugmsg || debugmsg_click) + console.log("uw::toggleMenu | toggling menu with id", id, "\n\n", document.getElementById(id)); + document.getElementById(id).classList.toggle("show"); +} + +function hideMenu(id){ + if(debugmsg) + console.log("uw::hideMenu | hiding menu with id " + id); + if(document.getElementById(id)) //Safety check in case there's no element with such id + document.getElementById(id).classList.remove("show"); +}