Skip to content

Commit

Permalink
Major release
Browse files Browse the repository at this point in the history
MASSIVE OVERALL :
+ optimization by prefetching json
+ handling of Arte+7 and Direct
+ handling of both types of direct/livestreams
+ handling of all availables languages
+ support for RMP4 protocol (possibly M3U8 playlist format now)
+ future selection of languages in a patch
+ new background-image for direct/livestream
+ various samples added
  • Loading branch information
Bumbadawg committed Nov 5, 2015
1 parent 53d4716 commit 17890b5
Show file tree
Hide file tree
Showing 5 changed files with 366 additions and 108 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
ARTE-7-PLAYGROUND
=================

Current version: **1.7.1**.
Current version: **2.0.0**.

CONTRIBUTORS
-----------

Bumbadawg
GuGuss
aug-riedinger
maxlath
uahim

DESCRIPTION
-----------
Expand Down Expand Up @@ -33,14 +42,21 @@ INSTALL - FIREFOX & OTHER
USAGE
-----

Go to a video on [ARTE+7 website](http://www.arte.tv/guide/fr/plus7) and you should see 4 buttons under the video:
Go to a video on [ARTE+7 website](http://www.arte.tv/guide/fr/plus7) and you should see buttons under the video:

Select language

and

Download
* **High** Quality
* **Standard** Quality
* **Low** Quality
* **Metadata** (Text file containing the video metadata)

In case of a livestream/direct, you'll be able to either watch it on your browser
or copy the link into [VLC](http://www.videolan.org/vlc/)

FAQ
---

Expand Down
269 changes: 163 additions & 106 deletions arte-downloader.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// @namespace GuGuss
// @description Display direct links to MP4 videos of Arte+7 programs
// @include http://*.arte.tv/*
// @version 1.7.1
// @version 2.0.0
// @updateURL https://github.com/GuGuss/ARTE-7-Playground/blob/master/arte-downloader.user.js
// @grant GM_xmlhttpRequest
// @icon https://icons.duckduckgo.com/ip2/www.arte.tv.ico
Expand All @@ -23,7 +23,14 @@ var videoPlayerURL = "arte_vp_url";
var videoPlayerLiveURL = "arte_vp_live-url";
var bLive = true;

var languageCode = { // aka. versionCode
var qualityCode = {
'Low': 'HQ',
'Standard': 'EQ',
'High': 'SQ'
};

var languages = {
// 'versionCode' : 'language'
'VO-STF': 'Original (subtitled in french)',
'VA-STA': 'German subtitled',
'VF-STF': 'French subtitled',
Expand All @@ -32,14 +39,48 @@ var languageCode = { // aka. versionCode
'VOF-STMF': 'Sourds et malentendants'
};

function createButton(quality, language) {
var availableLanguages = Object.assign({}, languages); // Clone object
for (l in availableLanguages) {
availableLanguages[l] = 0;
}

function addLanguage(language) {
if (availableLanguages[language] === 0) {
availableLanguages[language] = languages[language];
console.log("- language found: " + availableLanguages[language]);
}
}

function preParsePlayerJson() {
if (playerJson) {
var videos = Object.keys(playerJson["videoJsonPlayer"]["VSR"]);
var numberOfVideos = videos.length;
console.log(numberOfVideos + " versions of the video have been found.");

// Loop through all videos URLs.
for (var key in videos) {

// Check if video format is "HBBTV".
if (playerJson["videoJsonPlayer"]["VSR"][videos[key]]["videoFormat"] === "HBBTV") {

// Add the language
addLanguage(playerJson["videoJsonPlayer"]["VSR"][videos[key]]["versionCode"]);
}
}
}
}

function createButton(quality, language, text) {
var button = document.createElement('a');
button.setAttribute('class', 'btn btn-default');
button.setAttribute('style', 'text-align: center; display: table-cell;');
button.innerHTML = "<strong>" + quality + "</strong> Quality <span class='icomoon-angle-down force-icomoon-font'></span>";
button.innerHTML = "<strong>" + quality + " (" + language + ") </strong> Quality <span class='icomoon-angle-down force-icomoon-font'></span>";
if (text !== undefined) {
button.innerHTML = text;
}

var videoName = getVideoName(playerJson, quality);
var videoUrl = getVideoUrl(playerJson, quality, language);
var videoName = getVideoName(quality);
var videoUrl = getVideoUrl(quality, language);
button.setAttribute('download', videoName);
button.setAttribute('href', videoUrl);
button.setAttribute('target', '_blank');
Expand All @@ -64,148 +105,164 @@ function createButtonMetadata(element) {
return button;
}

function createButtons(container) {
container.appendChild(createButton('High'));
container.appendChild(createButton('Standard'));
container.appendChild(createButton('Low'));
function createLanguageComboBox() {
var languageComboBox = document.createElement('select');
languageComboBox.setAttribute("id", "languageComboBox");
for (l in availableLanguages) {
if (availableLanguages[l] !== 0) {
languageComboBox.innerHTML += "<option value='" + l + "' selected>" + availableLanguages[l] + "</option>";
}
}
languageComboBox.setAttribute('class', 'btn btn-default');
languageComboBox.setAttribute('style', 'width:97%');

return languageComboBox;
}

// Decorates videos with download buttons
var decorateVideo = function (element) {
function createButtons(videoElement) {
preParsePlayerJson();

var parent = videoElement.parentNode.parentNode;
var container = document.createElement('div');
container.setAttribute('style', 'display: table; width: 100%;');
parent.appendChild(container);

container.appendChild(createLanguageComboBox());
var languageComboBox = document.getElementById("languageComboBox");
var selectedLanguage = languageComboBox.options[languageComboBox.selectedIndex].value;

if (bLive) {
container.appendChild(createButton('High', selectedLanguage, "RPM4 playlist (copy/paste into VLC) <span class='icomoon-angle-down force-icomoon-font'></span>"));
} else {
container.appendChild(createButton('Low', selectedLanguage));
container.appendChild(createButton('Standard', selectedLanguage));
container.appendChild(createButton('High', selectedLanguage));
//container.appendChild(createButtonMetadata(videoElement)); // @TODO display instead of download
}

var credit = document.createElement('div');
credit.setAttribute('style', 'width: 100%; text-align: center; font-size: 0.8em; padding: 3px; background-image:url("data:image/gif;base64,R0lGODlhAwADAIAAAMhFJuFdPiH5BAAAAAAALAAAAAADAAMAAAIERB5mBQA7")');
credit.innerHTML = 'Arte+7 Downloader v.' + GM_info.script.version
+ ' built by and for the community with love'
+ '<br /><a href="https://github.com/GuGuss/ARTE-7-Downloader">Contribute Here.</a>';
parent.appendChild(credit);
}

function getPlayerJson(playerUrl, videoElement) {
console.log('Json video player URL: ' + playerUrl);
GM_xmlhttpRequest({
method: "GET",
url: playerUrl,
onload: function (response) {
playerJson = JSON.parse(response.responseText);
createButtons(videoElement);
}
});
}

// Get the content of the JSON file.
var playerUrl;
// Decorates a video with download buttons
function decorateVideo(videoElement) {

// if it's a stream, get the video player
// if it's a stream, get the video player URL through the stream Json
if (bLive === true) {
console.log("Livestream URL: " + videoElement.getAttribute(videoPlayerLiveURL));
var livePlayerUrl = videoElement.getAttribute(videoPlayerLiveURL);
GM_xmlhttpRequest(
{
method: "GET",
url: element.getAttribute(videoPlayerLiveURL),
url: videoElement.getAttribute(videoPlayerLiveURL),
onload: function (response) {
// Look for player URL inside the livestream player URL
var json = JSON.parse(response.responseText);
playerUrl = json["videoJsonPlayer"]["videoPlayerUrl"];
console.log("Json live video player URL: " + playerUrl);
GM_xmlhttpRequest({
method: "GET",
url: playerUrl,
onload: function (response) {
playerJson = JSON.parse(response.responseText); // Parse the JSON text into a JavaScript object
createButtons(container);
}
});
var playerUrl = json["videoJsonPlayer"]["videoPlayerUrl"];

// if not player URL: look for playlist file inside the livestream player
if (playerUrl === undefined) {
console.log("Video player URL not available. Fetching livestream player URL");
getPlayerJson(livePlayerUrl, videoElement);
console.log(getVideoUrl('High'));
} else {
getPlayerJson(playerUrl, videoElement);
}

}
}
);
} else { // the player URL is the Json
playerUrl = element.getAttribute(videoPlayerURL);
console.log("Json video player URL: " + playerUrl);
GM_xmlhttpRequest({
method: "GET",
url: playerUrl,
onload: function (response) {
playerJson = JSON.parse(response.responseText); // Parse the JSON text into a JavaScript object
createButtons(container);
}
});
} else { // otherwise get directly
var playerUrl = videoElement.getAttribute(videoPlayerURL);
getPlayerJson(playerUrl, videoElement);
}

var languageRadioList = document.createElement('select');
languageRadioList.innerHTML = "<option value='VO-STF' selected>" + languageCode['VO-STF'] + "</option>"
+ "<option value='VA-STA'>" + languageCode['VA-STA'] + "</option>"
+ "<option value='VF-STF'>" + languageCode['VF-STF'] + "</option>"
+ "<option value='VOF'>" + languageCode['VOF'] + "</option>"
+ "<option value='VOA'>" + languageCode['VOA'] + "</option>"
+ "<option value='VOF-STMF'>" + languageCode['VOF-STMF'] + "</option>";
languageRadioList.setAttribute('class', 'btn btn-default');
languageRadioList.setAttribute('style', 'width:98%');

var credit = document.createElement('div');
credit.setAttribute('style', 'width: 100%; text-align: center; font-size: 0.8em; padding: 3px;');
credit.innerHTML = 'Arte+7 Downloader v.' + GM_info.script.version
+ ' built by and for the community with <strong><3</strong><br /><a href="https://github.com/GuGuss/ARTE-7-Downloader">Contribute Here.</a>';

container.appendChild(languageRadioList);
//container.appendChild(createButtonMetadata(element)); // @TODO display instead of download

var parent = element.parentNode.parentNode;
parent.appendChild(container);
parent.appendChild(credit);
};

var videoPlayerElement = document.querySelector("div[" + videoPlayerLiveURL + "]");

// If it is not a livestream
if (videoPlayerElement == null) {
bLive = false;
videoPlayerElement = document.querySelector("div[" + videoPlayerURL + "]");
}

decorateVideo(videoPlayerElement);

/*
* Parse the content of the JSON file and extract the video name.
*/
function getVideoName(json, quality) {
var name = (json['videoJsonPlayer']['VST']['VNA']).split('_').join(' ');
return '[' + quality.toUpperCase() + '] ' + name.charAt(0).toUpperCase() + name.slice(1) + '.mp4';;
function getVideoName(quality) {
var name;
if (bLive) {
name = (playerJson['videoJsonPlayer']['VTI']);
} else {
name = (playerJson['videoJsonPlayer']['VST']['VNA']).split('_').join(' ');
}
return '[' + quality.toUpperCase() + '] ' + name.charAt(0).toUpperCase() + name.slice(1) + '.mp4';
}

/*
* Parse the content of the JSON file and extract the metadata informations.
*/
function getMetadata(json) {
var metadata = json['videoJsonPlayer']['V7T'] + '\n\n' + json['videoJsonPlayer']['VDE'] + '\n\n' + json['videoJsonPlayer']['VTA'];
return metadata;
function getMetadata() {
return playerJson['videoJsonPlayer']['V7T'] + '\n\n' + playerJson['videoJsonPlayer']['VDE'] + '\n\n' + playerJson['videoJsonPlayer']['VTA'];
}

/*
* Parse the content of the JSON file and extract the MP4 videos URLs in the required language.
* @TODO : parse once the .json
*/
function getVideoUrl(json, quality, language) {
if (json) {
function getVideoUrl(quality, language) {

var qualityCode = {
'Low': 'HQ',
'Standard': 'EQ',
'High': 'SQ'
};
// Get videos object
var videos = Object.keys(playerJson["videoJsonPlayer"]["VSR"]);

var videos = Object.keys(json["videoJsonPlayer"]["VSR"]);
var numberOfVideos = videos.length;
console.log(numberOfVideos + " versions of the video have been found.");
// Loop through all videos URLs.
for (var key in videos) {

// Loop through all videos URLs.
for (var key in videos) {

// Check if video format is "HBBTV".
if (json["videoJsonPlayer"]["VSR"][videos[key]]["videoFormat"] === "HBBTV") {
//console.log(json["videoJsonPlayer"]["VSR"][videos[key]]["versionCode"]);
// Check if video format is "HBBTV".
if (playerJson["videoJsonPlayer"]["VSR"][videos[key]]["videoFormat"] === "HBBTV") {

// Get the original version (french dubbed)
//if (json["videoJsonPlayer"]["VSR"][videos[key]]["versionCode"] === "VOF") {
// Check language
if (playerJson["videoJsonPlayer"]["VSR"][videos[key]]["versionCode"] === language) {

// Get the video URL using the requested quality.
if (json["videoJsonPlayer"]["VSR"][videos[key]]["VQU"] === qualityCode[quality]) {
var url = json["videoJsonPlayer"]["VSR"][videos[key]]["url"];
if (playerJson["videoJsonPlayer"]["VSR"][videos[key]]["VQU"] === qualityCode[quality]) {
var url = playerJson["videoJsonPlayer"]["VSR"][videos[key]]["url"];
console.log(qualityCode[quality] + " MP4 URL : " + url);
return (url);
}
//}
}

// otherwise check if video format is a playlist
else if (json["videoJsonPlayer"]["VSR"][videos[key]]["videoFormat"] === "M3U8_HQ") {

// Get playlist URL
var url = json["videoJsonPlayer"]["VSR"][videos[key]]["url"];
console.log("playlist URL : " + url);
return (url);
}
}
return 0;

// Check otherwise if video format is a playlist
/*else if (playerJson["videoJsonPlayer"]["VSR"][videos[key]]["videoFormat"] === "RMP4") {
// Get playlist URL
var url = playerJson["videoJsonPlayer"]["VSR"][videos[key]]["streamer"] + playerJson["videoJsonPlayer"]["VSR"][videos[key]]["url"];
console.log("playlist URL : " + url);
return (url);
}*/
}
return 'video-not-found';
}



/*
* main: script entry
*/
var videoPlayerElement = document.querySelector("div[" + videoPlayerLiveURL + "]");

// If it is not a livestream
if (videoPlayerElement === null) {
bLive = false;
videoPlayerElement = document.querySelector("div[" + videoPlayerURL + "]");
}

decorateVideo(videoPlayerElement);
Loading

0 comments on commit 17890b5

Please sign in to comment.