/*jslint indent: 4, maxerr: 50, browser: true, devel: true, sub: false, fragment: false, nomen: true, plusplus: true, bitwise: true, regexp: true, newcap: true */ // ==UserScript== // Do not modify and re-release this script! // If you would like to add support for other sites, please tell me and I'll put it in the includes. // @id youtube-me-again // @name YouTube Me Again! // @namespace hateradio))) // @author hateradio // @version 6.0.1.1 // @description ytma! automatically converts YouTube(TM), Vimeo, Vine, Soundcloud, WebM, and MP4 links into real embedded videos. // @homepage https://greasyfork.org/en/scripts/1023-youtube-me-again // @icon https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytma32.png // @icon64 https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytma64.png // @screenshot https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytmascreen5.png // @include https://vine.co/v/*/embed/simple // @match https://vine.co/v/*/embed/simple // @include http*://*youtube-nocookie.com/embed/* // @match *://*.youtube-nocookie.com/embed/* // @include http*://*youtube.com/embed/* // @match *://*.youtube.com/embed/* // @include https://gfycat.com/iframe/* // @match https://gfycat.com/iframe/* // @include http://*.neogaf.com/forum/showthread.php* // @include http://*.neogaf.com/forum/showpost.php?p* // @include http://*.neogaf.com/forum/newreply.php* // @include http://*.neogaf.com/forum/editpost.php* // @include http://*.neogaf.com/forum/private.php* // @match http://*.neogaf.com/forum/showthread.php* // @match http://*.neogaf.com/forum/showpost.php?p* // @match http://*.neogaf.com/forum/newreply.php* // @match http://*.neogaf.com/forum/editpost.php* // @match http://*.neogaf.com/forum/private.php* // @include http*://*what.cd/forums.php?*viewthread* // @include http*://*what.cd/torrents.php?* // @include http*://*what.cd/user.php?* // @match *://*.what.cd/forums.php?*viewthread* // @match *://*.what.cd/torrents.php?* // @match *://*.what.cd/user.php?* // @updated 14 May 2015 // @grant GM_xmlhttpRequest // @grant unsafeWindow // @run-at document-end // @downloadURL none // ==/UserScript== /* Changes: ### 6.0 * New: Imgur GIFV (WEBM/MP4) support * New: Button to remove cache (descriptions/thumbnail links/etc) * New: SoundCloud playlist support * Default video quality is now 720p/HD * Soundcloud now uses HTML5 player * Players that open on scroll will no longer trigger the opening of players higher on the page * Adds HTML5, Gfycat, Imgur icons on links * Improved Soundcloud and GfyCat URL matchers * Restructured code base to simplify creation of media controls * Restructured CSS * Patched back Gfycat iFrame setting for Safari (it is incompatible with new settings) * Updates YouTube data API Removes: * Object tag for YouTube for Flash (Deprecated) * "Batch" loading of descriptions (Only manual and scroll methods are supported) Whitelist these sites on NoScript/NotScript/etc. ------------------------------------------------ * neogaf.com * youtube.com * youtube-nocookie.com * googlevideo.com (HTML5 player sends videos from this domain) * googleapis.com (YT video data) * vimeo.com * vimeocdn.com * soundcloud.com * sndcdn.com * vineco.com * vine.com * vine.co * gfycat.com * dropboxusercontent.com Whitelist these on Ghostery --------------------------- * SoundCloud (Widgets, Audio / Music Player) */ (function () { 'use strict'; var $$, strg, update; if (!Function.prototype.bind) { Function.prototype.bind = function (self) { var args = [].slice.call(arguments, 1), fn = this; return function () { return fn.apply(self, args.concat([].slice.call(arguments))); }; }; } function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); } function inject(func) { var script = document.createElement('script'); script.type = 'text/javascript'; script.textContent = '(' + func + ')();'; document.body.appendChild(script); document.body.removeChild(script); } // D O M Handle $$ = { s: function (selector, cb) { var s = document.querySelectorAll(selector), i = -1; while (++i < s.length) { if (cb(s[i], i, s) === false) { break; } } }, o: function (object, cb) { var i; for (i in object) { if (object.hasOwnProperty(i)) { if (cb(i, object[i], object) === false) { break; } } } }, a: function (e) { var i = 1, j = arguments.length, f = document.createDocumentFragment(); for (i; i < j; i++) { if (arguments[i]) { f.appendChild(arguments[i]); } } e.appendChild(f); return e; }, e: function (t, o, e, p) { var c = document.createElement(t); $$.o(o, function (k, v) { var b = k.charAt(0); switch (b) { case '_': c.dataset[k.substring(1)] = v; break; case '$': c.setAttribute(k.substring(1), v); break; default: c[k] = v; } }); if (e && p) { c.appendChild(e); } else if (e) { e.appendChild(c); } return c; }, x: function (selector) { return this.ary(document.querySelectorAll(selector)); }, ary: function (ary) { return Array.from ? Array.from(ary) : Array.prototype.slice.call(ary); } }; // S T O R A G E HANDLE strg = { MAX: 5012, on: false, test: function () { try { var a, b = localStorage, c = Math.random().toString(16).substr(2, 8); b.setItem(c, c); a = b.getItem(c); return a === c ? !b.removeItem(c) : false; } catch (e) { return false; } }, read: function (key) { try { return JSON.parse(localStorage.getItem(key)); } catch (e) { console.error(e.lineNumber + ':' + e.message); return undefined; } }, save: function (key, val) { return this.on ? !localStorage.setItem(key, JSON.stringify(val)) : false; }, wipe: function (key) { return this.on ? !localStorage.removeItem(key) : false; }, zero: function (o) { var k; for (k in o) { if (o.hasOwnProperty(k)) { return false; } } return true; }, grab: function (key, def) { var s = strg.read(key); return strg.zero(s) ? def : s; }, size: function () { var length = 0, key; try { for (key in window.localStorage) { if (window.localStorage.hasOwnProperty(key)) { length += window.localStorage[key].length; } } } catch (e) {} return 3 + ((length * 16) / (8 * 1024)); }, full: function () { try { var date = +(new Date()); localStorage.setItem(date, date); localStorage.removeItem(date); return false; } catch (e) { if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') { return true; } } }, init: function () { this.on = this.test(); } }; strg.init(); // U P D A T E HANDLE update = { name: 'ytma!', version: 6011, key: 'ujs_YTMA_UPDT_HR', callback: 'ytmaupdater', page: 'https://greasyfork.org/scripts/1023-youtube-me-again', uric: 'https://dl.dropboxusercontent.com/u/14626536/userscripts/updt/ytma/ytma.js', // If you get "Failed to load source for:" in Firebug, allow dropboxusercontent.com to run scripts. interval: 5, day: (new Date()).getTime(), time: function () { return new Date(this.day + (1000 * 60 * 60 * 24 * this.interval)).getTime(); }, top: document.head || document.body, css: function (t) { if (!this.style) { this.style = document.createElement('style'); this.style.type = 'text/css'; this.top.appendChild(this.style); } this.style.appendChild(document.createTextNode(t + '\n')); }, js: function (t) { var j = document.createElement('script'); j.type = 'text/javascript'; j[/^https?\:\/\//i.test(t) ? 'src' : 'textContent'] = t; this.top.appendChild(j); }, notification: function (j) { if (j) { if (this.version < j.version) { window.localStorage.setItem(this.key, JSON.stringify({date: this.time(), version: j.version, page: j.page })); } else { return true; } } var a = document.createElement('a'), b = JSON.parse(window.localStorage.getItem(this.key)); a.href = b.page || '#'; a.target = '_blank'; a.id = 'userscriptupdater'; a.title = 'Update now.'; a.textContent = 'An update for ' + this.name + ' is available.'; document.body.appendChild(a); return true; }, check: function (opt) { if (!strg.on) { return; } // typeof (GM_updatingEnabled) === 'boolean' || var stored = strg.read(this.key), j, page; this.csstxt(); if (opt || !stored || stored.date < this.day) { page = stored && stored.page ? stored.page : '#'; strg.save(this.key, {date: this.time(), version: this.version, page: page}); j = this.notification.toString() .replace('function', 'function ' + this.callback) .replace('this.version', this.version) .replace(/(?:this\.key)/g, "'" + this.key + "'") .replace('this.time()', this.time()) .replace('this.name', "'" + this.name + "'"); this.js(j); this.js(this.uric); } else if (this.version < stored.version) { this.notification(); } }, csstxt: function () { if (!this.pop) { this.pop = true; this.css('#userscriptupdater,#userscriptupdater:visited{-moz-box-shadow:0 0 6px #787878;-webkit-box-shadow:0 0 6px #787878;box-shadow:0 0 6px #787878;border:1px solid #777;-moz-border-radius:4px;border-radius:4px;cursor:pointer;color:#555;font-family:Arial, Verdana, sans-serif;font-size:11px;font-weight:700;text-align:justify;min-height:45px;position:fixed;z-index:999999;right:10px;top:10px;width:170px;background:#ebebeb url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACsAAACLCAYAAAD4QWAuAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1NUIzQjc3MTI4N0RFMDExOUM4QzlBNkE2NUU3NDJFNCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGN0Q1OEQyNjdEQzUxMUUwQThCNEE3MTU1NDU1NzY2OSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGN0Q1OEQyNTdEQzUxMUUwQThCNEE3MTU1NDU1NzY2OSIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1NUIzQjc3MTI4N0RFMDExOUM4QzlBNkE2NUU3NDJFNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1NUIzQjc3MTI4N0RFMDExOUM4QzlBNkE2NUU3NDJFNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po6YcvQAAAQFSURBVHja7JzBSxRRHMdnp+gkiLdOgtshKGSljQVF8CK0biEErYfwFmT+BQpdA0MIBEFtTx2qSxESaAt5ioUQFDp5sjl06rbnumzfp7+VbZx5M+/Nb9wZ+f3g56wzO28//ua93/u9J/stdDodx2/P3o85llaFT8JvwlvwTfhf00a2Hv8IPO86PHYHvg//An8OfwRfg/9RfzvTZ7DBvoZXQq6p6D7MCuwT+N2I92zAB/sNO0yPO8quwxf7DasABmK+d0XTVVKHnYIvG96z1i9Ymw8ep/R2obAqNdkm41e2sFct71v1/f4BiXyOJpRpHKZ918s9527B5+FvLwJWDaoR3zmvZ/bZw2HPNyMeBOTeb/BfaXaDEuVMvx2G3QDQMkW21wZsUpkp7GbIeU9zz3TI+WXTVGYCW6XRbApb1lxbTwt2VVMltS1hVWRnuWFVqhoNudbW9NchHIpc+ToO7GDE49JFtRij/ZG4gy0O7CIVIjZWNuhiw0lhK1SA6GzI8ppxKouCjTNaOWC7qWzKFrYaNw/SQOKwNVtYk4KjyAQ7RpnHCHaeCg7ugZQon7sBj3RYM62mHdmTVAaGxbiRNVmqRM3/bUvgDQCX/CcLvZsceEOF1v82dgPTrkdVVp2iXU8Q4e9ob0IHu59gUecxdwdlMwBunusGAJ1NuPr0KLoFdYQ3GGBXAiMLWC9gBRDX2gTa9g3Wp7Rbk8TqaPfjWWRp9I0kaLARVCbiXMO/xLGwdfCd7Oa4eDGQdD0fYYcJ7z/bzXHpxbWEDRaddO1FF3aSobE6pazAawztX0H7465mXWVqB2hwqWdwFeFfGaM+Wlh4V/rkMO2fpmy3VWTf5AD0NzLLkYsfn53T7fUs21k2UPmw5jBs9qZgx/AH4Ns+VxvQwJg0rGXTMPUfnhYgj0MLmayb6+TIBFZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBVZgBTZzVrg3U+Nsz1iTo7m7c+GRFU2ONGBFkyMNWNHkSANWNDl0xqbJAZ+j1/nR5HBOv6zm/8JaPjQ5KKqiyRFVpORfk8PRf3NZq8lRrd3PhiaHc6pvcLk0ORDdfGlyAFg0OdKAPUlliG76mhyGUNaDLXOaHIjuJdXkoKVKXzU5wlJZZjU5AFyKKhErFkuVbjcoUo3Apcmhnu6Ebkcmc5oczd2dZlA3YNHkUAFwUtLkcJlWnm1a1ng94AvkbKnM1SxVTKwRMphYNDkAPNiFFU0OZuPV5NDMYiyaHOgKvJoc8CVftFk1ORRsi/FxvYR3yH9qZjYba+VGkwOTw5GCzZcmByzTmhyI6ra/kNkiz4wmByD/0+T4J8AAyDkZArebBxMAAAAASUVORK5CYII=) no-repeat 13px 15px;padding:12px 20px 10px 65px}#userscriptupdater:hover,#userscriptupdater:visited:hover{color:#55698c!important;background-position:13px -85px;border-color:#8f8d96}'); } } }; /** Y T M A CLASS * Bare YTMA class, filled through _new() or _reactivate() */ function YTMA() {} YTMA.events = { clicks: function (e) { // YTMA global click dispatcher var t = e.target; if (t) { // console.log('YTMA.clicks'); if (t.tagName === 'VAR' && t.hasAttribute('data-ytmuid')) { // trigger the ui console.log('show', t.dataset.ytmuid); YTMA.UI.createFromTrigger(t).showPlayer(); } else if (t.hasAttribute('data-ytmdescription')) { console.log('load', t.dataset.ytmid); YTMA.external.events.manualLoad(e); } } }, thumb: { start: function (e) { var el = e.target; el.dataset.thumb = el.dataset.thumb > 0 ? (el.dataset.thumb % 3) + 1 : 2; el.style.backgroundImage = ['url(https://i3.ytimg.com/vi/', el.dataset.ytmid, '/', el.dataset.thumb, '.jpg)'].join(''); el.dataset.timeout = window.setTimeout(YTMA.events.thumb.start.bind(this, e), 800); }, stop: function (e) { window.clearTimeout(e.target.dataset.timeout); } } }; YTMA.num = 0; YTMA.create = function (link) { var data = YTMA.grabIdAndSite(link), id, y; if (data.valid === true) { y = new YTMA()._new(data.id, data.site, link); id = y.data.uid; YTMA.set[id] = y; YTMA.set[id].setup(); return y; } return {}; }; YTMA.grabIdAndSite = function (link) { var uri = link.href, id, site, match; try { site = YTMA.reg.siteByTest[YTMA.reg.site.test(uri) ? RegExp.lastMatch : '']; // console.log(site); if (site === 'html5') { // || site === 'html5-audio' id = uri.slice(-15); } else if (site === 'soundcloud') { if (!YTMA.reg.extra.soundcloud.playlist.test(uri)) { link.href = uri = YTMA.reg.fix.soundcloud(uri); } match = YTMA.reg.matchers.soundcloud.exec(uri); if (match) { id = YTMA.escapeId(match[1]).slice(-50); } } else { id = uri.match(YTMA.reg.matchers[site])[1]; } if (id && YTMA.DB.sites[site]) { return {id: id, site: site, valid: true}; } throw TypeError('Invalid ID/Site: ' + id + ' @ ' + site); } catch (e) { console.error(uri, e); return {valid: false}; } }; YTMA.escapeId = function (id) { return (id += '').replace(/(?:\W)/g, '_'); }; YTMA.route = { host: document.location.host.replace('www.', ''), control: { $: { patchSafari: function () { YTMA.DB.videoTag.gfycat = false; YTMA.DB.sources.gfycat = YTMA.DB.sources.$gfycatFrame; }, checkStorage: function () { if (strg.full() === true) { console.log('storage is full!'); try { localStorage.removeItem(YTMA.external.version); strg.on = strg.test(); } catch (e) { console.error(e); } } }, runOnce: function () { if (!document.body.hasAttribute('ytma-enabled')) { document.body.setAttribute('ytma-enabled', true); this.checkStorage(); if (!YTMA.DB.extension) { update.check(); } YTMA.css(); YTMA.user.init(); YTMA.DB.postInit(); document.body.addEventListener('click', YTMA.events.clicks, false); } } }, go: function (host) { if (/(?:googlevideo|youtube-nocookie\.com|youtube\.com\.?)/i.test(host)) { this.sites.youtube(); } else if (this.sites[host]) { this.sites[host](); } else { this.sites.$generic(); } }, sites: { $generic: function () { YTMA.route.control.$.runOnce(); if (YTMA.DB.browser.safari) { // safari patch YTMA.route.control.$.patchSafari(); } if (YTMA.selector.processor() > 0) { YTMA.user.fn.loadPreferences(); } }, 'gfycat.com': function () { var v = document.querySelector('video'); v.controls = true; update.css('body,html {overflow:hidden;height:100%;width:100%} video {display:table;height:100%;margin:0 auto;}'); document.body.appendChild(v); }, 'vine.co': function () { // console.log('vine.co'); window.addEventListener('resize', function () { $$.s('[style]', function (e) { e.removeAttribute('style'); }); }); }, youtube: function () { // lets force some quality parity console.log('now inside youtube . . .', document.location); if (/(?:vq=(\w+))/.test(document.location.search)) { document.body.setAttribute('gm-player-quality', RegExp.lastParen); } if (/(?:volume=(\d+))/.test(document.location.search)) { document.body.setAttribute('gm-player-volume', RegExp.lastParen); } inject(function () { var max = 10, count = 1, intr = window.setInterval(function () { console.log('inside says: ', count, !!window.yt); if (window.yt && window.player) { var p = window.yt.player.getPlayerByElement(window.player); if (document.body.hasAttribute('gm-player-quality')) { console.log('inside says: setting quality to ', document.body.getAttribute('gm-player-quality')); p.setPlaybackQuality(document.body.getAttribute('gm-player-quality')); } if (document.body.hasAttribute('gm-player-volume')) { console.log('inside says: setting volume to ', document.body.getAttribute('gm-player-volume')); p.setVolume(document.body.getAttribute('gm-player-volume')); } window.clearInterval(intr); } else { console.log(count); count += 1; if (count > max) { window.clearInterval(intr); } } }, 500); }); } } }, load: function () { this.control.go(this.host); } }; YTMA.main = function () { YTMA.route.load(); }; YTMA.set = {}; YTMA.collect = function (id) { var i, a = []; for (i in YTMA.set) { if (YTMA.set.hasOwnProperty(i) && YTMA.set[i].data.id === id) { a.push(YTMA.set[i]); } } return a; }; YTMA.reg = { site : /\b(youtu)|(vimeo)|(vine)|(soundcloud)|(gfycat)|(imgur)|(\.webm$)|(\.mp4$)|(\.gifv$)/, time : /(?:t\=(?:(\d+)m)?(\d+))/, ios : /(?:\b(?:ipod|iphone|ipad))\b/i, matchers: { youtube: /(?:(?:(?:v\=|#p\/u\/\d*?\/)|(?:v\=|#p\/c\/[a-zA-Z0-9]+\/\d*?\/)|(?:embed\/)|(?:v\/)|(?:\.be\/))([A-Za-z0-9-_]{11}))/i, vimeo: /(?:vimeo\.com\/(\d+))/i, vine: /(?:vine\.co\/v\/([A-Za-z0-9-_]{11}))/i, soundcloud: /(?:\/\/(?:\bwww|m\.\b)?soundcloud\.com\/(.+?\/.+))/i, gfycat: /(?:gfycat\.com\/(?:(\b(?:[A-Z][a-z]*){3,}\b)))/, imgur: /(?:imgur\.com\/(\w+)\.(?:gifv|mp4|webm))/i }, extra: { soundcloud: { playlist: /(?:soundcloud\.com\/.+\/sets\/)/ } }, siteByTest: { youtu: 'youtube', vimeo: 'vimeo', vine: 'vine', gfycat: 'gfycat', imgur: 'imgur', '.webm': 'html5', '.mp4': 'html5', // '.mp3': 'html5-audio', '.gifv': 'html5', soundcloud: 'soundcloud' }, fix: { $removeSearch: function (uri, keepHash) { var s = uri.indexOf('?'), h = uri.indexOf('#'), hash = ''; if (s > -1) { if (keepHash && h > -1) { hash = uri.substr(h); } uri = uri.substr(0, s) + hash; } return uri; }, soundcloud: function (uri) { var match = YTMA.reg.matchers.soundcloud.exec(uri), id; if (match) { id = match[1].split('/', 2).join('/'); uri = this.$removeSearch('https://soundcloud.com/' + id, true); } return uri; } } }; YTMA.img = { fav: { soundcloud : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNp0UjFOw0AQnD3bCYaEoIgiUIQKikiAKKGgSAkFL0BQ0FEgUfECShpewB+QEE+gokDiBxGRiCCEBBzHd8ucLYGQ4Kw7+9azc7OzJ6oKnFYUxgD+W/DHYNA54GIooifTitYqg1okaPFff6BcTLF5fECYb5IJNJ3kMfUP2dxHPycwcQ0SliARocSGsA46YkKWQW0GS6BDAGlu5Myu84AgSmHKM/DY0NegwwR2+AJrSjBre5BaA1H7GFKpI729QHp9jqiaeTBn5mB7fWirjWB9B9JYBrwEMnop5d0zfD53YO9vYMY8SQcpZGkTZvsIstiivDfoaxfIxt8exYeXCLYOSOwlJZQ6twSpL0DfX4EoZtkCqc7/Njalbxnfdt+oSwhurkBnCWI/1FlgqgKNZ3JnZDSA3FFSpYdQAoF56tKNDmhOYTzJ3OSHXZkflJhYEyawcnH02HpmxZ+DrRJlgmacvrsHRmHln2tRnIiAy5WTLwEGAK4QoBQmtGHkAAAAAElFTkSuQmCC', youtube : 'https://www.youtube.com/favicon.ico', vimeo : 'https://vimeo.com/favicon.ico', vine : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABcklEQVQ4jX2SvyvFYRTGP+9NdzAYbpIkysA/ICnKoEwvA4vlUkoyGQzvoOiK4R0YbDLhDhbi9maWIjEqcScWkyRhMNzXcM/3On39OMt5nvOe85wfvSbGyH9mgs8Cq8AUkAMegU1gJVpXqfu3umpbwITiLUBB8HJGuryb4KMJ/izVvUMVnwNjwJPwGYCMkLL4zlT3XoUL0boD4FBNUhO4Fd9ogm9SRVmFn8Una79qgWuV2K3wvcLJdG3iL7TaiUocAI4Fn0vnHDBrgt+L1g2q3NoEl8CH4KHkMVr3CSwI7QeOTPA9WsAk/8AEvw+MSrwrWleuJQVfABZJWbTOZBTfVXg6lbgEHKjQTcL1BFngAWimeuH2aN2LvHUDV1JcjNbl0zdI9l0T2pDsboKvB7Yl/ga4X2+gku+AVqAC9AFzwLik5KN1xT8FRGQEOBL6yfdn2onWTZKyTDoQrSsB60KT4lNSh/1TQETmgQ1ZowQMy41+2BeLRXeRaKuHSAAAAABJRU5ErkJggg==', html5 : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdlJREFUeNpcks9rE0EUx7+b3TRktxvbhUhrNm6SrUWtxxbxJ9iLl0JFKWg8WLD05EWhIuRieogXwYPX4tGb/gPSq/oP6KH+uG2MFaRJJXaTbp7fWbsl+uDDzLx533lv3ozmeyUM2VlSJxeISULygTwhr5Og1JDgOXlPrpLRMAxTIpLlfJa8Ipv/i56Re4lT07SYKIqQSh2eO0/eqYnujI35HF8O19jr9XBneRmt1je0d3ag63qy5ZIAvNObE+WKTJXKktENoVPsrCntdlsWFxbiNXNJyS3KdMUXxv8w6LzY7XZhmiYer9fBYOTzR5HL5XCzWsWxYhFnTs/gxcYGgiCAZVmOyhR5BVcm8nlZvbsi29+3ZdgGg4Gs1+viua4UJiZVpkiJeqo0VaIqxbGPSKfTORRduXQ59peLx5PyItWaj9yDQtmt21XYto1GoxGvbywtxaNhGHE3ab+V6L6aKYczPo7ZuTk8WnuIWq2G64vX4JU8zJw8BXXv5D21gx+xydrn7VEb/f0+tj5twa/4+Pz1C6Y4Oo6DZrOJdDrdYuxkIlKP+ZbZzoV7e8iyk8kD/9rdRXpkBJlMpsmDC/98I97pPF//AQUBl/2/jRvsm5b1kxmeJgJlfwQYAKZQxgzeI6/EAAAAAElFTkSuQmCC', gyfcat : 'https://gfycat.com/favicon.ico', imgur : 'https://imgur.com/favicon.ico' }, css: { load : 'data:image/gif;base64,R0lGODlhDgAKAJEAAP///+BKV////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAADgAKAAACHFSOeQYI71p6MtAJz41162yBH+do5Ih1kKG0QgEAIfkEBQoAAgAsAAABAA0ACAAAAhSUYGEoerkgdIzKGlu2ET/9ceJmFAAh+QQFCgACACwAAAEADQAIAAACFJRhcbmiglx78SXKYK6za+NxHyYVACH5BAUKAAIALAAAAQANAAgAAAIWVCSAl+hqEGRTLhtbdvTqnlUf9nhTAQAh+QQFCgACACwAAAEADQAIAAACFZRiYCh6uaCRzNXYsKVT+5eBW3gJBQAh+QQJCgACACwAAAAADgAKAAACGpSPaWGwfZhwQtIK8VTUvuxpm9Yp4XlmpiIUADs=' } }; YTMA.selector = { // to build the selector all: 'a[href*="youtube."], a[href*="youtu.be/"], a[href*="vimeo.com/"], a[href*="vine.co/"], a[href*="gfycat.com/"], a[href*=".webm"], a[href*=".mp4"], a[href*=".mp3"], a[href*=".gifv"], a[href*="soundcloud.com/"]', parentBlacklist: ['.smallfont', '.colhead_dark', '.spoiler', 'pre'], chrome37Blacklist: 'a[href*="pomf.se/"]', ignore: function () { var i, j, ignore = [], all = this.all.split(','), blacklist = this.parentBlacklist; for (i = 0; i < blacklist.length; i++) { for (j = 0; j < all.length; j++) { ignore.push(blacklist[i] + ' ' + all[j]); } } //console.log(ignore); return ignore.join(','); }, links: function () { var links; $$.x(YTMA.selector.ignore()).map(function (el) { el.setAttribute('ytmaignore', true); }); links = $$.x(YTMA.selector.all).filter(function (el) { var r = !el.hasAttribute('ytmaprocessed') && !el.hasAttribute('ytmaignore'); el.setAttribute('ytmaprocessed', true); return r; }); return links; }, processor: function () { var links = this.links(); if (links.length > 0) { if (window.chrome && (/(?:Chrome\/(\d+))/.exec(window.navigator.appVersion) && RegExp.lastParen < 38)) { $$.s(YTMA.selector.chrome37Blacklist, function (a) { if (/(?:\.webm)/i.test(a.href)) { a.dataset.ytmscroll = false; } }); } links.forEach(YTMA.create); } return links.length; } }; /** * User Preferences * size: Small (240p), Medium (360p), Large (480p), XL (720p) * ratio: 1 4:3, 2 16:9 * quality: 240, 360, 480, 720, 1080 * focus: 0/1; Will attempt to set the window's focus near the video * autoShow: 0/1; Will automatically display HTML5 videos, which currently lack descriptions and thumbnails * desc: (Descriptions) 0 None; 1 Yes on scroll; 2 Yes all at once * yt_nocookie: 0/1; Will disable/enable youtube-nocookie.com * yt_volume: positive number; youtube volume * yt_annotation: 0/1; youtube annotations */ YTMA.user = { KEY: 'ytmasetts', $form: null, init: function () { this.load(); if (strg.on) { this.fn.makeForm(); this.mark(); } }, valid: { focus: [0, 1], desc: [0, 1, 2], ratio: [1, 2], size: [240, 360, 480, 720], quality: [240, 360, 480, 720, 1080], autoShow: [0, 1], yt_nocookie: [0, 1], yt_annotation: [0, 1], // hide | show yt_volume: 100 // todo? function () { a = []; for (i = 0; i < 100; i++) { a[i] = i; } } }, mapping: { // map values to some other values used by an external API, for example yt_annotation: [3, 1] // 3 = hide | 1 = show }, validate: function (property, n) { n = +n; if (property === 'yt_volume') { return n >= 0 && n <= 100 ? (+n) : YTMA.user.defaults()[property]; } return YTMA.user.valid[property].indexOf(n) > -1 ? n : YTMA.user.defaults()[property]; }, defaults: function () { return { focus : 0, desc : 1, ratio : 2, size : 360, quality : 720, autoShow : 1, yt_nocookie : 0, yt_annotation : 1, yt_volume : 100 }; }, load: function () { var s = strg.grab(YTMA.user.KEY, {}); YTMA.user.preferences = { size : YTMA.user.validate('size', s.size), ratio : YTMA.user.validate('ratio', s.ratio), desc : YTMA.user.validate('desc', s.desc), focus : YTMA.user.validate('focus', s.focus), quality : YTMA.user.validate('quality', s.quality), autoShow : YTMA.user.validate('autoShow', s.autoShow), yt_nocookie : YTMA.user.validate('yt_nocookie', s.yt_nocookie), yt_annotation : YTMA.user.validate('yt_annotation', s.yt_annotation), yt_volume : YTMA.user.validate('yt_volume', s.yt_volume) }; $$.o(YTMA.user.mapping, function (key, val) { if (!val.hasOwnProperty('indexOf')) { YTMA.user.preferences[key] = val[YTMA.user.valid[key].indexOf(YTMA.user.preferences[key])]; } }); console.log('loaded: ', YTMA.user.preferences); }, mark: function () { var a = {}; a.ytma__focus = !!YTMA.user.preferences.focus; a.ytma__autoShow = !!YTMA.user.preferences.autoShow; a.ytma__yt_nocookie = !!YTMA.user.preferences.yt_nocookie; a.ytma__yt_annotation = !!YTMA.user.preferences.yt_annotation; a.ytma__yt_volume = YTMA.user.preferences.yt_volume; a['ytma__ratio' + YTMA.user.preferences.ratio] = true; a['ytma__size' + YTMA.user.preferences.size] = true; a['ytma__desc' + YTMA.user.preferences.desc] = true; a['ytma__quality' + YTMA.user.preferences.quality] = !!YTMA.user.preferences.quality; // console.log('marking', a); $$.o(a, function (id, val) { try { var el = document.getElementById(id); el.checked = val; el.value = val; } catch (e) { // console.log(id, e); } }); }, events: { save: function (e) { var o = {}; if (e && /(?:INPUT|LABEL)/i.test(e.target.nodeName)) { // console.log(YTMA.user.$form.querySelectorAll('[data-key]')); // [data-key]:checked $$.ary(YTMA.user.$form.querySelectorAll('[data-key]')).forEach(function (e) { var key; key = e.dataset.key; if (e.type === 'checkbox') { o[key] = +e.checked; } else if (e.type === 'radio') { if (e.checked) { if (e.hasAttribute('data-num')) { o[key] = +e.dataset.num; } } } else { o[key] = +e.value; } }); if (strg.save(YTMA.user.KEY, o)) { YTMA.user.load(); } else { YTMA.user.error.classList.remove('ytm_none'); } } }, reset: function () { YTMA.user.preferences = YTMA.user.defaults(); YTMA.user.mark(); strg.wipe(YTMA.user.KEY); YTMA.user.error.classList.add('ytm_none'); }, clear: function () { try { localStorage.removeItem(YTMA.external.version); YTMA.user.events.reset(); console.log('removed all YTMA cache'); } catch (e) { console.error(e); } }, formToggle: function (e) { if (!e || (e && e.target && !/(?:INPUT|LABEL)/i.test(e.target.nodeName))) { YTMA.user.$form.classList.toggle('ytm_none'); } }, formToggleKeyboard: function (e) { // press CTRL+SHIFT+Y (META+SHIFT+Y) to display settings form if ((e.ctrlKey || e.metaKey) && e.shiftKey && String.fromCharCode(e.which).toLowerCase() === 'y') { e.preventDefault(); YTMA.user.events.formToggle(); } } }, fn: { $scroller: null, $once: false, loadPreferences: function () { if (YTMA.user.preferences.desc === 1) { YTMA.user.fn.onScrollViewDescriptions(); } this.loadPreferencesOnce(); }, loadPreferencesOnce: function () { if (this.$once) { return; } this.$once = true; if (YTMA.user.preferences.autoShow === 1) { YTMA.user.fn.onScrollViewMedia(); } }, showMedia: function () { console.log('showMedia'); return new YTMA.Scroll('a.ytm_scroll:not([data-ytmscroll="false"])', function (link) { if (YTMA.Scroll.visibleAll(link, 50)) { $$.s('var[data-ytmsid="' + link.dataset.ytmsid + '"]:not([data-ytmscroll="false"])', function (trigger) { var ui = YTMA.UI.createFromTrigger(trigger); ui.showOnScroll(link); }); } }); }, toggleMedia: function () { return new YTMA.Scroll('div.ytm_panel_switcher', function (div) { var v = div.querySelector('video'), paused = v && (v.paused || v.ended), ui = YTMA.set[div.dataset.ytmuid].getUI(); if (paused && !YTMA.Scroll.visibleAll(div, 0)) { return ui.play.switchStandby(); } if (ui.play.isStandby() && YTMA.Scroll.visibleAll(div, 200)) { return ui.play.switchOn(); } // todo ascertain embedded player properties // f = div.querySelector('iframe, object'); // if (f && !YTMA.Scroll.visibleAll(div, 200)) { // y.hidePlayer(); // } }); }, onScrollViewMedia: function () { this.showMedia(); this.toggleMedia(); }, onScrollViewDescriptions: function () { if (YTMA.user.fn.$scroller) { YTMA.user.fn.$scroller.stop(); } YTMA.user.fn.$scroller = new YTMA.Scroll('span.ytm_manual > a.ytm_title:not(.ytm_error)', function (a) { if (YTMA.Scroll.visibleAll(a, 200)) { YTMA.ajax.loadFromDataset(a.dataset); // console.log('doc', document.querySelectorAll(YTMA.user.fn.$scroller.selector).length, a.dataset.id); } if (document.querySelectorAll(YTMA.user.fn.$scroller.selector).length === 0) { YTMA.user.fn.$scroller.stop(); } }); }, makeForm: function () { var e, f = [ '
ytma! Site Settings
', '
Load Descriptions

', '
HTML5 Players

', '
Player Size

', '
Quality

', '
Aspect Ratio

', '
YouTube', '

', '

', '

', '
', '
Window Focus

', '

Error! Your settings could not be saved.

' ].join(''); YTMA.user.$form = $$.e('div', {className: 'ytm_fix_center ytm_none ytm_box', innerHTML: f}, document.body); YTMA.user.error = document.getElementById('ytm_settings_error'); e = YTMA.Scroll.debounce(YTMA.user.events.save, 500); YTMA.user.$form.addEventListener('submit', function (evt) { evt.preventDefault(); }, false); YTMA.user.$form.addEventListener('keyup', e, false); YTMA.user.$form.addEventListener('click', e, false); YTMA.user.$form.addEventListener('dblclick', YTMA.user.events.formToggle, false); document.getElementById('ytmaclose').addEventListener('click', YTMA.user.events.formToggle, false); document.getElementById('ytmareset').addEventListener('click', YTMA.user.events.reset, false); document.getElementById('ytmaclear').addEventListener('click', YTMA.user.events.clear, false); document.body.addEventListener('keydown', YTMA.user.events.formToggleKeyboard, false); } } }; YTMA.css = function () { var playerCss = YTMA.Player.css.generator(); // console.log(playerCss); update.css(playerCss); // images update.css([ '.ytm_loading{background:url(', YTMA.img.css.load, ') 0 3px no-repeat;}', '.ytm_link{background:url(', YTMA.img.fav.youtube, ') 0 center no-repeat !important;margin-left:4px;padding-left:20px!important;}', '.ytm_link.ytm_link_vimeo{background-image:url(', YTMA.img.fav.vimeo, ') !important;background-size:12px 12px !important;padding-left:18px!important}', '.ytm_link.ytm_link_vine{background-image:url(', YTMA.img.fav.vine, ') !important;background-size:10px 10px!important;padding-left:16px!important}', '.ytm_link.ytm_link_soundcloud{background-image:url(', YTMA.img.fav.soundcloud, ')!important;padding-left:17px!important}', '.ytm_link.ytm_link_html5{background-image:url(', YTMA.img.fav.html5, ') !important;padding-left:16px!important}', '.ytm_link.ytm_link_gfycat{background-image:url(', YTMA.img.fav.gyfcat, ') !important;background-size:12px 12px !important;padding-left:16px!important;}', '.ytm_link.ytm_link_imgur{background-image:url(', YTMA.img.fav.imgur, ') !important;background-size:12px 12px !important;padding-left:16px!important}' ].join('')); // todo // if (window.NO_YTMA_CSS) { return; } update.css('.ytm_none,.ytm_link br{display:none!important}.ytm_box{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ytm_block{display:block;position:relative;clear:both;text-align:left;border:0;margin:0;padding:0;overflow:hidden}.ytm_normalize{font-weight:400!important;font-style:normal!important;line-height:1.2!important}.ytm_sans{font-family:Arial,Helvetica,sans-serif!important}.ytm_spacer{overflow:auto;margin:0 0 6px;padding:4px}.ytm_spacer.ytm_site_slim{display:inline}.ytm_clear:after{content:"";display:table;clear:both}.ytm_center{text-align:center}.ytm_link b,.ytm_link strong{font-weight:400!important}.ytm_link u{text-decoration:none!important}.ytm_link i,.ytm_link em{font-style:normal!important}.ytm_trigger{width:118px;height:66px;background-color:#262626!important;cursor:pointer;background-position:-1px -12px;float:left;box-shadow:2px 2px rgba(0,0,0,.3);background-size:auto 90px!important;color:#fff;text-shadow:#333 0 0 2px;font-size:13px}.ytm_trigger:hover{box-shadow:2px 2px #9eae9e;opacity:.95}.ytm_trigger var{z-index:2;height:100%;width:100%;position:absolute;left:0;top:0;text-align:right}.ytm_label{display:block;padding:3px 6px;line-height:1.2;font-style:normal}.ytm_init{height:22px;background:rgba(11,11,11,.62);padding:4px 25px 6px 6px}.ytm_site_vine .ytm_trigger{background-color:#90ee90!important;background-size:120px auto!important}.ytm_site_slim .ytm_trigger{background:#e34c26!important;height:auto;box-shadow:0 0 2px #ffdb9d inset,2px 2px rgba(0,0,0,.3);margin:0 3px 0 0;width:auto;transition:all .3s ease-in-out 0s}.ytm_site_slim .ytm_trigger:hover{opacity:.8}.ytm_site_slim .ytm_label{text-shadow:0 0 1px #f06529}.ytm_site_slim .ytm_init{background:transparent}.ytm_bd{float:left;max-width:500px;margin:2px 10px;font-size:90%}.ytm_title{font-weight:700}.ytm_error{color:#cc2f24;font-style:italic}.ytm_loading{font-style:italic;padding:1px 1.5em}.ytm_descr{word-wrap:break-word;max-height:48px;overflow:auto;padding-right:20px}.ytm_descr[data-full]{cursor:pointer}.ytm_descr_open{resize:both;white-space:pre-line}.ytm_descr_open[style]{max-height:none}.ytm_projector{margin-bottom:4px}ul.ytm_control{overflow:hidden;margin:0!important;padding:3px 0 1px;list-style-position:outside!important}.ytm_control li{display:inline;margin:0!important;padding:0!important}.ytm_control li>ul{display:inline-block;margin:0;padding:0 1px 0 0}.ytm_control li ul li{-webkit-user-select:none;-moz-user-select:none;-o-user-select:none;user-select:none;list-style-type:none;cursor:pointer;float:left;color:#858585;border:1px solid #1d1d1d;border-bottom:1px solid #000;border-top:1px solid #292929;box-shadow:0 0 1px #555;height:14px;font-size:12px!important;line-height:12px!important;background:#222;background:linear-gradient(#2d2c2c,#222);margin:0!important;padding:5px 9px 3px!important}.ytm_control li ul li:first-child{border-radius:2px 0 0 2px}.ytm_control li ul li:last-child{border-left:0!important;border-radius:0 2px 2px 0;margin:0 2px 0 0!important}.ytm_control li ul li:first-child:last-child,.ytm_li_setting{border-radius:2px}.ytm_control li ul li:hover{color:#ccc;text-shadow:1px 1px 0 #333;background:#181818}.ytm_control li ul li[id]{color:#ddd;text-shadow:0 0 2px #444}.ytm_panel_size{background:#000}.ytm_panel_switcher[data-standby="true"]{background:#111}.ytm_panel_switcher[data-standby="true"]:after{cursor:cell;color:#0e0e0e;content:"ytma!";display:block;font-size:85px;font-style:italic;font-weight:700;left:50%;position:absolute;text-shadow:2px 1px #181818,-1px -1px #0a0a0a;top:50%;transform:translate(-50%,-50%)}.ytm_site_soundcloud .ytm_panel_size.ytm_soundcloud-playlist{height:334px!important}.ytm_fix_center{background:rgba(51,51,51,.41);height:100%;left:0;position:fixed;top:0;width:100%;z-index:99998}#ytm_settings{z-index:99999;max-width:500px;max-height:85%;overflow:auto;background:#fbfbfb;border:1px solid #bbb;color:#444;box-shadow:0 0 5px rgba(0,0,0,.2),0 0 3px rgba(239,239,239,.1) inset;margin:4% auto;padding:4px 8px 0}#ytm_settings p{margin:5px 0;padding:0}#ytm_settings fieldset{vertical-align:top;border-radius:3px;border:1px solid #ccc;margin:0 0 5px}#ytm_settings fieldset span{display:inline-block;min-width:5em}#ytm_settings input{vertical-align:baseline!important;margin:3px 5px!important}#ytm_settingst{font-size:110%;border-bottom:1px solid #d00;margin:3px 0 9px;padding:0 3px 3px}#ytm_settings label{cursor:pointer}#ytm_settings small{font-size:90%}#ytm_opts button{cursor:pointer;margin:10px 5px 8px 2px;padding:3px;border:1px solid #adadad;border-radius:2px;background:#eee;font-size:90%}#ytm_opts button:hover{background:#ddd}'); }; YTMA.ajax = { load: function (site, id, uri) { var cache = YTMA.external.dataFromStorage(site, id); console.log('YTMA.ajax.load:', site, id, uri); console.log('@cache:', cache); if (cache) { return YTMA.external.populate(cache); } if (YTMA.DB.ajaxExtension[site]) { return this.gmxhr(uri, site, id); } console.log('ajax.site?', YTMA.DB.ajax[site].replace('%key', id).replace('%uri', uri)); if (YTMA.DB.ajax[site]) { console.log('preping uri'); uri = YTMA.DB.ajax[site].replace('%key', id).replace('%uri', uri); return this.xhr(uri, site, id); } return null; }, loadFromDataset: function (dataset) { return this.load(dataset.ytmsite, dataset.ytmid, dataset.ytmuri); }, gmxhr: function (uri, site, id) { try { // alert('gmxhr starting!'); // console.log('gmxhr starting!'); GM_xmlhttpRequest({ method: 'GET', url: uri, onload: function (response) { console.log(response); YTMA.external.parse(response.responseText, site, id); }, onerror: function () { console.log('GM Cannot XHR'); YTMA.ajax.failure.call({id: id}); } }); YTMA.ajax.preProcess(id); } catch (e) { if (YTMA.DB.extension) { console.log('attempting cs xhr'); this.xhr(uri, site, id); } else { console.log('No applicable CORS request available.'); this.failure.call({id: id}); } } }, xhr: function (uri, site, id) { var x = new XMLHttpRequest(); console.log('xhr', uri, id, site); YTMA.ajax.preProcess(id); x.onreadystatechange = function () { if (this.readyState === this.DONE) { // console.log(this.readyState, this.status); if (this.status === 200) { YTMA.external.parse(this.responseText, site, id); } else if (this.status === 403) { YTMA.external.populate({site: site, id: id, title: 'Error 403', desc: ''}); YTMA.external.save({site: site, id: id, title: 'Error 403', desc: ''}); } else { // if (this.status >= 400 || this.status === 0) { YTMA.ajax.failure.call({id: id}); } } }; try { console.log('sending'); x.open('get', uri, true); x.send(); } catch (e) { console.error('Cannot send xhr', uri); YTMA.ajax.failure.call({id: id}); console.error(e); } }, failure: function () { $$.s('.ytm_bd._' + YTMA.escapeId(this.id), function (el) { var a = el.querySelector('a'); a.dataset.tries = a.dataset.tries ? parseFloat(a.dataset.tries) + 1 : 1; a.textContent = 'Error, unable to load data. [Retry ' + (a.dataset.tries > 0 ? a.dataset.tries : '') + ']'; a.className = 'ytm_error ytm_title'; }); }, preProcess: function (id) { $$.s('.ytm_manual._' + YTMA.escapeId(id) + ' a', function (el) { el.classList.add('ytm_loading'); el.textContent = 'Loading data . . .'; el.title = 'Retry loading data.'; }); } }; /** E X T E R N A L Apparatus * Data from external sites */ YTMA.external = { version: 'ytma.4.1.dat', parse: function (response, site, id) { if (this.parsers[site]) { response = YTMA.DB.ajax[site] ? JSON.parse(response) : response; this.populate(this.helper.cutDescription(this.parsers[site](response, id))); } }, parsers: { soundcloud: function (j, id) { return { site: 'soundcloud', id: id, //unescape(j.html).match(/tracks\/(\d+)/)[1], title: j.title, desc: j.description, th: YTMA.reg.fix.$removeSearch(j.thumbnail_url) }; }, vimeo: function (j) { j = j[0]; return { site: 'vimeo', id: j.id, title: j.title + ' ' + YTMA.external.helper.time(j.duration), desc: j.description.replace(//g, ''), th: decodeURI(j.thumbnail_medium) }; }, youtube: function (j, id) { if (j.pageInfo.totalResults < 1) { return { id: id, error: true }; } j = j.items[0]; var o = { site: 'youtube', id: id, title: j.snippet.title + ' ' + YTMA.external.helper.time(j.contentDetails.duration), desc: j.snippet.description // aspectRatio: j.contentDetails.aspectRatio }; return o; }, vine: function (html, id) { var o, doc = document.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = html; o = { site: 'vine', id: id, //doc.querySelector('meta[property="twitter:app:url:googleplay"]').content.split('/').slice(-1), title: doc.querySelector('meta[property="twitter:title"]').content, desc: doc.querySelector('meta[property="twitter:description"]').content, th: doc.querySelector('meta[property="twitter:image"]').content.split('?')[0] }; doc = null; return o; }, gfycat: function (j, id) { j = j.gfyItem; if (j) { return { site: 'gfycat', id: id || j.gfyName, title: j.title || j.gfyName }; } } }, set: function (data) { if (!this.db[data.site]) { this.db[data.site] = {}; } this.db[data.site][data.id] = data; return this.save(); }, unset: function (data) { // console.log('unset', data.id); if (data.site) { delete this.db[data.site][data.id]; return this.save(); } }, limitDB: function (max, db) { // limits an object's items by half of the max // removes the older items at the start of the object var keys = Object.keys(db), half = Math.floor(max / 2), start, ndb, i; if (keys.length > max) { ndb = {}; start = keys.length - half; for (i = start; i < keys.length; i++) { ndb[keys[i]] = db[keys[i]]; } } return ndb || db; }, save: function () { this.db = this.limitDB(1000, this.db); return strg.save(this.version, this.db); }, helper: { cutDescription: function (data) { if (data.desc && data.desc.length > 140) { data.full = data.desc; data.desc = data.desc.substr(0, 130) + ' . . .'; } return data; }, time: function (iso8601) { var p = '', a, i; // P#DT#H#M#S || PT#H#M#S try { a = iso8601.replace(/(?:PT?)/, '').split(/(?:D|H|M|S)/g).slice(0, -1); for (i = (a.length - 1); i > 0; i--) { if ((a[i - 1] >= 0) && a[i] > 0) { a[i] = ('00' + a[i]).slice(-2); } } p = '(' + a.join(':') + ')'; } catch (e) { } return p; }, thumbnail: function (data) { $$.s('[data-ytmid="%id"].ytm_trigger'.replace('%id', data.id), function (el) { el.setAttribute('style', 'background: url(' + data.th + ')'); }); }, titleToggle: function () { this.classList.toggle('ytm_descr_open'); this.textContent = this.textContent.length < 140 ? this.dataset.full : this.dataset.full.substr(0, 130) + ' . . .'; this.removeAttribute('style'); } }, validate: function (data) { if (!data || !data.id || data.error) { return YTMA.ajax.failure.call(data); } if (data.id && !data.title && !data.desc) { this.unset(data.id); return YTMA.ajax.failure.call(data); } return true; }, populate: function (data, ignoreValidation) { if (!ignoreValidation && !this.validate(data)) { return; } this.set(data); if (data.th) { this.helper.thumbnail(data); } $$.s('.ytm_bd._' + YTMA.escapeId(data.id), function (el) { var q; el.innerHTML = '' + data.title + ''; if (data.desc) { q = $$.e('q', { className: 'ytm_descr ytm_block', textContent: data.desc }, el); if (data.full) { q.dataset.full = data.full; q.title = 'Click to toggle the length of the description.'; q.addEventListener('dblclick', YTMA.external.helper.titleToggle, false); } } }); }, dataFromStorage: function (site, id) { if (this.db && this.db[site]) { return this.db[site][id]; } }, events: { manualLoad: function (e) { // console.log(this); e.preventDefault(); YTMA.ajax.loadFromDataset(e.target.dataset); } } }; YTMA.external.db = strg.grab(YTMA.external.version, {}); /** Database */ YTMA.DB = { postInit: function () { if (YTMA.user.preferences.yt_nocookie) { YTMA.DB.sites.youtube = 'https://www.youtube-nocookie.com/'; } else { YTMA.DB.sites.youtube = 'https://www.youtube.com/'; } }, fn: { hasAjax: function (site) { return YTMA.DB.ajax[site] || YTMA.DB.ajaxExtension[site]; } }, extension: window.chrome && window.chrome.extension, browser: { pod: YTMA.reg.ios.test(navigator.userAgent), ie: !!document.documentMode, // IE, basically | window.navigator.cpuClass safari: Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 }, sites: { youtube: 'https://www.youtube.com/', vimeo: 'http://vimeo.com/', vine: 'https://vine.co/', gfycat: 'https://gfycat.com/', html5: true, 'html5-audio': true, soundcloud: 'https://soundcloud.com/', imgur: 'https://i.imgur.com/' }, customControls: { $get: function (site) { var customBar = this[site] || {}; return { ratio: customBar.ratio === undefined ? true : customBar.ratio, size: customBar.size === undefined ? true : customBar.size }; }, vine: { ratio: false, size: true }, soundcloud: { ratio: false, size: false } }, slim: { html5: true }, scroll: { html5: true, soundcloud: true, gfycat: true, imgur: true }, playerSize: { ratios: { 1: 'sd', 2: 'hd', 3: 'pr' }, sizes: { 0 : 'h', 240 : 's', 360 : 'm', 480 : 'l', 720 : 'xl' }, aspects: { 1: 4 / 3, 2: 16 / 9, 3: 16 / 9 }, $get: function (ratio, size) { return 'ytm_panel ytm_block ytm_panel-' + this.ratios[ratio] + ' ytm_panel-' + this.sizes[size]; } }, qualities: { 240 : 'small', 360 : 'medium', 480 : 'large', 720 : 'hd720', 1080 : 'hd1080', 1081 : 'highres', $get: function (quality) { return this[quality] || this[360]; } }, ajax: { youtube: 'https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=%key' + window.atob('JmtleT1BSXphU3lEVG5INkxzRERyVElYaFZTZWRQQjlyRHo1czBSczQzZnM='), vimeo: 'https://vimeo.com/api/v2/video/%key.json', soundcloud: 'https://soundcloud.com/oembed?format=json&url=%uri', gfycat: 'http://gfycat.com/cajax/get/%key' }, ajaxExtension: { // cross-site request with extension/GM support vine: 'https://vine.co/v/%key' }, videoTag: { // sites / types that use video tag html5: true, imgur: true, gfycat: true }, // videoTypes: (function () { // var v = document.createElement('video'); // return { // ogg: !!v.canPlayType('video/ogg; codecs="theora, vorbis"'), // webm: !!v.canPlayType('video/webm'), // mp4: !!v.canPlayType('video/mp4') // }; // }()), sources: { 'html5-audio': function (data) { return [ {type: 'audio/mp3', src: data.uri} ]; }, html5: function (data) { // attaching the type as either mp4 or webm return [ {type: 'video/mp4', src: data.uri}, {type: 'video/webm', src: data.uri} ]; }, imgur: function (data) { return [ {type: 'video/webm', src: 'https://i.imgur.com/' + data.id + '.webm'}, {type: 'video/mp4', src: 'https://i.imgur.com/' + data.id + '.mp4'} ]; }, $gfycatFrame: function (data) { return [{type: 'text/html', src: 'https://gfycat.com/iframe/' + data.id }, false]; }, gfycat: function (data) { return [ {type: 'video/mp4', src: 'http://zippy.gfycat.com/' + data.id + '.mp4'}, {type: 'video/mp4', src: 'http://fat.gfycat.com/' + data.id + '.mp4'}, {type: 'video/mp4', src: 'http://giant.gfycat.com/' + data.id + '.mp4'}, {type: 'video/webm', src: 'http://zippy.gfycat.com/' + data.id + '.webm'}, {type: 'video/webm', src: 'http://fat.gfycat.com/' + data.id + '.webm'}, {type: 'video/webm', src: 'http://giant.gfycat.com/' + data.id + '.webm'} ]; }, youtube: function (data, attrs) { var params = '?html5=1&version=3&modestbranding=1&theme=dark&color=white&showinfo=1&vq=' + attrs.quality + '&iv_load_policy=' + YTMA.user.preferences.yt_annotation + '&start=' + attrs.start + '&volume=' + YTMA.user.preferences.yt_volume; return [ {type: 'text/html', src: YTMA.DB.sites[data.site] + 'embed/' + data.id + params} ]; }, vimeo: function (data) { return [{type: 'text/html', src: 'http://player.vimeo.com/video/' + data.id + '?badge=0'}, null]; }, vine: function (data) { return [{type: 'text/html', src: 'https://vine.co/v/' + data.id + '/embed/simple?audio=1'}, null]; // card }, soundcloud: function (data) { return [ {type: 'text/html', src: 'https://w.soundcloud.com/player/?show_comments=false&url=' + data.uri}, null ]; } } }; /** U I CLASS * Class for the player controls */ YTMA.UI = function (ytma) { this.ytmx = ytma; this.play = new YTMA.Player(this.ytmx); this.open = false; this.selected = { size: null, ratio: null }; this.trigger = ytma.spn; this.projector = $$.e('div', {className: 'ytm_projector ytm_none ytm_block ytm_normalize ytm_sans'}); this.control = $$.e('ul', {className: 'ytm_control ytm_sans'}); this.customBar = YTMA.DB.customControls.$get(this.ytmx.data.site); this.controlBar(); }; YTMA.UI.ratios = { SD: 1, HD: 2, PORTRAIT: 3 }; YTMA.UI.sizes = { HIDDEN: 0, S: 240, M: 360, L: 480, X: 720 }; /** Trigger is the VAR element */ YTMA.UI.createFromTrigger = function (t) { console.log('createFromTrigger'); if (t.hasAttribute('data-ytmuid') && !YTMA.set[t.dataset.ytmuid]) { console.log('createFromTrigger-new'); YTMA.set[t.dataset.ytmuid] = new YTMA()._reactivate(t); } console.log('createFromTrigger-ui'); return YTMA.set[t.dataset.ytmuid].getUI(); }; YTMA.UI.events = { $fire: { settings: function () { YTMA.user.events.formToggle(); }, close: function () { if (YTMA.DB.scroll[this.ytmx.data.site]) { console.log('events.close-1'); this.hideAllPlayers(); } else { console.log('events.close-2'); this.ytmx.disableOpenOnScroll(); this.hidePlayer(); } }, ratio: function (li) { var n = parseInt(li.dataset.value, 10); this.play.dimmensions(n); this.markSelected(li, 'ratio'); }, size: function (li) { var n = parseInt(li.dataset.value, 10); this.play.dimmensions(null, n); this.markSelected(li, 'size'); } }, videoBar: function (e) { var el = e.target, t; if (el.tagName.toLowerCase() === 'li' && el.dataset && el.dataset.type) { t = el.dataset.type; if (YTMA.UI.events.$fire[t]) { YTMA.UI.events.$fire[t].call(this, el); } } } }; YTMA.UI.prototype = { constructor: YTMA.UI, resetViewSize: function () { this.play.dimmensions(); this.setControlBarSize(this.play.attrs.size); }, showOnScroll: function (el) { if (!this.open && this.ytmx.canScroll() && this.ytmx.isBelow(el)) { this.showPlayer(); } }, showPlayer: function () { this.open = true; this.trigger.classList.add('ytm_none'); this.projector.classList.remove('ytm_none'); this.attachPlayPanel(); this.play.switchOn(); if (YTMA.user.preferences.focus) { document.location.hash = '#' + this.ytmx.container.id; } }, hidePlayer: function () { this.open = false; this.play.switchOff(); this.trigger.classList.remove('ytm_none'); this.projector.classList.add('ytm_none'); }, attachPlayPanel: function () { if (!this.play.panel.parentNode) { // console.log('attaching display panel'); this.projector.appendChild(this.play.panel); } }, hideAllPlayers: function () { var group = YTMA.collect(this.ytmx.data.id); console.log('closing all', this.ytmx.data.id, group.length); group.forEach(function (y) { y.disableOpenOnScroll(); y.getUI().hidePlayer(); }); }, setControlBarSize: function (size) { this.markSelected(this.control.querySelector('li[data-value="' + size + '"]'), 'size'); }, controlBar: function () { var f = document.createDocumentFragment(); $$.a(f, this.customBar.ratio ? this.buildList('ytm_ratios', [ {type: 'ratio', text: '4:3', value: YTMA.UI.ratios.SD, title: 'SD'}, {type: 'ratio', text: '16:9', value: YTMA.UI.ratios.HD, title: 'Landscape'}, {type: 'ratio', text: '9:16', value: YTMA.UI.ratios.PORTRAIT, title: 'Portrait'}]) : null, this.customBar.size ? this.buildList('ytm_sizes', [ {type: 'size', text: '\u00D8', value: YTMA.UI.sizes.HIDDEN, title: 'Hide the video.'}, {type: 'size', text: 'S', value: YTMA.UI.sizes.S, title: '240p'}, {type: 'size', text: 'M', value: YTMA.UI.sizes.M, title: '360p'}, {type: 'size', text: 'L', value: YTMA.UI.sizes.L, title: '480p'}, {type: 'size', text: 'X', value: YTMA.UI.sizes.X, title: '720p'}]) : null, this.buildList('ytm_options', [ strg.on ? {type: 'settings', text: '!', title: 'YTMA Settings'} : null, {type: 'close', text: '\u00D7', title: 'Close the video.'}]) ); this.control.appendChild(f); this.control.addEventListener('click', YTMA.UI.events.videoBar.bind(this), false); this.projector.appendChild(this.control); this.ytmx.container.insertBefore(this.projector, this.trigger.nextSibling); }, markSelected: function (el, type) { el.id = type + this.ytmx.data.uid; try { this.selected[type].removeAttribute('id'); } catch (e) {} this.selected[type] = el; }, buildList: function (className, elements) { var li = $$.e('li'), ul = $$.e('ul', {className: className}, li), f = document.createDocumentFragment(), i, e; for (i = 0; i < elements.length; i++) { e = elements[i]; if (e) { f.appendChild(this.li(e.type, e.text, e.value, e.title)); } } ul.appendChild(f); return li; }, li: function (type, txt, value, title) { var l = $$.e('li', {_type: type, textContent: txt, _value: value, title: title}); if ((type === 'size' && this.play.attrs.size === value) || (type === 'ratio' && this.play.attrs.ratio === value)) { this.markSelected(l, type); } return l; } }; /** P L A Y E R CLASS * @param parent YTMA instance */ YTMA.Player = function (parent) { this.parent = parent; this.mode = 'off'; this.attrs = { sources: null, quality: YTMA.DB.qualities.$get(YTMA.user.preferences.quality), size: null, ratio: null, start: this.time(), type: null }; this.attrs.sources = YTMA.DB.sources[parent.data.site](parent.data, this.attrs); this.attrs.type = this.findType(); this.media = YTMA.Player.makeMedia[this.attrs.type](this); this.channel = $$.e('div', {className: 'ytm_panel_channel ytm_block'}, this.media, true); this.switcher = $$.e('div', {className: 'ytm_panel_switcher ytm_panel_size ytm_block ytm_' + this.attrs.type, _ytmuid: this.parent.data.uid, _standby: true}); this.panel = $$.e('div', {className: 'ytm_panel ytm_block'}, this.switcher, true); if (parent.data.site === 'soundcloud' && YTMA.reg.extra.soundcloud.playlist.test(parent.anchor.href)) { this.media.classList.add('ytm_soundcloud-playlist'); this.switcher.classList.add('ytm_soundcloud-playlist'); } this.dimmensions(YTMA.user.preferences.ratio, YTMA.user.preferences.size); }; YTMA.Player.css = { item: function (key, value) { if (isNumber(value)) { value += 'px'; } return '\t' + key + ': ' + value + ';\n'; }, iter: function (css, cssEntries) { $$.o(cssEntries, function (key, value) { css.push(YTMA.Player.css.item(key, value)); }); css.push('}'); }, generator: function () { var css = []; $$.o(this.sizes, function (size, sizes) { $$.o(sizes, function (dimm, keys) { css.push('\n.ytm_panel-' + size + '.ytm_panel-' + dimm + ' .ytm_panel_size {\n'); YTMA.Player.css.iter(css, keys); }); }); // add site overrides $$.o(this.sites, function (site, data) { $$.o(data, function (setting, keys) { if (setting === 'all') { css.push('\n.ytm_site_' + site + ' .ytm_panel_size {\n'); } else { css.push('\n.ytm_site_' + site + ' .ytm_panel-' + setting + ' .ytm_panel_size {\n'); } YTMA.Player.css.iter(css, keys); }); }); return css.join(''); }, sizes: (function () { var merge = {}; $$.o(YTMA.DB.playerSize.sizes, function (num, size) { if (num >= 0) { merge[size] = {}; $$.o(YTMA.DB.playerSize.ratios, function (k, ratio) { if (ratio === 'pr') { var w = Math.floor(num * 0.95); // smaller than the normal sizes merge[size][ratio] = { width: w, height: Math.floor(Math.floor(w * YTMA.DB.playerSize.aspects[k])) }; } else { merge[size][ratio] = { width: Math.floor(num * YTMA.DB.playerSize.aspects[k]), height: num }; } }); } }); return merge; }()), sites: { // custom sizes per site soundcloud: { all: { height: '118px !important' } }, vine: { s: { width: 240, height: 240 }, m: { width: 360, height: 360 }, l: { width: 480, height: 480 }, xl: { width: 720, height: 720 } } } }; YTMA.Player.makeMedia = { $css: function (type) { return 'ytm_panel_media ytm_panel_size ytm_block ytm_' + type; }, video: function (player) { var video = $$.e('video', { controls: true, autoplay: false, loop: true, className: this.$css('video'), $allowscriptaccess: true, preload: 'metadata' }); player.attrs.sources.forEach(function (source) { $$.e('source', {src: source.src, $type: source.type}, video); }); return video; }, iframe: function (player) { return $$.e('iframe', { $allowfullscreen: true, // $sandbox: 'allow-same-origin allow-scripts allow-popups', $type: player.attrs.sources[0].type, src: player.attrs.sources[0].src, className: this.$css('iframe') }); }, audio: function (player) { return $$.e('audio', { src: player.attrs.sources[0].src, $type: player.attrs.sources[0].type }); } }; YTMA.Player.prototype = { constructor: YTMA.Player, dimmensions: function (ratio, size) { this.attrs.ratio = isNumber(ratio) ? ratio : this.attrs.ratio; this.attrs.size = isNumber(size) ? size : this.attrs.size; this.panel.className = YTMA.DB.playerSize.$get(this.attrs.ratio, this.attrs.size); }, time: function () { try { var m = this.parent.data.uri.match(YTMA.reg.time).slice(1, 3); return ((+m[0] || 0) * 60) + (+m[1] || 0); } catch (e) { return 0; } }, findType: function () { if (this.parent.data.site === 'html5-audio') { return 'audio'; } if (YTMA.DB.videoTag[this.parent.data.site]) { return 'video'; } return 'iframe'; }, switchOff: function () { // console.log('removed media'); if (this.media.pause) { console.log('pausing'); this.media.pause(); } try { this.switcher.removeChild(this.channel); } catch (e) { // console.error(e); } this.mode = 'off'; }, switchOn: function () { if (this.attrs.size === 0) { this.attrs.size = YTMA.user.preferences.size; this.parent.ui.resetViewSize(); } // console.log('switch to media'); this.switcher.appendChild(this.channel); this.switcher.dataset.standby = false; this.mode = 'on'; }, switchStandby: function () { // console.log('switch to standby'); this.switchOff(); this.switcher.dataset.standby = true; this.mode = 'standby'; }, isStandby: function () { return this.mode === 'standby'; } }; YTMA.prototype = { constructor: YTMA, getUI: function () { if (!this.ui) { this.ui = new YTMA.UI(this); } return this.ui; }, setup: function () { try { this.dom.mod[this.data.site].call(this); } catch (e) {} this.dom.link.call(this); this.dom.span.call(this); }, disableOpenOnScroll: function () { this.anchor.dataset.ytmscroll = false; }, canScroll: function () { return this.anchor.dataset.ytmscroll === 'true'; }, isBelow: function (link) { return YTMA.Scroll.compare(this.anchor, link) < 1; }, dom: { mod: { // modifies YTMA interface according to site youtube: function () { this.spn.title = 'ytma!'; this.spn.addEventListener('mouseenter', YTMA.events.thumb.start, false); this.spn.addEventListener('mouseleave', YTMA.events.thumb.stop, false); this.spn.style.backgroundImage = ['url(https://i3.ytimg.com/vi/', this.data.id, '/1.jpg)'].join(''); this.achor.href = this.achor.href.replace('http:', 'https:').replace('youtu.be/', 'youtube.com/watch?v='); }, vimeo: function () { this.spn.title = 'vimeo too!'; }, vine: function () { this.spn.title = 'vine me!'; this.achor.href = this.achor.href.replace('http:', 'https:'); }, soundcloud: function () { this.spn.title = 'sound off!'; this.achor.href = this.achor.href.replace('http:', 'https:'); }, html5: function () { this.spn.title = 'html5 go!'; }, gfycat: function () { this.spn.style.backgroundImage = ['url(https://thumbs.gfycat.com/', this.data.id, '-poster.jpg)'].join(''); this.spn.title = 'gfycat meow!'; this.achor.href = this.achor.href.replace('http:', 'https:'); }, imgur: function () { this.spn.style.backgroundImage = ['url(https://i.imgur.com/', this.data.id, 'h.jpg)'].join(''); this.spn.title = 'imgur it!'; this.achor.href = this.achor.href.replace('http:', 'https:'); } }, link: function () { if (this.anchor.getElementsByTagName('img').length === 0) { this.anchor.className += ' ytm_link ytm_link_' + this.data.site + ' '; } this.anchor.dataset.ytmid = this.data.id; this.anchor.dataset.ytmuid = this.data.uid; this.anchor.dataset.ytmsid = this.data.sid; this.anchor.title = 'Visit the video page.'; this.anchor.parentNode.insertBefore(this.container, this.anchor.nextSibling); }, span: function () { var f = document.createDocumentFragment(); $$.e('span', {className: 'ytm_init ytm_label ytm_sans ytm_box', textContent: this.spn.title}, this.spn); $$.e('var', {className: 'ytm_label ytm_box', _ytmid: this.data.id, _ytmuid: this.data.uid, _ytmsid: this.data.sid, _ytmsite: this.data.site, textContent: '\u25B6'}, this.spn); this.spn.title = 'Watch now!'; f.appendChild(this.spn); if (YTMA.DB.fn.hasAjax(this.data.site)) { f.appendChild(this.dom.dataLoadLink.call(this)); } if (YTMA.DB.slim[this.data.site]) { this.container.classList.add('ytm_site_slim'); } if (YTMA.DB.scroll[this.data.site]) { this.anchor.classList.add('ytm_scroll'); } this.container.appendChild(f); }, dataLoadLink: function () { var a, s; s = $$.e('span', {className: 'ytm_bd ytm_normalize ytm_manual _' + this.data.sid}); a = $$.e('a', { className: 'ytm_title', textContent: 'Load description.', href: '#', title: 'Load this video\'s description.', _ytmid: this.data.id, _ytmsite: this.data.site, _ytmuri: this.data.uri, _ytmdescription: 'true' }); return $$.a(s, a); } } }; /** * Creates a new YTMA from the given attributes * @String|Number id Unique ID * @String site Website eg: youtube, vimeo * @HTMLAnchorElement a Anchor element */ YTMA.prototype._new = function (id, site, a) { var uid = YTMA.escapeId(id + '_' + (YTMA.num += 1)); this.data = { id: id, uid: YTMA.escapeId(uid), // unique id sid: YTMA.escapeId(id), // shared id site: site, uri: a.href }; this.ui = null; if (!a.hasAttribute('data-ytmscroll')) { a.dataset.ytmscroll = true; } this.anchor = a; this.spn = $$.e('span', {className: 'ytm_trigger ytm_block ytm_normalize ytm_sans', _ytmid: this.data.id, _ytmsite: this.data.site}); this.container = $$.e('div', {id: 'w' + this.data.uid, className: 'ytm_spacer ytm_block ytm_site_' + this.data.site}); return this; }; /** * Recreates a YTMA object from a trigger element * @HTMLElement */ YTMA.prototype._reactivate = function (trigger) { var id = trigger.dataset.ytmid, a = document.querySelector('a[data-ytmuid="' + trigger.dataset.ytmuid + '"]'); this.data = { id: id, uid: trigger.dataset.ytmuid, sid: trigger.dataset.ytmsid, site: trigger.dataset.ytmsite, uri: a.href }; this.ui = null; this.anchor = a; this.spn = trigger.parentElement; this.container = this.spn.parentElement; return this; }; /** S C R O L L CLASS * Window-Scroll Event Helper */ YTMA.Scroll = (function () { function Scroll(selector, cb, delay) { this.selector = selector; this.cb = cb; // console.log('YTMA.Scroll Monitor: ', selector); this.bound = Scroll.debounce(this.monitor.bind(this), delay || 500); this.bound(); window.addEventListener('scroll', this.bound, false); } Scroll.debounce = function (fn, delay) { var timeout; delay = delay || 250; return function () { var self = this, args = arguments, timed; timed = function () { timeout = null; fn.apply(self, args); }; window.clearTimeout(timeout); timeout = window.setTimeout(timed, delay); }; }; Scroll.visible = function (el) { var bound = el.getBoundingClientRect(); return (bound.top >= 0 && bound.top <= document.documentElement.clientHeight); }; Scroll.visibleAll = function (el, offset) { var bound = el.getBoundingClientRect(), height = document.documentElement.clientHeight; offset = isNumber(offset) ? +offset : 0; return ((bound.bottom + offset >= 0) && (bound.top <= height + offset || bound.bottom <= height - offset)); }; /** Returns 1, 0, -1 when el1 is above, exactly the same, or below el2 */ Scroll.compare = function (el1, el2) { var a = el1.getBoundingClientRect().y, b = el2.getBoundingClientRect().y; if (a < b) { return 1; } if (a === b) { return 0; } return -1; }; Scroll.prototype = { stop: function () { // console.log('clear scroll: ', this.selector); window.removeEventListener('scroll', this.bound); }, monitor: function () { $$.s(this.selector, this.cb); } }; return Scroll; }()); YTMA.main(); }());