SaveTube

Download videos from video sharing web sites.

当前为 2019-09-12 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name SaveTube
  3. // @version 2019.09.12
  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']['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 WebM'] || saver['videoList']['Medium Bitrate Audio WebM'] || saver['videoList']['Medium Bitrate Audio MP4'];
  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. if (!ytVideosEncodedFmts) {
  584. ytVideosEncodedFmtsNew = getMyContent(page.url, '"formats\\\\?":\\s*(\\[.*?\\])', false);
  585. if (ytVideosEncodedFmtsNew) {
  586. ytVideosEncodedFmts = '';
  587. ytVideosEncodedFmtsNew = cleanMyContent(ytVideosEncodedFmtsNew, false);
  588. ytVideosEncodedFmtsNew = ytVideosEncodedFmtsNew.match(new RegExp('"url":\s*".*?"', 'g'));
  589. if (ytVideosEncodedFmtsNew) {
  590. for (var i = 0 ; i < ytVideosEncodedFmtsNew.length; i++) {
  591. ytVideosEncodedFmts += ytVideosEncodedFmtsNew[i].replace(/"/g, '').replace('url:', 'url=') + ',';
  592. }
  593. }
  594. }
  595. }
  596. ytVideosAdaptiveFmts = getMyContent(page.url, '"adaptive_fmts\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  597. if (!ytVideosAdaptiveFmts) {
  598. ytVideosAdaptiveFmtsNew = getMyContent(page.url, '"adaptiveFormats\\\\?":\\s*(\\[.*?\\])', false);
  599. if (ytVideosAdaptiveFmtsNew) {
  600. ytVideosAdaptiveFmts = '';
  601. ytVideosAdaptiveFmtsNew = cleanMyContent(ytVideosAdaptiveFmtsNew, false);
  602. ytVideosAdaptiveFmtsNew = ytVideosAdaptiveFmtsNew.match(new RegExp('"url":\s*".*?"', 'g'));
  603. if (ytVideosAdaptiveFmtsNew) {
  604. for (var i = 0 ; i < ytVideosAdaptiveFmtsNew.length; i++) {
  605. ytVideosAdaptiveFmts += ytVideosAdaptiveFmtsNew[i].replace(/"/g, '').replace('url:', 'url=') + ',';
  606. }
  607. }
  608. }
  609. }
  610. if (!ytVideosAdaptiveFmts) {
  611. var ytDASHVideos, ytDASHContent;
  612. ytDASHVideos = getMyContent(page.url, '"dashmpd\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  613. if (ytDASHVideos) {
  614. ytDASHVideos = cleanMyContent(ytDASHVideos, false);
  615. ytDASHContent = getMyContent(ytDASHVideos + '?pacing=0', 'TEXT', false);
  616. if (ytDASHContent) {
  617. var ytDASHVideo, ytDASHVideoParts, ytDASHVideoServer, ytDASHVideoParams;
  618. ytDASHVideos = ytDASHContent.match(new RegExp('<BaseURL>.*?</BaseURL>', 'g'));
  619. if (ytDASHVideos) {
  620. ytVideosAdaptiveFmts = '';
  621. for (var i = 0; i < ytDASHVideos.length; i++) {
  622. ytDASHVideo = ytDASHVideos[i].replace('<BaseURL>', '').replace('</BaseURL>', '');
  623. if (ytDASHVideo.indexOf('source/youtube') == -1) continue;
  624. ytDASHVideoParts = ytDASHVideo.split('videoplayback/');
  625. ytDASHVideoServer = ytDASHVideoParts[0] + 'videoplayback?';
  626. ytDASHVideoParams = ytDASHVideoParts[1].split('/');
  627. ytDASHVideo = '';
  628. for (var p = 0; p < ytDASHVideoParams.length; p++) {
  629. if (p % 2) ytDASHVideo += ytDASHVideoParams[p] + '&';
  630. else ytDASHVideo += ytDASHVideoParams[p] + '=';
  631. }
  632. ytDASHVideo = encodeURIComponent(ytDASHVideoServer + ytDASHVideo);
  633. ytDASHVideo = ytDASHVideo.replace('itag%3D', 'itag=');
  634. ytVideosAdaptiveFmts += ytDASHVideo + ',';
  635. }
  636. }
  637. }
  638. }
  639. }
  640. if (ytVideosEncodedFmts) {
  641. ytVideosContent = ytVideosEncodedFmts;
  642. }
  643. else {
  644. ytHLSVideos = getMyContent(page.url, '"hls(?:vp|ManifestUrl)\\\\?":\\s*\\\\?"(.*?)\\\\?"', false);
  645. if (ytHLSVideos) {
  646. ytHLSVideos = cleanMyContent(ytHLSVideos, false);
  647. if (ytHLSVideos.indexOf('keepalive/yes/') != -1) ytHLSVideos = ytHLSVideos.replace('keepalive/yes/', '');
  648. }
  649. else {
  650. var ytVideoID = page.url.match(/(\?|&)v=(.*?)(&|$)/);
  651. ytVideoID = (ytVideoID) ? ytVideoID[2] : null;
  652. if (ytVideoID) {
  653. var ytVideosInfoPage = page.win.location.protocol + '//' + page.win.location.hostname + '/get_video_info?video_id=' + ytVideoID + '&eurl=https://youtube.googleapis.com/v/';
  654. ytVideosEncodedFmts = getMyContent(ytVideosInfoPage, 'url_encoded_fmt_stream_map=(.*?)&', false);
  655. if (ytVideosEncodedFmts) {
  656. ytVideosEncodedFmts = cleanMyContent(ytVideosEncodedFmts, true);
  657. ytVideosContent = ytVideosEncodedFmts;
  658. }
  659. else {
  660. ytVideosEncodedFmtsNew = getMyContent(ytVideosInfoPage, 'formats%22%3A(%5B.*?%5D)', false);
  661. if (ytVideosEncodedFmtsNew) {
  662. ytVideosEncodedFmts = '';
  663. ytVideosEncodedFmtsNew = cleanMyContent(ytVideosEncodedFmtsNew, true);
  664. ytVideosEncodedFmtsNew = ytVideosEncodedFmtsNew.match(new RegExp('"(url|cipher)":\s*".*?"', 'g'));
  665. if (ytVideosEncodedFmtsNew) {
  666. for (var i = 0 ; i < ytVideosEncodedFmtsNew.length; i++) {
  667. ytVideosEncodedFmts += ytVideosEncodedFmtsNew[i].replace(/"/g, '').replace('url:', 'url=').replace('cipher:', '') + ',';
  668. }
  669. if (ytVideosEncodedFmts.indexOf('%3A%2F%2F') != -1) {
  670. ytVideosEncodedFmts = cleanMyContent(ytVideosEncodedFmts, true);
  671. }
  672. ytVideosContent = ytVideosEncodedFmts;
  673. }
  674. }
  675. }
  676. if (!ytVideosAdaptiveFmts) {
  677. ytVideosAdaptiveFmts = getMyContent(ytVideosInfoPage, 'adaptive_fmts=(.*?)&', false);
  678. if (ytVideosAdaptiveFmts) {
  679. ytVideosAdaptiveFmts = cleanMyContent(ytVideosAdaptiveFmts, true);
  680. }
  681. else {
  682. ytVideosAdaptiveFmtsNew = getMyContent(ytVideosInfoPage, 'adaptiveFormats%22%3A(%5B.*?%5D)', false);
  683. if (ytVideosAdaptiveFmtsNew) {
  684. ytVideosAdaptiveFmts = '';
  685. ytVideosAdaptiveFmtsNew = cleanMyContent(ytVideosAdaptiveFmtsNew, true);
  686. ytVideosAdaptiveFmtsNew = ytVideosAdaptiveFmtsNew.match(new RegExp('"(url|cipher)":\s*".*?"', 'g'));
  687. if (ytVideosAdaptiveFmtsNew) {
  688. for (var i = 0 ; i < ytVideosAdaptiveFmtsNew.length; i++) {
  689. ytVideosAdaptiveFmts += ytVideosAdaptiveFmtsNew[i].replace(/"/g, '').replace('url:', 'url=').replace('cipher:', '') + ',';
  690. }
  691. if (ytVideosAdaptiveFmts.indexOf('%3A%2F%2F') != -1) {
  692. ytVideosAdaptiveFmts = cleanMyContent(ytVideosAdaptiveFmts, true);
  693. }
  694. }
  695. }
  696. }
  697. }
  698. }
  699. }
  700. }
  701. if (ytVideosAdaptiveFmts && !ytHLSVideos) {
  702. if (ytVideosContent) ytVideosContent += ',' + ytVideosAdaptiveFmts;
  703. else ytVideosContent = ytVideosAdaptiveFmts;
  704. }
  705.  
  706. /* Create Saver */
  707. var ytDefaultVideo = 'Low Definition MP4';
  708. function ytSaver() {
  709. saver = {'videoList': ytVideoList, 'videoSave': ytDefaultVideo, 'videoTitle': ytVideoTitle};
  710. option['definitions'] = ['Ultra High Definition', 'Quad High Definition', 'Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  711. option['containers'] = ['MP4', 'WebM', 'Any'];
  712. }
  713.  
  714. /* Parse Videos */
  715. function ytVideos() {
  716. var ytVideoFormats = {
  717. '18': 'Low Definition MP4',
  718. '22': 'High Definition MP4',
  719. '43': 'Low Definition WebM',
  720. '133': 'Very Low Definition Video MP4',
  721. '134': 'Low Definition Video MP4',
  722. '135': 'Standard Definition Video MP4',
  723. '136': 'High Definition Video MP4',
  724. '137': 'Full High Definition Video MP4',
  725. '140': 'Medium Bitrate Audio MP4',
  726. '242': 'Very Low Definition Video WebM',
  727. '243': 'Low Definition Video WebM',
  728. '244': 'Standard Definition Video WebM',
  729. '247': 'High Definition Video WebM',
  730. '248': 'Full High Definition Video WebM',
  731. '249': 'Low Bitrate Audio WebM',
  732. '250': 'Medium Bitrate Audio WebM',
  733. '251': 'High Bitrate Audio WebM',
  734. '264': 'Quad High Definition Video MP4',
  735. '271': 'Quad High Definition Video WebM',
  736. '272': 'Ultra High Definition Video WebM',
  737. '298': 'High Definition Video MP4',
  738. '299': 'Full High Definition Video MP4',
  739. '302': 'High Definition Video WebM',
  740. '303': 'Full High Definition Video WebM',
  741. '308': 'Quad High Definition Video WebM',
  742. '313': 'Ultra High Definition Video WebM',
  743. '315': 'Ultra High Definition Video WebM',
  744. '333': 'Standard Definition Video WebM',
  745. '334': 'High Definition Video WebM',
  746. '335': 'Full High Definition Video WebM',
  747. '337': 'Ultra High Definition Video WebM'
  748. };
  749. var ytVideoFound = false;
  750. var ytVideos = ytVideosContent.split(',');
  751. var ytVideoParse, ytVideoCodeParse, ytVideoCode, myVideoCode, ytVideo, ytSign, ytSignP;
  752. for (var i = 0; i < ytVideos.length; i++) {
  753. if (!ytVideos[i].match(/^url/)) {
  754. ytVideoParse = ytVideos[i].match(/(.*)(url=.*$)/);
  755. if (ytVideoParse) ytVideos[i] = ytVideoParse[2] + '&' + ytVideoParse[1];
  756. }
  757. ytVideoCodeParse = ytVideos[i].match(/itag=(\d{1,3})/);
  758. ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null;
  759. if (ytVideoCode) {
  760. myVideoCode = ytVideoFormats[ytVideoCode];
  761. if (myVideoCode) {
  762. ytVideo = cleanMyContent(ytVideos[i], true);
  763. if (myVideoCode.indexOf('Video') != -1) {
  764. if (ytVideo.indexOf('source=yt_otf') != -1) continue;
  765. }
  766. ytVideo = ytVideo.replace(/url=/, '').replace(/&$/, '');
  767. if (ytVideo.match(/itag=/) && ytVideo.match(/itag=/g).length > 1) {
  768. if (ytVideo.match(/itag=\d{1,3}&/)) ytVideo = ytVideo.replace(/itag=\d{1,3}&/, '');
  769. else if (ytVideo.match(/&itag=\d{1,3}/)) ytVideo = ytVideo.replace(/&itag=\d{1,3}/, '');
  770. }
  771. if (ytVideo.match(/clen=/) && ytVideo.match(/clen=/g).length > 1) {
  772. if (ytVideo.match(/clen=\d+&/)) ytVideo = ytVideo.replace(/clen=\d+&/, '');
  773. else if (ytVideo.match(/&clen=\d+/)) ytVideo = ytVideo.replace(/&clen=\d+/, '');
  774. }
  775. if (ytVideo.match(/lmt=/) && ytVideo.match(/lmt=/g).length > 1) {
  776. if (ytVideo.match(/lmt=\d+&/)) ytVideo = ytVideo.replace(/lmt=\d+&/, '');
  777. else if (ytVideo.match(/&lmt=\d+/)) ytVideo = ytVideo.replace(/&lmt=\d+/, '');
  778. }
  779. if (ytVideo.match(/type=(video|audio).*?&/)) ytVideo = ytVideo.replace(/type=(video|audio).*?&/, '');
  780. else ytVideo = ytVideo.replace(/&type=(video|audio).*$/, '');
  781. if (ytVideo.match(/xtags=[^%=]*&/)) ytVideo = ytVideo.replace(/xtags=[^%=]*?&/, '');
  782. else if (ytVideo.match(/&xtags=[^%=]*$/)) ytVideo = ytVideo.replace(/&xtags=[^%=]*$/, '');
  783. if (ytVideo.match(/&sig=/) && !ytVideo.match(/&lsig=/)) ytVideo = ytVideo.replace(/&sig=/, '&signature=');
  784. else if (ytVideo.match(/&s=/)) {
  785. ytSign = ytVideo.match(/&s=(.*?)(&|$)/);
  786. ytSign = (ytSign) ? ytSign[1] : null;
  787. if (ytSign) {
  788. ytSign = ytDecryptSignature(ytSign);
  789. if (ytSign) {
  790. ytSignP = ytVideo.match(/&sp=(.*?)(&|$)/);
  791. ytSignP = (ytSignP) ? ytSignP[1] : ((ytVideo.match(/&lsig=/)) ? 'sig' : 'signature');
  792. ytVideo = ytVideo.replace(/&s=.*?(&|$)/, '&' + ytSignP + '=' + ytSign + '$1');
  793. }
  794. else ytVideo = '';
  795. }
  796. else ytVideo = '';
  797. }
  798. ytVideo = cleanMyContent(ytVideo, true);
  799. if (ytVideo.indexOf('ratebypass') == -1) ytVideo += '&ratebypass=yes';
  800. if (ytVideo && ytVideo.indexOf('http') == 0) {
  801. if (!ytVideoFound) ytVideoFound = true;
  802. ytVideoList[myVideoCode] = ytVideo;
  803. }
  804. }
  805. }
  806. }
  807.  
  808. if (ytVideoFound) {
  809. /* DASH */
  810. if (ytVideoList['Medium Bitrate Audio MP4'] || ytVideoList['Medium Bitrate Audio WebM']) {
  811. for (var myVideoCode in ytVideoList) {
  812. if (myVideoCode.indexOf('Video') != -1) {
  813. if (!ytVideoList[myVideoCode.replace(' Video', '')]) {
  814. ytVideoList[myVideoCode.replace(' Video', '')] = 'DASH';
  815. }
  816. }
  817. }
  818. }
  819. feature['dash'] = true;
  820.  
  821. /* Create Saver */
  822. feature['autoget'] = true;
  823. ytSaver();
  824. createMySaver();
  825. }
  826. else {
  827. saver = {};
  828. if (ytVideosContent.indexOf('conn=rtmp') != -1) saver['warnMess'] = '!support';
  829. else saver['warnMess'] = '!videos';
  830. createMySaver();
  831. }
  832. }
  833.  
  834. /* Parse HLS */
  835. function ytHLS() {
  836. var ytHLSFormats = {
  837. '92': 'Very Low Definition MP4',
  838. '93': 'Low Definition MP4',
  839. '94': 'Standard Definition MP4',
  840. '95': 'High Definition MP4',
  841. '96': 'Full High Definition MP4'
  842. };
  843. ytVideoList["Any Definition MP4"] = ytHLSVideos;
  844. if (ytHLSContent) {
  845. var ytHLSVideo, ytVideoCodeParse, ytVideoCode, myVideoCode;
  846. var ytHLSMatcher = new RegExp('(http.*?m3u8)', 'g');
  847. ytHLSVideos = ytHLSContent.match(ytHLSMatcher);
  848. if (ytHLSVideos) {
  849. for (var i = 0; i < ytHLSVideos.length; i++) {
  850. ytHLSVideo = ytHLSVideos[i];
  851. ytVideoCodeParse = ytHLSVideo.match(/\/itag\/(\d{1,3})\//);
  852. ytVideoCode = (ytVideoCodeParse) ? ytVideoCodeParse[1] : null;
  853. if (ytVideoCode) {
  854. myVideoCode = ytHLSFormats[ytVideoCode];
  855. if (myVideoCode && ytHLSVideo) {
  856. ytVideoList[myVideoCode] = ytHLSVideo;
  857. }
  858. }
  859. }
  860. }
  861. }
  862.  
  863. /* Create Saver */
  864. ytVideoTitle = null;
  865. ytDefaultVideo = 'Any Definition MP4';
  866. ytSaver();
  867. createMySaver();
  868. }
  869.  
  870. /* Get Videos */
  871. var ytVideoList = {};
  872. if (ytVideosContent) {
  873. if (ytVideosContent.match(/^s=/) || ytVideosContent.match(/&s=/) || ytVideosContent.match(/,s=/) || ytVideosContent.match(/u0026s=/)) {
  874. var ytScriptURL = getMyContent(page.url, '"js":\\s*"(.*?)"', true);
  875. if (!ytScriptURL) ytScriptURL = getMyContent(page.url.replace(/watch.*?v=/, 'embed/').replace(/&.*$/, ''), '"js":\\s*"(.*?)"', true);
  876. if (ytScriptURL) {
  877. ytScriptURL = page.win.location.protocol + '//' + page.win.location.hostname + ytScriptURL;
  878. ytScriptSrc = getMyContent(ytScriptURL, 'TEXT', false);
  879. if (ytScriptSrc) ytDecryptFunction();
  880. ytVideos();
  881. }
  882. else {
  883. saver = {
  884. 'warnMess': 'other',
  885. 'warnContent': '<b>SaveTube:</b> Couldn\'t get the signature link. Please report it <a href="' + contact + '" style="color:#00892C">here</a>.'
  886. };
  887. createMySaver();
  888. }
  889. }
  890. else {
  891. ytVideos();
  892. }
  893. }
  894. else {
  895. if (ytHLSVideos) {
  896. ytHLSContent = getMyContent(ytHLSVideos, 'TEXT', false);
  897. ytHLS();
  898. }
  899. else {
  900. saver = {'warnMess': '!content'};
  901. createMySaver();
  902. }
  903. }
  904.  
  905. }
  906.  
  907. // =====DailyMotion===== //
  908.  
  909. else if (page.url.indexOf('dailymotion.com/video') != -1) {
  910.  
  911. /* Video Availability */
  912. if (getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"error":\\{"title":"(.*?)"', false)) return;
  913. if (getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"error_title":"(.*?)"', false)) return;
  914.  
  915. /* Get Video Title */
  916. var dmVideoTitle = getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"title":"(.*?)"', false);
  917. if (dmVideoTitle) {
  918. dmVideoTitle = dmVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  919. dmVideoTitle = dmVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  920. dmVideoTitle = dmVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  921. dmVideoTitle = dmVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  922. dmVideoTitle = dmVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  923. }
  924.  
  925. /* Get Videos Content */
  926. var dmVideosContent = getMyContent(page.url.replace(/\/video\//, "/embed/video/"), '"qualities":\\{(.*?)\\]\\},', false);
  927.  
  928. /* Get Videos */
  929. if (dmVideosContent) {
  930. var dmVideoFormats = {'auto': 'Low Definition MP4', '240': 'Very Low Definition MP4', '380': 'Low Definition MP4',
  931. '480': 'Standard Definition MP4', '720': 'High Definition MP4', '1080': 'Full High Definition MP4'};
  932. var dmVideoList = {};
  933. var dmVideoFound = false;
  934. var dmVideoParser, dmVideoParse, myVideoCode, dmVideo;
  935. for (var dmVideoCode in dmVideoFormats) {
  936. dmVideoParser = '"' + dmVideoCode + '".*?"type":"video.*?mp4","url":"(.*?)"';
  937. dmVideoParse = dmVideosContent.match(dmVideoParser);
  938. if (!dmVideoParse) {
  939. dmVideoParser = '"' + dmVideoCode + '".*?"type":"application.*?mpegURL","url":"(.*?)"';
  940. dmVideoParse = dmVideosContent.match(dmVideoParser);
  941. }
  942. dmVideo = (dmVideoParse) ? dmVideoParse[1] : null;
  943. if (dmVideo) {
  944. if (!dmVideoFound) dmVideoFound = true;
  945. dmVideo = cleanMyContent(dmVideo, true);
  946. myVideoCode = dmVideoFormats[dmVideoCode];
  947. if (!dmVideoList[myVideoCode]) dmVideoList[myVideoCode] = dmVideo;
  948. }
  949. }
  950.  
  951. if (dmVideoFound) {
  952. /* Create Saver */
  953. var dmDefaultVideo = 'Low Definition MP4';
  954. saver = {'videoList': dmVideoList, 'videoSave': dmDefaultVideo, 'videoTitle': dmVideoTitle};
  955. feature['container'] = false;
  956. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  957. option['containers'] = ['MP4'];
  958. createMySaver();
  959. }
  960. else {
  961. saver = {'warnMess': '!videos'};
  962. createMySaver();
  963. }
  964. }
  965. else {
  966. saver = {'warnMess': '!content'};
  967. createMySaver();
  968. }
  969.  
  970. }
  971.  
  972. // =====Vimeo===== //
  973.  
  974. else if (page.url.indexOf('vimeo.com/') != -1) {
  975.  
  976. /* Page Type */
  977. var viPageType = getMyContent(page.url, 'meta\\s+property="og:type"\\s+content="(.*?)"', false);
  978. if (!viPageType || (viPageType != 'video' && viPageType != 'profile')) return;
  979.  
  980. /* Get Video Title */
  981. var viVideoTitle;
  982. if (viPageType == 'video') {
  983. viVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  984. }
  985. else {
  986. viVideoTitle = getMyContent(page.url, '"title":"(.*?)"', false);
  987. }
  988. if (viVideoTitle) {
  989. viVideoTitle = viVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  990. viVideoTitle = viVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  991. viVideoTitle = viVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  992. viVideoTitle = viVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  993. viVideoTitle = viVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  994. viVideoTitle = viVideoTitle.replace(/on\sVimeo$/, '');
  995. }
  996.  
  997. /* Get Content Source */
  998. var viVideoSource = getMyContent(page.url, 'config_url":"(.*?)"', false);
  999. if (viVideoSource) viVideoSource = cleanMyContent(viVideoSource, false);
  1000. else {
  1001. viVideoSource = getMyContent(page.url, 'data-config-url="(.*?)"', false);
  1002. if (viVideoSource) viVideoSource = viVideoSource.replace(/&amp;/g, '&');
  1003. }
  1004.  
  1005. /* Get Videos Content */
  1006. var viVideosContent;
  1007. if (viVideoSource) {
  1008. viVideosContent = getMyContent(viVideoSource, '"progressive":\\[(.*?)\\]', false);
  1009. }
  1010.  
  1011. /* Get Videos */
  1012. if (viVideosContent) {
  1013. var viVideoFormats = {'1440p': 'Quad High Definition MP4', '1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '540p': 'Standard Definition MP4',
  1014. '480p': 'Standard Definition MP4', '360p': 'Low Definition MP4', '270p': 'Very Low Definition MP4', '240p': 'Very Low Definition MP4'};
  1015. var viVideoList = {};
  1016. var viVideoFound = false;
  1017. var viVideo, myVideoCode;
  1018. var viVideos = viVideosContent.split('},');
  1019. for (var i = 0; i < viVideos.length; i++) {
  1020. for (var viVideoCode in viVideoFormats) {
  1021. if (viVideos[i].indexOf('"quality":"' + viVideoCode + '"') != -1) {
  1022. viVideo = viVideos[i].match(/"url":"(.*?)"/);
  1023. viVideo = (viVideo) ? viVideo[1] : null;
  1024. if (viVideo) {
  1025. if (!viVideoFound) viVideoFound = true;
  1026. myVideoCode = viVideoFormats[viVideoCode];
  1027. viVideoList[myVideoCode] = viVideo;
  1028. }
  1029. }
  1030. }
  1031. }
  1032.  
  1033. if (viVideoFound) {
  1034. /* Create Saver */
  1035. var viDefaultVideo = 'Low Definition MP4';
  1036. saver = {'videoList': viVideoList, 'videoSave': viDefaultVideo, 'videoTitle': viVideoTitle};
  1037. feature['container'] = false;
  1038. option['definitions'] = ['Quad High Definition', 'Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1039. option['containers'] = ['MP4'];
  1040. createMySaver();
  1041. }
  1042. else {
  1043. saver = {'warnMess': '!videos'};
  1044. createMySaver();
  1045. }
  1046. }
  1047. else {
  1048. saver = {'warnMess': '!content'};
  1049. createMySaver();
  1050. }
  1051.  
  1052. }
  1053.  
  1054. // =====MetaCafe===== //
  1055.  
  1056. else if (page.url.indexOf('metacafe.com/watch') != -1) {
  1057.  
  1058. /* Get Videos Content */
  1059. var mcVideosContent = getMyContent(page.url, 'flashvars\\s*=\\s*\\{(.*?)\\};', false);
  1060.  
  1061. /* Get Videos */
  1062. if (mcVideosContent) {
  1063. var mcVideoList = {};
  1064. var mcVideoFound = false;
  1065. var mcVideoFormats = {'video_alt_url2': 'High Definition MP4', 'video_alt_url': 'Low Definition MP4', 'video_url': 'Very Low Definition MP4'};
  1066. var mcVideoFormatz = {'video_alt_url2': '_720p', 'video_alt_url': '_360p', 'video_url': '_240p'};
  1067. var mcVideoHLS = mcVideosContent.match(/"src":"(.*?)"/);
  1068. mcVideoHLS = (mcVideoHLS) ? cleanMyContent(mcVideoHLS[1], false) : null;
  1069. if (mcVideoHLS) {
  1070. var mcVideoParser, mcVideoParse, myVideoCode, mcVideo;
  1071. for (var mcVideoCode in mcVideoFormats) {
  1072. mcVideoParser = '"' + mcVideoCode + '":"(.*?)"';
  1073. mcVideoParse = mcVideosContent.match(mcVideoParser);
  1074. mcVideo = (mcVideoParse) ? mcVideoParse[1] : null;
  1075. if (mcVideo) {
  1076. if (!mcVideoFound) mcVideoFound = true;
  1077. myVideoCode = mcVideoFormats[mcVideoCode];
  1078. mcVideoList[myVideoCode] = mcVideoHLS.replace('.m3u8', mcVideoFormatz[mcVideoCode] + '.m3u8');
  1079. }
  1080. }
  1081. }
  1082.  
  1083. if (mcVideoFound) {
  1084. /* Create Saver */
  1085. var mcDefaultVideo = 'Low Definition MP4';
  1086. saver = {'videoList': mcVideoList, 'videoSave': mcDefaultVideo};
  1087. feature['container'] = false;
  1088. option['definitions'] = ['High Definition', 'Low Definition', 'Very Low Definition'];
  1089. option['containers'] = ['MP4'];
  1090. createMySaver();
  1091. }
  1092. else {
  1093. saver = {'warnMess': '!videos'};
  1094. createMySaver();
  1095. }
  1096. }
  1097. else {
  1098. saver = {};
  1099. var ytVideoId = page.url.match(/\/yt-(.*?)\//);
  1100. if (ytVideoId && ytVideoId[1]) {
  1101. var ytVideoLink = 'http://youtube.com/watch?v=' + ytVideoId[1];
  1102. saver['warnMess'] = 'embed';
  1103. saver['warnContent'] = ytVideoLink;
  1104. }
  1105. else saver['warnMess'] = '!videos';
  1106. createMySaver();
  1107. }
  1108.  
  1109. }
  1110.  
  1111. // =====Veoh===== //
  1112.  
  1113. else if (page.url.indexOf('veoh.com/watch') != -1) {
  1114.  
  1115. /* Get Video Availability */
  1116. if (getMyElement('', 'div', 'class', 'veoh-video-player-error', 0, false)) return;
  1117.  
  1118. /* Get Video Title */
  1119. var veVideoTitle = getMyContent(page.url, 'meta\\s+name="og:title"\\s+content="(.*?)"', false);
  1120. if (veVideoTitle) {
  1121. veVideoTitle = veVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1122. veVideoTitle = veVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1123. veVideoTitle = veVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1124. veVideoTitle = veVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1125. veVideoTitle = veVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1126. }
  1127.  
  1128. /* Get Videos Content */
  1129. var veVideosContent = getMyContent(page.url.replace(/\/watch\//, '/watch/getVideo/'), '"src"\\s*:\\s*\\{(.*?)\\}', false);
  1130.  
  1131. /* Get Videos */
  1132. if (veVideosContent) {
  1133. var veVideoFormats = {'Regular': 'Low Definition MP4', 'HQ': 'Standard Definition MP4'};
  1134. var veVideoList = {};
  1135. var veVideoFound = false;
  1136. var veVideoParser, veVideoParse, veVideo, myVideoCode;
  1137. for (var veVideoCode in veVideoFormats) {
  1138. veVideoParser = veVideoCode + '":"(.*?)"';
  1139. veVideoParse = veVideosContent.match(veVideoParser);
  1140. veVideo = (veVideoParse) ? veVideoParse[1] : null;
  1141. if (veVideo) {
  1142. if (!veVideoFound) veVideoFound = true;
  1143. myVideoCode = veVideoFormats[veVideoCode];
  1144. veVideoList[myVideoCode] = cleanMyContent(veVideo, false);
  1145. }
  1146. }
  1147.  
  1148. if (veVideoFound) {
  1149. /* Create Saver */
  1150. var veDefaultVideo = 'Low Definition MP4';
  1151. saver = {'videoList': veVideoList, 'videoSave': veDefaultVideo, 'videoTitle': veVideoTitle};
  1152. feature['container'] = false;
  1153. feature['fullsize'] = false;
  1154. option['definition'] = 'LD';
  1155. option['definitions'] = ['Standard Definition', 'Low Definition'];
  1156. option['containers'] = ['MP4'];
  1157. createMySaver();
  1158. }
  1159. else {
  1160. saver = {};
  1161. var ytVideoId = getMyContent(page.url, 'youtube.com/embed/(.*?)("|\\?)', false);
  1162. if (!ytVideoId) ytVideoId = getMyContent(page.url, '"videoId":"yapi-(.*?)"', false);
  1163. if (ytVideoId) {
  1164. var ytVideoLink = 'http://youtube.com/watch?v=' + ytVideoId;
  1165. saver['warnMess'] = 'embed';
  1166. saver['warnContent'] = ytVideoLink;
  1167. }
  1168. else saver['warnMess'] = '!videos';
  1169. createMySaver();
  1170. }
  1171. }
  1172. else {
  1173. saver = {'warnMess': '!content'};
  1174. createMySaver();
  1175. }
  1176.  
  1177. }
  1178.  
  1179. // =====Viki===== //
  1180.  
  1181. else if (page.url.indexOf('viki.com/videos') != -1) {
  1182.  
  1183. /* Get Video Title */
  1184. var vkVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  1185. if (vkVideoTitle) {
  1186. vkVideoTitle = vkVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1187. vkVideoTitle = vkVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1188. vkVideoTitle = vkVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1189. vkVideoTitle = vkVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1190. vkVideoTitle = vkVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1191. }
  1192.  
  1193. /* Get Video ID */
  1194. var vkVideoID = page.url.match(/videos\/(\d+v)/);
  1195. vkVideoID = (vkVideoID) ? vkVideoID[1] : null;
  1196.  
  1197. /* Get Videos Content */
  1198. var vkVideosContent;
  1199. if (vkVideoID) {
  1200. /* SHA-1
  1201. Copyright 2008-2018 Brian Turek, 1998-2009 Paul Johnston & Contributors
  1202. Distributed under the BSD License
  1203. See https://caligatio.github.com/jsSHA/ for more information
  1204. */
  1205. var SHA1FuncBody;
  1206. var SHA1Key = 'sha1js';
  1207. try {
  1208. if (localStorage.getItem(SHA1Key)) {
  1209. SHA1FuncBody = localStorage.getItem(SHA1Key);
  1210. }
  1211. else throw false;
  1212. }
  1213. catch(e) {
  1214. SHA1FuncBody = getMyContent('https://raw.githack.com/Caligatio/jsSHA/master/src/sha1.js', 'TEXT', false);
  1215. localStorage.setItem(SHA1Key, SHA1FuncBody);
  1216. }
  1217. var SHA1Func = new Function('a', SHA1FuncBody);
  1218. var SHA1 = new SHA1Func();
  1219. if (SHA1.jsSHA) {
  1220. var shaObj = new SHA1.jsSHA("SHA-1", "TEXT");
  1221. var vkTimestamp = parseInt(Date.now() / 1000);
  1222. var vkQuery = "/v5/videos/" + vkVideoID + "/streams.json?app=100005a&t=" + vkTimestamp + "&site=www.viki.com"
  1223. var vkToken = "MM_d*yP@`&1@]@!AVrXf_o-HVEnoTnm$O-ti4[G~$JDI/Dc-&piU&z&5.;:}95\=Iad";
  1224. shaObj.setHMACKey(vkToken, "TEXT");
  1225. shaObj.update(vkQuery);
  1226. var vkSig = shaObj.getHMAC("HEX");
  1227. var vkSource = "https://api.viki.io" + vkQuery + "&sig=" + vkSig;
  1228. vkVideosContent = getMyContent(vkSource, 'TEXT', false);
  1229. }
  1230. }
  1231.  
  1232. /* Get Videos */
  1233. if (vkVideosContent) {
  1234. var vkVideoList = {};
  1235. var vkVideoFormats = {'1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '480p': 'Standard Definition MP4',
  1236. '360p': 'Low Definition MP4', '240p': 'Very Low Definition MP4'};
  1237. var vkVideoFound = false;
  1238. var vkVideoParser, vkVideoParse, vkVideo, myVideoCode;
  1239. for (var vkVideoCode in vkVideoFormats) {
  1240. vkVideoParser = '"' + vkVideoCode + '".*?"https":\{"url":"(.*?)"';
  1241. vkVideoParse = vkVideosContent.match(vkVideoParser);
  1242. vkVideo = (vkVideoParse) ? vkVideoParse[1] : null;
  1243. if (vkVideo) {
  1244. if (!vkVideoFound) vkVideoFound = true;
  1245. myVideoCode = vkVideoFormats[vkVideoCode];
  1246. vkVideoList[myVideoCode] = vkVideo;
  1247. }
  1248. }
  1249.  
  1250. // Unauthorized
  1251. var vkUnauthorized = (vkVideosContent.indexOf('unauthorized') != -1) ? true : false;
  1252.  
  1253. // DASH/HLS/Subtitles
  1254. vkVideosContent = getMyContent(page.url.replace('/videos/', '/player5_fragment/'), 'TEXT', false);
  1255. if (vkVideosContent) {
  1256. vkVideoEncDASH = vkVideosContent.match(/dash\+xml".*?stream=(.*?)"/);
  1257. vkVideoEncDASH = (vkVideoEncDASH) ? vkVideoEncDASH[1] : null;
  1258. vkVideoEncHLS = vkVideosContent.match(/x-mpegURL".*?stream=(.*?)"/);
  1259. vkVideoEncHLS = (vkVideoEncHLS) ? vkVideoEncHLS[1] : null;
  1260. if (vkVideoEncDASH || vkVideoEncHLS) {
  1261. vkVideoEncKey = vkVideosContent.match(/chabi:\s*'(.*?)'/);
  1262. vkVideoEncKey = (vkVideoEncKey) ? vkVideoEncKey[1] : null;
  1263. vkVideoEncIV = vkVideosContent.match(/ecta:\s*'(.*?)'/);
  1264. vkVideoEncIV = (vkVideoEncIV) ? vkVideoEncIV[1] : null;
  1265. if (vkVideoEncKey && vkVideoEncIV) {
  1266. /* AES
  1267. Copyright 2015-2018 Richard Moore
  1268. MIT License.
  1269. See https://github.com/ricmoo/aes-js/ for more information
  1270. */
  1271. var AESFuncBody;
  1272. var AESKey = 'aesjs';
  1273. try {
  1274. if (localStorage.getItem(AESKey)) {
  1275. AESFuncBody = localStorage.getItem(AESKey);
  1276. }
  1277. else throw false;
  1278. }
  1279. catch(e) {
  1280. AESFuncBody = getMyContent('https://raw.githack.com/ricmoo/aes-js/master/index.js', 'TEXT', false);
  1281. localStorage.setItem(AESKey, AESFuncBody);
  1282. }
  1283. var AESFunc = new Function('a', AESFuncBody);
  1284. var AES = new AESFunc();
  1285. var AESKey = AES.aesjs.utils.utf8.toBytes(vkVideoEncKey);
  1286. var AESIV = AES.aesjs.utils.utf8.toBytes(vkVideoEncIV);
  1287. var encryptedBytes, decryptedBytes;
  1288. // HLS
  1289. encryptedBytes = AES.aesjs.utils.hex.toBytes(vkVideoEncHLS);
  1290. AESCBC = new AES.aesjs.ModeOfOperation.cbc(AESKey, AESIV);
  1291. decryptedBytes = AESCBC.decrypt(encryptedBytes);
  1292. var vkHLSManifest = AES.aesjs.utils.utf8.fromBytes(decryptedBytes);
  1293. if (vkHLSManifest) {
  1294. if (!vkVideoFound) vkVideoFound = true;
  1295. vkVideoList['Any Definition HLS'] = vkHLSManifest;
  1296. }
  1297. // DASH
  1298. encryptedBytes = AES.aesjs.utils.hex.toBytes(vkVideoEncDASH);
  1299. AESCBC = new AES.aesjs.ModeOfOperation.cbc(AESKey, AESIV);
  1300. decryptedBytes = AESCBC.decrypt(encryptedBytes);
  1301. var vkDASHManifest = AES.aesjs.utils.utf8.fromBytes(decryptedBytes);
  1302. if (vkDASHManifest) {
  1303. var vkDASHDomain = vkDASHManifest.split('/').splice(0, 5).join('/');
  1304. var vkDASHContent = getMyContent(vkDASHManifest, 'TEXT', false);
  1305. if (vkDASHContent) {
  1306. var vkDASHVideo;
  1307. var vkDASHVideos = vkDASHContent.match(new RegExp('<BaseURL>.*?</BaseURL>', 'g'));
  1308. if (vkDASHVideos) {
  1309. for (var i = 0; i < vkDASHVideos.length; i++) {
  1310. vkDASHVideo = vkDASHVideos[i].replace('<BaseURL>', '').replace('</BaseURL>', '');
  1311. if (vkDASHVideo.indexOf('http') != 0) vkDASHVideo = vkDASHDomain + '/' + vkDASHVideo;
  1312. for (var vkVideoCode in vkVideoFormats) {
  1313. if (vkDASHVideo.indexOf(vkVideoCode) != -1) {
  1314. myVideoCode = vkVideoFormats[vkVideoCode];
  1315. if (vkDASHVideo.indexOf('track1') != -1) {
  1316. if (!vkVideoFound) vkVideoFound = true;
  1317. if (!vkVideoList[myVideoCode]) {
  1318. vkVideoList[myVideoCode.replace('MP4', 'Video MP4')] = vkDASHVideo;
  1319. }
  1320. }
  1321. if (vkDASHVideo.indexOf('track2') != -1) {
  1322. if (!vkVideoList[myVideoCode]) {
  1323. vkVideoList[myVideoCode.replace('MP4', 'Audio MP4')] = vkDASHVideo;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. }
  1329. }
  1330. for (var vkVideoCode in vkVideoFormats) {
  1331. myVideoCode = vkVideoFormats[vkVideoCode];
  1332. if (!vkVideoList[myVideoCode]) {
  1333. if (vkVideoList[myVideoCode.replace('MP4', 'Video MP4')] && vkVideoList[myVideoCode.replace('MP4', 'Audio MP4')]) {
  1334. vkVideoList[myVideoCode] = 'DASH';
  1335. }
  1336. }
  1337. }
  1338. }
  1339. }
  1340. }
  1341. }
  1342. // Subtitles
  1343. var vkSubtitles = vkVideosContent.match(/"srclang":"en".*?"src":"(.*?)"/);
  1344. vkSubtitles = (vkSubtitles) ? vkSubtitles[1] : null;
  1345. if (vkSubtitles) vkVideoList['EN Subtitles WebVTT'] = vkSubtitles;
  1346. }
  1347.  
  1348. /* Create Saver */
  1349. if (vkVideoFound) {
  1350. var vkDefaultVideo = 'Low Definition MP4';
  1351. saver = {'videoList': vkVideoList, 'videoSave': vkDefaultVideo, 'videoTitle': vkVideoTitle};
  1352. feature['container'] = false;
  1353. feature['dash'] = true;
  1354. option['definition'] = 'LD';
  1355. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1356. option['containers'] = ['MP4'];
  1357. createMySaver();
  1358. }
  1359. else {
  1360. if (vkUnauthorized) {
  1361. saver = {
  1362. 'warnMess': 'other',
  1363. 'warnContent': '<b>SaveTube:</b> Authorization required!'
  1364. };
  1365. }
  1366. else saver = {'warnMess': '!videos'};
  1367. createMySaver();
  1368. }
  1369. }
  1370. else {
  1371. saver = {'warnMess': '!content'};
  1372. createMySaver();
  1373. }
  1374.  
  1375. }
  1376.  
  1377. // =====IMDB===== //
  1378.  
  1379. else if (page.url.indexOf('imdb.com') != -1) {
  1380.  
  1381. /* Redirect To Video Page */
  1382. if (page.url.indexOf('/video/') == -1 && page.url.indexOf('/videoplayer/') == -1) {
  1383. page.doc.addEventListener('click', function(e) {
  1384. var p = e.target.parentNode;
  1385. while (p) {
  1386. if (p.tagName === 'A' && p.href.indexOf('/video/imdb') != -1) {
  1387. page.win.location.href = p.href.replace(/imdb\/inline.*/, '');
  1388. }
  1389. p = p.parentNode;
  1390. }
  1391. }, false);
  1392. return;
  1393. }
  1394.  
  1395. /* Get Video Title */
  1396. var imdbVideoTitle = getMyContent(page.url, 'meta\\s+property="og:title"\\s+content="(.*?)"', false);
  1397. if (imdbVideoTitle) {
  1398. imdbVideoTitle = imdbVideoTitle.replace(/&quot;/g, '\'').replace(/&#34;/g, '\'').replace(/"/g, '\'');
  1399. imdbVideoTitle = imdbVideoTitle.replace(/&#39;/g, '\'').replace(/'/g, '\'');
  1400. imdbVideoTitle = imdbVideoTitle.replace(/&amp;/g, 'and').replace(/&/g, 'and');
  1401. imdbVideoTitle = imdbVideoTitle.replace(/\?/g, '').replace(/[#:\*]/g, '-').replace(/\//g, '-');
  1402. imdbVideoTitle = imdbVideoTitle.replace(/^\s+|\s+$/, '').replace(/\.+$/g, '');
  1403. }
  1404.  
  1405. /* Get Video Id */
  1406. var imdbVideoId = page.url.replace(/.*videoplayer\//, '').replace(/(\/|\?).*/, '');
  1407.  
  1408. /* Get Videos Content */
  1409. var imdbVideosContent = getMyContent(page.url, '"' + imdbVideoId + '":\\{("aggregateUpVotes.*?videoId)', false);
  1410.  
  1411. /* Get Videos */
  1412. var imdbVideoList = {};
  1413. if (imdbVideosContent) {
  1414. var imdbVideoFormats = {'1080p': 'Full High Definition MP4', '720p': 'High Definition MP4', '480p': 'Standard Definition MP4',
  1415. '360p': 'Low Definition MP4', 'SD': 'Low Definition MP4', '240p': 'Very Low Definition MP4'};
  1416. var imdbVideoFound = false;
  1417. var imdbVideoParser, imdbVideoParse, myVideoCode, imdbVideo;
  1418. for (var imdbVideoCode in imdbVideoFormats) {
  1419. imdbVideoParser = '"definition":"' + imdbVideoCode + '".*?"videoUrl":"(.*?)"';
  1420. imdbVideoParse = imdbVideosContent.match(imdbVideoParser);
  1421. imdbVideo = (imdbVideoParse) ? imdbVideoParse[1] : null;
  1422. if (imdbVideo) {
  1423. imdbVideo = cleanMyContent(imdbVideo, false);
  1424. if (!imdbVideoFound) imdbVideoFound = true;
  1425. myVideoCode = imdbVideoFormats[imdbVideoCode];
  1426. if (!imdbVideoList[myVideoCode]) imdbVideoList[myVideoCode] = imdbVideo;
  1427. }
  1428. }
  1429.  
  1430. if (imdbVideoFound) {
  1431. /* Create Saver */
  1432. var imdbDefaultVideo = 'Low Definition MP4';
  1433. saver = {'videoList': imdbVideoList, 'videoSave': imdbDefaultVideo, 'videoTitle': imdbVideoTitle};
  1434. feature['container'] = false;
  1435. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1436. option['containers'] = ['MP4'];
  1437. createMySaver();
  1438. }
  1439. else {
  1440. saver = {'warnMess': '!videos'};
  1441. createMySaver();
  1442. }
  1443. }
  1444. else {
  1445. imdbVideo = getMyContent(page.url, '"videoUrl":"(.*?)"', false);
  1446. if (imdbVideo) {
  1447. /* Create Saver */
  1448. imdbVideo = cleanMyContent(imdbVideo, false);
  1449. imdbVideoList[imdbDefaultVideo] = imdbVideo;
  1450. var imdbDefaultVideo = 'Low Definition MP4';
  1451. saver = {'videoList': imdbVideoList, 'videoSave': imdbDefaultVideo, 'videoTitle': imdbVideoTitle};
  1452. feature['container'] = false;
  1453. option['definitions'] = ['Full High Definition', 'High Definition', 'Standard Definition', 'Low Definition', 'Very Low Definition'];
  1454. option['containers'] = ['MP4'];
  1455. createMySaver();
  1456. }
  1457. else {
  1458. saver = {'warnMess': '!content'};
  1459. createMySaver();
  1460. }
  1461. }
  1462.  
  1463. }
  1464.  
  1465. }
  1466.  
  1467.  
  1468. // ==========Run========== //
  1469.  
  1470. SaveTube();
  1471.  
  1472. page.win.setInterval(function() {
  1473. if (page.url != page.win.location.href) {
  1474. if (saver['saverPanel'] && saver['saverPanel'].parentNode) {
  1475. removeMyElement(saver['saverPanel'].parentNode, saver['saverPanel']);
  1476. }
  1477. page.doc = page.win.document;
  1478. page.body = page.doc.body;
  1479. page.url = page.win.location.href;
  1480. SaveTube();
  1481. }
  1482. }, 500);
  1483.  
  1484. })();