Better ReplayTV support
[raitv.user.js] / raitv.user.js
1 // ==UserScript==
2 // @name        RaiTV video
3 // @description Turn RaiTV silverlight objects into video tags
4 // @namespace   http://oblomov.myopenid.com
5 // @include     http://rai.tv/*
6 // @include     http://rai.it/*
7 // @include     http://www.rai.tv/*
8 // @include     http://www.rai.it/*
9 // @include     http://archivioluce.com/*
10 // @include     http://www.archivioluce.com/*
11 // @author      Giuseppe "Oblomov" Bilotta
12 // @version     20130607.2301
13 // ==/UserScript==
14
15 /* Since the Chrome sandbox is _extremely_ restrictive and we can't
16  * access things such as window.videoURL from the actual document,
17  * we have to resort to script injection to be completely cross-platform.
18  */
19
20 (function() {
21
22 function addScript(source) {
23         var script = document.createElement('script');
24         script.setAttribute("type", "application/javascript");
25         script.textContent = '(' + source + ')();';
26         document.body.appendChild(script);
27 }
28
29
30 addScript(
31 function() {
32         function getURL(name) {
33                 var list = document.getElementsByName(name) ;
34                 if (list && list[0]) {
35                         return list[0].content;
36                 } else {
37                         var altname = name.toUpperCase().replace('VIDEO',
38                                 'video').replace('ANDROID', 'android');
39                         console.log(name, altname);
40                         console.log(window[name], window[altname]);
41                         return window[altname];
42                 }
43         }
44
45         var urls = {
46                 std: getURL('videourl'),
47                 mp4: getURL('videourl_mp4'),
48                 wmv: getURL('videourl_wmv'),
49                 h264: getURL('videourl_h264'),
50                 m3u8: getURL('videourl_m3u8'),
51                 m3u8_android: getURL('videourl_m3u8_android'),
52         }
53
54         function srctag(url, av, fmt) {
55                 if (!url)
56                         return '' ;
57                 var f = null;
58                 if (fmt != 'std') {
59                         f = fmt.replace('_android','');
60                 }
61                 return '<source src="' + url + '" ' + (f ? 'type="' + av + '/' + fmt + '" ' : '') + '/>'
62         }
63
64         function H5video(fmt) {
65                 return srctag(urls[fmt], 'video', fmt);
66         }
67
68         // create a link element for one of the page-wide media streams
69         function H5a(fmt) {
70                 if (urls[fmt]) {
71                         var a = document.createElement('a');
72                         a.href = urls[fmt];
73                         a.innerHTML = fmt.toUpperCase();
74                         a.setAttribute('style', 'font-weight:bold;margin-left:1em;color:white');
75                         return a;
76                 }
77                 return null
78         }
79
80         // create a link element for a raw URL
81         function H5aRaw(name, url) {
82                 if (url) {
83                         var a = document.createElement('a');
84                         a.href = url;
85                         a.innerHTML = name.toUpperCase();
86                         a.setAttribute('style', 'font-weight:bold;margin-left:1em;color:red');
87                         return a;
88                 }
89                 return null
90         }
91
92         var streamlist = document.createElement("li");
93
94         // reset stream list: this is used in the playTg and playAudio
95         // functions to reset the stream list when changing stream,
96         function slReset() {
97                 streamlist.innerHTML = '<span>Stream/Download:</span>';
98         }
99         // and of course once at the beginning of it all 8-)
100         slReset();
101
102         var sch;
103
104         var placeStreamList = function() {
105                 // find place to append the stream list to
106                 // if possible, look for an existing ul in what is likely to be the top
107                 // otherwise, create an ul and put it either in a miniLink if available,
108                 // or the top otherwise
109                 // TODO use some smarter mechanism
110                 var pp = sch.parentNode.parentNode.previousElementSibling;
111                 var specs = pp.getElementsByTagName('ul');
112                 if (!specs || !specs[0]) {
113                         specs = document.createElement('ul');
114                         specs.className = 'Specifiche';
115                         var mid = document.getElementById('Notizie');
116                         if (mid) {
117                                 mid = mid.lastElementChild;
118                                 mid.insertBefore(specs, mid.firstElementChild);
119                         } else {
120                                 pp.appendChild(specs);
121                         }
122                 } else {
123                         specs = specs[0];
124                 }
125                 specs.appendChild(streamlist);
126                 console.log(streamlist, 'appended');
127
128         }
129
130         var ourReplayTV = function(det) {
131                 if (!sch) {
132                         sch = document.getElementById("SilverlightPlayer");
133                         sch.style.width = '100%';
134                         sch.style.height = '100%';
135                         placeStreamList();
136                 }
137                 // stop loading any current audio/video
138                 if (sch.firstChild && sch.firstChild.src) {
139                         console.log('stopping current A/V');
140                         sch.firstChild.src = '';
141                 }
142
143                 slReset();
144
145                 var srcs = "";
146                 for (var k in det) {
147                         if (k.match(/^h264/)) {
148                                 var url = det[k];
149                                 if (url && url.length > 0) {
150                                         srcs += srctag(url, 'video', 'h264');
151                                         var r = k.split('_');
152                                         if (r[1]) {
153                                                 r = r[0] + " (" + r[1] + "KB/s)";
154                                         } else {
155                                                 r = r[0];
156                                         }
157                                         streamlist.appendChild(H5aRaw(r, url));
158                                 }
159                         }
160                 }
161                 // re-create the video player
162                 sch.innerHTML = "<video width='100%' height='100%' controls autoplay>" +
163                         srcs +
164                         "<h3>Sorry, no supported video format found :-(</h3></video>";
165
166         }
167
168         if (window.replayTv) {
169                 window.replayTv.playVideo_ujs = window.replayTv.playVideo;
170                 window.replayTv.playVideo = function(det) {
171                         console.log("IN");
172                         try {
173                                 window.replayTv.playVideo_ujs.call(window.replayTv, det);
174                         } catch (e) {
175                                 console.log(e);
176                         }
177                         ourReplayTV(det);
178                         console.log("OUT");
179                 }
180                 if (window.replayTv.currVideo) {
181                         window.replayTv.playVideo(window.replayTv.vid2data[window.replayTv.currVideo]);
182                 }
183         }
184
185         sch = document.getElementById("silverlightControlHost");
186         if (sch) {
187                 // debug
188                 console.log(urls);
189
190                 placeStreamList();
191                 // if we are on a page that defines the videourl* metas, go straight to creating
192                 // the video element
193                 if (urls.std) {
194                         // prevent other JS with messing with this element further
195                         sch.id = 'html5mediaHost';
196                         sch.innerHTML = "<video style='width:100%; height:100%' controls>" +
197                                 H5video('mp4') + H5video('wmv') + H5video('h264') +
198                                 H5video('m3u8') + H5video('m3u8_android') +
199                                 H5video('std') +
200                                 "<h3>Sorry, no supported video format found :-(</h3></video>";
201                         console.log(sch, 'hacked');
202
203                         for (var fmt in urls) {
204                                 var a = H5a(fmt);
205                                 if (a)
206                                         streamlist.appendChild(a);
207                         }
208                         return; // done
209                 }
210
211                 // hack the play* JS functions
212                 if (window.playTg) {
213                         window.playTg = function (liveTg, video, h264, androidUrl) {
214                                 var dataP = new Date();
215                                 var ggP, mmP, aaaaP;
216                                 ggP = dataP.getDate() + "-";
217                                 mmP = dataP.getMonth() + 1 + "-";
218                                 aaaaP = 1900 + dataP.getYear();
219
220                                 // prevent page from refreshing, the site only checks for
221                                 // the existence of object/embed, not audio/video
222                                 window.refreshByJS = false;
223
224                                 // stop loading any current audio/video
225                                 if (sch.firstChild && sch.firstChild.src) {
226                                         console.log('stopping current A/V');
227                                         sch.firstChild.src = '';
228                                 }
229
230                                 // re-create the video player
231                                 sch.innerHTML = "<video width='258' height='195' controls autoplay>" +
232                                         srctag(h264, 'video') +
233                                         srctag(androidUrl, 'video') +
234                                         srctag(video, 'video') +
235                                         "<h3>Sorry, no supported video format found :-(</h3></video>";
236
237                                 // re-create stream list
238                                 slReset();
239                                 // oh we would like to indicate the media type somehow,
240                                 // but it seems to be somewhat random. Not even a HEAD
241                                 // on the URL works reliably all the time
242                                 var a = H5aRaw('1', h264);
243                                 if (a)
244                                         streamlist.appendChild(a);
245                                 if (androidUrl != h264) {
246                                         a = H5aRaw('2', androidUrl);
247                                         if (a)
248                                                 streamlist.appendChild(a);
249                                 }
250                                 if ((video != androidUrl) && (video != h264)) {
251                                         a = H5aRaw('3', video);
252                                         if (a)
253                                                 streamlist.appendChild(a);
254                                 }
255
256                                 setNielsen(location.href + '&video=' + liveTg + '&data=' + ggP + mmP + aaaaP + '', true);
257                                 console.log('playTg', liveTg, video, h264, androidUrl)
258                         }
259                         console.log('playTg hacked');
260                 }
261
262                 if (window.playAudio) {
263                         window.playAudio = function (grrEdizione, mediaUrl, mediatype) {
264                                 var dataP = new Date();
265                                 var ggP, mmP, aaaaP;
266                                 ggP = dataP.getDate() + "-";
267                                 mmP = dataP.getMonth() + 1 + "-";
268                                 aaaaP = 1900 + dataP.getYear();
269
270                                 // prevent page from refreshing, the site only checks for
271                                 // the existence of object/embed, not audio/video
272                                 window.refreshByJS = false;
273
274                                 // stop loading any current audio/video
275                                 if (sch.firstChild && sch.firstChild.src) {
276                                         console.log('stopping current A/V');
277                                         sch.firstChild.src = '';
278                                 }
279
280                                 // re-create the audio player
281                                 sch.innerHTML = "<audio width='258' height='35' controls autoplay>" +
282                                         srctag(mediaUrl, 'audio') +
283                                         "<h3>Sorry, no supported audio format found :-(</h3></audio>";
284
285                                 // re-create stream list
286                                 slReset();
287                                 var a = H5aRaw(mediatype ? mediatype : '(???)', mediaUrl);
288                                 if (a)
289                                         streamlist.appendChild(a);
290
291                                 setNielsen(location.href + '&audio=' + grrEdizione + '&data=' + ggP + mmP + aaaaP + '', true);
292                                 console.log('playAudio', grrEdizione, mediaUrl, mediatype);
293                         }
294                         console.log('playAudio hacked');
295                 }
296         }
297
298         // Archivio Luce
299         if (window.ply  && window.ply.configuration
300                         && window.ply.configuration.file
301                         && window.cnt) {
302                 var src = window.ply.configuration.file.replace(/^mms:\/\//,'http://');
303                 var width = window.ply.configuration.width;
304                 var height = window.ply.configuration.height;
305
306                 window.cnt.innerHTML = "<video style='width:" + width +
307                                         "px; height:" + height + "' controls autostart>" +
308                                         srctag(src, 'video', null) +
309                                         "</video>";
310                 console.log(window.cnt, 'hacked');
311                 window.cnt.appendChild(H5aRaw("WMV", src));
312         }
313 })
314
315 })();