Video Download Button

This script adds a download button on many video sites.

当前为 2016-07-06 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Video Download Button
  3. // @namespace VDBMB
  4. // @author MegaByte
  5. // @description This script adds a download button on many video sites.
  6. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
  7. // @run-at document-end
  8. // @noframes
  9. // @include http*://*streamcloud.eu/*
  10. // @include http*://*powerwatch.pw/*
  11. // @include http*://*vivo.sx/*
  12. // @include http*://*shared.sx/*
  13. // @include http*://*youtube.com/watch?v=*
  14. // @include http*://*nowvideo.sx/video/*
  15. // @version 2.2.2
  16. // @grant GM_addStyle
  17. // @grant GM_download
  18. // ==/UserScript==
  19.  
  20.  
  21. this.$ = this.jQuery = jQuery.noConflict(true);
  22.  
  23. function main() {
  24. var site = window.location.href || document.URL;
  25.  
  26. if(site.includes("streamcloud.eu")) streamcloud();
  27. else if(site.includes("powerwatch.pw")) powerwatch();
  28. else if(site.includes("vivo.sx")) vivo();
  29. else if(site.includes("shared.sx")) shared();
  30. else if(site.includes("youtube.com")) youtube();
  31. else if(site.includes("nowvideo.sx")) nowvideo();
  32. }
  33.  
  34. function streamcloud() {
  35. if($("#player_code").length === 0) return;
  36. var url = searchInScripts("file:\\s?\"https?:\\/\\/.+?\\.mp4\"", "http", ".mp4");
  37. if(url !== null)
  38. $(".container-fluid ul.nav").prepend("<li>" + button(url) + "</li>");
  39. }
  40.  
  41. function powerwatch() {
  42. if($("#vplayer").length === 0) return;
  43. var url = searchInScripts("file:\\s?\"https?:\\/\\/.+?\\.mp4\"", "http", ".mp4");
  44. if(url !== null) {
  45. $("h5.h4-fine").html("<span class='head'>"+$("h5.h4-fine").html()+"</span><span class='down'>" + button(url) + "</span>")
  46. GM_addStyle("h5.h4-fine { display: flex; } h5.h4-fine .head { flex-grow: 1; } h5.h4-fine .down { flex-grow: 0; }");
  47. }
  48. }
  49.  
  50. function vivo() {
  51. $.fn.extend({
  52. getStyleObject: function() {
  53. var dom = this.get(0);
  54. var style;
  55. var returns = {};
  56. if(window.getComputedStyle) {
  57. var camelize = function(a,b){
  58. return b.toUpperCase();
  59. };
  60. style = window.getComputedStyle(dom, null);
  61. for(var i = 0, l = style.length; i < l; i++) {
  62. var prop = style[i];
  63. var camel = prop.replace(/\-([a-z])/g, camelize);
  64. var val = style.getPropertyValue(prop);
  65. returns[camel] = val;
  66. };
  67. return returns;
  68. };
  69. if(style = dom.currentStyle) {
  70. for(var prop in style){
  71. returns[prop] = style[prop];
  72. };
  73. return returns;
  74. };
  75. return this.css();
  76. },
  77. copyCSS: function(source) {
  78. var styles = $(source).getStyleObject();
  79. this.css(styles);
  80. }
  81. });
  82. var e = $(".stream-content");
  83. if(e.length === 0) return;
  84. var url = e.attr("data-url");
  85. if(typeof url === "undefined") return;
  86. var lightBTN = $(".light-switch.btn");
  87. var downBTN = $("<div class='download'>" + button(url) + "</div>");
  88. downBTN.copyCSS(lightBTN);
  89. lightBTN.parent().prepend(downBTN);
  90. GM_addStyle(".download { margin-right: 15px !important;} .download:hover { color: #fff !important; background-color: #39b3d7 !important; border-color: #269abc !important; } .download a { text-decoration: none; color: white; }");
  91. }
  92.  
  93. function shared() {
  94. var e = $(".stream-content");
  95. if(e.length === 0) return;
  96. var url = e.attr("data-url");
  97. if(typeof url === "undefined") return;
  98. $(".light-switch").parent().prepend("<div class='download'>" + button(url) + "</div>");
  99. GM_addStyle(".addthis_toolbox { width: unset !important; } .download { position: relative; background-color: #FF6550; color: #FFF; float: right; font-size: 13px; font-weight: 700; height: 32px; line-height: 32px; margin: 0 0 0 10px; padding: 0 15px; width: auto; cursor: pointer; -webkit-transition: all .35s ease-in; -moz-transition: all .35s ease-in; -o-transition: all .35s ease-in; transition: all .35s ease-in; opacity: 1; z-index: 300; } .download a { text-decoration: none; color: white;}");
  100. }
  101.  
  102. function youtube() {
  103. var TYPE = {'5':{'label':'FLV 240p','type':'flv','quality':'240','3d':false,'audio':true,'video':true},
  104. '6':{'label':'FLV 270p','type':'flv','quality':'270','3d':false,'audio':true,'video':true},
  105. '13':{'label':'3GP','type':'3gp','quality':'','3d':false,'audio':true,'video':true},
  106. '17':{'label':'3GP 144p','type':'3gp','quality':'144','3d':false,'audio':true,'video':true},
  107. '18':{'label':'MP4 360p','type':'mp4','quality':'360','3d':false,'audio':true,'video':true},
  108. '22':{'label':'MP4 720p','type':'mp4','quality':'720','3d':false,'audio':true,'video':true},
  109. '34':{'label':'FLV 360p','type':'flv','quality':'360','3d':false,'audio':true,'video':true},
  110. '35':{'label':'FLV 480p','type':'flv','quality':'480','3d':false,'audio':true,'video':true},
  111. '36':{'label':'3GP 240p','type':'3gp','quality':'240','3d':false,'audio':true,'video':true},
  112. '37':{'label':'MP4 1080p','type':'mp4','quality':'1080','3d':false,'audio':true,'video':true},
  113. '38':{'label':'MP4 2160p','type':'mp4','quality':'2160','3d':false,'audio':true,'video':true},
  114. '43':{'label':'WebM 360p','type':'webm','quality':'360','3d':false,'audio':true,'video':true},
  115. '44':{'label':'WebM 480p','type':'webm','quality':'480','3d':false,'audio':true,'video':true},
  116. '45':{'label':'WebM 720p','type':'webm','quality':'720','3d':false,'audio':true,'video':true},
  117. '46':{'label':'WebM 1080p','type':'webm','quality':'1080','3d':false,'audio':true,'video':true},
  118. '82':{'label':'MP4-3D 360p','type':'mp4','quality':'360','3d':true,'audio':true,'video':true},
  119. '83':{'label':'MP4-3D 480p','type':'mp4','quality':'480','3d':true,'audio':true,'video':true},
  120. '84':{'label':'MP4-3D 720p','type':'mp4','quality':'720','3d':true,'audio':true,'video':true},
  121. '85':{'label':'MP4-3D 1080p','type':'mp4','quality':'1080','3d':true,'audio':true,'video':true},
  122. '92':{'label':'MP4 240p','type':'mp4','quality':'240','3d':false,'audio':true,'video':true},
  123. '93':{'label':'MP4 360p','type':'mp4','quality':'360','3d':false,'audio':true,'video':true},
  124. '94':{'label':'MP4 480p','type':'mp4','quality':'480','3d':false,'audio':true,'video':true},
  125. '95':{'label':'MP4 720p','type':'mp4','quality':'720','3d':false,'audio':true,'video':true},
  126. '96':{'label':'MP4 1080p','type':'mp4','quality':'1080','3d':false,'audio':true,'video':true},
  127. '100':{'label':'WebM-3D 360p','type':'webm','quality':'360','3d':true,'audio':true,'video':true},
  128. '101':{'label':'WebM-3D 480p','type':'webm','quality':'480','3d':true,'audio':true,'video':true},
  129. '102':{'label':'WebM-3D 720p','type':'webm','quality':'720','3d':true,'audio':true,'video':true},
  130. '132':{'label':'MP4 240p','type':'mp4','quality':'240','3d':false,'audio':true,'video':true},
  131. '133':{'label':'MP4 240p - no audio','type':'mp4','quality':'240','3d':false,'audio':false,'video':true},
  132. '134':{'label':'MP4 360p - no audio','type':'mp4','quality':'360','3d':false,'audio':false,'video':true},
  133. '135':{'label':'MP4 480p - no audio','type':'mp4','quality':'480','3d':false,'audio':false,'video':true},
  134. '136':{'label':'MP4 720p - no audio','type':'mp4','quality':'720','3d':false,'audio':false,'video':true},
  135. '137':{'label':'MP4 1080p - no audio','type':'mp4','quality':'1080','3d':false,'audio':false,'video':true},
  136. '138':{'label':'MP4 2160p - no audio','type':'mp4','quality':'2160','3d':false,'audio':false,'video':true},
  137. '139':{'label':'M4A 48kbps - audio','type':'m4a','quality':'48','3d':false,'audio':true,'video':false},
  138. '140':{'label':'M4A 128kbps - audio','type':'m4a','quality':'128','3d':false,'audio':true,'video':false},
  139. '141':{'label':'M4A 256kbps - audio','type':'m4a','quality':'256','3d':false,'audio':true,'video':false},
  140. '151':{'label':'MP4','type':'mp4','quality':'','3d':false,'audio':true,'video':true},
  141. '167':{'label':'WebM 360p - no audio','type':'webm','quality':'360','3d':false,'audio':false,'video':true},
  142. '168':{'label':'WebM 480p - no audio','type':'webm','quality':'480','3d':false,'audio':false,'video':true},
  143. '169':{'label':'WebM 720p - no audio','type':'webm','quality':'720','3d':false,'audio':false,'video':true},
  144. '170':{'label':'WebM 1080p - no audio','type':'webm','quality':'1080','3d':false,'audio':false,'video':true},
  145. '171':{'label':'WebM 128kbps - audio','type':'webm','quality':'128','3d':false,'audio':true,'video':false},
  146. '172':{'label':'WebM 256kbps - audio','type':'webm','quality':'256','3d':false,'audio':true,'video':false},
  147. '218':{'label':'WebM 480p - no audio','type':'webm','quality':'480','3d':false,'audio':false,'video':true},
  148. '219':{'label':'WebM - no audio','type':'webm','quality':'','3d':false,'audio':false,'video':true},
  149. '242':{'label':'WebM 240p - no audio','type':'webm','quality':'240','3d':false,'audio':false,'video':true},
  150. '243':{'label':'WebM 360p - no audio','type':'webm','quality':'360','3d':false,'audio':false,'video':true},
  151. '244':{'label':'WebM 480p - no audio','type':'webm','quality':'480','3d':false,'audio':false,'video':true},
  152. '245':{'label':'WebM 480p - no audio','type':'webm','quality':'480','3d':false,'audio':false,'video':true},
  153. '246':{'label':'WebM 720p - no audio','type':'webm','quality':'720','3d':false,'audio':false,'video':true},
  154. '247':{'label':'WebM 720p - no audio','type':'webm','quality':'720','3d':false,'audio':false,'video':true},
  155. '248':{'label':'WebM 1080p - no audio','type':'webm','quality':'1080','3d':false,'audio':false,'video':true},
  156. '264':{'label':'MP4 1440p - no audio','type':'mp4','quality':'1440','3d':false,'audio':false,'video':true},
  157. '266':{'label':'MP4 2160p - no audio','type':'mp4','quality':'2160','3d':false,'audio':false,'video':true},
  158. '271':{'label':'WebM 1440p - no audio','type':'webm','quality':'1440','3d':false,'audio':false,'video':true},
  159. '272':{'label':'WebM 2160p - no audio','type':'webm','quality':'2160','3d':false,'audio':false,'video':true},
  160. '298':{'label':'MP4 720p60 - no audio','type':'mp4','quality':'720','3d':false,'audio':false,'video':true},
  161. '299':{'label':'MP4 1080p60 - no audio','type':'mp4','quality':'1080','3d':false,'audio':false,'video':true},
  162. '302':{'label':'WebM 2160p60 - no audio','type':'webm','quality':'2160','3d':false,'audio':false,'video':true},
  163. '303':{'label':'WebM 1080p60 - no audio','type':'webm','quality':'1080','3d':false,'audio':false,'video':true},
  164. '308':{'label':'WebM 1440p60 - no audio','type':'webm','quality':'1440','3d':false,'audio':false,'video':true},
  165. '313':{'label':'WebM 2160p60 - no audio','type':'webm','quality':'2160','3d':false,'audio':false,'video':true},
  166. '315':{'label':'WebM 2160p60 - no audio','type':'webm','quality':'2160','3d':false,'audio':false,'video':true}};
  167. var CUSTOM_ORDER = ['5','18','34','43','35','135','44','22','298','45','37','299','46','264','38','266','139','140','141','*'];
  168. var FORMAT_ORDER = ['mp4','webm','flv','m4a', '3gp', '*'];
  169. var FORMAT_RULE = {'flv':'max','mp4':'all','webm':'all','m4a':'none', '3gp':'max'}; //options = all, max, min, none, random;
  170. var BASE_RULE = {'3d':"all",'audio':'all','video':'all'};
  171. var SORTBY = 2; //0=custom, 1=quality, 2=type;
  172. var w = gindow();
  173. if (!w.ytplayer || !w.ytplayer.config || !w.ytplayer.config.args) { console.log("Player Config not found"); return; }
  174. var config = w.ytplayer.config.args;
  175. var length = config["length_seconds"];
  176. var lang = config["host_language"];
  177. var title = config["title"];
  178. var data = config["url_encoded_fmt_stream_map"].split(",");
  179. var fdata = [];
  180. for(var dat of data) {
  181. var attr = dat.split("&");
  182. var map = {};
  183. for(var att of attr) {
  184. var ar = att.split("=");
  185. var name = ar[0];
  186. var value = decodeURIComponent(ar[1]);
  187. map[name] = value;
  188. }
  189. map["simple_type"] = TYPE[map["itag"]]["type"];
  190. fdata.push(map);
  191. }
  192. var ffdata = formatLinks(fdata, TYPE, CUSTOM_ORDER, FORMAT_ORDER, FORMAT_RULE, BASE_RULE, SORTBY);
  193. var links = "";
  194. for(var f of ffdata)
  195. links += "<li><span class='yt-ui-menu-item'><a class='download-link' download='" + title + "." + f["simple_type"] + "' href='" + f["url"] + "'>" + TYPE[f["itag"]]["label"] + "</a></span></a></li>";
  196. $("#watch8-secondary-actions").prepend("<button title='Download' aria-expanded='false' aria-pressed='false' aria-labelledby='yt-uix-tooltip25-arialabel' role='button' type='button' data-tooltip-text='Download' class='yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-tooltip' id='download-video-button'><span><span class='yt-uix-button-icon-wrapper'><img style='width:20px;height:20px;background-size:20px 20px;background-repeat:no-repeat;background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABG0lEQVRYR+2W0Q3CMAxE2wkYAdiEEWADmIxuACMwCmzABpCTEmRSO7YTQX+ChECV43t2nF7GYeHPuLD+0AKwC/DnWMAp/N5qimkBuAfBdRTF/+2/AV6ZYFUxVYuicAfoHegd6B3oHfhZB+ByF+JyV8FkrAB74pqH3DU5L3iGoBURhdVODIQF4EjEkWLmmhYALOQgNIBcHHke4buhxXAAaFnaAhqbQ5QAOHHkwhZ8balkx1ICCiEBWNZ+CivdB7REHIC2ZjZK2oWklDDdB1NSdCd/Js2PqQMpSIKYVcM8kE6QCwDBNRCqOBJrW0CL8kCYxL0A1k6YxWsANAiXeC2ABOEWbwHAWrwxpzgkmA/JtIqnxTOElmPnjlkc4A3FykAhA42AxwAAAABJRU5ErkJggg==);' class='yt-uix-button-icon' src='//s.ytimg.com/yt/img/pixel-vfl3z5WfW.gif'></span><span class='yt-uix-button-content'>Download </span><ul class='yt-uix-button-menu hid' style='min-width: 114px; left: 40px; top: 501px; display: none;'>" + links + "</ul></span></button>");
  197. $(".download-link").click(function(e) {
  198. if (typeof GM_download === "undefined") return;
  199. e.preventDefault();
  200. var url = $(this).attr("href");
  201. var name = $(this).attr("download");
  202. GM_download(url, name);
  203. });
  204. GM_addStyle(".download-link { text-decoration: none; color: inherit; } .download-link:hover { text-decoration: none; }");
  205. }
  206. function formatLinks(DATA, TYPE, CORDER, FORDER, FRULE, BRULE, SORT) {
  207. for(var rule in BRULE) {
  208. var list = getKeysOfSubMap(TYPE, DATA.slice(), rule, true);
  209. switch(BRULE[rule]) {
  210. case "max": removeAll(DATA, list, getMaxQuality(TYPE, list)); break;
  211. case "min": removeAll(DATA, list, getMinQuality(TYPE, list)); break;
  212. case "none": removeAll(DATA, list); break;
  213. }
  214. }
  215. for(var rule in FRULE) {
  216. var list = getKeysOfSubMap(TYPE, DATA.slice(), "type", rule);
  217. switch(FRULE[rule]) {
  218. case "max": removeAll(DATA, list, getMaxQuality(TYPE, list)); break;
  219. case "min": removeAll(DATA, list, getMinQuality(TYPE, list)); break;
  220. case "none": removeAll(DATA, list); break;
  221. }
  222. }
  223. switch(SORT) {
  224. case 0:
  225. var obj = {};
  226. for(var t of CORDER)
  227. obj[t] = [];
  228. for(var e of DATA) {
  229. var t = e["itag"];
  230. if(!CORDER.includes(t)) t="*";
  231. obj[t].push(e);
  232. }
  233. DATA = [];
  234. for(var t of CORDER)
  235. DATA.push.apply(DATA, obj[t]);
  236. break;
  237. case 1:
  238. for(var i in DATA) for(var j in DATA)
  239. if(TYPE[DATA[j]["itag"]]["quality"] < TYPE[DATA[i]["itag"]]["quality"]) {
  240. var tmp = DATA[i];
  241. DATA[i] = DATA[j];
  242. DATA[j] = tmp;
  243. }
  244. break;
  245. case 2:
  246. var obj = {};
  247. for(var t of FORDER)
  248. obj[t] = [];
  249. for(var e of DATA) {
  250. var t = TYPE[e["itag"]]["type"];
  251. if(!FORDER.includes(t)) t="*";
  252. obj[t].push(e);
  253. }
  254. DATA = [];
  255. for(var t of FORDER)
  256. DATA.push.apply(DATA, obj[t]);
  257. break;
  258. }
  259. return DATA;
  260. }
  261.  
  262. function removeAll(target, list, exclude) {
  263. if(typeof exclude != "undefined") list.splice(exclude, 1);
  264. var l = [];
  265. for(var j in list)
  266. l[j] = list[j]["itag"];
  267. var i = target.length;
  268. while(i--)
  269. if(l.includes(target[i]["itag"]))
  270. target.splice(i, 1);
  271. }
  272.  
  273. function getMaxQuality(TYPE, list) {
  274. var max = null;
  275. for(var e in list) {
  276. if(max === null) { max=e; continue; }
  277. if(TYPE[list[e]["itag"]]["quality"] > max["quality"])
  278. max = e;
  279. }
  280. return max;
  281. }
  282. function getMinQuality(TYPE, list) {
  283. var min = null;
  284. for(var e in list) {
  285. if(min === null) { min=e; continue; }
  286. if(TYPE[list[e]["itag"]]["quality"] < min["quality"])
  287. min = e;
  288. }
  289. return min;
  290. }
  291. function getKeysOfSubMap(TYPE, data, key, val) {
  292. var i = data.length;
  293. while(i--) {
  294. if(TYPE[data[i]["itag"]][key] !== val) data.splice(i, 1);
  295. }
  296. return data;
  297. }
  298.  
  299. function nowvideo() {
  300. var w = gindow();
  301. var args = w.flashvars;
  302. if(typeof args == "undefined") return;
  303. var file = args["file"];
  304. var key = args["filekey"];
  305. var domain = args["domain"];
  306. var data_url = domain + "/api/player.api.php?file=" + file + "&key=" + key;
  307. $.get(data_url, function(data) {
  308. var vars = {};
  309. var attr = data.split("&");
  310. for(var a of attr) {
  311. var tmp = a.split("=");
  312. vars[tmp[0]] = tmp[1];
  313. }
  314. var url = vars["url"];
  315. var title = vars["title"];
  316. var download = [$("#content_player > a[href*=premium]"),
  317. $("#videoPlayer param[name*=flashvars]")];
  318. download[0].attr("href", url);
  319. download[1].attr("value", download[1].attr("value").replace(/premiumLink=.*?(&|$)/g, "premiumLink="+url+"&"));
  320. });
  321. }
  322.  
  323. main();
  324.  
  325. function gindow() {
  326. return (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
  327. }