SaveTube

Download videos from video sharing web sites.

当前为 2016-09-04 提交的版本,查看 最新版本

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