Plex Freebox

Add a "play on freebox server" button on plex interface.

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

You will need to install an extension such as Tampermonkey to install this script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name        Plex Freebox
// @namespace   Kalmac
// @description Add a "play on freebox server" button on plex interface.
// @include     http://plex.tv/web/app*
// @include     https://plex.tv/web/app*
// @version     1.01
// @grant       GM_xmlhttpRequest
// @require     https://cdn.jsdelivr.net/jquery.cookie/1.4.1/jquery.cookie.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha1.js
// @license     GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// ==/UserScript==
(function () {
    var HOST = 'http://mafreebox.freebox.fr';
    var APP_ID = 'fr.freebox.kalmac';
    var APP_NAME = 'Plex 4 Freebox';
    var APP_VERSION = '0.1';
    var DEVICE_NAME = 'Plex remote';
    var COOKIE_TRACK_ID = 'freebox_plex_track_id';    
    var COOKIE_TOKEN = 'freebox_plex_token';   
    var COOKIE_AIRPLAY_PASS = 'freebox_plex_airplay_pass';
    var STATE_UNINITIALIZED = 0;
    var STATE_INITIALIZED = 1;
    var STATE_UNAUTHORIZED = 2;
    var STATE_PENDING = 3;
    var STATE_AUTHORIZED = 4;
    
    var STATE_ERROR = 10;
    
    var track_id, token, state = STATE_UNINITIALIZED;
    
    function callFreeboxApi(path, callback, params, method, headers) {
        if (typeof(params) != 'object') {
            params = {};
        }
        if (method !== 'POST') {
            method = 'GET';
        }
        if (typeof(headers) != 'object') {
            headers = {};
        }
        
        GM_xmlhttpRequest({
            url: HOST + path,
            data: JSON.stringify(params),
            method: method,
            headers: headers,
            onload:function(response) {
                callback(JSON.parse(response.responseText));
            },
            onerror: function(response) {
                state = STATE_ERROR;
                core();
            }
        });
    }
    
    function init() {
        track_id = $.cookie(COOKIE_TRACK_ID);
        token = $.cookie(COOKIE_TOKEN);
        if (typeof(track_id) != 'undefined' && typeof(token) != 'undefined') {
            state = STATE_PENDING;
        } else {
            state = STATE_UNAUTHORIZED;
        }
    }
    
    function authorize() {
        callFreeboxApi('/api/v3/login/authorize/', function(response) {
            if (response.success) {
                $.cookie(COOKIE_TRACK_ID, response.result.track_id, { expires: 1000, path: '/' });
                $.cookie(COOKIE_TOKEN, response.result.app_token, { expires: 1000, path: '/' });
                state = STATE_INITIALIZED;
                core();
            }
        }, {
            'app_id': APP_ID,
            'app_name': APP_NAME,
            'app_version': APP_VERSION,
            'device_name': DEVICE_NAME }, 'POST');
        
        var airplay_password = prompt("Veuillez autoriser l\'appli sur votre Freebox (fleche de droite) et saisir le mot de passe AirPlay...", "1111");
        $.cookie(COOKIE_AIRPLAY_PASS, airplay_password, { expires: 1000, path: '/' });
        updateAdminButton('Veuillez autoriser l\'appli sur votre Freebox (fleche de droite).', 'refresh', false);
    }
    
    function pending() {
        callFreeboxApi('/api/v3/login/authorize/' + track_id, function(response) {
            if (response.success) {
                switch(response.result.status) {
                    case 'pending':
                        break;
                    case 'granted':
                        state = STATE_AUTHORIZED;
                        break;
                    default:
                        console.log('Freebox returned ' + response.result.status);
                        $.removeCookie(COOKIE_TRACK_ID, { path: '/' });
                        $.removeCookie(COOKIE_TOKEN, { path: '/' });
                        state = STATE_INITIALIZED;
                        break;
                }
            }
        });
    }
    
    
    function insertAdminButton() {
        var result = false;
        if (!$('li#plex-freebox-admin').length) {
            var elt = $('li#primary-player-dropdown');
            if (elt.length == 1) {
                elt.after('<li id="plex-freebox-admin"><a class="settings-btn" href="#" title="Plex 4 Freebox" data-toggle="tooltip" data-original-title="Plex 4 Freebox"><i class="glyphicon refresh"></i></a></li>');
                
                state = STATE_INITIALIZED;
            }
        }
        return result;
    }
    
    function updateAdminButton(text, glyph, callback) {
        var button = $('li#plex-freebox-admin > a');
        var icon = $('li#plex-freebox-admin > a > i');
        
        button.unbind('click');
        icon.attr('class', 'glyphicon');
        
        button.attr('data-original-title', text);
        button.attr('title', text);
        icon.addClass(glyph);
        if (callback) {
            button.click(callback);
        }
    }
    
    function decoratePlayer() {
        
        if ($('button#plex-freebox-play').length == 0) {
            $('div.video-controls-right span#player-quality-dropdown').before('<button id="plex-freebox-play" class="btn-link recommend-btn pull-left" title="Play 4 Freebox"><i class="glyphicon play">F</i></button>');
            $('button#plex-freebox-play').click(function(event) {
                play(event);
                event.preventDefault();
                return false;
            });
        }
    }
    
    function play(event) {
        
        login(function(challenge) {
            session(challenge, function(session_token) {
                
                var pass = $.cookie(COOKIE_AIRPLAY_PASS);
                var video = $('video#html-video').attr('src');
                var params = {
                    'action':'start',
                    'media_type': 'video',
                    'media': video,
                    'password': typeof(pass) == 'undefined'?'1111':pass
                };
                
                callFreeboxApi('/api/v3/airmedia/receivers/Freebox%20Player/', function(response) {
                    if (!response.success) {
                        alert(response.msg);
                    }
                }, params, 'POST', {'X-Fbx-App-Auth': session_token});
            });
        });
        
        
        event.preventDefault();
        return false;
    }
    
    function login(callback) {
        callFreeboxApi('/api/v3/login/', function(response) {
        	callback(response.result.challenge);
        });
    }
    
    function session(challenge, callback) {
        
        var params = {
            'app_id':APP_ID,
            'password': CryptoJS.HmacSHA1(challenge, token).toString(CryptoJS.enc.Hex)
        };
        
        callFreeboxApi('/api/v3/login/session/', function(response) {
        	callback(response.result.session_token);
        }, params, 'POST');
        
    }
    
    function core() {
        var retry = false;
        
        switch(state) {
            case STATE_UNINITIALIZED:
                insertAdminButton();
                retry = 1000;
                break;
            case STATE_INITIALIZED:
                updateAdminButton('Plex 4 Freebox en attente ...', 'refresh', false);
                init();
                retry = 2000;
                break;
            case STATE_UNAUTHORIZED:
                updateAdminButton('Cliquez ici pour authoriser Plex 4 Freebox', 'router', authorize);
                // no retry core until button is clicked.
                break;
            case STATE_PENDING:
                updateAdminButton('Plex 4 Freebox en attente ...', 'refresh', false);
                pending();
                retry = 2000;
                break;
            case STATE_AUTHORIZED:
                updateAdminButton('Plex 4 Freebox', 'ok', false);
                decoratePlayer();
                retry = 2000;
                break;
                
                
            case STATE_ERROR:
                updateAdminButton('Plex 4 Freebox : ERREUR FATALE!', 'remove', false);
                break;
                
        }
        
        console.log('core with state = ' + state);
        
        if (retry) {
            setTimeout(core, retry);
        }
    }
    
    $( window ).load(function() {
        
        core();
    });
    
}) ();