- // ==UserScript==
- // @name Rai.tv native video player and direct links - LEGACY
- // @namespace http://andrealazzarotto.com
- // @description This script allows you to watch and download videos on Rai.tv.
- // @include http://www*.rai.*/dl/RaiTV/programmi/media/*
- // @include https://www*.rai.*/dl/RaiTV/programmi/media/*
- // @include http://www*.rai.*/dl/RaiTV/tematiche/*
- // @include https://www*.rai.*/dl/RaiTV/tematiche/*
- // @include http://www*.rai.*/dl/*PublishingBlock-*
- // @include https://www*.rai.*/dl/*PublishingBlock-*
- // @include http://www*.rai.*/dl/replaytv/replaytv.*
- // @include https://www*.rai.*/dl/replaytv/replaytv.*
- // @include http://rai.it/*
- // @include https://rai.it/*
- // @include http://*.rai.it/*
- // @include https://*.rai.it/*
- // @include http://www.rainews.it/dl/rainews/*
- // @include https://www.rainews.it/dl/rainews/*
- // @include http://www.rainews.it/tgr/*
- // @include https://www.rainews.it/tgr/*
- // @version 9.2.0
- // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js
- // @require https://unpkg.com/@ungap/from-entries@0.1.2/min.js
- // @grant GM_xmlhttpRequest
- // @grant GM.xmlHttpRequest
- // @connect rai.it
- // @connect rai.tv
- // @connect raiplay.it
- // @connect akamaized.net
- // @connect akamaihd.net
- // @connect msvdn.net
- // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
- // ==/UserScript==
-
- /* Greasemonkey 4 wrapper */
- if (typeof GM !== "undefined" && !!GM.xmlHttpRequest)
- GM_xmlhttpRequest = GM.xmlHttpRequest;
-
- function fetch(params) {
- return new Promise(function(resolve, reject) {
- params.onload = resolve;
- params.onerror = reject;
- GM_xmlhttpRequest(params);
- });
- }
-
- var checkQuality = (url, rate) => {
- return fetch({
- method: 'GET',
- url: url,
- headers: {
- 'User-Agent': 'raiweb',
- 'Range': 'bytes=0-255',
- },
- }).then(
- (response) => {
- let headers = fromEntries(response.responseHeaders.split("\n").map(element => element.trim().toLowerCase().split(":")));
- let range = headers['content-range'] || '/0';
- let size = +(range.split('/').slice(1,)[0] || 0);
- let megabytes = Math.round(size / 1024 / 1024);
- if (size > 102400) {
- return { quality: rate, url: url, megabytes: megabytes };
- } else {
- return null;
- }
- },
- () => null
- );
- }
-
- var qualities = async (url) => {
- let bases = [];
- let rates = [5000, 3200, 2401, 2400, 1800, 1500, 1200, 800, 600, 400];
- if (url.indexOf('.m3u8') > 0) {
- let parts = url.replace(/\?.*/, '').split(',');
- // Verify all the rates
- const new_rates = parts.slice(1).map(value => value.replace(/\/.*/, '')).reverse().filter(value => !isNaN(value));
- // Handle single rate case
- if (new_rates.length) {
- rates = new_rates;
- } else {
- let rate = url.split('.mp4')[0].split('_').slice(-1)[0];
- rates = [rate];
- }
- const path = parts[0];
- let servers = [
- 'creativemedia1.rai.it',
- 'creativemedia2.rai.it',
- 'creativemedia3.rai.it',
- 'creativemedia4.rai.it',
- 'creativemedia6-rai-it.akamaized.net',
- 'creativemedia7-rai-it.akamaized.net',
- 'download2.rai.it',
- 'download2-geo.rai.it',
- 'creativemediax1.rai.it',
- 'creativemediax2.rai.it',
- ];
- let file_path;
- if (path.indexOf('akamaized.net') > 0 || path.indexOf('akamaihd.net') > 0) {
- const path_parts = path.split('.net/');
- file_path = '/' + path_parts[1];
- } else {
- const path_parts = path.split('msvdn.net/');
- const first = path_parts[1].replace(/^[^0-9]+/, '');
- file_path = first.slice(1);
- }
- // Fix the "/i/" prefix
- if (file_path.slice(0, 3) === '/i/') {
- file_path = file_path.replace('/i/', '/');
- }
- file_path = file_path.replace(/_[1-9]+0?0[01]\.mp4.*/, '_');
- if (file_path.indexOf('.mp4') > 0) {
- file_path = file_path.replace(/\.mp4.*/, '');
- rates = [''];
- }
- bases = servers.map(server => {
- return `http://${server}${file_path}${rates[0]}.mp4`;
- });
- console.log(bases);
- } else {
- bases.push(url);
-
- var ending = url.match(/_[1-9]+0?0[01]\.mp4/);
- if (!ending || !ending.length) {
- let result = await checkQuality(url, '');
- return [result].filter(value => (value !== null));
- }
- }
-
- let promises = [];
- bases.forEach(url => {
- var promise = Promise.all(rates.map(rate => {
- var quality_url = url.replace(/_[1-9]+0?0[01]\.mp4/, `_${rate}.mp4`);
- return checkQuality(quality_url, rate);
- }));
- promises.push(promise);
- });
- const groups = await Promise.all(promises);
- for (let i = 0; i < groups.length; i++) {
- const filtered = groups[i].filter(value => (value !== null));
- if (filtered.length) {
- return filtered;
- }
- }
-
- return [];
- };
-
- var solveRelinker = (url) => {
- var secure = url.replace('http://', 'https://');
- return fetch({
- method: 'HEAD',
- url: secure,
- headers: {
- 'User-Agent': 'raiweb',
- },
- }).then(
- (response) => {
- let final = response.finalUrl;
- let valid = (final.indexOf('mp4') > 0 || final.indexOf('.m3u8') > 0) && final.indexOf('DRM_') < 0;
- if (valid) {
- return qualities(response.finalUrl).then(results => {
- return results[0].url;
- });
- }
- }
- );
- };
-
- function playerElement() {
- var selectors = [
- "#Player.Player",
- "div.player-container",
- "div.Player:has(video)",
- "div.Player:has(embed)",
- "div.Player",
- "div#Player",
- "div#idPlayer",
- "div.videoContainer:has(iframe)",
- "div.mediaRaiTV:has(iframe)",
- "div.entry-content > div:has(iframe)",
- "div.video-iframe",
- "div.player-video",
- ];
-
- for (var k in selectors) {
- var PL = $(selectors[k]).get(0);
- if(PL)
- return $( PL );
- }
-
- return null;
- }
-
- function appendMsg(text, PL) {
- if(!PL)
- PL = playerElement();
- $("#subcontent").remove();
- PL.append("<div id='subcontent'>" + text + "</div>");
- $("#subcontent").css({
- "padding": "5px",
- "color": "white",
- 'width': '60%',
- 'min-width': '18rem',
- 'max-width': '100%',
- "background": "rgba(0,0,0,0.5)",
- 'margin': '15px auto'
- });
- $("#subcontent p").css({
- 'margin': '.2em auto',
- 'padding': 0
- });
- $("#subcontent a").css({
- 'color': 'white',
- 'font-weight': 'bold',
- 'text-decoration': 'underline'
- });
- }
-
- function suggestAlternative(relinker) {
- appendMsg("<p>Link diretto non disponibile. Prova a scaricarlo con <code>youtube-dl</code>:</p><pre><code>youtube-dl \"" + relinker + "\"</code></pre><p>Attenzione! Alcuni video si possono salvare solo dall'Italia.</p>");
- }
-
- function placeHolder(url, kind, PL, remove) {
- remove = typeof remove !== 'undefined' ? remove : true;
-
- if(!PL)
- PL = playerElement();
- if(remove)
- $("#direct-link").remove();
-
- var wrapper = PL.closest('.video-player-wrapper');
- if (!wrapper.length) {
- wrapper = $('<div class="video-player-wrapper" />');
- PL.wrap(wrapper);
- };
- var direct = $('<div id="direct-link" />');
- $('.video-player-wrapper').append(direct);
- direct.css({
- 'padding': '5px',
- 'margin': '10px auto 15px',
- 'width': '60%',
- 'min-width': '18rem',
- 'max-width': '100%',
- 'border': '1px solid #888',
- 'text-align': 'center',
- 'box-shadow': '0px 5px 15px 0px rgba(0, 0, 0, .7)',
- 'background-color': '#cfc',
- })
- .append('<a href="'+url+'">' + kind + " Direct Link</a>");
- direct.find('a').css({
- 'font-size': '13px',
- 'font-weight': 'normal',
- 'color': 'black'
- });
-
- wrapper.parent().css('overflow', 'visible');
-
- appendMsg('<center>' +
- '<iframe allowtransparency="true" style="width: 102px; height: 20px; position: relative; vertical-align: middle; display: inline-block;" src="https://www.facebook.com/v2.12/plugins/like.php?href=https%3A%2F%2Ffacebook.com%2FAndreaLazzarottoSoftware&layout=button_count&sdk=joey&share=false&show_faces=false" frameborder="0"></iframe>' +
- ' — <a href="https://lazza.me/DonazioneScript">Fai una donazione</a>' +
- '</center>', $('.video-player-wrapper'));
- }
-
- function setUP(url, kind) {
- if(kind.toLowerCase().indexOf("smooth") != -1 ||
- kind.toLowerCase().indexOf("csm") != -1)
- return;
-
- // fix spaces
- url = url.split(' ').join('%20');
-
- placeHolder(url, kind);
- }
-
- function decide(videoURL, videoURL_MP4, estensioneVideo) {
- if (videoURL_MP4) {
- // handle the relinker client-side
- solveRelinker(videoURL_MP4).then(r => {
- setUP(r, "MP4");
- }).catch(() => {
- suggestAlternative(videoURL_MP4);
- });
- }
- else if (videoURL) {
- // handle the relinker client-side
- solveRelinker(videoURL).then(r => {
- if (r.substr(r.length - 4).substr(0,1) == '.') {
- estensioneVideo = r.substr(r.length - 3).toUpperCase();
- }
- setUP(r, estensioneVideo);
- }).catch(() => {
- suggestAlternative(videoURL);
- });
- } // end if (videoURL)
- }
-
- function parseQuery(hash) {
- var result = {};
- var parts = hash.split("&");
- for(var i = 0; i<parts.length; i++) {
- var pair = parts[i].split("=");
- result[pair[0]] = pair[1];
- }
- return result;
- }
-
- function setUpFromURL(url) {
- // get the original page content
- GM_xmlhttpRequest({
- method: 'GET',
- url: url,
- onload: function(responseDetails) {
- var r = responseDetails.responseText;
- // kill script tags to avoid execution (and errors!)
- r = r.replace(new RegExp('script', 'g'), 'dummy');
- var data = $('<div></div>').append(r).html();
-
- var videoURL = null;
- var videoURL_MP4 = null;
- var estensioneVideo = null;
-
- // set the correct variables
- try {
- videoURL = data.match(/videoURL = ["'](.*?)["']/)[1];
- }
- catch(e) {}
- try {
- videoURL = data.match(/data-video-url="([^"]*)"/)[1];
- }
- catch(e) {}
- try {
- videoURL_MP4 = data.match(/videoURL_MP4 = ["'](.*?)["']/)[1];
- }
- catch(e) {}
- try {
- estensioneVideo = data.match(/estensioneVideo = ["'](.*?)["']/)[1];
- }
- catch(e) {}
-
- decide(videoURL, videoURL_MP4, estensioneVideo);
- }
- });
- }
-
- $(document).ready(function(){
-
- unsafeWindow.createPlayer = function() { return false; };
- $("body").append(`
- <style>
- iframe~.tagManagerError {
- display: none;
- }
-
- @media screen and (max-width: 639px) {
- .videoOverlay {
- position: unset;
- height: auto;
- z-index: unset;
- padding-top: 0;
- padding-bottom: 0 !important;
- transform: scale(0.65);
- margin-left: -10vw;
- margin-right: -10vw;
- width: 120vw;
- transform-origin: top center;
- background: none;
- font-size: 6vw;
- }
- .videoOverlay *,
- .videoOverlay .button {
- font-size: inherit !important;
- }
- }
- </style>
- `);
-
- var isRaiPlay = !!$(".Player[data-video-url]").length;
- var isReplay = !!$("script[src*='/replaytv.js'], script[src*='/replaytv.dev.js']").length;
- var isTematiche = window.location.href.indexOf("tematiche") > 0;
- var isPublishingBlock = window.location.href.indexOf("PublishingBlock") > 0;
- var isRubriche = window.location.href.indexOf("rubriche") > 0;
- var isTGR = window.location.href.indexOf("rainews.it/tgr") > 0;
- var isMultiple = (isTematiche || isPublishingBlock || isRubriche);
-
- console.log("isRaiPlay: " + isRaiPlay);
- console.log("isReplay: " + isReplay);
- console.log("isTematiche: " + isTematiche);
- console.log("isPublishingBlock: " + isPublishingBlock);
- console.log("isRubriche: " + isRubriche);
- console.log("isMultiple: " + isMultiple);
- console.log("isTGR: " + isTGR);
-
- var frames = $("iframe[src*='/dl/objects/embed.html'], iframe[src*='/dl/ray/'], " +
- "iframe[src*='/dl/Rai/'], iframe[src*='/dl/siti/'], iframe[src*='ContentItem'], iframe[src*='iframe/video/']");
-
- if (isRaiPlay) {
- var PL = $(".Player[data-video-url]");
- var relinker = PL.data('video-url');
- console.log(relinker);
- solveRelinker(relinker).then(r => {
- var estensioneVideo = "";
- if (r.substr(r.length - 4).substr(0,1) == '.')
- estensioneVideo = r.substr(r.length - 3).toUpperCase();
- if(r.length > 0) {
- setUP(r, estensioneVideo, PL);
- }
- }).catch(() => {
- suggestAlternative(relinker);
- });
- }
-
- if(!isMultiple && !isReplay &&
- (unsafeWindow.videoURL || unsafeWindow.videoURL_MP4)) {
- console.log("[Has video URL]");
-
- var videoURL = $("meta[name=videourl]").attr("content");
- if(!videoURL)
- videoURL = unsafeWindow.videoURL;
- var videoURL_MP4 = $("meta[name=videourl_h264]").attr("content");
- if(!videoURL_MP4)
- videoURL_MP4 = unsafeWindow.videoURL_MP4;
- if(!videoURL_MP4)
- videoURL_MP4 = $("meta[name=videourl_mp4]").attr("content");
- var estensioneVideo = unsafeWindow.estensioneVideo;
- if(estensioneVideo)
- estensioneVideo = estensioneVideo.toUpperCase();
- else
- estensioneVideo = "Unknown";
- if(unsafeWindow.MediaItem.type == 'WMV')
- // avoid bug when estensioneVideo = CSM and MediaItem.type = WMV
- estensioneVideo = "WMV";
-
- decide(videoURL, videoURL_MP4, estensioneVideo);
-
- }
- // end Rai.tv "standard"
-
- else if(frames.length && !isReplay && !isMultiple) {
- var url = frames.attr("src");
- if(url.indexOf("embed.html") > 0)
- url = "http://www.rai.tv" + url.replace(/.*embed.html\?/, "");
- if(url.indexOf("/iframe/video") > 0)
- url = url.replace("/iframe/video", "/video");
- setUpFromURL(url);
- }
-
- // end iframes
-
- else if(isTGR) {
- $("div.Player").each(function() {
- var relinker = $(this).attr('data-mediaurl');
- if (relinker) {
- setTimeout(function() {
- decide(relinker);
- $("div.Player").parent().css('padding', 0);
- }, 1000);
- }
- });
- }
-
- else if(isMultiple && !isReplay) {
- if(unsafeWindow.videoURL) {
- document.videoURL = '';
- setInterval(function() {
- if(!playerElement())
- return;
- document.prevURL = document.videoURL;
- document.videoURL = unsafeWindow.videoURL;
- if(document.videoURL && (document.prevURL != document.videoURL)) {
- decide(document.videoURL);
- }
- }, 400);
- }
- else
- setInterval(function() {
- if(!playerElement())
- return;
- document.HprevId = document.Hid;
- document.Hid = $("div.Player").attr("data-id");
- console.log(document.Hid);
- if(!document.Hid)
- try {
- document.Hid = $("div.player-video iframe").attr("src").split("media/")[1].split(".html")[0];
- }
- catch(e) {}
-
- // remove video list click events to allow opening of "real" pages
- // if not on "tematiche"
- if(!isTematiche) {
- $(".listaVideo a").unbind("click");
- }
- if(document.Hid && (document.Hid != document.HprevId)) {
- var completeURL = "http://www.rai.tv/dl/RaiTV/" +
- "programmi/media/" + document.Hid + ".html";
- setUpFromURL(completeURL);
- }
- }, 400);
- }
-
- // end Tematiche
-
- else if($("script:contains('draw')").length > 0 ||
- $("div.infoVideo").length > 0) {
- var videoURL = $("script:contains('draw')").text().split("'")[1];
- if(videoURL !== null && videoURL.indexOf("relinker") > 0) {
- GM_xmlhttpRequest({
- method: 'GET',
- url: videoURL,
- headers: {
- 'Accept': 'application/atom+xml,application/xml,text/xml'
- },
- onload: function(responseDetails) {
- var r = responseDetails.responseText;
- var doc = $.parseXML(r);
- var $xml = $( doc );
-
- var url = $xml.find("REF").attr("HREF");
- url = url.replace("http://", "mms://");
-
- setUP(url, "MMS Stream");
- }
- });
- }
- else if(videoURL !== null && videoURL.indexOf(".html") > 0) {
- setUpFromURL(videoURL);
- }
- else { // last try
- var PL = playerElement();
- var initParams = PL.find("param[name=initParams]").attr("value");
- if (initParams.indexOf("mediaUri") != -1) {
- var url = initParams.split("mediaUri=")[1].split(",")[0];
- decide(url, null, null); // decide will find the type
- }
- }
- }
-
- // end pages like report.rai.it
-
- // handle RTMP based flash objects on Rai.it
- $("object").not("object object").each(function() {
- var o = $(this);
- var flashvars = o.find("param[name=flashvars]").attr("value");
- if(!flashvars)
- flashvars = o.find("embed").attr("flashvars");
- if(!flashvars)
- flashvars = "";
- var path = flashvars.replace(/.*percorso[^=]*=/gi, "")
- .replace(/&.*/gi, "").replace(/\?.*/gi, "");
- if(path.toLowerCase().indexOf("rtmp")!=-1) {
- var url = path.replace('mp4:','').replace('rtmp','http')
- .replace('.mp4','') + '.mp4';
- placeHolder(url, "MP4", o, false);
- }
- });
- // end code for flash videos
-
- // handle new pages with projekktor
- var pj;
- try {
- pj = unsafeWindow.projekktor();
- }
- catch (e) {
- pj = false;
- }
- if(pj) {
- var files = pj.media;
- var src = files[files.length - 1].file[0].src;
- var el = $('div.projekktor').parent();
- placeHolder(src, 'MP4', el);
- el.css('background', 'transparent');
- }
- // end projekktor
-
- // handle WP-Video
- $('div[class^="wp-video"]').each(function() {
- var url = $(this).find('video').attr('src');
- placeHolder(url, "MP4", $(this), false);
- });
-
- // handle jwplayer
- $('script:contains("jwplayer(")').each(function() {
- var content;
- try {
- content = $(this).text().split('sources:')[1].split('[{')[1].split('}]')[0];
- }
- catch (e) { return; }
- parts = content.split('file:').filter(function(x){return x.indexOf('m3u8') > 0;});
- if(parts.length) {
- var m3u8_url;
- try {
- m3u8_url = parts[0].split('"')[1];
- }
- catch (e) { return; }
- placeHolder(m3u8_url, 'M3U8 Stream', $(this).parent(), false);
- appendMsg(
- "<p>Ricordo che per registrare i video in formato M3U8 va utilizzato <code>ffmpeg</code>. " +
- "Maggiori informazioni <a href='http://lazza.me/1PLyi12'>cliccando qui</a>.</p>" +
- "<p style='text-align:right'>— Andrea</p>", $(this).parent());
- }
-
- });
-
- }); // end document.ready