YouTube Me Again!

ytma! automatically converts YouTube(TM), Vimeo, Vine, Soundcloud, WebM, and MP4 links into real embedded videos.

目前为 2014-07-22 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // Do not modify and re-release this script!
  3. // If you would like to add support for other sites, please tell me and I'll put it in the includes.
  4. //
  5. // @id youtube-me-again
  6. // @name YouTube Me Again!
  7. // @namespace hateradio)))
  8. // @author hateradio
  9. // @version 5.1
  10. // @description ytma! automatically converts YouTube(TM), Vimeo, Vine, Soundcloud, WebM, and MP4 links into real embedded videos.
  11. // @homepage https://userscripts.org/scripts/show/60843
  12. // @icon https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytma32.png
  13. // @icon64 https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytma64.png
  14. // @screenshot https://dl.dropboxusercontent.com/u/14626536/userscripts/i/ytma/ytmascreen5.png
  15.  
  16. // @include https://vine.co/v/*/embed/simple
  17. // @match https://vine.co/v/*/embed/simple
  18.  
  19. // @include https://gfycat.com/iframe/*
  20. // @match https://gfycat.com/iframe/*
  21.  
  22. // @include http://*.neogaf.com/forum/showthread.php*
  23. // @include http://*.neogaf.com/forum/showpost.php?p*
  24. // @include http://*.neogaf.com/forum/newreply.php*
  25. // @include http://*.neogaf.com/forum/editpost.php*
  26. // @include http://*.neogaf.com/forum/private.php*
  27.  
  28. // @match http://*.neogaf.com/forum/showthread.php*
  29. // @match http://*.neogaf.com/forum/showpost.php?p*
  30. // @match http://*.neogaf.com/forum/newreply.php*
  31. // @match http://*.neogaf.com/forum/editpost.php*
  32. // @match http://*.neogaf.com/forum/private.php*
  33.  
  34. // @include http*://*what.cd/forums.php?*viewthread*
  35. // @include http*://*what.cd/torrents.php?*
  36. // @include http*://*what.cd/user.php?*
  37.  
  38. // @match *://*.what.cd/forums.php?*viewthread*
  39. // @match *://*.what.cd/torrents.php?*
  40. // @match *://*.what.cd/user.php?*
  41.  
  42. // @updated 21 July 2014 |
  43. // -updated 24 Aug 2013 | 17,400
  44. // -updated 04 June 2013 | 13,586
  45.  
  46. // @grant GM_xmlhttpRequest
  47. // ==/UserScript==
  48.  
  49. /**
  50.  
  51. Whitelist these sites on NoScript/NotScript/etc.
  52. neogaf.com
  53. youtube.com
  54. youtube-nocookie.com
  55. vimeo.com
  56. vimeocdn.com
  57. vineco.com
  58. soundcloud.com
  59. vine.com
  60. vine.co
  61. gfycat.com
  62. dropboxusercontent.com
  63.  
  64. */
  65.  
  66. /*jslint indent: 4, maxerr: 50, browser: true, devel: true, nomen: true, plusplus: true, regexp: true, newcap: true */
  67.  
  68. (function () {
  69. 'use strict';
  70.  
  71. var $$, strg, update;
  72.  
  73. if (!Function.prototype.bind) {
  74. Function.prototype.bind = function (self) {
  75. var args = [].slice.call(arguments, 1), fn = this;
  76. return function () {
  77. return fn.apply(self, args.concat([].slice.call(arguments)));
  78. };
  79. };
  80. }
  81.  
  82. function isNumber(n) {
  83. return !isNaN(parseFloat(n)) && isFinite(n);
  84. }
  85.  
  86. // DOM Handle
  87. $$ = {
  88. s: function (selector, cb) { var s = document.querySelectorAll(selector), i = -1; while (++i < s.length) { if (cb(s[i], i, s) === false) { break; } } },
  89. o: function (object, cb) { var i; for (i in object) { if (object.hasOwnProperty(i)) { if (cb(i, object[i], object) === false) { break; } } } },
  90. a: function (e) { var i = 1, j = arguments.length, f = document.createDocumentFragment(); for (i; i < j; i++) { f.appendChild(arguments[i]); } e.appendChild(f); return e; },
  91. e: function (t, o, e, p) { var a, b, c = document.createElement(t); if (typeof (o) === 'object') { for (a in o) { if (o.hasOwnProperty(a)) { b = a.charAt(0); switch (b) { case '_': c.style[a.substring(1)] = o[a]; break; case '$': c.setAttribute(a.substring(1), o[a]); break; default: c[a] = o[a]; break; } } } } if (e && p) { c.appendChild(e); } else if (e) { e.appendChild(c); } return c; }
  92. };
  93.  
  94. // S T O R A G E HANDLE
  95. strg = {
  96. on: (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; } }()),
  97. read: function (key) { return this.on ? JSON.parse(localStorage.getItem(key)) : false; },
  98. save: function (key, val) { return this.on ? !localStorage.setItem(key, JSON.stringify(val)) : false; },
  99. wipe: function (key) { return this.on ? !localStorage.removeItem(key) : false; },
  100. zero: function (o) { var k; for (k in o) { if (o.hasOwnProperty(k)) { return false; } } return true; },
  101. grab: function (key, def) { var s = strg.read(key); return strg.zero(s) ? def : s; }
  102. };
  103.  
  104. // U P D A T E HANDLE
  105. update = {
  106. name: 'ytma!',
  107. version: 5100,
  108. key: 'ujs_YTMA_UPDT_HR',
  109. callback: 'ytmaupdater',
  110. page: 'https://greasyfork.org/scripts/1023-youtube-me-again',
  111. 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.
  112. interval: 5,
  113. day: (new Date()).getTime(),
  114. time: function () { return new Date(this.day + (1000 * 60 * 60 * 24 * this.interval)).getTime(); },
  115. top: document.head || document.body,
  116. css: function (t) {
  117. if (!this.style) {
  118. this.style = document.createElement('style');
  119. this.style.type = 'text/css';
  120. this.top.appendChild(this.style);
  121. }
  122. this.style.appendChild(document.createTextNode(t + '\n'));
  123. },
  124. js: function (t) {
  125. var j = document.createElement('script');
  126. j.type = 'text/javascript';
  127. j[/^https?\:\/\//i.test(t) ? 'src' : 'textContent'] = t;
  128. this.top.appendChild(j);
  129. },
  130. notification: function (j) {
  131. if (j) {
  132. if (this.version < j.version) {
  133. window.localStorage.setItem(this.key,
  134. JSON.stringify({date: this.time(), version: j.version, page: j.page }));
  135. } else {
  136. return true;
  137. }
  138. }
  139. var a = document.createElement('a'), b = JSON.parse(window.localStorage.getItem(this.key));
  140. a.href = b.page || '#';
  141. a.target = '_blank';
  142. a.id = 'userscriptupdater';
  143. a.title = 'Update now.';
  144. a.textContent = 'An update for ' + this.name + ' is available.';
  145. document.body.appendChild(a);
  146. return true;
  147. },
  148. check: function (opt) {
  149. if (!strg.on) { return; } // typeof (GM_updatingEnabled) === 'boolean' ||
  150. var stored = strg.read(this.key), j, page;
  151. this.csstxt();
  152. if (opt || !stored || stored.date < this.day) {
  153. page = stored && stored.page ? stored.page : '#';
  154. strg.save(this.key, {date: this.time(), version: this.version, page: page});
  155. j = this.notification.toString()
  156. .replace('function', 'function ' + this.callback)
  157. .replace('this.version', this.version)
  158. .replace(/(?:this\.key)/g, "'" + this.key + "'")
  159. .replace('this.time()', this.time())
  160. .replace('this.name', "'" + this.name + "'");
  161. this.js(j);
  162. this.js(this.uric);
  163. } else if (this.version < stored.version) { this.notification(); }
  164. },
  165. csstxt: function () {
  166. 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}'); }
  167. }
  168. };
  169.  
  170. /** Y T M A CLASS
  171. * Should not be used directly, only through YTMA.create()
  172. * @param id Unique ID
  173. * @param site Website eg: youtube, vimeo
  174. * @param a Anchor element
  175. */
  176. function YTMA(id, site, a, uid) {
  177. this.data = {
  178. id: id,
  179. uid: YTMA.escapeId(uid),
  180. sid: YTMA.escapeId(id),
  181. site: site,
  182. uri: a.href
  183. };
  184.  
  185. this.a = a;
  186. this.spn = $$.e('span', {title: 'YTMA!', className: 'ytm_links', '$data-ytmid': this.data.id, '$data-ytmuid': this.data.uid});
  187. this.spn.addEventListener('click', this.show.bind(this), false);
  188. this.wrp = $$.e('div', {className: 'ytm_wrap'});
  189. this.wrs = $$.e('div', {id: 'w' + this.data.uid, className: 'ytm_clear ytm_site_' + this.data.site});
  190. this.ul = $$.e('ul', {className: 'ytm_bar arialsans'});
  191.  
  192. this.setup(a);
  193. }
  194.  
  195. YTMA.num = 0;
  196.  
  197. YTMA.create = function (link) {
  198. var data = YTMA.getIdAndSite(link.href), id;
  199. if (data.valid === true) {
  200. id = YTMA.escapeId(data.id + '_' + (YTMA.num += 1));
  201. YTMA.set[id] = new YTMA(data.id, data.site, link, id);
  202. return YTMA.set[id];
  203. }
  204. return {};
  205. };
  206.  
  207. YTMA.getIdAndSite = function (uri) {
  208. var id, site;
  209. try {
  210. site = YTMA.reg.siteByTest[YTMA.reg.site.test(uri) ? RegExp.lastMatch : ''];
  211. // console.log(uri, site);
  212. if (site === 'html5') {
  213. id = uri.slice(-15);
  214. } else if (site === 'soundcloud') {
  215. id = YTMA.escapeId(uri).slice(-50);
  216. } else {
  217. id = uri.match(YTMA.reg.matchers[site])[1];
  218. }
  219.  
  220. if (id && YTMA.DB.sites[site]) {
  221. return {id: id, site: site, valid: true};
  222. }
  223. throw TypeError('invalid id/site: ' + site + ' % ' + id);
  224. } catch (e) {
  225. // console.info(uri, e);
  226. return {valid: false};
  227. }
  228. };
  229.  
  230. YTMA.route = {
  231. host: document.location.host,
  232. control: {
  233. go: function (host) {
  234. (this[host] || this.generic)();
  235. },
  236. generic: function () {
  237. if (!YTMA.DB.extension) {
  238. update.check();
  239. }
  240.  
  241. YTMA.user.init();
  242. YTMA.css();
  243. YTMA.ajaxQueue.init();
  244. YTMA.factory();
  245. },
  246. 'gfycat.com': function () {
  247. update.css('body,html {overflow:hidden} video {width: 100% }');
  248. },
  249. 'vine.co': function () {
  250. // console.log('vine.co');
  251. // YTMA.user.init();
  252. // if (YTMA.user.preferences.autoShow === 1) { return; }
  253.  
  254. var video = document.getElementById('video');
  255. if (video) { video.muted = false; }
  256. }
  257. },
  258. start: function () {
  259. this.control.go(this.host);
  260. }
  261. };
  262.  
  263. YTMA.main = function () {
  264. if (!this.initializer) {
  265. this.initializer = true;
  266. YTMA.route.start();
  267. }
  268. };
  269.  
  270. YTMA.set = {};
  271.  
  272. YTMA.collect = function (id) {
  273. var i, a = [];
  274. for (i in YTMA.set) {
  275. if (YTMA.set.hasOwnProperty(i) && YTMA.set[i].data.id === id) {
  276. a.push(YTMA.set[i]);
  277. }
  278. }
  279. return a;
  280. };
  281.  
  282. YTMA.reg = {
  283. site : /(youtu)|(vimeo)|(vine)|(soundcloud)|(gfycat)|(\.webm$)|(\.mp4$)/,
  284. time : /(?:t\=(?:(\d+)m)?(\d+)?s?)/,
  285. ios : /(?:\b(?:ipod|iphone|ipad))\b/i,
  286. matchers: {
  287. youtubeOld: /(?:(?:youtu)(?:\.be\/|.*?(?:v\=|#p\/u\/\d*?\/)|.*?(?:v\=|#p\/c\/[a-zA-Z0-9]+\/\d*?\/)|.*?(?:embed\/))([A-Za-z0-9-_]{11}))/i,
  288. youtube: /(?:(?:(?:v\=|#p\/u\/\d*?\/)|(?:v\=|#p\/c\/[a-zA-Z0-9]+\/\d*?\/)|(?:embed\/)|(?:\.be\/))([A-Za-z0-9-_]{11}))/i,
  289. vimeo: /(?:vimeo\.com\/(\d+))/i,
  290. vine: /(?:vine\.co\/v\/([A-Za-z0-9-_]{11}))/i,
  291. soundcloud: /(?:soundcloud\.com\/(.+?\/.+))/i,
  292. gfycat: /(?:gfycat.com\/(\w+))/i // /(?:gfycat.com\/(.+)(?!\.))/i
  293. },
  294. siteByTest: {
  295. youtu: 'youtube',
  296. vimeo: 'vimeo',
  297. vine: 'vine',
  298. gfycat: 'gfycat',
  299. '.webm': 'html5',
  300. '.mp4': 'html5',
  301. soundcloud: 'soundcloud'
  302. }
  303. };
  304.  
  305. YTMA.img = {
  306. fav: {
  307. soundcloud : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNp0UjFOw0AQnD3bCYaEoIgiUIQKikiAKKGgSAkFL0BQ0FEgUfECShpewB+QEE+gokDiBxGRiCCEBBzHd8ucLYGQ4Kw7+9azc7OzJ6oKnFYUxgD+W/DHYNA54GIooifTitYqg1okaPFff6BcTLF5fECYb5IJNJ3kMfUP2dxHPycwcQ0SliARocSGsA46YkKWQW0GS6BDAGlu5Myu84AgSmHKM/DY0NegwwR2+AJrSjBre5BaA1H7GFKpI729QHp9jqiaeTBn5mB7fWirjWB9B9JYBrwEMnop5d0zfD53YO9vYMY8SQcpZGkTZvsIstiivDfoaxfIxt8exYeXCLYOSOwlJZQ6twSpL0DfX4EoZtkCqc7/Njalbxnfdt+oSwhurkBnCWI/1FlgqgKNZ3JnZDSA3FFSpYdQAoF56tKNDmhOYTzJ3OSHXZkflJhYEyawcnH02HpmxZ+DrRJlgmacvrsHRmHln2tRnIiAy5WTLwEGAK4QoBQmtGHkAAAAAElFTkSuQmCC',
  308. youtube : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAABUUlEQVQ4y8WTP0sDQRDFf3e3iQlBIQeCYAgaEVGMTRr9AKnERtTCwg9hYWkRBBEFEf+g4OcwgWgTRSy0EhTBKmAnsYiex2Yva2GUZCMRKxceu8O893YGZuC/j3XlxqLAMTACpIHwL5pbQAJ3k5W3JaE0q8DiHz5NN+7MRTz2ZCt0VqFpRhAOMbR3SCiVwswZyNo1SNaAZgSRCO7cAhOnJeKz85j5JiRtqXGlhma818H3faRtM7i9y8DWDqorgsmTGldIcNrb1Hie9x11T8+QCAIeV5ZNoiNqWrfL660GL+UypYN9Ej9whYQAowqNxvd9AO4Lec7X1xiVPtKyTH0gpKYC9LYYqDpetcrZ5gbP+RPGhY2DhWwvoGId9USvgUyLLXApFcPCoc+2Os3EjVDoomkAMBX+7EqhOxkUhdLkgH5g7GvCOggegNfGuwDk/n0Z+QAjkqDhSKnyRwAAAABJRU5ErkJggg==',
  309. vimeo : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABhQTFRFutjhDKrTKqzN+Pz9H5CxT7nVis7g////lqc5nAAAAAh0Uk5T/////////wDeg71ZAAAAP0lEQVR42iTMyREAMAgCQASP/jsOGj7s8AATPxzwUDai0AG1SQhsYdeEolVLt8c8llZHYuXyTeb9YYo/8wQYAC81AOQXjj+CAAAAAElFTkSuQmCC',
  310. vine : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABcklEQVQ4jX2SvyvFYRTGP+9NdzAYbpIkysA/ICnKoEwvA4vlUkoyGQzvoOiK4R0YbDLhDhbi9maWIjEqcScWkyRhMNzXcM/3On39OMt5nvOe85wfvSbGyH9mgs8Cq8AUkAMegU1gJVpXqfu3umpbwITiLUBB8HJGuryb4KMJ/izVvUMVnwNjwJPwGYCMkLL4zlT3XoUL0boD4FBNUhO4Fd9ogm9SRVmFn8Una79qgWuV2K3wvcLJdG3iL7TaiUocAI4Fn0vnHDBrgt+L1g2q3NoEl8CH4KHkMVr3CSwI7QeOTPA9WsAk/8AEvw+MSrwrWleuJQVfABZJWbTOZBTfVXg6lbgEHKjQTcL1BFngAWimeuH2aN2LvHUDV1JcjNbl0zdI9l0T2pDsboKvB7Yl/ga4X2+gku+AVqAC9AFzwLik5KN1xT8FRGQEOBL6yfdn2onWTZKyTDoQrSsB60KT4lNSh/1TQETmgQ1ZowQMy41+2BeLRXeRaKuHSAAAAABJRU5ErkJggg=='
  311. },
  312. css: {
  313. load : 'data:image/gif;base64,R0lGODlhDgAKAJEAAP///+BKV////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAADgAKAAACHFSOeQYI71p6MtAJz41162yBH+do5Ih1kKG0QgEAIfkEBQoAAgAsAAABAA0ACAAAAhSUYGEoerkgdIzKGlu2ET/9ceJmFAAh+QQFCgACACwAAAEADQAIAAACFJRhcbmiglx78SXKYK6za+NxHyYVACH5BAUKAAIALAAAAQANAAgAAAIWVCSAl+hqEGRTLhtbdvTqnlUf9nhTAQAh+QQFCgACACwAAAEADQAIAAACFZRiYCh6uaCRzNXYsKVT+5eBW3gJBQAh+QQJCgACACwAAAAADgAKAAACGpSPaWGwfZhwQtIK8VTUvuxpm9Yp4XlmpiIUADs='
  314. }
  315. };
  316.  
  317. YTMA.selector = {
  318. 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*="soundcloud.com/"]',
  319. parentBlacklist: ['.smallfont', '.colhead_dark', '.spoiler'],
  320. chromeBlacklist: 'a[href*="pomf.se/"]'
  321. };
  322.  
  323. YTMA.selector.ignore = (function (all, blacklist) {
  324. var i, j, ignore = [];
  325. for (i = 0; i < blacklist.length; i++) {
  326. for (j = 0; j < all.length; j++) {
  327. ignore.push(blacklist[i] + ' ' + all[j]);
  328. }
  329. }
  330. //console.log(ignore);
  331. return ignore.join(',');
  332. }(YTMA.selector.all.split(','), YTMA.selector.parentBlacklist));
  333.  
  334. YTMA.links = (function () {
  335. var links = [];
  336. $$.s(YTMA.selector.ignore, function (el) { el.setAttribute('ytmaignore', true); });
  337.  
  338. if (window.chrome) {
  339. $$.s(YTMA.selector.chromeBlacklist, function (el) {
  340. if (/(?:.\webm)/i.test(el.href)) {
  341. el.dataset.scroll = false;
  342. }
  343. });
  344. }
  345.  
  346. $$.s(YTMA.selector.all, function (el) { if (!el.hasAttribute('ytmaignore')) { links.push(el); } });
  347. return links;
  348. }());
  349.  
  350. YTMA.factory = function () {
  351. if (YTMA.links.length === 0) { return; }
  352.  
  353. YTMA.links.forEach(YTMA.create);
  354.  
  355. if (YTMA.user.preferences.desc === 1) {
  356. YTMA.user.fn.onScrollViewDescriptions();
  357. }
  358.  
  359. if (YTMA.user.preferences.desc === 2) {
  360. YTMA.ajax.start();
  361. }
  362.  
  363. if (YTMA.user.preferences.autoShow === 1) {
  364. YTMA.user.fn.onScrollViewMedia();
  365. }
  366. };
  367.  
  368. YTMA.escapeId = function (id) {
  369. return (id += '').replace(/(?:\W)/g, '_');
  370. };
  371.  
  372. /**
  373. * User Preferences
  374. * flash: 0 "Frame"; 1 "Object"
  375. * size: Small (240p), Medium (360p), Large (480p), XL (720p)
  376. * ratio: 1 4:3, 2 16:9
  377. * quality: 240, 360, 480, 720, 1080
  378. * focus: 0/1; Will attempt to set the window's focus near the video
  379. * autoShow: 0/1; Will automatically display HTML5 videos, which currently lack descriptions and thumbnails
  380. * desc: (Descriptions) 0 None; 1 Yes on scroll; 2 Yes all at once
  381. */
  382. YTMA.user = {
  383. init: function () {
  384. this.load();
  385. if (strg.on) {
  386. this.form();
  387. this.mark();
  388. }
  389. },
  390. valid: {
  391. focus: [0, 1],
  392. desc: [0, 1, 2],
  393. flash: [0, 1],
  394. ratio: [1, 2],
  395. size: [240, 360, 480, 720],
  396. quality: [240, 360, 480, 720, 1080],
  397. autoShow: [0, 1]
  398. },
  399. validate: function (property, n) {
  400. n = +n;
  401. return YTMA.user.valid[property].indexOf(n) > -1 ? n : YTMA.user.defaults()[property];
  402. },
  403. defaults: function () {
  404. return {
  405. focus : 0,
  406. desc : 1,
  407. flash : YTMA.DB.browser.pod || YTMA.DB.browser.ie ? 0 : 1, // if iOS or IE9+, use "html5" player
  408. ratio : 2,
  409. size : 360,
  410. quality : 360,
  411. autoShow : 1
  412. };
  413. },
  414. load: function () {
  415. var s = strg.grab('ytmasetts', {});
  416. YTMA.user.preferences = {
  417. flash : YTMA.user.validate('flash', s.flash),
  418. size : YTMA.user.validate('size', s.size),
  419. ratio : YTMA.user.validate('ratio', s.ratio),
  420. desc : YTMA.user.validate('desc', s.desc),
  421. focus : YTMA.user.validate('focus', s.focus),
  422. quality : YTMA.user.validate('quality', s.quality),
  423. autoShow : YTMA.user.validate('autoShow', s.autoShow)
  424. };
  425. // console.log(YTMA.user.preferences);
  426. },
  427. save: function (evt) {
  428. var e = evt.target;
  429. if (e.tagName.toLowerCase() === 'input') {
  430. switch (e.name) {
  431. case 'ytmaflash':
  432. YTMA.user.preferences.flash = +e.checked;
  433. break;
  434. case 'ytmasize':
  435. YTMA.user.preferences.size = +e.value;
  436. break;
  437. case 'ytmaratio':
  438. YTMA.user.preferences.ratio = +e.value;
  439. break;
  440. case 'ytmainfo':
  441. YTMA.user.preferences.desc = +e.value;
  442. break;
  443. case 'ytmafocus':
  444. YTMA.user.preferences.focus = +e.checked;
  445. break;
  446. case 'ytmaiq':
  447. YTMA.user.preferences.quality = +e.value;
  448. break;
  449. case 'ytmaautoshow':
  450. YTMA.user.preferences.autoShow = +e.checked;
  451. break;
  452. default:
  453. return;
  454. }
  455. YTMA.user.error.className = strg.save('ytmasetts', YTMA.user.preferences) ? 'ytm_none' : '';
  456. YTMA.user.load();
  457. // console.log('n', YTMA.user.preferences);
  458. }
  459. },
  460. mark: function () {
  461. var a = {};
  462. a.ytmaflash = !!YTMA.user.preferences.flash;
  463. a.ytmafocus = !!YTMA.user.preferences.focus;
  464. a.ytmaautoshow = !!YTMA.user.preferences.autoShow;
  465. a['ytmaratio' + YTMA.user.preferences.ratio] = true;
  466. a['ytmasize' + YTMA.user.preferences.size] = true;
  467. a['ytmainfo' + YTMA.user.preferences.desc] = true;
  468. a['ytmaiq' + YTMA.user.preferences.quality] = !!YTMA.user.preferences.quality;
  469. $$.o(a, function (id, bool) {
  470. try {
  471. document.getElementById(id).checked = bool;
  472. } catch (e) {}
  473. });
  474. },
  475. reset: function () {
  476. YTMA.user.preferences = YTMA.user.defaults();
  477. YTMA.user.mark();
  478. strg.wipe('ytmasetts');
  479. },
  480. form: function () {
  481. var f = [
  482. '<div id="ytm_settings"><form action=""><div id="ytm_settingst">ytma! Site Settings</div><div id="ytmaclears">',
  483. '<fieldset><legend title="Load descriptions from the content sever.">Get Descriptions</legend><p><span class="ytmahalf"><input id="ytmainfo0" type="radio" value="0" name="ytmainfo"><label for="ytmainfo0">Never</label></span><span class="ytmahalf"><input id="ytmainfo1" type="radio" value="1" name="ytmainfo"><label for="ytmainfo1" title="Load descriptions as they become visible on the screen.">Automatically</label></span><span style="display:inline-block"><input id="ytmainfo2" type="radio" value="2" name="ytmainfo"><label for="ytmainfo2" title="Add descriptions when the page loads.">On page load <small>(Old Method)</small></label></span></p></fieldset>',
  484. '<fieldset><legend>Flash Support</legend><p><input name="ytmaflash" type="checkbox" id="ytmaflash" value="f" /><label for="ytmaflash">Use Flash.*</label></p></fieldset>',
  485. '<fieldset id="ytmasizefield"><legend>Player Size</legend><p><span class="ytmahalf"><input type="radio" name="ytmasize" value="240" id="ytmasize240" /><label for="ytmasize240">S <small>240p</small></label></span><span class="ytmahalf"><input name="ytmasize" type="radio" id="ytmasize360" value="360" /><label for="ytmasize360">M <small>360p</small></label></span><span class="ytmahalf"><input type="radio" name="ytmasize" value="480" id="ytmasize480" /><label for="ytmasize480">L <small>480p</small></label></span><span class="ytmahalf"><input type="radio" name="ytmasize" value="720" id="ytmasize720" /><label for="ytmasize720">X <small>720p</small></label></span></p></fieldset>',
  486. '<fieldset><legend>Quality</legend><p><span class="ytmahalf"><input name="ytmaiq" value="240" id="ytmaiq240" type="radio"><label for="ytmaiq240">240p</label></span><span class="ytmahalf"><input name="ytmaiq" id="ytmaiq360" value="360" type="radio"><label for="ytmaiq360">360p</label></span><span class="ytmahalf"><input name="ytmaiq" value="480" id="ytmaiq480" type="radio"><label for="ytmaiq480">480p</label></span><span class="ytmahalf"><input name="ytmaiq" value="720" id="ytmaiq720" type="radio"><label for="ytmaiq720">720p</label></span><span class="ytmahalf"><input name="ytmaiq" value="1080" id="ytmaiq1080" type="radio"><label for="ytmaiq1080">1080p</label></span></p></fieldset>',
  487. '<fieldset><legend>Aspect Ratio</legend><p><span class="ytmahalf"><input name="ytmaratio" type="radio" id="ytmaratio2" value="2" /><label for="ytmaratio2">16:9</label></span><span class="ytmahalf"><input type="radio" name="ytmaratio" value="1" id="ytmaratio1" /><label for="ytmaratio1">4:3</label></span></p></fieldset>',
  488. '<fieldset><legend>Player On Scroll</legend><p><input name="ytmaautoshow" id="ytmaautoshow" type="checkbox"><label for="ytmaautoshow">Automatically display WebM/MP4 <code>&lt;video&gt;</code>s, Vine and Soundcloud players.</label></p></fieldset>',
  489. '<fieldset><legend>Window Focus</legend><p><input name="ytmafocus" type="checkbox" id="ytmafocus" value="focus" /><label for="ytmafocus">After clicking the thumbnail, set the video at the top of the window.</label></p></fieldset>',
  490. '</div><p><small id="ytm_settings_error" class="ytm_none">Error! Your settings could not be saved.</small></p><p id="ytm_opts"><small id="ytmaclose">Close</small> <small id="ytmareset">Reset</small> <small>*Disable this option for iOS and other devices.</small></p></form></div>'
  491. ].join('');
  492.  
  493. YTMA.form = $$.e('div', {className: 'ytm_fix_center ytm_none', innerHTML: f}, document.body);
  494. YTMA.user.error = document.getElementById('ytm_settings_error');
  495.  
  496. YTMA.form.addEventListener('click', YTMA.user.save, false);
  497. document.getElementById('ytmaclose').addEventListener('click', YTMA.user.fn.formToggle, false);
  498. document.getElementById('ytmareset').addEventListener('click', YTMA.user.reset, false);
  499. document.body.addEventListener('keydown', YTMA.user.fn.formToggleKey, false);
  500. },
  501. fn: {
  502. formToggleKey: function (e) {
  503. // press CTRL+SHIFT+Y (or META instead of CTRL) to display settings form
  504. if ((e.ctrlKey || e.metaKey) && e.shiftKey && String.fromCharCode(e.which).toLowerCase() === 'y') {
  505. e.preventDefault();
  506. YTMA.user.fn.formToggle();
  507. }
  508. },
  509. formToggle: function () {
  510. YTMA.form.classList.toggle('ytm_none');
  511. },
  512. showMedia: function () {
  513. return new YTMA.Scroll('.ytm_scroll:not([data-scroll="false"])', function (link) {
  514. if (YTMA.Scroll.visibleAll(link, 50)) {
  515. $$.s('a[data-ytmsid="' + link.dataset.ytmsid + '"]:not([data-scroll="false"])', function (a) {
  516. var y = YTMA.set[a.dataset.ytmuid];
  517. if (!y.data.open) {
  518. // console.log('show');
  519. y.show();
  520. }
  521. });
  522. }
  523. });
  524. },
  525. toggleMedia: function () {
  526. return new YTMA.Scroll('.ytm_wrap .ytm_player', function (div) {
  527. var v = div.querySelector('video'),
  528. paused = v && (v.paused || v.ended),
  529. y = YTMA.set[div.dataset.ytmuid];
  530.  
  531. if (paused && !YTMA.Scroll.visibleAll(div, 0)) {
  532. return y.player.switchToPlaceholder();
  533. }
  534.  
  535. if (y.player.isPlaceholder() && YTMA.Scroll.visibleAll(div, 200)) {
  536. return y.player.switchToMedia();
  537. }
  538.  
  539. // todo ascertain embedded player properties
  540. // f = div.querySelector('iframe, object');
  541. // if (f && !YTMA.Scroll.visibleAll(div, 200)) {
  542. // y.toggle();
  543. // }
  544. });
  545. },
  546. onScrollViewMedia: function () {
  547. this.showMedia();
  548. this.toggleMedia();
  549. },
  550. onScrollViewDescriptions: function () {
  551. var scroller = new YTMA.Scroll('.ytm_manual a:not(.ytm_error)', function (a) {
  552. if (YTMA.Scroll.visibleAll(a, 200)) {
  553. var d = a.dataset;
  554. YTMA.ajax.load(d.site, d.id, d.uri);
  555. // console.log('doc', document.querySelectorAll(scroller.selector).length, a.dataset.id);
  556. }
  557.  
  558. if (document.querySelectorAll(scroller.selector).length === 0) {
  559. scroller.stop();
  560. }
  561. });
  562. }
  563. }
  564. };
  565.  
  566. YTMA.css = function () {
  567. update.css(['\n/* ytma! */\n.ytm_clear,.ytm_wrap,.ytm_video{position:relative;clear:both;text-align:left;border:0;margin:0;padding:0;display:block}.ytm_clear{overflow:auto;margin:0 0 6px}#ytm_settings,.arialsans{font-family:Arial,Helvetica,sans-serif!important}.ytm_links{line-height: 1.2;display:block;width:118px;height:66px;overflow:hidden;font-style:normal;background-color:#262626!important;cursor:pointer;background-position:-1px -12px;position:relative;float:left;box-shadow:2px 2px rgba(0, 0, 0, 0.3);margin:4px;background-size:auto 90px !important;}.ytm_links:hover{box-shadow: 2px 2px #9eae9e;opacity:.95}.ytm_links img{border:0;opacity:1;top:28px;left:42px;z-index:9;position:absolute}.ytm_links:hover img{opacity:.9}.ytm_init{display:block;background:rgba(11, 11, 11, 0.62);color:#fff;text-shadow:#333 0 0 2px;text-align:left;font-size:11px;margin:0;padding:3px 6px;height:12px;}.ytm_wrap{overflow:hidden;font-style:normal;margin:3px 0 0;padding:1px 2px} ul.ytm_bar{overflow:hidden;margin:0 !important;padding:3px 0 1px;list-style-position:outside !important}.ytm_bar li{display: inline;margin:0!important;padding:0!important}.ytm_bar li > ul {display: inline-block; margin: 0; padding: 0 1px 0 0;}.ytm_bar 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, #222222);margin:0 !important;padding:5px 9px 3px !important}.ytm_bar li ul li:first-child{border-radius:2px 0 0 2px}.ytm_li_mid{border-left:0!important}.ytm_bar li ul li:last-child{border-left:0!important;border-radius:0 2px 2px 0;margin:0 2px 0 0 !important}.ytm_bar li ul li:first-child:last-child{border-radius: 2px;}.ytm_li_setting{border-radius:2px}.ytm_bar li ul li:hover{color:#ccc;text-shadow:1px 1px 0 #333;background:#181818} .ytm_bar li ul li[id]{color:#ddd;text-shadow:0 0 2px #444} .ytm_loading{font-style:italic;background:url(', YTMA.img.css.load, ') 0 3px no-repeat;padding: 1px 1.5em}.ytm_link{background:url(', YTMA.img.fav.youtube, ') 2px -1px no-repeat !important;border-radius:1px;padding:0 3px 0 21px !important}.ytm_link.ytm_link_vimeo{background:url(', YTMA.img.fav.vimeo, ') 3px 2px no-repeat !important;padding:0 3px 0 16px !important}.ytm_link.ytm_link_vine{background:url(', YTMA.img.fav.vine, ') 3px 2px no-repeat !important;background-size: 10px 10px !important;padding:0 3px 0 16px !important}.ytm_link.ytm_link_soundcloud{background:url(', YTMA.img.fav.soundcloud, ') 1px 1px no-repeat !important;padding:0 0 0 16px !important}.ytm_link b,.ytm_link strong{font-weight:400!important}.ytm_link u{text-decoration:none}.ytm_link i,.ytm_link em{font-style:normal}.ytm_link:hover{background-color:#fff}.ytm_title{float:left;max-width:500px;font-style:normal;font-weight:700;margin:5px 0 0 3px;font-size:.9em}.ytm_error{color:#CC2F24;font-style:italic} q[ondblclick]{cursor:pointer}.ytm_descr{display:block;word-wrap:break-word;font-weight:400;max-height:48px;overflow:auto;padding-right:20px}.ytm_descr_open{resize:both;white-space:pre-line;}.ytm_descr_open[style]{max-height:none}#ytm_settings{z-index: 99999;font-size:12px;max-width:410px;border-radius:3px;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:10% auto;padding:4px 8px 0}#ytm_settings *{font-weight:400}#ytm_settings p{font-size:12px;clear:both;margin:5px 0;padding:0}#ytmaclears{overflow:hidden}#ytm_settings fieldset{vertical-align:top;border-radius:3px;border:1px solid #ccc;display:inline-block;width:180px;margin:0 2px}#ytm_settings p>input{margin:3px 3px 0 4px !important}#ytm_settings p>span>input[type=radio]{margin:3px 5px!important}#ytm_settingst{font-size:14px;border-bottom:1px solid #D00;margin:3px 0 9px;padding:0 3px 3px}#ytm_settings .ytmahalf{width:80px;display:inline-block}#ytm_settings .ytmahalf label{width:50px;display:inline-block;cursor:pointer}#ytm_settings_error{font-weight:700;color:#d00}#ytm_settings small{font-size:11px}#ytm_opts small[id]{cursor:pointer;display:inline-block;margin:10px 5px 8px 2px;padding:0 3px; border: 1px solid #adadad; border-radius:2px}#ytm_opts small[id]:hover{background:#ddd}.ytm_none,.ytm_link br{display:none} .ytm_fix_center {position:fixed; left:0; top:0; height:90%; width:90%}',
  568. '.ytm_video{background:#000}.ytm_placeholder[data-empty="true"]{background:#111}.ytm_placeholder[data-empty="true"]:after{cursor:cell; color: #0E0E0E; content: "YTMA!"; display: block; font-size: 85px; font-style: italic; font-weight: bold; left: 50%; position: absolute; text-shadow:2px 1px #181818, -1px -1px #0A0A0A; top: 50%; transform: translate(-50%, -50%); }',
  569. '.ytm_player_s .ytm_video {width:426px;height:240px} .ytm_player_m .ytm_video {width:640px;height:360px} .ytm_player_l .ytm_video {width:853px;height:480px} .ytm_player_xl .ytm_video {width:1280px;height:720px}',
  570. '.ytm_player_s.ytm_player_sd .ytm_video{width:320px} .ytm_player_m.ytm_player_sd .ytm_video{width:480px} .ytm_player_l.ytm_player_sd .ytm_video{width:640px} .ytm_player_xl.ytm_player_sd .ytm_video{width:960px}',
  571. '.ytm_player_s.ytm_player_pr .ytm_video{height:320px;width:180px} .ytm_player_m.ytm_player_pr .ytm_video{height:480px;width:270px} .ytm_player_l.ytm_player_pr .ytm_video{height:640px;width:360px} .ytm_player_xl.ytm_player_pr .ytm_video{height:960px;width:540px}',
  572. '.ytm_site_vine .ytm_links {background-color:lightgreen !important;background-size: 120px auto !important;}',
  573. '.ytm_site_vine .ytm_player_s .ytm_video{width:240px;height:240px} .ytm_site_vine .ytm_player_m .ytm_video{width:360px;height:360px} .ytm_site_vine .ytm_player_l .ytm_video{width:480px;height:480px} .ytm_site_vine .ytm_player_xl .ytm_video{width:720px;height:720px}',
  574. '.ytm_site_vine .ytm_bar :first-child ul, .ytm_site_soundcloud .ytm_bar ul:not(.ytm_options){display:none} .ytm_site_soundcloud .ytm_video{height: 81px !important;}',
  575. '.ytm_link.ytm_link_html5 {background: none !important;margin:0 4px;padding: 0 !important;} .ytm_clear.ytm_site_slim {display:inline} .ytm_site_slim .ytm_links{background:#E34C26 !important;height: auto;box-shadow: 0 0 2px #FFDB9D inset, 2px 2px rgba(0, 0, 0, 0.3); margin: 0 3px 0 0;width: auto; transition:all 0.3s ease-in-out 0s} .ytm_site_slim .ytm_links:hover { opacity:.8 } .ytm_site_slim .ytm_init{background:transparent;text-shadow:0 0 1px #f06529;border: 1px solid #f06529; padding: 2px 5px}.ytm_init:after{ content: "\\25B6"; float: right; font-size: 110%;line-height:1em; padding: 0 0 0 6px; }',
  576. '.ytm_player_h{height:0 !important;width:0 !important}'].join(''));
  577. };
  578.  
  579. YTMA.ajaxQueue = {
  580. init: function () {
  581. $$.o(YTMA.DB.ajax, function (site) {
  582. YTMA.ajaxQueue.sites[site] = {
  583. set: {},
  584. current: 0,
  585. length: 0,
  586. throttle: null,
  587. timeout: 10000
  588. };
  589. });
  590. },
  591. sites: {},
  592. add: function (site, id, uri) {
  593. if (this.sites[site] && !this.sites[site].set[id]) {
  594. this.sites[site].set[id] = uri;
  595. this.sites[site].length += 1;
  596. }
  597. },
  598. remove: function (site, id) {
  599. if (this.sites[site] && this.sites[site].set[id]) {
  600. delete this.sites[site].set[id];
  601. this.sites[site].length -= 1;
  602. }
  603. }
  604. };
  605.  
  606. YTMA.ajax = {
  607. maxBatch: 50,
  608. interval: 250,
  609. start: function () {
  610. var time = 100;
  611. if (YTMA.ajaxQueue.sites.youtube.length > 100) {
  612. time = 2500;
  613. YTMA.ajaxQueue.sites.youtube.timeout = 15000;
  614. }
  615. $$.o(YTMA.DB.ajax, function (site) { return new YTMA.ajax.Batch(site, time); });
  616. },
  617. load: function (site, id, uri) {
  618. var cache = YTMA.external.dataFromStorage(site, id);
  619. // console.log('load', site, id, uri, cache);
  620.  
  621. if (cache) {
  622. return YTMA.external.populate(cache);
  623. }
  624.  
  625. if (YTMA.DB.csr[site]) {
  626. return this.gmxhr(uri, site, id);
  627. }
  628.  
  629. if (YTMA.DB.ajax[site]) {
  630. uri = YTMA.DB.ajax[site].replace('%key', id).replace('%uri', uri);
  631. return this.xhr(uri, site, id);
  632. }
  633. },
  634. gmxhr: function (uri, site, id) {
  635. if (typeof GM_xmlhttpRequest === 'function') {
  636. // alert('gmxhr starting!');
  637. // console.log('gmxhr starting!');
  638. YTMA.ajax.preProcess(id);
  639. GM_xmlhttpRequest({
  640. method: 'GET',
  641. url: uri,
  642. onload: function (response) {
  643. YTMA.external.parse(response.responseText, site, id);
  644. },
  645. onerror: function () {
  646. // console.log('GM Cannot XHR');
  647. YTMA.ajax.failure.call({id: id});
  648. }
  649. });
  650. } else if (YTMA.DB.extension) {
  651. // console.log('attempting cs xhr');
  652. this.xhr(uri, site, id);
  653. }
  654. },
  655. xhr: function (uri, site, id) {
  656. var x = new XMLHttpRequest();
  657. // console.log('xhr', uri, id, site);
  658.  
  659. YTMA.ajax.preProcess(id);
  660.  
  661. x.onreadystatechange = function () {
  662. if (this.readyState === this.DONE) {
  663. // console.log(this.readyState, this.status);
  664. if (this.status === 200) {
  665. YTMA.external.parse(this.responseText, site, id);
  666. } else if (this.status === 403) {
  667. YTMA.external.populate({site: site, id: id, title: 'Error 403', desc: ''});
  668. YTMA.external.save({site: site, id: id, title: 'Error 403', desc: ''});
  669. } else { // if (this.status >= 400 || this.status === 0) {
  670. YTMA.ajax.failure.call({id: id});
  671. }
  672. }
  673. };
  674.  
  675. try {
  676. x.open('get', uri, true);
  677. x.send();
  678. } catch (e) {
  679. // console.error('Cannot send xhr', e.message);
  680. YTMA.ajax.failure.call({id: id});
  681. }
  682. },
  683. failure: function () {
  684. $$.s('.ytm_title._' + YTMA.escapeId(this.id), function (el) {
  685. var a = el.querySelector('a');
  686. a.dataset.tries = a.dataset.tries ? parseFloat(a.dataset.tries) + 1 : 1;
  687. a.textContent = 'Error, unable to load data. [Retry ' + (a.dataset.tries > 0 ? a.dataset.tries : '') + ']';
  688. a.className = 'ytm_error';
  689. });
  690. },
  691. preProcess: function (id) {
  692. $$.s('.ytm_manual._' + YTMA.escapeId(id) + ' a', function (el) {
  693. el.classList.add('ytm_loading');
  694. el.textContent = 'Loading data . . .';
  695. el.title = 'Retry loading data.';
  696. });
  697. }
  698. };
  699.  
  700. /** B A T C H Class
  701. * Creates and loads Cross-site XHR in batches
  702. * @param site Site
  703. * @param time Milliseconds to start loading the queue
  704. */
  705. YTMA.ajax.Batch = function (site, time) {
  706. this.site = site;
  707. this.queue = YTMA.ajaxQueue.sites[site];
  708. // console.log(site, this.queue);
  709. this.descriptionsFromStorage();
  710. if (YTMA.user.preferences.desc === 2) {
  711. this.pause(time);
  712. }
  713. };
  714.  
  715. YTMA.ajax.Batch.prototype = {
  716. constructor: YTMA.ajax.Batch,
  717. descriptionsFromStorage: function () {
  718. $$.o(this.queue.set, this.loadDescription.bind(this));
  719. },
  720. clear: function () {
  721. // console.log('clear', this.queue.throttle);
  722. window.clearInterval(this.queue.throttle);
  723. },
  724. pause: function (ms) { // console.log('pause queue.throttle');
  725. this.clear();
  726. if (this.queue.length > 0) {
  727. // console.log('throttling: ' + ms);
  728. window.setTimeout(this.start.bind(this), ms);
  729. }
  730. },
  731. start: function () {
  732. this.clear();
  733. // console.log('start', this.queue.length);
  734. this.queue.throttle = window.setInterval(this.loader.bind(this), YTMA.ajax.interval);
  735. },
  736. loader: function () {
  737. if (this.queue.length > 0) {
  738. $$.o(this.queue.set, this.next.bind(this));
  739. } else {
  740. this.clear(); // console.log('loader queue.throttle');
  741. }
  742. },
  743. loadDescription: function (id) { // console.log('current:', id, this.queue.current);
  744. var data = YTMA.external.dataFromStorage(this.site, id);
  745. if (data) {
  746. // console.log('from strg', id);
  747. YTMA.external.populate(data);
  748. YTMA.ajaxQueue.remove(this.site, id);
  749. }
  750. },
  751. next: function (id) { //console.log('nx current:', id, this.queue.length, this.queue.current);
  752. this.queue.current += 1;
  753.  
  754. YTMA.ajax.load(this.site, id, this.queue.set[id]);
  755. YTMA.ajaxQueue.remove(this.site, id);
  756.  
  757. if (this.queue.current > 0 && this.queue.current % YTMA.ajax.maxBatch === 0) {
  758. this.pause(this.queue.timeout);
  759. return false;
  760. }
  761. }
  762. };
  763.  
  764. /** E X T E R N A L Access
  765. * Data from external sites
  766. */
  767. YTMA.external = {
  768. version: 'ytma.4.1.dat',
  769. parse: function (response, site, id) {
  770. if (this.parsers[site]) {
  771. response = YTMA.DB.csr[site] ? response : JSON.parse(response);
  772. this.populate(this.helper.cutDescription(this.parsers[site](response, id)));
  773. }
  774. },
  775. parsers: {
  776. soundcloud: function (j, id) {
  777. return {
  778. site: 'soundcloud',
  779. id: id, //unescape(j.html).match(/tracks\/(\d+)/)[1],
  780. title: j.title,
  781. desc: j.description,
  782. th: j.thumbnail_url //,
  783. // embd: j.html
  784. };
  785. },
  786. vimeo: function (j) {
  787. j = j[0];
  788. return {
  789. site: 'vimeo',
  790. id: j.id,
  791. title: j.title + ' ' + YTMA.external.helper.time(j.duration),
  792. desc: j.description.replace(/<br.?.?>/g, ''),
  793. th: unescape(j.thumbnail_medium)
  794. };
  795. },
  796. youtube: function (j) {
  797. j = j.entry;
  798. var o = {
  799. site: 'youtube',
  800. id: j.media$group.yt$videoid.$t,
  801. error: !j.media$group.yt$duration
  802. };
  803. if (!o.error) {
  804. o.title = j.title.$t + ' ' + YTMA.external.helper.time(j.media$group.yt$duration.seconds);
  805. o.desc = j.media$group.media$description.$t;
  806. }
  807. return o;
  808. },
  809. vine: function (html, id) {
  810. var o, doc = document.implementation.createHTMLDocument("");
  811. doc.documentElement.innerHTML = html;
  812.  
  813. o = {
  814. site: 'vine',
  815. id: id, //doc.querySelector('meta[property="twitter:app:url:googleplay"]').content.split('/').slice(-1),
  816. title: doc.querySelector('meta[property="twitter:title"]').content,
  817. desc: doc.querySelector('meta[property="twitter:description"]').content,
  818. th: doc.querySelector('meta[property="twitter:image"]').content.split('?')[0]
  819. };
  820.  
  821. doc = null;
  822.  
  823. return o;
  824. }
  825. },
  826. set: function (data) {
  827. if (!this.db[data.site]) {
  828. this.db[data.site] = {};
  829. }
  830. this.db[data.site][data.id] = data;
  831. return this.save();
  832. },
  833. unset: function (data) {
  834. // console.log('unset', data.id);
  835. if (data.site) {
  836. delete this.db[data.site][data.id];
  837. return this.save();
  838. }
  839. },
  840. limitDB: function (max) {
  841. var i, x = 0, half = Math.round(max / 2), db = {};
  842.  
  843. if (Object.keys(this.db).length >= max) {
  844. for (i in this.db) {
  845. if (this.db.hasOwnProperty(i)) {
  846. if (x >= half) {
  847. break;
  848. }
  849. db[i] = this.db[i];
  850. x++;
  851. }
  852. }
  853. this.db = db;
  854. }
  855.  
  856. return this.db;
  857. },
  858. save: function () {
  859. return strg.save(this.version, this.limitDB(1200));
  860. },
  861. helper: {
  862. cutDescription: function (data) {
  863. if (data.desc && data.desc.length > 140) {
  864. data.full = data.desc;
  865. data.desc = data.desc.substr(0, 130) + ' . . .';
  866. }
  867. return data;
  868. },
  869. time: function (secs) {
  870. var p = '', H, M, S;
  871. try {
  872. H = Math.floor(secs / 3600) % 60;
  873. M = H ? ('0' + Math.floor(secs / 60) % 60).slice(-2) : Math.floor(secs / 60) % 60;
  874. S = ('0' + secs % 60).slice(-2);
  875. p = [' (', H ? H + ':' : '', M, ':', S, ')'].join('');
  876. } catch (e) {}
  877. return p;
  878. },
  879. thumbnail: function (data) {
  880. $$.s('[data-ytmid="%id"].ytm_links'.replace('%id', data.id), function (el) {
  881. el.setAttribute('style', 'background: url(' + data.th + ')');
  882. });
  883. },
  884. titleToggle: function () {
  885. this.className = this.className === 'ytm_descr' ? 'ytm_descr ytm_descr_open' : 'ytm_descr';
  886. this.textContent = this.textContent.length < 140 ? this.dataset.full : this.dataset.full.substr(0, 130) + ' . . .';
  887. this.removeAttribute('style');
  888. }
  889. },
  890. validate: function (data) {
  891. if (!data || !data.id || data.error) {
  892. return YTMA.ajax.failure.call(data);
  893. }
  894.  
  895. if (data.id && !data.title && !data.desc) {
  896. this.unset(data.id);
  897. return YTMA.ajax.failure.call(data);
  898. }
  899.  
  900. return true;
  901. },
  902. populate: function (data, ignoreValidation) {
  903. if (!ignoreValidation && !this.validate(data)) { return; }
  904.  
  905. this.set(data);
  906.  
  907. if (data.th) { this.helper.thumbnail(data); }
  908.  
  909. $$.s('.ytm_title._' + YTMA.escapeId(data.id), function (el) {
  910. var q;
  911. el.textContent = data.title;
  912. if (data.desc) {
  913. q = $$.e('q', { className: 'ytm_descr', textContent: data.desc }, el);
  914. if (data.full) {
  915. q.dataset.full = data.full;
  916. q.title = 'Click to toggle the length of the description.';
  917. q.ondblclick = YTMA.external.helper.titleToggle;
  918. }
  919. }
  920. });
  921. },
  922. dataFromStorage: function (site, id) {
  923. if (this.db && this.db[site]) {
  924. return this.db[site][id];
  925. }
  926. }
  927. };
  928. YTMA.external.db = strg.grab(YTMA.external.version, {});
  929.  
  930. /** Database */
  931. YTMA.DB = {
  932. extension: window.chrome && window.chrome.extension,
  933. slim: {
  934. html5: true
  935. },
  936. dataless: {
  937. html5: true,
  938. gfycat: true
  939. },
  940. scroll: {
  941. html5: true,
  942. soundcloud: true
  943. },
  944. sites: {
  945. youtube: 'https://www.youtube-nocookie.com/',
  946. vimeo: 'http://vimeo.com/',
  947. vine: 'https://vine.co/',
  948. gfycat: 'https://gfycat.com/',
  949. html5: true,
  950. soundcloud: 'https://soundcloud.com'
  951. },
  952. browser: {
  953. pod: YTMA.reg.ios.test(navigator.userAgent),
  954. ie: !document.body.addEventListener && document.selection // IE, basically | window.navigator.cpuClass
  955. },
  956. player: {
  957. ratio: {
  958. SD: 1,
  959. HD: 2,
  960. PORTRAIT: 3
  961. },
  962. size: {
  963. HIDDEN: 0,
  964. S: 240,
  965. M: 360,
  966. L: 480,
  967. X: 720
  968. }
  969. },
  970. playerSize: {
  971. ratios: {
  972. 1: 'sd',
  973. 2: '',
  974. 3: 'pr'
  975. },
  976. sizes: {
  977. 0 : 'h',
  978. 240 : 's',
  979. 360 : 'm',
  980. 480 : 'l',
  981. 720 : 'xl'
  982. },
  983. get: function (ratio, size) {
  984. return 'ytm_player ytm_player_' + this.ratios[ratio] + ' ytm_player_' + this.sizes[size];
  985. }
  986. },
  987. ratios: {
  988. 1: 3 / 4,
  989. 2: 9 / 16,
  990. 3: 16 / 10
  991. },
  992. sizes: {
  993. 0 : 0,
  994. 240 : 360,
  995. 360 : 640,
  996. 480 : 853,
  997. 720 : 1280
  998. },
  999. qualities: {
  1000. 240 : 'small',
  1001. 360 : 'medium',
  1002. 480 : 'large',
  1003. 720 : 'hd720',
  1004. 1080 : 'hd1080',
  1005. 1081 : 'highres',
  1006. get: function (quality) {
  1007. return this[quality] || this[360];
  1008. }
  1009. },
  1010. ajax: {
  1011. youtube: 'https://gdata.youtube.com/feeds/api/videos/%key?v=2&alt=json',
  1012. vimeo: 'https://vimeo.com/api/v2/video/%key.json',
  1013. soundcloud: 'https://soundcloud.com/oembed?format=json&url=%uri'
  1014. // vine: 'https://vine.co/v/%key'
  1015. },
  1016. csr: { // cross-site request
  1017. vine: true
  1018. },
  1019. sources: {
  1020. html5: function () {
  1021. return [{src: this.parent.data.uri}];
  1022. },
  1023. gfycat: function () {
  1024. return [{type: 'text/html', src: 'https://gfycat.com/iframe/' + this.parent.data.id }, false];
  1025. },
  1026. youtube: function () {
  1027. return [
  1028. {type: 'text/html', src: YTMA.DB.sites[this.parent.data.site] + 'embed/' + this.parent.data.id + '?version=3&theme=dark&color=white&showinfo=1&vq=' + this.$quality + '#at=' + this.$start},
  1029. {type: 'application/x-shockwave-flash', src: YTMA.DB.sites[this.parent.data.site] + 'v/' + this.parent.data.id + '?version=3&theme=dark&color=white&showinfo=1&vq=' + this.$quality + '&start=' + this.$start}
  1030. ];
  1031. },
  1032. vimeo: function () {
  1033. return [{type: 'text/html', src: 'http://player.vimeo.com/video/' + this.parent.data.id + '?badge=0'}, false];
  1034. },
  1035. vine: function () {
  1036. return [{type: 'text/html', src: 'https://vine.co/v/' + this.parent.data.id + '/embed/simple'}, false]; // card
  1037. },
  1038. soundcloud: function () { // https://p1.soundcloud.com/player.swf?referer=&url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F101399476
  1039. return [{type: 'application/x-shockwave-flash', src: 'https://p1.soundcloud.com/player.swf?show_comments=false&url=' + this.parent.data.uri}, false];
  1040. }
  1041. }
  1042. };
  1043.  
  1044. /** P L A Y E R CLASS
  1045. * @param parent YTMA instance
  1046. */
  1047. YTMA.Player = function (parent) {
  1048. this.parent = parent;
  1049. this.$quality = this.$size = this.$ratio = this.$source = null;
  1050. this.$start = this.time();
  1051. this.$quality = YTMA.DB.qualities.get(YTMA.user.preferences.quality);
  1052. this.$source = YTMA.DB.sources[this.parent.data.site].call(this);
  1053.  
  1054. this.$media = this.mediaFrame();
  1055. this.$proxy = $$.e('div', {className: 'ymt_proxy'}, this.$media, true);
  1056. this.$placeholder = $$.e('div', {className: 'ytm_placeholder ytm_video'});
  1057. this.$placeholder.dataset.empty = true;
  1058.  
  1059. this.$player = $$.e('div', {className: 'ytm_player', '$data-ytmuid': this.parent.data.uid}, this.$placeholder, true);
  1060.  
  1061. this.dimmensions(YTMA.user.preferences.ratio, YTMA.user.preferences.size);
  1062. };
  1063.  
  1064. YTMA.Player.prototype = {
  1065. constructor: YTMA.Player,
  1066. dimmensions: function (ratio, size) {
  1067. this.$ratio = isNumber(ratio) ? ratio : this.$ratio;
  1068. this.$size = isNumber(size) ? size : this.$size;
  1069. this.$player.className = YTMA.DB.playerSize.get(this.$ratio, this.$size);
  1070. },
  1071. reset: function () {
  1072. this.dimmensions();
  1073. this.parent.events.select.call(this.parent,
  1074. this.parent.ul.querySelector('li[data-value="' + this.$size + '"]'), 'size');
  1075. },
  1076. time: function () {
  1077. try {
  1078. var m = this.parent.data.uri.match(YTMA.reg.time).slice(1, 3);
  1079. return ((+m[0] || 0) * 60) + (+m[1] || 0);
  1080. } catch (e) { return 0; }
  1081. },
  1082. mediaFrame: function () {
  1083. if (this.parent.data.site === 'html5') {
  1084. return $$.e('video', {
  1085. src: this.$source[0].src,
  1086. controls: true,
  1087. autoplay: false,
  1088. loop: true,
  1089. className: 'ytm_video',
  1090. $allowscriptaccess: true,
  1091. preload: 'metadata'
  1092. });
  1093. }
  1094. if (YTMA.user.preferences.flash === 1 && this.$source[1]) {
  1095. return $$.a($$.e('object', {$type: this.$source[1].type, data: this.$source[1].src, className: 'ytm_video'}),
  1096. $$.e('param', {name: 'movie', value: this.$source[1].src}),
  1097. $$.e('param', {name: 'AllowScriptAccess', value: 'always'}),
  1098. $$.e('param', {name: 'wmode', value: 'opaque'}),
  1099. $$.e('param', {name: 'allowFullScreen', value: 'true'}));
  1100. }
  1101. return $$.e('iframe', {$allowfullscreen: true, $type: this.$source[0].type, src: this.$source[0].src, className: 'ytm_video'});
  1102. },
  1103. removeMedia: function () {
  1104. this.mode = 'remove';
  1105. try {
  1106. this.$placeholder.removeChild(this.$proxy);
  1107. } catch (e) {
  1108. // console.error(e);
  1109. }
  1110. // console.log('removed media');
  1111. },
  1112. switchToMedia: function () {
  1113. if (this.$size === 0) { this.reset(); }
  1114. this.mode = 'media';
  1115. // console.log('switch to media');
  1116. this.$placeholder.appendChild(this.$proxy);
  1117. this.$placeholder.dataset.empty = false;
  1118. },
  1119. switchToPlaceholder: function () {
  1120. this.mode = 'placeholder';
  1121. // console.log('switch to placeholder');
  1122. this.$placeholder.removeChild(this.$proxy);
  1123. this.$placeholder.dataset.empty = true;
  1124. },
  1125. isPlaceholder: function () {
  1126. return this.mode === 'placeholder';
  1127. }
  1128. };
  1129.  
  1130. YTMA.prototype = {
  1131. constructor: YTMA,
  1132. events: {
  1133. videoBar: function (evt) {
  1134. var e = evt.target,
  1135. n = parseInt(e.dataset.value, 10),
  1136. t = e.dataset.type;
  1137.  
  1138. if (e.tagName.toLowerCase() === 'li') { // maybe: this.settings.fire[t].call(this, e, n)
  1139. if (t === 'settings') {
  1140. YTMA.user.fn.formToggle();
  1141. } else if (t === 'close') {
  1142. if (this.data.site === 'html5') {
  1143. this.dom.closeAll(this.data.id);
  1144. } else {
  1145. this.dom.disableOpenOnScroll.call(this);
  1146. this.toggle();
  1147. }
  1148. } else if (t === 'ratio') {
  1149. this.player.dimmensions(n);
  1150. this.events.select.call(this, e, 'ratio');
  1151. } else if (t === 'size') {
  1152. this.player.dimmensions(null, n);
  1153. this.events.select.call(this, e, 'size');
  1154. }
  1155. }
  1156. },
  1157. select: function (e, type) {
  1158. e.id = type + this.data.uid;
  1159. try {
  1160. this.selected[type].removeAttribute('id');
  1161. } catch (er) {}
  1162. this.selected[type] = e;
  1163. },
  1164. manualLoad: function (e) {
  1165. // console.log(this);
  1166. e.preventDefault();
  1167. var d = e.target.dataset;
  1168. YTMA.ajax.load(d.site, d.id, d.uri);
  1169. }
  1170. },
  1171. selected: {
  1172. size: null,
  1173. ratio: null
  1174. },
  1175. setup: function (link) {
  1176. this.dom.mod[this.data.site].call(this, link);
  1177. this.dom.link.call(this, link);
  1178. this.dom.span.call(this);
  1179. },
  1180. dom: {
  1181. closeAll: function (id) {
  1182. var group = YTMA.collect(id);
  1183. // console.log('closing', group.length);
  1184. group.forEach(function (y) {
  1185. // y.dom.disableOpenOnScroll.call(y);
  1186. y.a.dataset.scroll = false;
  1187. y.toggle();
  1188. });
  1189. },
  1190. disableOpenOnScroll: function () {
  1191. this.a.dataset.scroll = false;
  1192. },
  1193. list: function (className, elements) {
  1194. var li = $$.e('li'),
  1195. ul = $$.e('ul', {className: className}, li),
  1196. f = document.createDocumentFragment(),
  1197. i,
  1198. e;
  1199.  
  1200. for (i = 0; i < elements.length; i++) {
  1201. e = elements[i];
  1202. if (e) {
  1203. f.appendChild(this.dom.li.call(this, e.type, e.text, e.value, e.title));
  1204. }
  1205. }
  1206. ul.appendChild(f);
  1207. return li;
  1208. },
  1209. li: function (type, txt, value, title) {
  1210. var l = $$.e('li', {'$data-type': type, textContent: txt, '$data-value': value, title: title});
  1211. if ((type === 'size' && this.player.$size === value) || (type === 'ratio' && this.player.$ratio === value)) {
  1212. this.events.select.call(this, l, type);
  1213. }
  1214. return l;
  1215. },
  1216. link: function (link) {
  1217. if (link.getElementsByTagName('img').length === 0) {
  1218. link.className += ' ytm_link ytm_link_' + this.data.site + ' ';
  1219. }
  1220. link.dataset.ytmid = this.data.id;
  1221. link.dataset.ytmuid = this.data.uid;
  1222. link.dataset.ytmsid = this.data.sid;
  1223. link.title = 'Visit the video page.';
  1224. link.parentNode.insertBefore(this.wrs, link.nextSibling);
  1225. },
  1226. mod: { // modifies the link and other site-specific items
  1227. youtube: function (a) {
  1228. this.spn.title = 'YTMA!';
  1229. this.spn.addEventListener('mouseenter', this.thumb.start.bind(this), false);
  1230. this.spn.addEventListener('mouseleave', this.thumb.stop, false);
  1231. this.spn.style.backgroundImage = ['url(https://i3.ytimg.com/vi/', this.data.id, '/1.jpg)'].join('');
  1232. a.href = a.href.replace('http:', 'https:').replace('youtu.be/', 'youtube.com/watch?v=');
  1233. },
  1234. vimeo: function () {
  1235. this.spn.title = 'Vimeo Me Too!';
  1236. },
  1237. vine: function () {
  1238. this.spn.title = 'Vine Me!';
  1239. },
  1240. soundcloud: function () {
  1241. this.spn.title = 'Sound Off!';
  1242. },
  1243. html5: function () {
  1244. this.spn.title = 'HTML5 Me!';
  1245. },
  1246. gfycat: function () {
  1247. this.spn.style.backgroundImage = ['url(https://thumbs.gfycat.com/', this.data.id, '-poster.jpg)'].join('');
  1248. this.spn.title = 'Gfycat Meow!';
  1249. }
  1250. },
  1251. ui: function () {
  1252. var f = document.createDocumentFragment();
  1253. $$.a(f,
  1254. this.dom.list.call(this, 'ytm_ratios', [
  1255. {type: 'ratio', text: '4:3', value: YTMA.DB.player.ratio.SD, title: 'SD'},
  1256. {type: 'ratio', text: '16:9', value: YTMA.DB.player.ratio.HD, title: 'Landscape'},
  1257. {type: 'ratio', text: '9:16', value: YTMA.DB.player.ratio.PORTRAIT, title: 'Portrait'}]),
  1258. this.dom.list.call(this, 'ytm_sizes', [
  1259. {type: 'size', text: '\u00D8', value: YTMA.DB.player.size.HIDDEN, title: 'Hide the video.'},
  1260. {type: 'size', text: 'S', value: YTMA.DB.player.size.S, title: '240p'},
  1261. {type: 'size', text: 'M', value: YTMA.DB.player.size.M, title: '360p'},
  1262. {type: 'size', text: 'L', value: YTMA.DB.player.size.L, title: '480p'},
  1263. {type: 'size', text: 'X', value: YTMA.DB.player.size.X, title: '720p'}]),
  1264. this.dom.list.call(this, 'ytm_options', [
  1265. strg.on ? {type: 'settings', text: '!', title: 'YTMA Settings'} : false,
  1266. {type: 'close', text: '\u00D7', title: 'Close the video.'}])
  1267. );
  1268.  
  1269. this.ul.appendChild(f);
  1270. this.ul.addEventListener('click', this.events.videoBar.bind(this), false);
  1271. this.wrp.appendChild(this.ul);
  1272. this.spn.parentNode.insertBefore(this.wrp, this.spn.nextSibling);
  1273. },
  1274. span: function () {
  1275. var f = document.createDocumentFragment();
  1276.  
  1277. $$.e('span', {className: 'ytm_init arialsans', textContent: this.spn.title}, this.spn);
  1278. this.spn.title = 'Watch now!';
  1279. f.appendChild(this.spn);
  1280.  
  1281. if (!YTMA.DB.dataless[this.data.site]) {
  1282. f.appendChild(this.dom.preview.call(this));
  1283. }
  1284.  
  1285. if (YTMA.DB.slim[this.data.site]) {
  1286. this.wrs.classList.add('ytm_site_slim');
  1287. }
  1288.  
  1289. if (YTMA.DB.scroll[this.data.site]) {
  1290. this.a.classList.add('ytm_scroll');
  1291. }
  1292.  
  1293. if (YTMA.user.preferences.desc === 2) {
  1294. YTMA.ajaxQueue.add(this.data.site, this.data.id, this.data.uri);
  1295. }
  1296.  
  1297. this.wrs.appendChild(f);
  1298. },
  1299. preview: function () {
  1300. var a, s;
  1301. s = $$.e('span', {className: 'ytm_title ytm_manual _' + this.data.sid});
  1302. a = $$.e('a', {
  1303. textContent: YTMA.user.preferences.desc === 2 ? 'Loading data . . .' : 'Load description.',
  1304. href: '#',
  1305. title: 'Load this video\'s description.',
  1306. '$data-id': this.data.id,
  1307. '$data-site': this.data.site,
  1308. '$data-uri': this.data.uri
  1309. });
  1310. a.addEventListener('click', this.events.manualLoad.bind(this), false);
  1311. return $$.a(s, a);
  1312. }
  1313. },
  1314. createPlayer: function () {
  1315. this.player = new YTMA.Player(this);
  1316. this.dom.ui.call(this);
  1317. },
  1318. show: function () {
  1319. if (!this.player) {
  1320. this.createPlayer();
  1321. }
  1322.  
  1323. this.toggle(true);
  1324.  
  1325. if (YTMA.user.preferences.focus) {
  1326. document.location.hash = '#' + this.wrs.id;
  1327. }
  1328. },
  1329. toggle: function (show, placeholder) { // the object is removed from or reattached to the DOM
  1330. // if (this.data.open === !!show) { return; }
  1331. this.data.open = !!show;
  1332. if (show) {
  1333. this.spn.classList.add('ytm_none');
  1334. this.wrp.classList.remove('ytm_none');
  1335.  
  1336. if (!this.player.$player.parentNode) {
  1337. this.wrp.appendChild(this.player.$player);
  1338. }
  1339. this.player.switchToMedia();
  1340. } else {
  1341. if (placeholder) {
  1342. this.player.switchToPlaceholder();
  1343. } else {
  1344. if (this.player) {
  1345. this.player.removeMedia();
  1346. }
  1347. this.spn.classList.remove('ytm_none');
  1348. this.wrp.classList.add('ytm_none');
  1349. }
  1350. }
  1351. },
  1352. thumb: {
  1353. start: function (e) {
  1354. var el = e.target;
  1355. el.dataset.thumb = el.dataset.thumb > 0 ? (el.dataset.thumb % 3) + 1 : 2;
  1356. el.style.backgroundImage = ['url(https://i3.ytimg.com/vi/', el.dataset.ytmid, '/', el.dataset.thumb, '.jpg)'].join('');
  1357. el.dataset.timeout = window.setTimeout(this.thumb.start.bind(this, e), 800);
  1358. },
  1359. stop: function (e) {
  1360. window.clearTimeout(e.target.dataset.timeout);
  1361. }
  1362. }
  1363. };
  1364.  
  1365. /** S C R O L L CLASS
  1366. * Window-Scroll Event Helper
  1367. */
  1368. YTMA.Scroll = (function () {
  1369.  
  1370. function Scroll(selector, cb, delay) {
  1371. this.selector = selector;
  1372. this.cb = cb;
  1373.  
  1374. // console.log('YTMA.Scroll Monitor: ', selector);
  1375. this.bound = Scroll.debounce(this.monitor.bind(this), delay || 500);
  1376.  
  1377. this.bound();
  1378. window.addEventListener('scroll', this.bound, false);
  1379. }
  1380.  
  1381. Scroll.debounce = function (fn, delay) {
  1382. var timeout;
  1383. delay = delay || 250;
  1384.  
  1385. return function () {
  1386. var self = this, args = arguments, timed;
  1387.  
  1388. timed = function () {
  1389. timeout = null;
  1390. fn.apply(self, args);
  1391. };
  1392.  
  1393. window.clearTimeout(timeout);
  1394. timeout = window.setTimeout(timed, delay);
  1395. };
  1396. };
  1397.  
  1398. Scroll.visible = function (el) {
  1399. var bound = el.getBoundingClientRect();
  1400. return (bound.top >= 0 && bound.top <= document.documentElement.clientHeight);
  1401. };
  1402.  
  1403. Scroll.visibleAll = function (el, offset) {
  1404. var bound = el.getBoundingClientRect(),
  1405. height = document.documentElement.clientHeight;
  1406. offset = isNumber(offset) ? +offset : 0;
  1407. return ((bound.bottom + offset >= 0)
  1408. && (bound.top <= height + offset || bound.bottom <= height - offset));
  1409. };
  1410.  
  1411. Scroll.prototype = {
  1412. stop: function () {
  1413. // console.log('clear scroll: ', this.selector);
  1414. window.removeEventListener('scroll', this.bound);
  1415. },
  1416. monitor: function () {
  1417. $$.s(this.selector, this.cb);
  1418. }
  1419. };
  1420.  
  1421. return Scroll;
  1422.  
  1423. }());
  1424.  
  1425. YTMA.main();
  1426. window.YTMA = YTMA;
  1427.  
  1428. }());