SaveTube

Download videos from video sharing web sites.

当前为 2019-07-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name SaveTube
  3. // @version 2019.07.17
  4. // @description Download videos from video sharing web sites.
  5. // @author sebaro
  6. // @namespace http://sebaro.pro/savetube
  7. // @icon https://gitlab.com/sebaro/savetube/raw/master/savetube.png
  8. // @include http://youtube.com*
  9. // @include http://www.youtube.com*
  10. // @include https://youtube.com*
  11. // @include https://www.youtube.com*
  12. // @include http://gaming.youtube.com*
  13. // @include https://gaming.youtube.com*
  14. // @include http://m.youtube.com*
  15. // @include https://m.youtube.com*
  16. // @include http://dailymotion.com*
  17. // @include http://www.dailymotion.com*
  18. // @include https://dailymotion.com*
  19. // @include https://www.dailymotion.com*
  20. // @include http://vimeo.com*
  21. // @include http://www.vimeo.com*
  22. // @include https://vimeo.com*
  23. // @include https://www.vimeo.com*
  24. // @include http://metacafe.com*
  25. // @include http://www.metacafe.com*
  26. // @include https://metacafe.com*
  27. // @include https://www.metacafe.com*
  28. // @include http://veoh.com*
  29. // @include http://www.veoh.com*
  30. // @include https://veoh.com*
  31. // @include https://www.veoh.com*
  32. // @include http://viki.com*
  33. // @include http://www.viki.com*
  34. // @include https://viki.com*
  35. // @include https://www.viki.com*
  36. // @include http://imdb.com*
  37. // @include http://www.imdb.com*
  38. // @include https://imdb.com*
  39. // @include https://www.imdb.com*
  40. // @noframes
  41. // @grant none
  42. // @run-at document-end
  43. // ==/UserScript==
  44.  
  45.  
  46. /*
  47.  
  48. Copyright (C) 2010 - 2019 Sebastian Luncan
  49.  
  50. This program is free software: you can redistribute it and/or modify
  51. it under the terms of the GNU General Public License as published by
  52. the Free Software Foundation, either version 3 of the License, or
  53. (at your option) any later version.
  54.  
  55. This program is distributed in the hope that it will be useful,
  56. but WITHOUT ANY WARRANTY; without even the implied warranty of
  57. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  58. GNU General Public License for more details.
  59.  
  60. You should have received a copy of the GNU General Public License
  61. along with this program. If not, see <http://www.gnu.org/licenses/>.
  62.  
  63. Website: http://sebaro.pro/savetube
  64. Contact: http://sebaro.pro/contact
  65.  
  66. */
  67.  
  68.  
  69. (function() {
  70.  
  71.  
  72. // Don't run on frames or iframes
  73. if (window.top != window.self) return;
  74.  
  75.  
  76. // ==========Variables========== //
  77.  
  78. // Userscript
  79. var userscript = 'SaveTube';
  80.  
  81. // Page
  82. var page = {win: window, doc: window.document, body: window.document.body, url: window.location.href, site: window.location.hostname.match(/([^.]+)\.[^.]+$/)[1]};
  83.  
  84. // Saver
  85. var saver = {};
  86. var feature = {'definition': true, 'container': true, 'autoget': false, 'dash': false};
  87. var option = {'definition': 'HD', 'container': 'MP4', 'autoget': false, 'dash': false};
  88. var sources = {};
  89.  
  90. // Links
  91. var website = 'http://sebaro.pro/savetube';
  92. var contact = 'http://sebaro.pro/contact';
  93.  
  94.  
  95. // ==========Functions========== //
  96.  
  97. function createMyElement(type, content, event, action, target) {
  98. var obj = page.doc.createElement(type);
  99. if (content) {
  100. if (type == 'div') obj.innerHTML = content;
  101. else if (type == 'option') {
  102. obj.value = content;
  103. obj.innerHTML = content;
  104. }
  105. }
  106. if (event == 'change') {
  107. if (target == 'video') {
  108. obj.addEventListener('change', function() {
  109. saver['videoSave'] = this.value;
  110. if (feature['autoget'] && saver['buttonGet'] == 'Get') {
  111. if (option['autoget']) getMyVideo();
  112. }
  113. else {
  114. modifyMyElement(saver['buttonGet'] , 'div', 'Get', false);
  115. }
  116. }, false);
  117. }
  118. }
  119. else if (event == 'click') {
  120. obj.addEventListener('click', function() {
  121. if (action == 'close') {
  122. removeMyElement(page.body, target);
  123. }
  124. else if (action == 'logo') {
  125. page.win.location.href = website;
  126. }
  127. else if (action == 'get') {
  128. getMyVideo();
  129. }
  130. else if (action == 'autoget') {
  131. option['autoget'] = (option['autoget']) ? false : true;
  132. if (option['autoget']) {
  133. styleMyElement(saver['buttonGet'], {display: 'none'});
  134. styleMyElement(saver['buttonAutoget'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'});
  135. getMyVideo();
  136. }
  137. else {
  138. styleMyElement(saver['buttonGet'], {display: 'inline'});
  139. styleMyElement(saver['buttonAutoget'], {color: '#CCCCCC', textShadow: '0px 0px 0px'});
  140. }
  141. setMyOptions('autoget', option['autoget']);
  142. }
  143. else if (action == 'definition') {
  144. for (var itemDef = 0; itemDef < option['definitions'].length; itemDef++) {
  145. if (option['definitions'][itemDef].match(/[A-Z]/g).join('') == option['definition']) {
  146. var nextDef = (itemDef + 1 < option['definitions'].length) ? itemDef + 1 : 0;
  147. option['definition'] = option['definitions'][nextDef].match(/[A-Z]/g).join('');
  148. break;
  149. }
  150. }
  151. modifyMyElement(saver['buttonDefinition'], 'div', option['definition'], false);
  152. setMyOptions('definition', option['definition']);
  153. modifyMyElement(saver['buttonGet'] , 'div', 'Get', false);
  154. selectMyVideo();
  155. if (option['autoget']) getMyVideo();
  156. }
  157. else if (action == 'container') {
  158. for (var itemCont = 0; itemCont < option['containers'].length; itemCont++) {
  159. if (option['containers'][itemCont] == option['container']) {
  160. var nextCont = (itemCont + 1 < option['containers'].length) ? itemCont + 1 : 0;
  161. option['container'] = option['containers'][nextCont];
  162. break;
  163. }
  164. }
  165. modifyMyElement(saver['buttonContainer'], 'div', option['container'], false);
  166. setMyOptions('container', option['container']);
  167. modifyMyElement(saver['buttonGet'] , 'div', 'Get', false);
  168. selectMyVideo();
  169. if (option['autoget']) getMyVideo();
  170. }
  171. else if (action == 'dash') {
  172. option['dash'] = (option['dash']) ? false : true;
  173. if (option['dash']) {
  174. styleMyElement(saver['buttonDASH'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'});
  175. }
  176. else {
  177. styleMyElement(saver['buttonDASH'], {color: '#CCCCCC', textShadow: '0px 0px 0px'});
  178. }
  179. setMyOptions('dash', option['dash']);
  180. }
  181. else if (action == 'move') {
  182. if (saver['saverPanel'].style.right == '25px') {
  183. styleMyElement(saver['saverPanel'], {left: '25px', right: 'auto'});
  184. modifyMyElement(saver['buttonMove'], 'div', '>', false);
  185. }
  186. else {
  187. styleMyElement(saver['saverPanel'], {left: 'auto', right: '25px'});
  188. modifyMyElement(saver['buttonMove'], 'div', '<', false);
  189. }
  190. }
  191. }, false);
  192. }
  193. return obj;
  194. }
  195.  
  196. function getMyElement(obj, type, from, value, child, content) {
  197. var getObj, chObj, coObj;
  198. var pObj = (!obj) ? page.doc : obj;
  199. if (type == 'body') getObj = pObj.body;
  200. else {
  201. if (from == 'id') getObj = pObj.getElementById(value);
  202. else if (from == 'class') getObj = pObj.getElementsByClassName(value);
  203. else if (from == 'tag') getObj = pObj.getElementsByTagName(type);
  204. else if (from == 'ns') getObj = pObj.getElementsByTagNameNS(value, type);
  205. }
  206. chObj = (child >= 0) ? getObj[child] : getObj;
  207. if (content && chObj) {
  208. if (type == 'html' || type == 'body' || type == 'div' || type == 'option') coObj = chObj.innerHTML;
  209. else if (type == 'object') coObj = chObj.data;
  210. else coObj = chObj.textContent;
  211. return coObj;
  212. }
  213. else {
  214. return chObj;
  215. }
  216. }
  217.  
  218. function modifyMyElement(obj, type, content, clear) {
  219. if (content) {
  220. if (type == 'div') obj.innerHTML = content;
  221. else if (type == 'option') {
  222. obj.value = content;
  223. obj.innerHTML = content;
  224. }
  225. }
  226. if (clear) {
  227. if (obj.hasChildNodes()) {
  228. while (obj.childNodes.length >= 1) {
  229. obj.removeChild(obj.firstChild);
  230. }
  231. }
  232. }
  233. }
  234.  
  235. function styleMyElement(obj, styles) {
  236. for (var property in styles) {
  237. if (styles.hasOwnProperty(property)) obj.style[property] = styles[property];
  238. }
  239. }
  240.  
  241. function appendMyElement(parent, child) {
  242. parent.appendChild(child);
  243. }
  244.  
  245. function removeMyElement(parent, child) {
  246. parent.removeChild(child);
  247. }
  248.  
  249. function replaceMyElement(parent, orphan, child) {
  250. parent.replaceChild(orphan, child);
  251. }
  252.  
  253. function createMySaver() {
  254. /* Get My Options */
  255. getMyOptions();
  256.  
  257. /* The Panel */
  258. saver['saverPanel'] = createMyElement('div', '', '', '', '');
  259. styleMyElement(saver['saverPanel'], {position: 'fixed', backgroundColor: '#FFFFFF', padding: '5px 5px 10px 5px', bottom: '0px', right: '25px', zIndex: '2000000000', borderTop: '3px solid #EEEEEE', borderLeft: '3px solid #EEEEEE', borderRight: '3px solid #EEEEEE', borderRadius: '5px 5px 0px 0px'});
  260. appendMyElement(page.body, saver['saverPanel']);
  261.  
  262. /* Warnings */
  263. if (saver['warnMess']) {
  264. if (saver['warnContent']) showMyMessage(saver['warnMess'], saver['warnContent']);
  265. else showMyMessage(saver['warnMess']);
  266. return;
  267. }
  268.  
  269. /* Panel Items */
  270. var panelItemHeight = 18;
  271.  
  272. /* Panel Logo */
  273. saver['panelLogo'] = createMyElement('div', userscript, 'click', 'logo', '');
  274. saver['panelLogo'].title = '{SaveTube: click to visit the script web page}';
  275. styleMyElement(saver['panelLogo'], {height: panelItemHeight + 'px', border: '1px solid #32d132', borderRadius: '3px', padding: '0px 2px', marginRight: '3px', display: 'inline', color: '#32d132', fontSize: '12px', textShadow: '0px 1px 1px #AAAAAA', verticalAlign: 'middle', cursor: 'pointer'});
  276. appendMyElement(saver['saverPanel'], saver['panelLogo']);
  277.  
  278. /* Panel Video Menu */
  279. saver['videoMenu'] = createMyElement('select', '', 'change', '', 'video');
  280. saver['videoMenu'].title = '{Videos: select the video format for download}';
  281. styleMyElement(saver['videoMenu'], {width: '200px', height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px', display: 'inline', backgroundColor: 'inherit', color: '#336699', fontSize: '12px', textShadow: '1px 1px 1px #CCCCCC', verticalAlign: 'middle', cursor: 'pointer'});
  282. appendMyElement(saver['saverPanel'], saver['videoMenu'] );
  283. for (var videoCode in saver['videoList']) {
  284. saver['videoItem'] = createMyElement('option', videoCode, '', '', '');
  285. styleMyElement(saver['videoItem'], {padding: '0px', display: 'block', color: '#336699', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', cursor: 'pointer'});
  286. if (videoCode.indexOf('Video') != -1 || videoCode.indexOf('Audio') != -1) styleMyElement(saver['videoItem'], {color: '#8F6B32'});
  287. if (saver['videoList'][videoCode] == 'DASH') styleMyElement(saver['videoItem'], {color: '#CF4913'});
  288. if (saver['videoList'][videoCode] != 'DASH' || option['dash']) appendMyElement(saver['videoMenu'], saver['videoItem']);
  289. else delete saver['videoList'][videoCode];
  290. }
  291.  
  292. /* Panel Get Button */
  293. saver['buttonGet'] = createMyElement('div', 'Get', 'click', 'get', '');
  294. saver['buttonGet'].title = '{Get: click to download the selected video format}';
  295. styleMyElement(saver['buttonGet'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#C000C0', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', verticalAlign: 'middle', cursor: 'pointer'});
  296. if (option['autoget']) styleMyElement(saver['buttonGet'], {display: 'none'});
  297. appendMyElement(saver['saverPanel'], saver['buttonGet']);
  298.  
  299. /* Panel Autoget Button */
  300. if (feature['autoget']) {
  301. saver['buttonAutoget'] = createMyElement('div', 'AG', 'click', 'autoget', '');
  302. saver['buttonAutoget'].title = '{Autoget: click to enable/disable auto download on page load}';
  303. styleMyElement(saver['buttonAutoget'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#CCCCCC', fontSize: '12px', verticalAlign: 'middle', cursor: 'pointer'});
  304. if (option['autoget']) styleMyElement(saver['buttonAutoget'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'});
  305. appendMyElement(saver['saverPanel'], saver['buttonAutoget']);
  306. }
  307.  
  308. /* Panel Definition Button */
  309. if (feature['definition']) {
  310. saver['buttonDefinition'] = createMyElement('div', option['definition'], 'click', 'definition', '');
  311. saver['buttonDefinition'].title = '{Definition: click to change the preferred video definition}';
  312. styleMyElement(saver['buttonDefinition'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#008000', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', verticalAlign: 'middle', cursor: 'pointer'});
  313. appendMyElement(saver['saverPanel'], saver['buttonDefinition']);
  314. }
  315.  
  316. /* Panel Container Button */
  317. if (feature['container']) {
  318. saver['buttonContainer'] = createMyElement('div', option['container'], 'click', 'container', '');
  319. saver['buttonContainer'].title = '{Container: click to change the preferred video container}';
  320. styleMyElement(saver['buttonContainer'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#008000', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', verticalAlign: 'middle', cursor: 'pointer'});
  321. appendMyElement(saver['saverPanel'], saver['buttonContainer']);
  322. }
  323.  
  324. /* Panel DASH Button */
  325. if (feature['dash']) {
  326. saver['buttonDASH'] = createMyElement('div', 'MD', 'click', 'dash', '');
  327. saver['buttonDASH'].title = '{MPEG-DASH: click to enable/disable DASH download using the SaveTube protocol}';
  328. styleMyElement(saver['buttonDASH'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#CCCCCC', fontSize: '12px', verticalAlign: 'middle', cursor: 'pointer'});
  329. if (option['dash']) styleMyElement(saver['buttonDASH'], {color: '#008080', textShadow: '0px 1px 1px #CCCCCC'});
  330. appendMyElement(saver['saverPanel'], saver['buttonDASH']);
  331. }
  332.  
  333. /* Panel Move Button */
  334. saver['buttonMove'] = createMyElement('div', '<', 'click', 'move', '');
  335. saver['buttonMove'].title = '{Move: click to toggle left/right panel position}';
  336. styleMyElement(saver['buttonMove'], {height: panelItemHeight + 'px', border: '1px solid #CCCCCC', borderRadius: '3px', padding: '0px 5px', display: 'inline', color: '#CCCCCC', fontSize: '12px', textShadow: '0px 1px 1px #CCCCCC', verticalAlign: 'middle', cursor: 'pointer'});
  337. appendMyElement(saver['saverPanel'], saver['buttonMove']);
  338.  
  339. /* Disabled Features */
  340. if (!feature['autoget']) option['autoget'] = false;
  341. if (!feature['dash']) option['dash'] = false;
  342.  
  343. /* Select The Video */
  344. if (feature['definition'] || feature['container']) selectMyVideo();
  345.  
  346. /* Get The Video On Autoget */
  347. if (option['autoget']) getMyVideo();
  348. }
  349.  
  350. function selectMyVideo() {
  351. var vdoCont = (option['container'] != 'Any') ? [option['container']] : option['containers'];
  352. var vdoDef = option['definitions'];
  353. var vdoList = {};
  354. for (var vC = 0; vC < vdoCont.length; vC++) {
  355. if (vdoCont[vC] != 'Any') {
  356. for (var vD = 0; vD < vdoDef.length; vD++) {
  357. var format = vdoDef[vD] + ' ' + vdoCont[vC];
  358. if (!vdoList[vdoDef[vD]]) {
  359. for (var vL in saver['videoList']) {
  360. if (vL == format) {
  361. vdoList[vdoDef[vD]] = vL;
  362. break;
  363. }
  364. }
  365. }
  366. }
  367. }
  368. }
  369. var vdoDef2 = [];
  370. var keepDef = false;
  371. for (var vD = 0; vD < vdoDef.length; vD++) {
  372. var sD = vdoDef[vD].match(/[A-Z]/g).join('');
  373. if (sD == option['definition'] && keepDef == false) keepDef = true;
  374. if (keepDef == true) vdoDef2.push(vdoDef[vD])
  375. }
  376. for (var vD = 0; vD < vdoDef2.length; vD++) {
  377. if (vdoList[vdoDef2[vD]]) {
  378. saver['videoSave'] = vdoList[vdoDef2[vD]];
  379. break;
  380. }
  381. }
  382. saver['videoMenu'].value = saver['videoSave'];
  383. }
  384.  
  385. function getMyVideo() {
  386. var vdoURL = saver['videoList'][saver['videoSave']];
  387. var vdoDef = ' (' + saver['videoSave'].split(' ').slice(0, -1).join('').match(/[A-Z]/g).join('') + ')';
  388. var vdoExt = '.' + saver['videoSave'].split(' ').slice(-1).join('').toLowerCase();
  389. var vdoTle = (saver['videoTitle']) ? saver['videoTitle'] : '';
  390. if (feature['autoget'] && vdoTle && saver['videoSave'] == 'High Definition MP4') {
  391. page.win.location.href = vdoURL + '&title=' + vdoTle + vdoDef;
  392. }
  393. else {
  394. if (saver['videoList'][saver['videoSave']] == 'DASH') {
  395. var vdoV, vdoA;
  396. if (saver['videoSave'].indexOf('MP4') != -1) {
  397. vdoV = saver['videoList'][saver['videoSave'].replace('MP4', 'Video MP4')];
  398. vdoA = saver['videoList']['High Bitrate Audio MP4'] || saver['videoList']['Medium Bitrate Audio MP4'] || saver['videoList'][saver['videoSave'].replace('MP4', 'Audio MP4')];
  399. }
  400. else {
  401. vdoV = saver['videoList'][saver['videoSave'].replace('WebM', 'Video WebM')];
  402. vdoA = saver['videoList']['High Bitrate Audio Opus'] || saver['videoList']['Medium Bitrate Audio Opus'] || saver['videoList']['Low Bitrate Audio Opus'];
  403. }
  404. var vdoT = (vdoTle) ? vdoTle + vdoDef : page.site + vdoDef;
  405. vdoURL = 'savetube:' + vdoT + 'SEPARATOR' + vdoV + 'SEPARATOR' + vdoA;
  406. page.win.location.href = vdoURL;
  407. }
  408. else {
  409. var vdoLnk = '';
  410. if (vdoTle) {
  411. var vdoNme = vdoTle + vdoDef + vdoExt;
  412. vdoLnk = 'Get <a href="' + vdoURL + '" style="color:#00892C" download="' + vdoNme + '" target="_blank">Link</a>';
  413. }
  414. else {
  415. vdoLnk = 'Get <a href="' + vdoURL + '" style="color:#00892C" target="_blank">Link</a>';
  416. }
  417. modifyMyElement(saver['buttonGet'] , 'div', vdoLnk, false);
  418. }
  419. }
  420. }
  421.  
  422. function cleanMyContent(content, unesc) {
  423. var myNewContent = content;
  424. if (unesc) myNewContent = unescape(myNewContent);
  425. myNewContent = myNewContent.replace(/\\u0025/g, '%');
  426. myNewContent = myNewContent.replace(/\\u0026/g, '&');
  427. myNewContent = myNewContent.replace(/\\u002F/g, '/');
  428. myNewContent = myNewContent.replace(/\\/g, '');
  429. myNewContent = myNewContent.replace(/\n/g, '');
  430. return myNewContent;
  431. }
  432.  
  433. function getMyContent(url, pattern, clean) {
  434. var myPageContent, myVideosParse, myVideosContent;
  435. if (!sources[url]) {
  436. var xmlHTTP = new XMLHttpRequest();
  437. xmlHTTP.open('GET', url, false);
  438. xmlHTTP.send();
  439. sources[url] = (xmlHTTP.responseText) ? xmlHTTP.responseText : xmlHTTP.responseXML;
  440. //console.log('Request: ' + url + ' ' + pattern);
  441. }
  442. if (pattern == 'TEXT') {
  443. myVideosContent = sources[url];
  444. }
  445. else {
  446. myPageContent = (sources[url]) ? sources[url] : '';
  447. if (clean) myPageContent = cleanMyContent(myPageContent, true);
  448. myVideosParse = myPageContent.match(pattern);
  449. myVideosContent = (myVideosParse) ? myVideosParse[1] : null;
  450. }
  451. return myVideosContent;
  452. }
  453.  
  454. function setMyOptions(key, value) {
  455. key = page.site + '_' + userscript.toLowerCase() + '_' + key;
  456. try {
  457. localStorage.setItem(key, value);
  458. if (localStorage.getItem(key) == value) return;
  459. else throw false;
  460. }
  461. catch(e) {
  462. var date = new Date();
  463. date.setTime(date.getTime() + (356*24*60*60*1000));
  464. var expires = '; expires=' + date.toGMTString();
  465. page.doc.cookie = key + '=' + value + expires + '; path=/';
  466. }
  467. }
  468.  
  469. function getMyOptions() {
  470. for (var opt in option) {
  471. if (option.hasOwnProperty(opt)) {
  472. var key = page.site + '_' + userscript.toLowerCase() + '_' + opt;
  473. try {
  474. if (localStorage.getItem(key)) {
  475. option[opt] = localStorage.getItem(key);
  476. continue;
  477. }
  478. else throw false;
  479. }
  480. catch(e) {
  481. var cookies = page.doc.cookie.split(';');
  482. for (var i=0; i < cookies.length; i++) {
  483. var cookie = cookies[i];
  484. while (cookie.charAt(0) == ' ') cookie = cookie.substring(1, cookie.length);
  485. option[opt] = (cookie.indexOf(key) == 0) ? cookie.substring(key.length + 1, cookie.length) : option[opt];
  486. }
  487. }
  488. }
  489. }
  490. option['autoget'] = (option['autoget'] === true || option['autoget'] == 'true') ? true : false;
  491. option['dash'] = (option['dash'] === true || option['dash'] == 'true') ? true : false;
  492. }
  493.  
  494. function showMyMessage(cause, content) {
  495. styleMyElement(saver['saverPanel'], {color: '#AD0000', fontSize: '12px'});
  496. if (cause == '!content') {
  497. var myNoContentMess = '<b>SaveTube:</b> Couldn\'t get the videos content. Please report it <a href="' + contact + '" style="color:#00892C">here</a>.';
  498. modifyMyElement(saver['saverPanel'], 'div', myNoContentMess, false);
  499. }
  500. else if (cause == '!videos') {
  501. var myNoVideosMess = '<b>SaveTube:</b> Couldn\'t get any video. Please report it <a href="' + contact + '" style="color:#00892C">here</a>.';
  502. modifyMyElement(saver['saverPanel'], 'div', myNoVideosMess, false);
  503. }
  504. else if (cause == '!support') {
  505. var myNoSupportMess = '<b>SaveTube:</b> This video uses the RTMP protocol which is not supported.';
  506. modifyMyElement(saver['saverPanel'], 'div', myNoSupportMess, false);
  507. }
  508. else if (cause == 'embed') {
  509. var myEmbedMess = '<b>SaveTube:</b> This is an embedded video. You can get it <a href="' + content + '" style="color:#00892C">here</a>.';
  510. modifyMyElement(saver['saverPanel'], 'div', myEmbedMess, false);
  511. }
  512. else if (cause == 'other') {
  513. modifyMyElement(saver['saverPanel'], 'div', content, false);
  514. }
  515. }
  516.  
  517.  
  518. // ==========Websites========== //
  519.  
  520. function SaveTube() {
  521.  
  522. // =====YouTube===== //
  523.  
  524. if (page.url.indexOf('youtube.com/watch') != -1) {
  525.  
  526. /* Video Availability */
  527. if (getMyContent(page.url, '"playabilityStatus":\\{"status":"(ERROR|UNPLAYABLE)"', false)) return;
  528. var ytVideoUnavailable = getMyElement('', 'div', 'id', 'player-unavailable', -1, false);
  529. if (ytVideoUnavailable) {
  530. if (ytVideoUnavailable.className.indexOf('hid') == -1) {
  531. var ytAgeGateContent = getMyElement('', 'div', 'id', 'watch7-player-age-gate-content', -1, true);
  532. if (!ytAgeGateContent) return;
  533. else {
  534. if(ytAgeGateContent.indexOf('feature=private_video') != -1) return;
  535. }
  536. }
  537. }
  538.  
  539. /* Decrypt Signature */
  540. var ytScriptSrc;
  541. function ytDecryptSignature(s) {return null;}
  542. function ytDecryptFunction() {
  543. var ytSignFuncName, ytSignFuncBody, ytSwapFuncName, ytSwapFuncBody, ytFuncMatch;
  544. ytScriptSrc = ytScriptSrc.replace(/(\r\n|\n|\r)/gm, '');
  545. ytSignFuncName = ytScriptSrc.match(/"signature"\s*,\s*([^\)]*?)\(/);
  546. if (!ytSignFuncName) ytSignFuncName = ytScriptSrc.match(/c&&.\.set\(b,(?:encodeURIComponent\()?.*?([$a-zA-Z0-9]+)\(/);
  547. ytSignFuncName = (ytSignFuncName) ? ytSignFuncName[1] : null;
  548. if (ytSignFuncName) {
  549. ytFuncMatch = ytSignFuncName.replace(/\$/, '\\$') + '\\s*=\\s*function\\s*' + '\\s*\\(\\w+\\)\\s*\\{(.*?)\\}';
  550. ytSignFuncBody = ytScriptSrc.match(ytFuncMatch);
  551. ytSignFuncBody = (ytSignFuncBody) ? ytSignFuncBody[1] : null;
  552. if (ytSignFuncBody) {
  553. ytSwapFuncName = ytSignFuncBody.match(/((\$|_|\w)+)\.(\$|_|\w)+\(\w,[0-9]+\)/);
  554. ytSwapFuncName = (ytSwapFuncName) ? ytSwapFuncName[1] : null;
  555. if (ytSwapFuncName) {
  556. ytFuncMatch = 'var\\s+' + ytSwapFuncName.replace(/\$/, '\\$') + '=\\s*\\{(.*?)\\};';
  557. ytSwapFuncBody = ytScriptSrc.match(ytFuncMatch);
  558. ytSwapFuncBody = (ytSwapFuncBody) ? ytSwapFuncBody[1] : null;
  559. }
  560. if (ytSwapFuncBody) ytSignFuncBody = 'var ' + ytSwapFuncName + '={' + ytSwapFuncBody + '};' + ytSignFuncBody;
  561. ytSignFuncBody = 'try {' + ytSignFuncBody + '} catch(e) {return null}';
  562. ytDecryptSignature = new Function('a', ytSignFuncBody);
  563. }
  564. }
  565. }
  566.  
  567. /* Get Video Title */
  568. var ytVideoTitle = getMyContent(page.url, '"title":"(.*?)"', false);
  569. if (!ytVideoTitle) ytVideoTitle = getMyContent(page.url, '"videoPrimaryInfoRenderer":\\{"title":\\{"simpleText":"(.*?)"', false);
  570. if (!ytVideoTitle) ytVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  571. if (!ytVideoTitle) ytVideoTitle = getMyContent(page.url, 'meta\\s+itemprop="name"\\s+content="(.*?)"', false);
  572. if (ytVideoTitle) {
  573. ytVideoTitle = ytVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  574. ytVideoTitle = ytVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  575. ytVideoTitle = ytVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  576. ytVideoTitle = ytVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  577. ytVideoTitle = ytVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  578. }
  579.  
  580. /* Get Videos Content */
  581. var ytVideosEncodedFmts, ytVideosAdaptiveFmts, ytVideosContent, ytHLSVideos, ytHLSContent;
  582. ytVideosEncodedFmts = getMyContent(page.url, '"url_encoded_fmt_stream_map\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  583. ytVideosAdaptiveFmts = getMyContent(page.url, '"adaptive_fmts\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  584. if (!ytVideosAdaptiveFmts) {
  585. var ytDASHVideos, ytDASHContent;
  586. ytDASHVideos = getMyContent(page.url, '"dashmpd\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  587. if (ytDASHVideos) {
  588. ytDASHVideos = cleanMyContent(ytDASHVideos, false);
  589. ytDASHContent = getMyContent(ytDASHVideos + '?pacing=0', 'TEXT', false);
  590. if (ytDASHContent) {
  591. var ytDASHVideo, ytDASHVideoParts, ytDASHVideoServer, ytDASHVideoParams;
  592. ytDASHVideos = ytDASHContent.match(new RegExp('<BaseURL>.*?</BaseURL>', 'g'));
  593. if (ytDASHVideos) {
  594. ytVideosAdaptiveFmts = '';
  595. for (var i = 0; i < ytDASHVideos.length; i++) {
  596. ytDASHVideo = ytDASHVideos[i].replace('<BaseURL>', '').replace('</BaseURL>', '');
  597. if (ytDASHVideo.indexOf('source/youtube') == -1) continue;
  598. ytDASHVideoParts = ytDASHVideo.split('videoplayback/');
  599. ytDASHVideoServer = ytDASHVideoParts[0] + 'videoplayback?';
  600. ytDASHVideoParams = ytDASHVideoParts[1].split('/');
  601. ytDASHVideo = '';
  602. for (var p = 0; p < ytDASHVideoParams.length; p++) {
  603. if (p % 2) ytDASHVideo += ytDASHVideoParams[p] + '&';
  604. else ytDASHVideo += ytDASHVideoParams[p] + '=';
  605. }
  606. ytDASHVideo = encodeURIComponent(ytDASHVideoServer + ytDASHVideo);
  607. ytDASHVideo = ytDASHVideo.replace('itag%3D', 'itag=');
  608. ytVideosAdaptiveFmts += ytDASHVideo + ',';
  609. }
  610. }
  611. }
  612. }
  613. }
  614. if (ytVideosEncodedFmts) {
  615. ytVideosContent = ytVideosEncodedFmts;
  616. }
  617. else {
  618. ytHLSVideos = getMyContent(page.url, '"hls(?:vp|ManifestUrl)\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  619. if (ytHLSVideos) {
  620. ytHLSVideos = cleanMyContent(ytHLSVideos, false);
  621. if (ytHLSVideos.indexOf('keepalive/yes/') != -1) ytHLSVideos = ytHLSVideos.replace('keepalive/yes/', '');
  622. }
  623. else {
  624. var ytVideoID = page.url.match(/(\?|&)v=(.*?)(&|$)/);
  625. ytVideoID = (ytVideoID) ? ytVideoID[2] : null;
  626. if (ytVideoID) {
  627. var ytVideosInfo = getMyContent(page.win.location.protocol + '//' + page.win.location.hostname + '/get_video_info?video_id=' + ytVideoID + '&eurl=https://youtube.googleapis.com/v/', 'TEXT', false);
  628. if (ytVideosInfo) {
  629. ytVideosEncodedFmts = ytVideosInfo.match(/url_encoded_fmt_stream_map=(.*?)&/);
  630. ytVideosEncodedFmts = (ytVideosEncodedFmts) ? ytVideosEncodedFmts[1] : null;
  631. if (ytVideosEncodedFmts) {
  632. ytVideosEncodedFmts = cleanMyContent(ytVideosEncodedFmts, true);
  633. ytVideosContent = ytVideosEncodedFmts;
  634. }
  635. if (!ytVideosAdaptiveFmts) {
  636. ytVideosAdaptiveFmts = ytVideosInfo.match(/adaptive_fmts=(.*?)&/);
  637. ytVideosAdaptiveFmts = (ytVideosAdaptiveFmts) ? ytVideosAdaptiveFmts[1] : null;
  638. if (ytVideosAdaptiveFmts) ytVideosAdaptiveFmts = cleanMyContent(ytVideosAdaptiveFmts, true);
  639. }
  640. }
  641. }
  642. }
  643. }
  644. if (ytVideosAdaptiveFmts && !ytHLSVideos) {
  645. if (ytVideosContent) ytVideosContent += ',' + ytVideosAdaptiveFmts;
  646. else ytVideosContent = ytVideosAdaptiveFmts;
  647. }
  648.  
  649. /* Create Saver */
  650. var ytDefaultVideo = 'Low Definition MP4';
  651. function ytSaver() {
  652. saver = {'videoList': ytVideoList, 'videoSave': ytDefaultVideo, 'videoTitle': ytVideoTitle};
  653. option['definitions'] = ['Ultra High Definition', 'Quad High Definition', 'Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  654. option['containers'] = ['MP4', 'WebM', 'Any'];
  655. }
  656.  
  657. /* Parse Videos */
  658. function ytVideos() {
  659. var ytVideoFormats = {
  660. '18': 'Low Definition MP4',
  661. '22': 'High Definition MP4',
  662. '43': 'Low Definition WebM',
  663. '135': 'Standard Definition Video MP4',
  664. '136': 'High Definition Video MP4',
  665. '137': 'Full High Definition Video MP4',
  666. '140': 'Medium Bitrate Audio MP4',
  667. '171': 'Medium Bitrate Audio WebM',
  668. '244': 'Standard Definition Video WebM',
  669. '247': 'High Definition Video WebM',
  670. '248': 'Full High Definition Video WebM',
  671. '249': 'Low Bitrate Audio Opus',
  672. '250': 'Medium Bitrate Audio Opus',
  673. '251': 'High Bitrate Audio Opus',
  674. '264': 'Quad High Definition Video MP4',
  675. '271': 'Quad High Definition Video WebM',
  676. '272': 'Ultra High Definition Video WebM',
  677. '298': 'High Definition Video MP4',
  678. '299': 'Full High Definition Video MP4',
  679. '302': 'High Definition Video WebM',
  680. '303': 'Full High Definition Video WebM',
  681. '308': 'Quad High Definition Video WebM',
  682. '313': 'Ultra High Definition Video WebM',
  683. '315': 'Ultra High Definition Video WebM',
  684. '333': 'Standard Definition Video WebM',
  685. '334': 'High Definition Video WebM',
  686. '335': 'Full High Definition Video WebM',
  687. '337': 'Ultra High Definition Video WebM'
  688. };
  689. var ytVideoFound = false;
  690. var ytVideos = ytVideosContent.split(',');
  691. var ytVideoParse, ytVideoCodeParse, ytVideoCode, myVideoCode, ytVideo, ytSign, ytSignP;
  692. for (var i = 0; i < ytVideos.length; i++) {
  693. if (!ytVideos[i].match(/^url/)) {
  694. ytVideoParse = ytVideos[i].match(/(.*)(url=.*$)/);
  695. if (ytVideoParse) ytVideos[i] = ytVideoParse[2] + '&' + ytVideoParse[1];
  696. }
  697. ytVideoCodeParse = ytVideos[i].match(/itag=(\d{1,3})/);
  698. ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null;
  699. if (ytVideoCode) {
  700. myVideoCode = ytVideoFormats[ytVideoCode];
  701. if (myVideoCode) {
  702. ytVideo = cleanMyContent(ytVideos[i], true);
  703. ytVideo = ytVideo.replace(/url=/, '').replace(/&$/, '');
  704. if (ytVideo.match(/itag=/) && ytVideo.match(/itag=/g).length > 1) {
  705. if (ytVideo.match(/itag=\d{1,3}&/)) ytVideo = ytVideo.replace(/itag=\d{1,3}&/, '');
  706. else if (ytVideo.match(/&itag=\d{1,3}/)) ytVideo = ytVideo.replace(/&itag=\d{1,3}/, '');
  707. }
  708. if (ytVideo.match(/clen=/) && ytVideo.match(/clen=/g).length > 1) {
  709. if (ytVideo.match(/clen=\d+&/)) ytVideo = ytVideo.replace(/clen=\d+&/, '');
  710. else if (ytVideo.match(/&clen=\d+/)) ytVideo = ytVideo.replace(/&clen=\d+/, '');
  711. }
  712. if (ytVideo.match(/lmt=/) && ytVideo.match(/lmt=/g).length > 1) {
  713. if (ytVideo.match(/lmt=\d+&/)) ytVideo = ytVideo.replace(/lmt=\d+&/, '');
  714. else if (ytVideo.match(/&lmt=\d+/)) ytVideo = ytVideo.replace(/&lmt=\d+/, '');
  715. }
  716. if (ytVideo.match(/type=(video|audio).*?&/)) ytVideo = ytVideo.replace(/type=(video|audio).*?&/, '');
  717. else ytVideo = ytVideo.replace(/&type=(video|audio).*$/, '');
  718. if (ytVideo.match(/xtags=[^%=]*&/)) ytVideo = ytVideo.replace(/xtags=[^%=]*?&/, '');
  719. else if (ytVideo.match(/&xtags=[^%=]*$/)) ytVideo = ytVideo.replace(/&xtags=[^%=]*$/, '');
  720. if (ytVideo.match(/&sig=/) && !ytVideo.match(/&lsig=/)) ytVideo = ytVideo.replace(/&sig=/, '&signature=');
  721. else if (ytVideo.match(/&s=/)) {
  722. ytSign = ytVideo.match(/&s=(.*?)(&|$)/);
  723. ytSign = (ytSign) ? ytSign[1] : null;
  724. if (ytSign) {
  725. ytSign = ytDecryptSignature(ytSign);
  726. if (ytSign) {
  727. ytSignP = ytVideo.match(/&sp=(.*?)(&|$)/);
  728. ytSignP = (ytSignP) ? ytSignP[1] : ((ytVideo.match(/&lsig=/)) ? 'sig' : 'signature');
  729. ytVideo = ytVideo.replace(/&s=.*?(&|$)/, '&' + ytSignP + '=' + ytSign + '$1');
  730. }
  731. else ytVideo = '';
  732. }
  733. else ytVideo = '';
  734. }
  735. ytVideo = cleanMyContent(ytVideo, true);
  736. if (ytVideo.indexOf('ratebypass') == -1) ytVideo += '&ratebypass=yes';
  737. if (ytVideo && ytVideo.indexOf('http') == 0) {
  738. if (!ytVideoFound) ytVideoFound = true;
  739. ytVideoList[myVideoCode] = ytVideo;
  740. }
  741. }
  742. }
  743. }
  744.  
  745. if (ytVideoFound) {
  746. /* DASH */
  747. if (ytVideoList['Medium Bitrate Audio MP4'] || ytVideoList['Medium Bitrate Audio WebM'] || ytVideoList['Medium Bitrate Audio Opus']) {
  748. for (var myVideoCode in ytVideoList) {
  749. if (myVideoCode.indexOf('Video') != -1) {
  750. if (!ytVideoList[myVideoCode.replace(' Video', '')]) {
  751. ytVideoList[myVideoCode.replace(' Video', '')] = 'DASH';
  752. }
  753. }
  754. }
  755. }
  756. feature['dash'] = true;
  757.  
  758. /* Create Saver */
  759. feature['autoget'] = true;
  760. ytSaver();
  761. createMySaver();
  762. }
  763. else {
  764. saver = {};
  765. if (ytVideosContent.indexOf('conn=rtmp') != -1) saver['warnMess'] = '!support';
  766. else saver['warnMess'] = '!videos';
  767. createMySaver();
  768. }
  769. }
  770.  
  771. /* Parse HLS */
  772. function ytHLS() {
  773. var ytHLSFormats = {
  774. '92': 'Very Low Definition MP4',
  775. '93': 'Low Definition MP4',
  776. '94': 'Standard Definition MP4',
  777. '95': 'High Definition MP4',
  778. '96': 'Full High Definition MP4'
  779. };
  780. ytVideoList["Any Definition MP4"] = ytHLSVideos;
  781. if (ytHLSContent) {
  782. var ytHLSVideo, ytVideoCodeParse, ytVideoCode, myVideoCode;
  783. var ytHLSMatcher = new RegExp('(http.*?m3u8)', 'g');
  784. ytHLSVideos = ytHLSContent.match(ytHLSMatcher);
  785. if (ytHLSVideos) {
  786. for (var i = 0; i < ytHLSVideos.length; i++) {
  787. ytHLSVideo = ytHLSVideos[i];
  788. ytVideoCodeParse = ytHLSVideo.match(/\/itag\/(\d{1,3})\//);
  789. ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null;
  790. if (ytVideoCode) {
  791. myVideoCode = ytHLSFormats[ytVideoCode];
  792. if (myVideoCode && ytHLSVideo) {
  793. ytVideoList[myVideoCode] = ytHLSVideo;
  794. }
  795. }
  796. }
  797. }
  798. }
  799.  
  800. /* Create Saver */
  801. ytVideoTitle = null;
  802. ytDefaultVideo = 'Any Definition MP4';
  803. ytSaver();
  804. createMySaver();
  805. }
  806.  
  807. /* Get Videos */
  808. var ytVideoList = {};
  809. if (ytVideosContent) {
  810. if (ytVideosContent.match(/^s=/) || ytVideosContent.match(/&s=/) || ytVideosContent.match(/,s=/) || ytVideosContent.match(/u0026s=/)) {
  811. var ytScriptURL = getMyContent(page.url, '"js":\\s*"(.*?)"', true);
  812. if (!ytScriptURL) ytScriptURL = getMyContent(page.url.replace(/watch.*?v=/, 'embed/').replace(/&.*$/, ''), '"js":\\s*"(.*?)"', true);
  813. if (ytScriptURL) {
  814. ytScriptURL = page.win.location.protocol + '//' + page.win.location.hostname + ytScriptURL;
  815. ytScriptSrc = getMyContent(ytScriptURL, 'TEXT', false);
  816. if (ytScriptSrc) ytDecryptFunction();
  817. ytVideos();
  818. }
  819. else {
  820. saver = {
  821. 'warnMess': 'other',
  822. 'warnContent': '<b>SaveTube:</b> Couldn\'t get the signature link. Please report it <a href="' + contact + '" style="color:#00892C">here</a>.'
  823. };
  824. createMySaver();
  825. }
  826. }
  827. else {
  828. ytVideos();
  829. }
  830. }
  831. else {
  832. if (ytHLSVideos) {
  833. ytHLSContent = getMyContent(ytHLSVideos, 'TEXT', false);
  834. ytHLS();
  835. }
  836. else {
  837. saver = {'warnMess': '!content'};
  838. createMySaver();
  839. }
  840. }
  841.  
  842. }
  843.  
  844. // =====DailyMotion===== //
  845.  
  846. else if (page.url.indexOf('dailymotion.com/video') != -1) {
  847.  
  848. /* Video Availability */
  849. if (getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"error":\\{"title":"(.*?)"', false)) return;
  850. if (getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"error_title":"(.*?)"', false)) return;
  851.  
  852. /* Get Video Title */
  853. var dmVideoTitle = getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"title":"(.*?)"', false);
  854. if (dmVideoTitle) {
  855. dmVideoTitle = dmVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  856. dmVideoTitle = dmVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  857. dmVideoTitle = dmVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  858. dmVideoTitle = dmVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  859. dmVideoTitle = dmVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  860. }
  861.  
  862. /* Get Videos Content */
  863. var dmVideosContent = getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"qualities":\\{(.*?)\\]\\},', false);
  864.  
  865. /* Get Videos */
  866. if (dmVideosContent) {
  867. var dmVideoFormats = {'auto': 'Low Definition MP4', '240': 'Very Low Definition MP4', '380': 'Low Definition MP4',
  868. '480': 'Standard Definition MP4', '720': 'High Definition MP4', '1080': 'Full High Definition MP4'};
  869. var dmVideoList = {};
  870. var dmVideoFound = false;
  871. var dmVideoParser, dmVideoParse, myVideoCode, dmVideo;
  872. for (var dmVideoCode in dmVideoFormats) {
  873. dmVideoParser = '"' + dmVideoCode + '".*?"type":"video.*?mp4","url":"(.*?)"';
  874. dmVideoParse = dmVideosContent.match(dmVideoParser);
  875. if (!dmVideoParse) {
  876. dmVideoParser = '"' + dmVideoCode + '".*?"type":"application.*?mpegURL","url":"(.*?)"';
  877. dmVideoParse = dmVideosContent.match(dmVideoParser);
  878. }
  879. dmVideo = (dmVideoParse) ? dmVideoParse[1] : null;
  880. if (dmVideo) {
  881. if (!dmVideoFound) dmVideoFound = true;
  882. dmVideo = cleanMyContent(dmVideo, true);
  883. myVideoCode = dmVideoFormats[dmVideoCode];
  884. if (!dmVideoList[myVideoCode]) dmVideoList[myVideoCode] = dmVideo;
  885. }
  886. }
  887.  
  888. if (dmVideoFound) {
  889. /* Create Saver */
  890. var dmDefaultVideo = 'Low Definition MP4';
  891. saver = {'videoList': dmVideoList, 'videoSave': dmDefaultVideo, 'videoTitle': dmVideoTitle};
  892. feature['container'] = false;
  893. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  894. option['containers'] = ['MP4'];
  895. createMySaver();
  896. }
  897. else {
  898. saver = {'warnMess': '!videos'};
  899. createMySaver();
  900. }
  901. }
  902. else {
  903. saver = {'warnMess': '!content'};
  904. createMySaver();
  905. }
  906.  
  907. }
  908.  
  909. // =====Vimeo===== //
  910.  
  911. else if (page.url.indexOf('vimeo.com/') != -1) {
  912.  
  913. /* Page Type */
  914. var viPageType = getMyContent(page.url, 'meta\\s+property="og:type"\\s+content="(.*?)"', false);
  915. if (!viPageType || (viPageType != 'video' && viPageType != 'profile')) return;
  916.  
  917. /* Get Video Title */
  918. var viVideoTitle;
  919. if (viPageType == 'video') {
  920. viVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  921. }
  922. else {
  923. viVideoTitle = getMyContent(page.url, '"title":"(.*?)"', false);
  924. }
  925. if (viVideoTitle) {
  926. viVideoTitle = viVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  927. viVideoTitle = viVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  928. viVideoTitle = viVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  929. viVideoTitle = viVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  930. viVideoTitle = viVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  931. viVideoTitle = viVideoTitle.replace(/on\sVimeo$/, '');
  932. }
  933.  
  934. /* Get Content Source */
  935. var viVideoSource = getMyContent(page.url, 'config_url":"(.*?)"', false);
  936. if (viVideoSource) viVideoSource = cleanMyContent(viVideoSource, false);
  937. else {
  938. viVideoSource = getMyContent(page.url, 'data-config-url="(.*?)"', false);
  939. if (viVideoSource) viVideoSource = viVideoSource.replace(/&amp;/g, '&');
  940. }
  941.  
  942. /* Get Videos Content */
  943. var viVideosContent;
  944. if (viVideoSource) {
  945. viVideosContent = getMyContent(viVideoSource, '"progressive":\\[(.*?)\\]', false);
  946. }
  947.  
  948. /* Get Videos */
  949. if (viVideosContent) {
  950. var viVideoFormats = {'1440p': 'Quad High Definition MP4', '1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '540p': 'Standard Definition MP4',
  951. '480p': 'Standard Definition MP4', '360p': 'Low Definition MP4', '270p': 'Very Low Definition MP4', '240p': 'Very Low Definition MP4'};
  952. var viVideoList = {};
  953. var viVideoFound = false;
  954. var viVideo, myVideoCode;
  955. var viVideos = viVideosContent.split('},');
  956. for (var i = 0; i < viVideos.length; i++) {
  957. for (var viVideoCode in viVideoFormats) {
  958. if (viVideos[i].indexOf('"quality":"' + viVideoCode + '"') != -1) {
  959. viVideo = viVideos[i].match(/"url":"(.*?)"/);
  960. viVideo = (viVideo) ? viVideo[1] : null;
  961. if (viVideo) {
  962. if (!viVideoFound) viVideoFound = true;
  963. myVideoCode = viVideoFormats[viVideoCode];
  964. viVideoList[myVideoCode] = viVideo;
  965. }
  966. }
  967. }
  968. }
  969.  
  970. if (viVideoFound) {
  971. /* Create Saver */
  972. var viDefaultVideo = 'Low Definition MP4';
  973. saver = {'videoList': viVideoList, 'videoSave': viDefaultVideo, 'videoTitle': viVideoTitle};
  974. feature['container'] = false;
  975. option['definitions'] = ['Quad High Definition', 'Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  976. option['containers'] = ['MP4'];
  977. createMySaver();
  978. }
  979. else {
  980. saver = {'warnMess': '!videos'};
  981. createMySaver();
  982. }
  983. }
  984. else {
  985. saver = {'warnMess': '!content'};
  986. createMySaver();
  987. }
  988.  
  989. }
  990.  
  991. // =====MetaCafe===== //
  992.  
  993. else if (page.url.indexOf('metacafe.com/watch') != -1) {
  994.  
  995. /* Get Videos Content */
  996. var mcVideosContent = getMyContent(page.url, 'flashvars\\s*=\\s*\\{(.*?)\\};', false);
  997.  
  998. /* Get Videos */
  999. if (mcVideosContent) {
  1000. var mcVideoList = {};
  1001. var mcVideoFound = false;
  1002. var mcVideoFormats = {'video_alt_url2': 'High Definition MP4', 'video_alt_url': 'Low Definition MP4', 'video_url': 'Very Low Definition MP4'};
  1003. var mcVideoFormatz = {'video_alt_url2': '_720p', 'video_alt_url': '_360p', 'video_url': '_240p'};
  1004. var mcVideoHLS = mcVideosContent.match(/"src":"(.*?)"/);
  1005. mcVideoHLS = (mcVideoHLS) ? cleanMyContent(mcVideoHLS[1], false) : null;
  1006. if (mcVideoHLS) {
  1007. var mcVideoParser, mcVideoParse, myVideoCode, mcVideo;
  1008. for (var mcVideoCode in mcVideoFormats) {
  1009. mcVideoParser = '"' + mcVideoCode + '":"(.*?)"';
  1010. mcVideoParse = mcVideosContent.match(mcVideoParser);
  1011. mcVideo = (mcVideoParse) ? mcVideoParse[1] : null;
  1012. if (mcVideo) {
  1013. if (!mcVideoFound) mcVideoFound = true;
  1014. myVideoCode = mcVideoFormats[mcVideoCode];
  1015. mcVideoList[myVideoCode] = mcVideoHLS.replace('.m3u8', mcVideoFormatz[mcVideoCode] + '.m3u8');
  1016. }
  1017. }
  1018. }
  1019.  
  1020. if (mcVideoFound) {
  1021. /* Create Saver */
  1022. var mcDefaultVideo = 'Low Definition MP4';
  1023. saver = {'videoList': mcVideoList, 'videoSave': mcDefaultVideo};
  1024. feature['container'] = false;
  1025. option['definitions'] = ['High Definition', 'Low Definition', 'Very Low Definition'];
  1026. option['containers'] = ['MP4'];
  1027. createMySaver();
  1028. }
  1029. else {
  1030. saver = {'warnMess': '!videos'};
  1031. createMySaver();
  1032. }
  1033. }
  1034. else {
  1035. saver = {};
  1036. var ytVideoId = page.url.match(/\/yt-(.*?)\//);
  1037. if (ytVideoId && ytVideoId[1]) {
  1038. var ytVideoLink = 'http://youtube.com/watch?v=' + ytVideoId[1];
  1039. saver['warnMess'] = 'embed';
  1040. saver['warnContent'] = ytVideoLink;
  1041. }
  1042. else saver['warnMess'] = '!videos';
  1043. createMySaver();
  1044. }
  1045.  
  1046. }
  1047.  
  1048. // =====Veoh===== //
  1049.  
  1050. else if (page.url.indexOf('veoh.com/watch') != -1) {
  1051.  
  1052. /* Get Video Availability */
  1053. if (getMyElement('', 'div', 'class', 'veoh-video-player-error', 0, false)) return;
  1054.  
  1055. /* Get Video Title */
  1056. var veVideoTitle = getMyContent(page.url, 'meta\\s+name="og:title"\\s+content="(.*?)"', false);
  1057. if (veVideoTitle) {
  1058. veVideoTitle = veVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1059. veVideoTitle = veVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1060. veVideoTitle = veVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1061. veVideoTitle = veVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1062. veVideoTitle = veVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1063. }
  1064.  
  1065. /* Get Videos Content */
  1066. var veVideosContent = getMyContent(page.url.replace(/\/watch\//, '/watch/getVideo/'), '"src"\\s*:\\s*\\{(.*?)\\}', false);
  1067.  
  1068. /* Get Videos */
  1069. if (veVideosContent) {
  1070. var veVideoFormats = {'Regular': 'Low Definition MP4', 'HQ': 'Standard Definition MP4'};
  1071. var veVideoList = {};
  1072. var veVideoFound = false;
  1073. var veVideoParser, veVideoParse, veVideo, myVideoCode;
  1074. for (var veVideoCode in veVideoFormats) {
  1075. veVideoParser = veVideoCode + '":"(.*?)"';
  1076. veVideoParse = veVideosContent.match(veVideoParser);
  1077. veVideo = (veVideoParse) ? veVideoParse[1] : null;
  1078. if (veVideo) {
  1079. if (!veVideoFound) veVideoFound = true;
  1080. myVideoCode = veVideoFormats[veVideoCode];
  1081. veVideoList[myVideoCode] = cleanMyContent(veVideo, false);
  1082. }
  1083. }
  1084.  
  1085. if (veVideoFound) {
  1086. /* Create Saver */
  1087. var veDefaultVideo = 'Low Definition MP4';
  1088. saver = {'videoList': veVideoList, 'videoSave': veDefaultVideo, 'videoTitle': veVideoTitle};
  1089. feature['container'] = false;
  1090. feature['fullsize'] = false;
  1091. option['definition'] = 'LD';
  1092. option['definitions'] = ['Standard Definition', 'Low Definition'];
  1093. option['containers'] = ['MP4'];
  1094. createMySaver();
  1095. }
  1096. else {
  1097. saver = {};
  1098. var ytVideoId = getMyContent(page.url, 'youtube.com/embed/(.*?)("|\\?)', false);
  1099. if (!ytVideoId) ytVideoId = getMyContent(page.url, '"videoId":"yapi-(.*?)"', false);
  1100. if (ytVideoId) {
  1101. var ytVideoLink = 'http://youtube.com/watch?v=' + ytVideoId;
  1102. saver['warnMess'] = 'embed';
  1103. saver['warnContent'] = ytVideoLink;
  1104. }
  1105. else saver['warnMess'] = '!videos';
  1106. createMySaver();
  1107. }
  1108. }
  1109. else {
  1110. saver = {'warnMess': '!content'};
  1111. createMySaver();
  1112. }
  1113.  
  1114. }
  1115.  
  1116. // =====Viki===== //
  1117.  
  1118. else if (page.url.indexOf('viki.com/videos') != -1) {
  1119.  
  1120. /* Get Video Title */
  1121. var vkVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  1122. if (vkVideoTitle) {
  1123. vkVideoTitle = vkVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1124. vkVideoTitle = vkVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1125. vkVideoTitle = vkVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1126. vkVideoTitle = vkVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1127. vkVideoTitle = vkVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1128. }
  1129.  
  1130. /* Get Video ID */
  1131. var vkVideoID = page.url.match(/videos\/(\d+v)/);
  1132. vkVideoID = (vkVideoID) ? vkVideoID[1] : null;
  1133.  
  1134. /* Get Videos Content */
  1135. var vkVideosContent;
  1136. if (vkVideoID) {
  1137. /* SHA-1
  1138. Copyright 2008-2018 Brian Turek, 1998-2009 Paul Johnston & Contributors
  1139. Distributed under the BSD License
  1140. See https://caligatio.github.com/jsSHA/ for more information
  1141. */
  1142. var SHA1FuncBody;
  1143. var SHA1Key = 'sha1js';
  1144. try {
  1145. if (localStorage.getItem(SHA1Key)) {
  1146. SHA1FuncBody = localStorage.getItem(SHA1Key);
  1147. }
  1148. else throw false;
  1149. }
  1150. catch(e) {
  1151. SHA1FuncBody = getMyContent('https://raw.githack.com/Caligatio/jsSHA/master/src/sha1.js', 'TEXT', false);
  1152. localStorage.setItem(SHA1Key, SHA1FuncBody);
  1153. }
  1154. var SHA1Func = new Function('a', SHA1FuncBody);
  1155. var SHA1 = new SHA1Func();
  1156. if (SHA1.jsSHA) {
  1157. var shaObj = new SHA1.jsSHA("SHA-1", "TEXT");
  1158. var vkTimestamp = parseInt(Date.now() / 1000);
  1159. var vkQuery = "/v5/videos/" + vkVideoID + "/streams.json?app=100005a&t=" + vkTimestamp + "&site=www.viki.com"
  1160. var vkToken = "MM_d*yP@`&1@]@!AVrXf_o-HVEnoTnm$O-ti4[G~$JDI/Dc-&piU&z&5.;:}95\=Iad";
  1161. shaObj.setHMACKey(vkToken, "TEXT");
  1162. shaObj.update(vkQuery);
  1163. var vkSig = shaObj.getHMAC("HEX");
  1164. var vkSource = "https://api.viki.io" + vkQuery + "&sig=" + vkSig;
  1165. vkVideosContent = getMyContent(vkSource, 'TEXT', false);
  1166. }
  1167. }
  1168.  
  1169. /* Get Videos */
  1170. if (vkVideosContent) {
  1171. var vkVideoList = {};
  1172. var vkVideoFormats = {'1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '480p': 'Standard Definition MP4',
  1173. '360p': 'Low Definition MP4', '240p': 'Very Low Definition MP4'};
  1174. var vkVideoFound = false;
  1175. var vkVideoParser, vkVideoParse, vkVideo, myVideoCode;
  1176. for (var vkVideoCode in vkVideoFormats) {
  1177. vkVideoParser = '"' + vkVideoCode + '".*?"https":\{"url":"(.*?)"';
  1178. vkVideoParse = vkVideosContent.match(vkVideoParser);
  1179. vkVideo = (vkVideoParse) ? vkVideoParse[1] : null;
  1180. if (vkVideo) {
  1181. if (!vkVideoFound) vkVideoFound = true;
  1182. myVideoCode = vkVideoFormats[vkVideoCode];
  1183. vkVideoList[myVideoCode] = vkVideo;
  1184. }
  1185. }
  1186.  
  1187. // Unauthorized
  1188. var vkUnauthorized = (vkVideosContent.indexOf('unauthorized') != -1) ? true : false;
  1189.  
  1190. // DASH/HLS/Subtitles
  1191. vkVideosContent = getMyContent(page.url.replace('/videos/', '/player5_fragment/'), 'TEXT', false);
  1192. if (vkVideosContent) {
  1193. vkVideoEncDASH = vkVideosContent.match(/dash\+xml".*?stream=(.*?)"/);
  1194. vkVideoEncDASH = (vkVideoEncDASH) ? vkVideoEncDASH[1] : null;
  1195. vkVideoEncHLS = vkVideosContent.match(/x-mpegURL".*?stream=(.*?)"/);
  1196. vkVideoEncHLS = (vkVideoEncHLS) ? vkVideoEncHLS[1] : null;
  1197. if (vkVideoEncDASH || vkVideoEncHLS) {
  1198. vkVideoEncKey = vkVideosContent.match(/chabi:\s*'(.*?)'/);
  1199. vkVideoEncKey = (vkVideoEncKey) ? vkVideoEncKey[1] : null;
  1200. vkVideoEncIV = vkVideosContent.match(/ecta:\s*'(.*?)'/);
  1201. vkVideoEncIV = (vkVideoEncIV) ? vkVideoEncIV[1] : null;
  1202. if (vkVideoEncKey && vkVideoEncIV) {
  1203. /* AES
  1204. Copyright 2015-2018 Richard Moore
  1205. MIT License.
  1206. See https://github.com/ricmoo/aes-js/ for more information
  1207. */
  1208. var AESFuncBody;
  1209. var AESKey = 'aesjs';
  1210. try {
  1211. if (localStorage.getItem(AESKey)) {
  1212. AESFuncBody = localStorage.getItem(AESKey);
  1213. }
  1214. else throw false;
  1215. }
  1216. catch(e) {
  1217. AESFuncBody = getMyContent('https://raw.githack.com/ricmoo/aes-js/master/index.js', 'TEXT', false);
  1218. localStorage.setItem(AESKey, AESFuncBody);
  1219. }
  1220. var AESFunc = new Function('a', AESFuncBody);
  1221. var AES = new AESFunc();
  1222. var AESKey = AES.aesjs.utils.utf8.toBytes(vkVideoEncKey);
  1223. var AESIV = AES.aesjs.utils.utf8.toBytes(vkVideoEncIV);
  1224. var encryptedBytes, decryptedBytes;
  1225. // HLS
  1226. encryptedBytes = AES.aesjs.utils.hex.toBytes(vkVideoEncHLS);
  1227. AESCBC = new AES.aesjs.ModeOfOperation.cbc(AESKey, AESIV);
  1228. decryptedBytes = AESCBC.decrypt(encryptedBytes);
  1229. var vkHLSManifest = AES.aesjs.utils.utf8.fromBytes(decryptedBytes);
  1230. if (vkHLSManifest) {
  1231. if (!vkVideoFound) vkVideoFound = true;
  1232. vkVideoList['Any Definition HLS'] = vkHLSManifest;
  1233. }
  1234. // DASH
  1235. encryptedBytes = AES.aesjs.utils.hex.toBytes(vkVideoEncDASH);
  1236. AESCBC = new AES.aesjs.ModeOfOperation.cbc(AESKey, AESIV);
  1237. decryptedBytes = AESCBC.decrypt(encryptedBytes);
  1238. var vkDASHManifest = AES.aesjs.utils.utf8.fromBytes(decryptedBytes);
  1239. if (vkDASHManifest) {
  1240. var vkDASHDomain = vkDASHManifest.split('/').splice(0, 5).join('/');
  1241. var vkDASHContent = getMyContent(vkDASHManifest, 'TEXT', false);
  1242. if (vkDASHContent) {
  1243. var vkDASHVideo;
  1244. var vkDASHVideos = vkDASHContent.match(new RegExp('<BaseURL>.*?</BaseURL>', 'g'));
  1245. if (vkDASHVideos) {
  1246. for (var i = 0; i < vkDASHVideos.length; i++) {
  1247. vkDASHVideo = vkDASHVideos[i].replace('<BaseURL>', '').replace('</BaseURL>', '');
  1248. if (vkDASHVideo.indexOf('http') != 0) vkDASHVideo = vkDASHDomain + '/' + vkDASHVideo;
  1249. for (var vkVideoCode in vkVideoFormats) {
  1250. if (vkDASHVideo.indexOf(vkVideoCode) != -1) {
  1251. myVideoCode = vkVideoFormats[vkVideoCode];
  1252. if (vkDASHVideo.indexOf('track1') != -1) {
  1253. if (!vkVideoFound) vkVideoFound = true;
  1254. if (!vkVideoList[myVideoCode]) {
  1255. vkVideoList[myVideoCode.replace('MP4', 'Video MP4')] = vkDASHVideo;
  1256. }
  1257. }
  1258. if (vkDASHVideo.indexOf('track2') != -1) {
  1259. if (!vkVideoList[myVideoCode]) {
  1260. vkVideoList[myVideoCode.replace('MP4', 'Audio MP4')] = vkDASHVideo;
  1261. }
  1262. }
  1263. }
  1264. }
  1265. }
  1266. }
  1267. for (var vkVideoCode in vkVideoFormats) {
  1268. myVideoCode = vkVideoFormats[vkVideoCode];
  1269. if (!vkVideoList[myVideoCode]) {
  1270. if (vkVideoList[myVideoCode.replace('MP4', 'Video MP4')] && vkVideoList[myVideoCode.replace('MP4', 'Audio MP4')]) {
  1271. vkVideoList[myVideoCode] = 'DASH';
  1272. }
  1273. }
  1274. }
  1275. }
  1276. }
  1277. }
  1278. }
  1279. // Subtitles
  1280. var vkSubtitles = vkVideosContent.match(/"srclang":"en".*?"src":"(.*?)"/);
  1281. vkSubtitles = (vkSubtitles) ? vkSubtitles[1] : null;
  1282. if (vkSubtitles) vkVideoList['EN Subtitles WebVTT'] = vkSubtitles;
  1283. }
  1284.  
  1285. /* Create Saver */
  1286. if (vkVideoFound) {
  1287. var vkDefaultVideo = 'Low Definition MP4';
  1288. saver = {'videoList': vkVideoList, 'videoSave': vkDefaultVideo, 'videoTitle': vkVideoTitle};
  1289. feature['container'] = false;
  1290. feature['dash'] = true;
  1291. option['definition'] = 'LD';
  1292. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1293. option['containers'] = ['MP4'];
  1294. createMySaver();
  1295. }
  1296. else {
  1297. if (vkUnauthorized) {
  1298. saver = {
  1299. 'warnMess': 'other',
  1300. 'warnContent': '<b>SaveTube:</b> Authorization required!'
  1301. };
  1302. }
  1303. else saver = {'warnMess': '!videos'};
  1304. createMySaver();
  1305. }
  1306. }
  1307. else {
  1308. saver = {'warnMess': '!content'};
  1309. createMySaver();
  1310. }
  1311.  
  1312. }
  1313.  
  1314. // =====IMDB===== //
  1315.  
  1316. else if (page.url.indexOf('imdb.com') != -1) {
  1317.  
  1318. /* Redirect To Video Page */
  1319. if (page.url.indexOf('/video/') == -1 && page.url.indexOf('/videoplayer/') == -1) {
  1320. page.doc.addEventListener('click', function(e) {
  1321. var p = e.target.parentNode;
  1322. while (p) {
  1323. if (p.tagName === 'A' && p.href.indexOf('/video/imdb') != -1) {
  1324. page.win.location.href = p.href.replace(/imdb\/inline.*/, '');
  1325. }
  1326. p = p.parentNode;
  1327. }
  1328. }, false);
  1329. return;
  1330. }
  1331.  
  1332. /* Get Video Title */
  1333. var imdbVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  1334. if (imdbVideoTitle) {
  1335. imdbVideoTitle = imdbVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1336. imdbVideoTitle = imdbVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1337. imdbVideoTitle = imdbVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1338. imdbVideoTitle = imdbVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1339. imdbVideoTitle = imdbVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1340. }
  1341.  
  1342. /* Get Video Id */
  1343. var imdbVideoId = page.url.replace(/.*videoplayer\//, '').replace(/(\/|\?).*/, '');
  1344.  
  1345. /* Get Videos Content */
  1346. var imdbVideosContent = getMyContent(page.url, '"' + imdbVideoId + '":\\{("aggregateUpVotes.*?videoId)', false);
  1347.  
  1348. /* Get Videos */
  1349. var imdbVideoList = {};
  1350. if (imdbVideosContent) {
  1351. var imdbVideoFormats = {'1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '480p': 'Standard Definition MP4',
  1352. '360p': 'Low Definition MP4', 'SD': 'Low Definition MP4', '240p': 'Very Low Definition MP4'};
  1353. var imdbVideoFound = false;
  1354. var imdbVideoParser, imdbVideoParse, myVideoCode, imdbVideo;
  1355. for (var imdbVideoCode in imdbVideoFormats) {
  1356. imdbVideoParser = '"definition":"' + imdbVideoCode + '".*?"videoUrl":"(.*?)"';
  1357. imdbVideoParse = imdbVideosContent.match(imdbVideoParser);
  1358. imdbVideo = (imdbVideoParse) ? imdbVideoParse[1] : null;
  1359. if (imdbVideo) {
  1360. imdbVideo = cleanMyContent(imdbVideo, false);
  1361. if (!imdbVideoFound) imdbVideoFound = true;
  1362. myVideoCode = imdbVideoFormats[imdbVideoCode];
  1363. if (!imdbVideoList[myVideoCode]) imdbVideoList[myVideoCode] = imdbVideo;
  1364. }
  1365. }
  1366.  
  1367. if (imdbVideoFound) {
  1368. /* Create Saver */
  1369. var imdbDefaultVideo = 'Low Definition MP4';
  1370. saver = {'videoList': imdbVideoList, 'videoSave': imdbDefaultVideo, 'videoTitle': imdbVideoTitle};
  1371. feature['container'] = false;
  1372. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1373. option['containers'] = ['MP4'];
  1374. createMySaver();
  1375. }
  1376. else {
  1377. saver = {'warnMess': '!videos'};
  1378. createMySaver();
  1379. }
  1380. }
  1381. else {
  1382. imdbVideo = getMyContent(page.url, '"videoUrl":"(.*?)"', false);
  1383. if (imdbVideo) {
  1384. /* Create Saver */
  1385. imdbVideo = cleanMyContent(imdbVideo, false);
  1386. imdbVideoList[imdbDefaultVideo] = imdbVideo;
  1387. var imdbDefaultVideo = 'Low Definition MP4';
  1388. saver = {'videoList': imdbVideoList, 'videoSave': imdbDefaultVideo, 'videoTitle': imdbVideoTitle};
  1389. feature['container'] = false;
  1390. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1391. option['containers'] = ['MP4'];
  1392. createMySaver();
  1393. }
  1394. else {
  1395. saver = {'warnMess': '!content'};
  1396. createMySaver();
  1397. }
  1398. }
  1399.  
  1400. }
  1401.  
  1402. }
  1403.  
  1404.  
  1405. // ==========Run========== //
  1406.  
  1407. SaveTube();
  1408.  
  1409. page.win.setInterval(function() {
  1410. if (page.url != page.win.location.href) {
  1411. if (saver['saverPanel'] && saver['saverPanel'].parentNode) {
  1412. removeMyElement(saver['saverPanel'].parentNode, saver['saverPanel']);
  1413. }
  1414. page.doc = page.win.document;
  1415. page.body = page.doc.body;
  1416. page.url = page.win.location.href;
  1417. SaveTube();
  1418. }
  1419. }, 500);
  1420.  
  1421. })();