Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 15/07/2013, à 20:11

Totor

[Freebox Revolution] AirMedia en bash

Bonjour,

Avec l'arrivé de la mise à jour "Freebox OS", et surtout de son API... J'ai tenté d'écrire un petit script pour envoyer des fichiers multimédia via AirPlay sur la freebox. Chose que l'ont pouvait difficilement faire sous linux hmm

Bref, en fait, il y a 2 scripts.
Le 1er, sert à obtenir un token pour le script qui va faire du AirMedia (à utiliser qu'une seule fois), le 2nd est l'application en elle-même.

1er script:

#!/bin/bash

myHelp()
{
	[ $# -ne 0 ] && echo >&2 -e  "$@"
	myName=${FUNCNAME[$((${#FUNCNAME[@]}-1))]}
	cat >&2 <<EOF
	Usage : 
		${myName} -i app_id -n app_name -v app_version -d device_version
		${myName} -h

	Options:
	-i : ID de l'application
	-n : Nom de l'application
	-v : Version de l'application
	-d : Nom du device autorisé
	-h : Affiche cette aide
EOF
	[ $# -ne 0 ] && return 1
	return 0
}

while getopts :i:n:v:d:h option
do
	case "${option}" in
		h) myHelp
			exit 0;;
		:) myHelp "Argument manquant pour l'option '-${OPTARG}'"
			exit 1;;
		"?") myHelp "Option non valide : ${OPTARG}."
			exit 1;;
		i) app_id="${OPTARG}";;
		n) app_name="${OPTARG}";;	
		v) app_version="${OPTARG}";;	
		d) device_name="${OPTARG}";;	
	esac
done

[[ ${app_id} ]] || { myHelp "ID de l'application manquant !"; exit 1; }
[[ ${app_name} ]] || { myHelp "Nom de l'application manquant !"; exit 1; }
[[ ${app_version} ]] || { myHelp "Version de l'application manquante !"; exit 1; }
[[ ${device_name} ]] || { myHelp "Nom du device manquant !"; exit 1; }

chars=( '|' '/' '-' '\')

# demande d'autorisation de l\'application avec récupération du token :
IFS=$'"' read -a values < <(curl -v http://mafreebox.free.fr/api/v1/login/authorize/ -d '{"app_id":"'${app_id}'", "app_name":"'${app_name}'", "app_version":"'${app_version}'" , "device_name":"'${device_name}'"}' 2>/dev/null)

[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la demande d\'autorisation !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}

app_token="${values[7]//\\}"
app_token="${app_token//$'\r'}"
app_track="${values[10]//[:\}]}"
app_track="${app_track//$'\r'}"

printf "En attente d'authorisation - à valider sur l'écran du freebox Server :  "
i=0
while reponse=$(curl http://mafreebox.free.fr/api/v1/login/authorize/${app_track} 2>/dev/null) && [[ ${reponse} == *pending* ]]
do
	printf "\b%s" "${chars[i]}"
	sleep 1
	((i++)) && (( i == ${#chars[@]} )) && i=0
done
printf "\b\n"


case ${reponse} in	
	*timeout*)
		echo "Réponse trop tardive (time out) !" >&2; exit 2;;
	*granted*)
		printf "APP_ID=%s\nAPP_TOKEN=%s\nTRACK_ID=%s\n" "${app_id}" "${app_token}" "${app_track}";;
	*denied*)
		echo "Autorisation refusée !" >&2; exit 2;;
	*unknown*)
		echo "Erreur de token !" >&2; exit 2;;
esac
exit

ex : script -i fr.freebox.monAppli -n "Appli AirMedia" -v "1.0.0" -d $(hostname)

2nd Script :

#!/bin/bash

myHelp()
{
	[ $# -ne 0 ] && echo >&2 -e  "$@"
	myName=${FUNCNAME[$((${#FUNCNAME[@]}-1))]}
	cat >&2 <<EOF
	Usage : 
		${myName} -i app_id -t app_token -f fichier
		${myName} -h

	Options:
	-i : ID de l'application
	-t : Token d'authentification
	-f : Fichier audio/vidéo à jouer
	-h : Affiche cette aide
EOF
	[ $# -ne 0 ] && return 1
	return 0
}

while getopts :i:t:f:h option
do
	case "${option}" in
		h) myHelp
			exit 0;;
		:) myHelp "Argument manquant pour l'option '-${OPTARG}'"
			exit 1;;
		"?") myHelp "Option non valide : ${OPTARG}."
			exit 1;;
		i) app_id="${OPTARG}";;
		t) app_token="${OPTARG}";;	
		f) fichier="${OPTARG}";;
	esac
done

[[ ${app_id} ]] || { myHelp "ID de l'application manquant !"; exit 1; }
[[ ${app_token} ]] || { myHelp "Token de l'application manquant !"; exit 1; }
[[ ${fichier} ]] || { myHelp "Nom de fichier audio/vidéo manquant !"; exit 1; }

# demande du challenge :
IFS='"' read -a values < <(curl http://mafreebox.free.fr/api/v1/login/ 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la demande de challenge !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
CHALLENGE="${values[9]//\\}"

# construction du passord
read foo PASSWORD < <(printf "${CHALLENGE}" |openssl dgst -sha1 -hmac ${app_token})

# ouverture de la session
IFS='"' read -a values < <(curl http://mafreebox.free.fr/api/v1/login/session/ -d '{"app_id":"'${app_id}'", "password":"'${PASSWORD}'"}' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la demande de session !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
SESSION_TOKEN="${values[5]}"

# encodage du nom du fichier
FILE_PATH_ENCODED=$(base64 <(printf "%s" "${fichier}"))

# vérification de la connaissance du fichier
values=$(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v1/fs/ls/${FILE_PATH_ENCODED} 2>/dev/null)
[[ "${values}" == *success\ :false* ]] && {	
	cat >&2 <<EOF
Fichier inconnu du freebox Server !
Retour de la demande : ${values}
EOF
	exit 2
}

# création d'un partage pour obtention URL
IFS='"' read -a values < <(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v1/share_link/ -d '{ "path":"'${FILE_PATH_ENCODED}'","expire":"0","fullurl":""}' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la création du partage !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
FILE_TOKEN="${values[11]//\\}"
FILE_URL="${values[21]}"

values=$(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v1/airmedia/receivers/Freebox%20Player/ -d '{ "action": "start",   "media_type": "video", "media": "'${FILE_URL}'", "password": "" }' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la lecture du fichier ${fichier} !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}

echo "Envoi de ${fichier} réussi !"
echo "Pour suppression partage : curl -X DELETE -H \"X-Fbx-App-Auth: ${SESSION_TOKEN}\" http://mafreebox.free.fr/api/v1/share_link/${FILE_TOKEN}"

exit

ex : script -i fr.freebox.monAppli -t "<valeur retournée par le 1er script>" -f <fichier reconnu par le freebox server>

Pré-requis :
- curl
- base64

Note : L'API attend une URL "HTTP" comme nom de fichier, c'est pourquoi :
- il faut autoriser l'accès HTTP extérieur au freebox serveur
- ce script créé un partage pour chaque fichier envoyé. une instruction pour supprimer ce partage est retournée mais cette dernière n'est valable que le temps de la session d'authentification. Le partage peut également être supprimé via l'interface d'administration du freebox serveur (Gestion des partages dans le gestionnaire de fichiers)

Le fichier doit être connu du freebox serveur (donc fichier sur le disque dur ou sur un média USB branché et activé)
Ex : /Disque dur/Enregistrements/UneChanson.mp3

A améliorer :
L'API freebox OS ne permet pas à ce jour de vérifier si un média est toujours en court de lecture ou pas... Si un jour cela est réalisable, la suppression du partage sera géré intrinsèquement.

Dernière modification par Totor (Le 16/07/2013, à 08:08)


-- Lucid Lynx --

Hors ligne

#2 Le 23/07/2013, à 19:52

Southwell

Re : [Freebox Revolution] AirMedia en bash

Salut Totor

je m’intéresse aussi à cette API, j'ai commencé à faire une petite lib si ça t’intéresse :
https://github.com/cart0uche/pyfree

pour l'instant ça gère l'authentification, login, la liste des contacts, la liste des appels, bientôt la liste des appels manqués ..


"C'est à Madame Justice que je vais dédier ce concerto, en l'honneur des trop longues vacances qu'elle semble s'être accordée, elle qui est censée défendre les enfants des pauvres et punir les malfaiteurs et à la gloire des imposteurs qu'elle nourrit en son sein."

Hors ligne

#3 Le 30/08/2013, à 00:06

Titanothere

Re : [Freebox Revolution] AirMedia en bash

Bonjour,

Pas mal, mais visiblement cela ne fonctionne pas pour l'audio sur le FBB Server...
Pour l'installation : hostname : nom ou adresse IP de la machine cliente (qui va faire la demande)

Hors ligne

#4 Le 31/08/2013, à 14:14

Totor

Re : [Freebox Revolution] AirMedia en bash

Pour l'audio, ça "marchotte" chez moi ...
La lecture est cyclique : la piste commence a être lue puis redémarre au début pour une lecture un peu plus longue et ce indéfiniment.
Je pense que cela vient de l'API qui n'est pas encore au point.
En effet, elle ne semble pas prendre en compte l'audio car la doc ne mentionne que des médias de type photo et vidéo.

Sinon, j'avais fait évolué le script depuis, pour prendre en compte la version de l'API et pour ajouter un nouveau paramètre afin de choisir le player sur lequel on souhaite envoyer le média (à défaut, il s'agit du Freebox player) :

#!/bin/bash
# url api : http://dev.freebox.fr/sdk/os/airmedia/
v_api="1"

myHelp()
{
	[ $# -ne 0 ] && echo >&2 -e  "$@"
	myName=${FUNCNAME[$((${#FUNCNAME[@]}-1))]}
	cat >&2 <<EOF
	Usage : 
		${myName} -i app_id -t app_token -f fichier [ -p player ]
		${myName} -h

	Options:
	-i : ID de l'application
	-t : Token d'authentification
	-f : Fichier audio/vidéo à jouer
	-p : Player sur lequel doit être envoyé le contenu multimédia
	-h : Affiche cette aide
EOF
	[ $# -ne 0 ] && return 1
	return 0
}

rawurlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     cas e "$c" in
        [-_.~a-zA-Z0-9] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  echo "${encoded}"
}

player="Freebox Player"
while getopts :i:t:f:p:h option
do
	case "${option}" in
		h) myHelp
			exit 0;;
		:) myHelp "Argument manquant pour l'option '-${OPTARG}'"
			exit 1;;
		"?") myHelp "Option non valide : ${OPTARG}."
			exit 1;;
		i) app_id="${OPTARG}";;
		t) app_token="${OPTARG}";;	
		f) fichier="${OPTARG}";;
		p) player="${OPTARG}";;
	esac
done

player="$(rawurlencode "${player}")"
[[ ${app_id} ]] || { myHelp "ID de l'application manquant !"; exit 1; }
[[ ${app_token} ]] || { myHelp "Token de l'application manquant !"; exit 1; }
[[ ${fichier} ]] || { myHelp "Nom de fichier audio/vidéo manquant !"; exit 1; }

# demande du challenge :
IFS='"' read -a values < <(curl http://mafreebox.free.fr/api/v${v_api}/login/ 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la demande de challenge !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
CHALLENGE="${values[9]//\\}"

# construction du passord
read foo PASSWORD < <(printf "${CHALLENGE}" |openssl dgst -sha1 -hmac ${app_token})

# ouverture de la session
IFS='"' read -a values < <(curl http://mafreebox.free.fr/api/v${v_api}/login/session/ -d '{"app_id":"'${app_id}'", "password":"'${PASSWORD}'"}' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la demande de session !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
SESSION_TOKEN="${values[5]}"

# encodage du nom du fichier
FILE_PATH_ENCODED=$(base64 <(printf "%s" "${fichier}"))

# vérification de la connaissance du fichier
values=$(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v${v_api}/fs/ls/${FILE_PATH_ENCODED} 2>/dev/null)
[[ "${values}" == *success\ :false* ]] && {	
	cat >&2 <<EOF
Fichier inconnu du freebox Server !
Retour de la demande : ${values}
EOF
	exit 2
}

# création d'un partage pour obtention URL
IFS='"' read -a values < <(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v${v_api}/share_link/ -d '{ "path":"'${FILE_PATH_ENCODED}'","expire":"0","fullurl":""}' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la création du partage !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}
FILE_TOKEN="${values[11]//\\}"
FILE_URL="${values[21]}"

values=$(curl -H "X-Fbx-App-Auth: ${SESSION_TOKEN}" http://mafreebox.free.fr/api/v${v_api}/airmedia/receivers/${player}/ -d '{ "action": "start",   "media_type": "video", "media": "'${FILE_URL}'", "password": "" }' 2>/dev/null)
[[ "${values[@]}" == *success\ :false* ]] && {
	retour=$(printf '%s"' "${values[@]}")
	cat >&2 <<EOF
Erreur lors de la lecture du fichier ${fichier} !
Retour de la demande : ${retour%$'"'}
EOF
	exit 2
}

echo "Envoi de ${fichier} réussi !"
echo "Pour suppression partage : curl -X DELETE -H \"X-Fbx-App-Auth: ${SESSION_TOKEN}\" http://mafreebox.free.fr/api/v${v_api}/share_link/${FILE_TOKEN}"

exit

-- Lucid Lynx --

Hors ligne

#5 Le 02/09/2013, à 13:22

Titanothere

Re : [Freebox Revolution] AirMedia en bash

Merci Totor pour cette modification !
Ca devient très intéressant smile.
Faut-il conclure de ton dernier message que tu arrives à obtenir du son sur le FB-Server ?

La doc dit aussi :
{
   success: true,
   result: [
      {
         capabilities: {
            photo: true,
            screen: false,
            audio: true,
            video: true
         },
         name: "Freebox Player",
         password_protected: true
      },
      {
         capabilities: {
            photo: false,
            screen: false,
           audio: true,
            video: false
         },
         name: "Freebox Server",
         password_protected: false
      }
   ]
}

Hors ligne

#6 Le 08/09/2013, à 17:05

Totor

Re : [Freebox Revolution] AirMedia en bash

Attention, les informations que tu as sont les capacités du player ...
il ne s'agit en aucun cas de ce que l'API est capable d'envoyer !


-- Lucid Lynx --

Hors ligne