DRTV

Dette script gør det muligt at optage programmer fra DR TV og Bonanza så de kan ses offline

目前为 2015-12-02 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name DRTV
  3. // @namespace marlar
  4. // @description Dette script gør det muligt at optage programmer fra DR TV og Bonanza så de kan ses offline
  5. // @version 2.0
  6. // @include http://www.dr.dk/TV/se/*
  7. // @include http://www.dr.dk/tv/se/*
  8. // @include http://www.dr.dk/bonanza/*/serie/*
  9. // @include http://www.dr.dk/bonanza/serie/*
  10. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js
  11. // ==/UserScript==
  12.  
  13.  
  14. this.$ = this.jQuery = jQuery.noConflict(true);
  15.  
  16. if(document.location.href.match(/http:\/\/drnu\.tumblr\.com/)) {
  17. alert("Du skal ikke klikke på linket. Træk det op på bogmærkelinjen i din browser.");
  18. exit;
  19. }
  20.  
  21. if(document.location.href.match(/www.dr.dk\/tv\/?$/i)) {
  22. alert("Vælg en udsendelse og klik derefter igen på bogmærket");
  23. exit;
  24. }
  25.  
  26. if(document.location.href.match(/www.dr.dk\/bonanza\/.*kategori\//i)) {
  27. alert("Vælg først en underkategori");
  28. exit;
  29. }
  30.  
  31. var showType = document.location.href.match(/www.dr.dk\/(tv\/se|bonanza)/i);
  32. if(!showType) {
  33. if(confirm("Scriptet virker kun på DR TV eller Bonanza.\nØnsker du at gå dertil?\n\nNB: du skal klikke på bogmærket igen når du kommer derhen :-)")) {
  34. document.location="http://www.dr.dk/tv";
  35. }
  36. exit;
  37. }
  38. showType = showType[1];
  39.  
  40. $("body").prepend($("<style>\
  41. .bodymargin {margin-left:237px !important}\
  42. .showcb { vertical-align: text-bottom; visibility: hidden}\
  43. #showList p { font-size:13px; margin-left:10px; padding:5px 10px; text-indent:-18px; color: white}\
  44. #showList select { width: 96px; margin-bottom:5px; }\
  45. #showList a { color:yellow }\
  46. #makelist a, #showList .bigbutton a { font-size: 13px; color:lightblue; font-weight: bold; cursor: pointer; display: block; width:192px; padding:5px; border: 1px solid}\
  47. #makelist, #showList .bigbutton, #showWait { margin: 10px 0; font-size: 13px; }\
  48. #makelist { margin-top: 27px }\
  49. #showoptions, .bigbutton, #showWait { display: none }\
  50. #showWait { color: yellow }\
  51. #showintro { padding: 2px }\
  52. #resultlist { position: fixed; margin: 10%; z-index:99999 }\
  53. #resultlist textarea { border:6px solid silver; padding-top:20px; white-space: nowrap; overflow: auto; width: 100%; height: 100%}\
  54. #showclose { right: 0; position:absolute; z-index: 100000; cursor: pointer; margin: -4px 4px 0 0; font-weight:bold; font-size:13px; color:lightblue !important}\
  55. #resultlist a { right: 0; position:absolute; z-index: 100000; cursor: pointer; margin: 6px 7px 0 0; font-weight:bold; font-size:13px; color:red}\
  56. #autoscan { margin: 5px 0 10px 0}\
  57. .bold { font-weight: bold }\
  58. .justifywidth { width: 112px; float:left}\
  59. </style>"));
  60. $("<img id='dllogo' title='Klik for at åbne programscanneren' src='http://i42.tinypic.com/2iqgymr.png' style='display:none;top:0;position:fixed;left:0;z-index:99999;margin:4px;cursor:pointer'>").prependTo("body").click(function(){
  61. $("body").toggleClass("bodymargin");
  62. $("#showList").show();
  63. $("#dllogo").hide();
  64. });
  65. var showdata = new Array();
  66. $("body").addClass("bodymargin");
  67. $progDiv = $("<div id='showList'><a id='showclose' title='Luk'>[X]</a>\
  68. <div id='makelist' title='Scan programmer som kan optages'><a>Start programscanning</a></div>\
  69. <div class='bold autoscan' title='Scan automatisk når du skifter program\nBemærk: kan gøre programskift trægt!'><input type='checkbox' id='autoscan'> Scan automatisk</div>\
  70. <div id='showoptions'>\
  71. <div title='Vælg hvilken kvalitet du foretrækker.'><div class='justifywidth'>Kvalitet </div><select id='showQual'><option value='0'>Bedst</option><option value='1'>God</option><option value='2'>Mindre god</option><option value='3'>Dårligst</option></select></div>\
  72. <div title='Vælg det maksimale antal programmer som skal scannes for hver serie. Jo større tal, jo langsommere kan browseren føles.'><div class='justifywidth'>Max programmer </div><select id='maxprogs'><option selected>5</option><option>10</option><option>15</option><option>alle</option></select></div>\
  73. <div id='runbg' title='Kør optagkommandoerne i baggrunden (optag flere på en gang).'><br><input type='checkbox' id='bgmode'> Kør i baggrunden</div>\
  74. <div title='Quiet mode - vis ikke output undervejs'><input type='checkbox' id='quietmode'> Skjul output fra kommandoen</div>\
  75. </div>\
  76. <div class='bigbutton' id='browserdownload' title='Download film direkte i browseren'><a>Hent via browser</a></div>\
  77. <div class='bigbutton' id='makecmdline' title='Generér kommandolinjer til at copy-paste ind i terminalen'><a>Generér kommandolinje</a></div>\
  78. <div class='bigbutton' id='showlinks' title='Vis downloadlinks'><a>Vis links</a></div>\
  79. <h2 id='showWait'>Henter<br>programoversigt...</h2>\
  80. <div id='showintro'>Dette script genererer kommandolinjer til at optage udsendelser fra DR TV med programmet \
  81. <b>wget</b> som er standard i Linux, men fås også <a href='http://gnuwin32.sourceforge.net/packages/wget.htm'>til Windows</a>, eller direkte fra browseren. Sidstnævnte er det letteste, men wget giver flere muligheder.<br><br>\
  82. 1) Klik på linket herover for at scanne programmer der kan optages.<br><br>2) Når oversigten er dannet, kan du vælge den kvalitet som ønskes optages. Hvis en ønsket kvalitet ikke er til rådighed, vælges automatisk en anden.<br><br>\
  83. Du kan også vælge om output fra optageprogrammet skal undertrykkes (quiet) og om der skal optages i baggrunden (dvs. flere udsendelser på en gang).<br><br>\
  84. 3) Vælg tilsidst de programmer der skal optages og tryk på 'Generér kommandolinje' eller 'Hent via browser'<br><br>\
  85. 4) Klik dig evt. frem til andre programmer på DR NU og klik på 'Scan igen'<br><br>\
  86. <b>5) Respektér DRs ophavsret: Materialet må ikke gengives uden tilladelse jævnfør lov om ophavsret.</b></div>\
  87. </div>")
  88. .prependTo("body")
  89. .css({
  90. padding: "5px 0 0 5px",
  91. border: "4px solid lightblue",
  92. position: "fixed",
  93. top:0, left:0,
  94. zIndex:10000,
  95. backgroundColor:"#666666",
  96. fontSize: "13px",
  97. color:"white",
  98. width:"225px",
  99. height:"100%",
  100. overflow:"auto"
  101. });
  102.  
  103. $("#showclose").click(function(){
  104. $("body").toggleClass("bodymargin");
  105. $("#showList").hide();
  106. $("#dllogo").show();
  107. })
  108.  
  109. if(document.cookie.match(/autoscan=1/)) {
  110. $("#autoscan").attr("checked","checked");
  111. scanprogs();
  112. }
  113.  
  114. $("#autoscan").click(function(){
  115. var cookieval=0;
  116. var cookiename = this.id;
  117. if($(this).is(":checked")) {
  118. cookieval=1;
  119. scanprogs();
  120. }
  121. var date = new Date();
  122. date.setDate(date.getDate() + 365)
  123. document.cookie = cookiename + "=" + cookieval + "; expires=" + date + "; path=/"
  124. })
  125.  
  126. if(navigator.appVersion.indexOf("Win")!=-1) $("#runbg").hide();
  127. $("<div id='resultlist' style='display:none'><a onclick='document.getElementById(\"resultlist\").style.display=\"none\"'>[X]</a><textarea wrap='off'></textarea></div>").prependTo("body");
  128.  
  129. $("#resultlist").keyup(function(e) {
  130. if (e.keyCode == 27) { $(this).hide() } // esc
  131. });
  132.  
  133. function getDRNUShows() {
  134. $.ajaxSetup( { "async": false } );
  135. $("#showList p").remove();
  136. if(showType.toLowerCase() == "bonanza") {
  137. getBonanza();
  138. }
  139. else {
  140. getByProgramCard();
  141. getBySeriesUrl();
  142. }
  143. if( $("#showList p").length==1 ) $("#showList p input:checkbox").attr("checked","1");
  144. $.ajaxSetup( { "async": true } );
  145. var ea = 0; $("#maxprogs").parent().click(function(){ ea++; if(ea % 5 == 0) $(".showcb").prop("checked",1); })
  146. }
  147.  
  148. function getBonanza() {
  149. var maxprogs = $("#maxprogs").val();
  150. if(maxprogs=="alle") maxprogs=999;
  151. $(".listItem[onclick]").slice(0, maxprogs).each(function() {
  152. var onclick = $(this).attr("onclick").match(/{.*}/);
  153. if (onclick) {
  154. var json = $.parseJSON(onclick[0]);
  155. var showDate = json.FirstPublished.split("T")[0];
  156. var html = "<p id='prog" + json.AssetId + "'><input class='showcb' type='checkbox'>&nbsp;<b>" + json.Title + " (" + showDate + ")</b><br>" + json.Description + "</p>";
  157. $progDiv.append(html);
  158. var medialinks = new Array();
  159. var qual = 0;
  160. for (var i = 0; i < json.Files.length; i++) {
  161. var f = json.Files[i];
  162. if (f.Type.match(/Video|Audio/)) {
  163. var l = f.Location.match(/.*(bonanza.*)/)
  164. if (l) {
  165. switch (f.Type) {
  166. case "VideoHigh": qual = 3; break;
  167. case "VideoMid": qual = 2; break;
  168. case "VideoLow": qual = 1; break;
  169. case "Audio": qual = 0; break;
  170. }
  171. if(f.Location.match(/mp3$/i))
  172. medialinks.push(qual + "::" + l[0]);
  173. else
  174. medialinks.push(qual + "::" + "http://vodfiles.dr.dk/" + l[1]);
  175. }
  176. }
  177. }
  178. medialinks.sort(function(a,b){
  179. return b.split(/::/)[0]-a.split(/::/)[0];
  180. });
  181. showdata["prog"+json.AssetId] = [medialinks, json.Title + "-" + showDate];
  182. }
  183. })
  184. }
  185.  
  186.  
  187. function getByProgramCard() {
  188. var resourceUrl = $("script:contains('videoData')").text().match('resource: "(http://www.dr.dk/mu/programcard/expanded/[^"]*)"')[1];
  189. $.getJSON(resourceUrl, function(data) {
  190. var showId = "";
  191. //var showDate = data.publish.split("T")[0];
  192. var showDate = data.Data[0].PrimaryAssetStartPublish.split("T")[0];
  193. var html = "<p id='prog" + showId + "'><input class='showcb' type='checkbox'>&nbsp;<b>" + data.Data[0].Title + " (" + showDate + ")</b><br>" + data.Data[0].Description + "</p>";
  194. $progDiv.append(html);
  195. var medialinks = new Array();
  196. var asset="";
  197. for(var a in data.Data[0].Assets) {
  198. asset=data.Data[0].Assets[a]
  199. if(asset.Kind=="VideoResource") {
  200. break;
  201. }
  202. }
  203. if(!asset) return;
  204. $.each(asset.Links, function(resource, link) {
  205. bitrate = link.Bitrate;
  206. medialinks.push(bitrate + "::" + link.Uri);
  207. return true;
  208. });
  209. medialinks.sort(function(a,b){
  210. return b.split(/::/)[0]-a.split(/::/)[0];
  211. });
  212. showdata["prog"+showId]= [medialinks, data.Data[0].Title + "-" + showDate];
  213. });
  214. }
  215.  
  216. function getBySeriesUrl() {
  217. var serie = document.location.href.match(/http:\/\/www.dr.dk\/TV\/se\/([^\/]+)(\/([^\/]+))?\/?(#!.+)?$/i);
  218. if(!serie) return;
  219. var serieUrl = "http://www.dr.dk/nu/api/programseries/" + serie[1] + "/videos";
  220. var maxprogs = $("#maxprogs").val();
  221. if(maxprogs=="alle") maxprogs=999;
  222. $.getJSON(serieUrl, function(data) {
  223. var moreProgs = "<p style='font-weight:bold;color:#ADD8E6'>Flere programmer i serien</p>";
  224. if(data.length) $.each(data, function(showId, show) {
  225. // Method 1
  226. if(showId < maxprogs) {
  227. $.getJSON(show.videoResourceUrl, function(resData) {
  228. var html = moreProgs + "<p id='prog" + showId + "'><input class='showcb' type='checkbox'>&nbsp;<b>" + show.title + " (" + show.formattedBroadcastTime + ")</b><br>" + show.description + "</p>";
  229. moreProgs = "";
  230. $progDiv.append(html);
  231. var medialinks = new Array();
  232. $.each(resData.links, function(resource, link) {
  233. bitrate = link.bitrateKbps;
  234. medialinks.push(bitrate + "::" + link.uri);
  235. return true;
  236. });
  237. medialinks.sort(function(a,b){
  238. return b.split(/::/)[0]-a.split(/::/)[0];
  239. });
  240. showdata["prog"+showId]= [medialinks, show.title + "-" + show.formattedBroadcastTime];
  241. });
  242. }
  243. })
  244. });
  245. }
  246.  
  247. $('#makelist').click(function(){
  248. scanprogs();
  249. });
  250.  
  251. $('#makecmdline, #browserdownload, #showlinks').click(function(){
  252. if($("#showList input.showcb:checked").length==0) {
  253. alert("Du skal vælge et eller flere programmer på listen");
  254. return;
  255. }
  256. fixFlash();
  257. var buttonId = this.id;
  258. var width = $("body").width()-$("#showList").width();
  259. var height = $(window).height()*0.7;
  260.  
  261. var bgmode = $("#bgmode").is(":checked") ? "b" : "";
  262. var quietmode = $("#quietmode").is(":checked") ? "q" : "";
  263. var dash = bgmode+quietmode!="" ? " -" : "";
  264. var cmdline = "";
  265. $("#showList input.showcb:checked").parent().each(function(){
  266. var show = showdata[this.id][0];
  267. var qual = document.getElementById("showQual").selectedIndex;
  268. if(qual>show.length-1) qual = show.length-1;
  269. var rtmpUrl = show[qual].split(/::/)[1];
  270. var mp4Url = "";
  271. if(rtmpUrl.match(/bonanza/i))
  272. mp4Url = rtmpUrl;
  273. else
  274. mp4Url = rtmpUrl.replace(/(rtmp|rtsp|http).*[:\/]CMS\//, "http://vodfiles.dr.dk/CMS/").match(/.*?mp4/)[0];
  275. var match = mp4Url.match(/([^\/\?]*\.(mp4|flv|mp3))/);
  276. var filnavn = match[1];
  277. var filename = showdata[this.id][1].replace(/[-, :\?\/"']+/g,"-").replace(/\./g,"").replace(/-*_/,"_") + "." + match[2];
  278. filename = filename.replace("--","-");
  279. switch(buttonId) {
  280. case "showlinks":
  281. cmdline = cmdline + filename.replace(/\.(flv|mp4)/,"") + "\n" + mp4Url + "\n\n";
  282. break;
  283. case "makecmdline":
  284. cmdline = cmdline + "wget" + dash + bgmode + quietmode + " -O '" + filename + "' '" + mp4Url + "'\n";
  285. break;
  286. case "browserdownload":
  287. if(confirm("Titel: " + showdata[this.id][1] + "\nFilnavn: " + filnavn + "\n\nNår vinduet eller fanebladet med filmen vises, skal du trykke Ctrl-S for at gemme eller bruge menuen Filer > Gem. Derefter kan du lukke vinduet/fanebladet. Hvis du har sat kryds ved flere film, skal du bare vælge de pågældende vinduer/faneblade og trykke Ctrl-S.\n\nTip: Det kan være en god idé at omdøbe filen når du gemmer da navnet ofte er intetsigende."))
  288. window.open(mp4Url);
  289. break;
  290. }
  291. });
  292. if(buttonId=="makecmdline" || buttonId=="showlinks") {
  293. $("#resultlist").width(width).height(height).show();
  294. $("#resultlist textarea").val(cmdline).focus(function(){this.select()}).focus();
  295. }
  296. });
  297.  
  298. function scanprogs() {
  299. if(showType.toLowerCase() == "bonanza") $("#maxprogs").val("alle");
  300. $("#showWait").show();
  301. $("#resultlist,#showoptions,#makecmdline,#showlinks,#browserdownload,#makelist,#showintro,.autoscan").hide();
  302. $("#makelist a").text("Scan igen");
  303. $(".showcb").css("visibility","hidden");
  304. getDRNUShows();
  305. $("#showWait").hide();
  306. $("#showoptions,#makecmdline,#showlinks,#browserdownload,#makelist,.autoscan").show();
  307. $(".showcb").css("visibility","visible");
  308. }
  309.  
  310. var last_path = document.location.pathname;
  311. var timeout_id;
  312. start();
  313.  
  314. function start() {
  315. clearTimeout( timeout_id );
  316. var path = document.location.pathname;
  317. if ( path !== last_path ) {
  318. if($("#showList").is(":visible") && $("#autoscan").is(":checked")) scanprogs();
  319. last_path = path;
  320. }
  321. timeout_id = setTimeout( start, 1000 );
  322. };
  323.  
  324. function fixFlash() {
  325. $('object').each(function(){
  326. if($(this).find('param[name=wmode]').attr('value') != 'transparent') {
  327. $(this).prepend('<param name="wmode" value="transparent" />');
  328. $(this).parent().html($(this).parent().html());
  329. }
  330. });
  331. }