Aller au contenu

Asterisk : Utiliser Le Text To Speech De Google


Terrano

Messages recommandés

Edit 02/10/2015 :

 

TTS Google de nouveau opérationnel, une incompatibilité est apparu avec l'option --url-encode de curl et a été corrigé.

  • Google TTS de nouveau opérationnel
  • Ajout de l'option -o permettant de choisir l'origine prioritaire du son entre Google et VoiceRSS
  • Si le son a déjà été généré, on évite de le générer de nouveau
  • Si le son n'est pas généré correctement par l'origine prioritaire, la deuxième prend le relais

 

Edit 01/10/2015 :

Devant l'impossibilité de continuer à utiliser GoogleTTS à cause d'un Captcha, j'ai remplacé l'API Google par celle de VoiceRSS dans le fichier tts.sh

L'API VoiceRSS est gratuite à certaine conditions :

  • Ne pas dépasser les 350 requêtes par jour
  • Requête limitée a 100 kb
Pour obtenir la Key, rendez-vous ici : http://www.voicerss.org/registration.aspx
Pour le moment, j'ai une voix avec un peu d'écho, mais je vais améliorer ceci car on peut se passer de retraitement audio avec cette API et obtenir directement le bon format wav.
Stay connected for update ;)
 

Edit 01/04/2013 :

Mise à jour du script pour utilisation de Fonctions, de Paramètres, et augmentation des utilisations possibles avec Asterisk et eeDomus

 

Bonjour,

 

Je vais vous détailler comment rendre votre Asterisk encore plus convivial et intelligent que votre femme. :)

 

Tout d’abord, il faut installer ipkg, nous en aurons besoin pour utiliser deux outils : MD5Deep et mpg123

 

Vous pouvez vous référer au guide présent sur cette page :

http://www.vspecialist.co.uk/how-to-install-ipkg-on-a-synology-nas/

 

 

1.IPKG

 

Il faut se connecter en SSH en root sur votre NAS.

Tapez ensuite la commande suivante pour déterminer l’architecture de votre NAS :

cat /proc/cpuinfo | grep model

Pour ma part, j’obtient ceci :

model name      : Intel(R) Atom(TM) CPU D2701   @ 2.13GHz

Rendez-vous a l’adresse suivante pour trouver le paquet qui vous concerne :

http://ipkg.nslu2-linux.org/feeds/optware/

 

Pour mon architecture, c’est :

http://ipkg.nslu2-linux.org/feeds/optware/syno-i686/cross/unstable/syno-i686-bootstrap_1.2-7_i686.xsh

 

Exécutez les commandes suivantes :

cd /tmp
wget http://ipkg.nslu2-linux.org/feeds/optware/syno-i686/cross/unstable/syno-i686-bootstrap_1.2-7_i686.xsh
chmod +x syno-i686-bootstrap_1.2-7_i686.xsh
sh syno-i686-bootstrap_1.2-7_i686.xsh
rm syno-i686-bootstrap_1.2-7_i686.xsh
/opt/bin/ipkg update

Maintenant que ipkg est fonctionnel, procédons à l’installation des prérequis :

/opt/bin/ipkg install mpg123
/opt/bin/ipkg install MD5Deep
  1. Asterisk

 

Toujours sous SSH, pour faire parler asterisk, nous allons créer un dossier qui servira à stocker les scripts :

mkdir /volume1/scripts
mkdir /volume1/scripts/Asterisk
cd /volume1/scripts/Asterisk

Sous ce dossier, nous allons créer un script :

vi tts.sh

Tapez i puis saisissez le texte suivant

#!/bin/sh
# Need IPKG packages
# MD5deep
# mpg123

LANG="fr"
GOOGLEKEY="VotreCléGooglePourAPISpeechToText"
GOOGLETTS="http://translate.google.com/translate_tts?ie=UTF-8&total=1&idx=0&client=t&tl=$LANG"
GOOGLEREC="https://www.google.com/speech-api/v2/recognize?key=$GOOGLEKEY&lang=$LANG&output=json"
VOICERSSKEY="VotreCléVoiceRSSPourAPITextToSpeech"
VOICERSSTTS="http://api.voicerss.org/?key=$VOICERSSKEY&hl=$LANG-$LANG"
ASF="/var/lib/asterisk/sounds/"
AOF="/var/packages/Asterisk/target/var/spool/asterisk/outgoing/"
TMP="/tmp/"

makeweather () {
  WPHP=$1

  VALUE=$(/usr/bin/php -f $WPHP - $ACTION $CONTEXT $COUNTRY 3 3)
  echo "$VALUE"
}

recosound () {
    RECOFILE=$1
    RECOFOLDER=$2
    RECOCONTEXT=$3

    [ ! -d $ASF$RECOFOLDER ] && mkdir $ASF$RECOFOLDER

    case "$RECOCONTEXT" in
        ("initial")
            DATE=$(date +%Y%m%d%H%M%S%n)
            cd $ASF$RECOFOLDER
            mv $ASF$RECOFILE $ASF$RECOFOLDER/$RECOFILE
            curl -X POST --data-binary @"${RECOFILE}" --header 'Content-Type: audio/l16; rate=8000;' "$GOOGLEREC" >> $TMP$DATE.json
            [ -f $ASF$RECOFOLDER$RECOFILE ] && rm $ASF$RECOFOLDER$RECOFILE
            echo $TMP$DATE.json
            ;;
        ("confidence")
            RET=$(cat $RECOFILE | tail -n +2 | python -m 'json.tool' | jq '.result[].alternative[0].confidence')
            echo $RET
            ;;
        ("utterance")
            RET=$(cat $RECOFILE | tail -n +2 | python -m 'json.tool' | jq '.result[].alternative[0].transcript')
            echo $RET
            ;;
        (*)
            exit 1
            ;;
    esac
}

loadfile () {
  LOADFILE=$1
  LOADFOLDER=$2
  LOADFILTER=$3
  LOADORIGIN=$4

  let "INCR=0"
  while read -r line || [ -n "$line" ]
  do 
    VAR=$(echo $line | perl -nle 'm/{([^}]*)/; print $1')
    REP='{'$VAR'}'
    if [ "${VAR/$LOADFILTER}" != "$VAR" ]
    then
      TEXT=$line
      TEXT=${TEXT#*${REP}}
      let "INCR++"
    fi
  done < $LOADFILE
  if [[ $INCR == 1 ]]
  then
    makesound "${TEXT}" $LOADFOLDER $LOADORIGIN
  else
    echo $INCR
  fi
}

makefile () {
  TEXTTOSPEECH=$1
  SOUNDFOLDER=$2
  SOUNDORIGIN=$3

  while read -r line || [ -n "$line" ]
  do 
    TEXT=$line
    VAR=$(echo $TEXT | perl -nle 'm/{([^}]*)/; print $1')
    REP='{'$VAR'}'
    TEXT=${TEXT#*${REP}}
    makesound "${TEXT}" $SOUNDFOLDER $SOUNDORIGIN
  done < $TEXTTOSPEECH
}

makesoundgoogle () {
  TEXTTOSPEECH=$1
  SOUNDFOLDER=$2
  SOUNDFILE=$3
  FIRSTORIGIN=$4
  
  ENCODEDMESSAGE=$(/usr/bin/php -r "echo urlencode(\"$TEXTTOSPEECH\");")
  curl -H "Referer: http://translate.google.com/" -H "User-Agent: stagefright/1.2 (Linux;Android 5.0)" "$GOOGLETTS&q=$ENCODEDMESSAGE"  > $ASF$SOUNDFOLDER/$SOUNDFILE.mp3
  
  /opt/bin/mpg123 -r 8000 -w $ASF$SOUNDFOLDER/$SOUNDFILE.wav $ASF$SOUNDFOLDER/$SOUNDFILE.mp3 >$TMPres.txt 2>&1
  [ -f $ASF$SOUNDFOLDER/$SOUNDFILE.mp3 ] && rm $ASF$SOUNDFOLDER/$SOUNDFILE.mp3
  
  if grep -Fq "Illegal" $TMPres.txt
  then
    if [ "$FIRSTORIGIN" == "GOOGLE" ]
    then
        makesoundvoicerss "$TEXTTOSPEECH" $SOUNDFOLDER $SOUNDFILE
    else
      echo "ERROR"
    fi
  else
    echo "$SOUNDFOLDER/$SOUNDFILE"
  fi
}

makesoundvoicerss () {
  TEXTTOSPEECH=$1
  SOUNDFOLDER=$2
  SOUNDFILE=$3
  FIRSTORIGIN=$4
  
  curl -H "User-Agent: stagefright/1.2 (Linux;Android 5.0)" --data-urlencode "src=$TEXTTOSPEECH" "$VOICERSSTTS" > $ASF$SOUNDFOLDER/$SOUNDFILE.mp3

  /opt/bin/mpg123 -r 8000 -w $ASF$SOUNDFOLDER/$SOUNDFILE.wav $ASF$SOUNDFOLDER/$SOUNDFILE.mp3 >$TMPres.txt 2>&1
  [ -f $ASF$SOUNDFOLDER/$SOUNDFILE.mp3 ] && rm $ASF$SOUNDFOLDER/$SOUNDFILE.mp3
  
  if grep -Fq "Illegal" $TMPres.txt
  then
    if [ "$FIRSTORIGIN" == "VOICE" ]
    then
      makesoundgoogle "$TEXTTOSPEECH" $SOUNDFOLDER $SOUNDFILE
    else
      echo "ERROR"
    fi
  else
    echo "$SOUNDFOLDER/$SOUNDFILE"
  fi
}

makesound () {
  TEXTTOSPEECH=$1
  SOUNDFOLDER=$2
  SOUNDORIGIN=$3
  
  SOUND=$(echo -n $TEXTTOSPEECH | /opt/bin/md5deep)
    
  [ ! -d $ASF$SOUNDFOLDER ] && mkdir $ASF$SOUNDFOLDER
    
  if [ -f $ASF$SOUNDFOLDER/$SOUND.wav ]
  then
    echo "$SOUNDFOLDER/$SOUND"
  else
    case "$SOUNDORIGIN" in
      ("GOOGLE")
        makesoundgoogle "$TEXTTOSPEECH" $SOUNDFOLDER $SOUND $SOUNDORIGIN
        ;;
      ("VOICERSS")
        makesoundvoicerss "$TEXTTOSPEECH" $SOUNDFOLDER $SOUND $SOUNDORIGIN
        ;;
      (*)
        exit 1
        ;;
    esac
  fi
}

makecall () {
  CALLFILE=$1
  CALLFOLDER=$2
  CALLCALLED=$3
  CALLCALLER=$4
  CALLCONTEXT=$5
  CALLORIGIN=$6

  DATE=$(date +%Y%m%d%H%M%S%n)
  touch $TMP$DATE.call
  echo "Channel: $CALLCALLED" >> $TMP$DATE.call
  echo "Callerid: $CALLCALLER" >> $TMP$DATE.call
  echo "MaxRetries: 10" >> $TMP$DATE.call
  echo "RetryTime: 5" >> $TMP$DATE.call
  echo "WaitTime: 20" >> $TMP$DATE.call
  echo "Context: $CALLCONTEXT" >> $TMP$DATE.call
  echo "Extension: $CALLCALLER" >> $TMP$DATE.call

  let "INCR=1"
  while read -r line || [ -n "$line" ]
  do 
    TEXT=$line
    VAR=$(echo $TEXT | perl -nle 'm/{([^}]*)/; print $1')
    REP='{'$VAR'}'
    TEXT=${TEXT#*${REP}}
    echo "Setvar: $VAR="$(makesound "${TEXT}" $CALLFOLDER $CALLORIGIN) >> $TMP$DATE.call
    let "INCR++"
  done < $CALLFILE

  let "INCR--"
  echo "Setvar: file_max=$INCR" >> $TMP$DATE.call

  [ -f $CALLFILE ] && rm $CALLFILE
  mv $TMP$DATE.call $AOF
  echo "$DATE.call"
}

ORIGIN="GOOGLE"

while getopts ":a:t:T:F:f:c:C:s:o:" opt; do
  case $opt in
    a)
      echo "-a was triggered, Parameter: $OPTARG" >&2
      ACTION=$OPTARG
      ;;
    t)
      echo "-t was triggered, Parameter: $OPTARG" >&2
      FILE=$OPTARG
      ;;
    F)
      echo "-F was triggered, Parameter: $OPTARG" >&2
      CALLER=$OPTARG
      ;;
    T)
      echo "-T was triggered, Parameter: $OPTARG" >&2
      CALLED=$OPTARG
      ;;
    c)
      echo "-c was triggered, Parameter: $OPTARG" >&2
      CONTEXT=$OPTARG
      ;;
    C)
      echo "-C was triggered, Parameter: $OPTARG" >&2
      COUNTRY=$OPTARG
      ;;
    f)
      echo "-f was triggered, Parameter: $OPTARG" >&2
      FOLDER=$OPTARG
      ;;
    s)
      echo "-s was triggered, Parameter: $OPTARG" >&2
      SOURCE=$OPTARG
      ;;
    o)
      echo "-o was triggered, Parameter: $OPTARG" >&2
      ORIGIN=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

case "$ACTION" in
    ("CALL")
      echo $(makecall "${FILE}" $FOLDER $CALLED $CALLER $CONTEXT $ORIGIN)
      ;;
    ("SOUND")
      echo $(makesound "${FILE}" $FOLDER $ORIGIN) | tr -d '\n'
      ;;
    ("WEATHER")
      echo $(makeweather $SOURCE $ACTION $CONTEXT $COUNTRY) | tr -d '\n'
      ;;
    ("FILE")
      echo $(makefile "${FILE}" $FOLDER $ORIGIN) | tr -d '\n'
      ;;
    ("LOAD")
      echo $(loadfile "${FILE}" $FOLDER $CALLER $ORIGIN) | tr -d '\n'
      ;;
    ("RECOG")
      echo $(recosound "${FILE}" $FOLDER $CONTEXT) | tr -d '\n'
      ;;
    (*)
      exit 1
      ;;
esac

Tapez echappement et :wq puis entrée.

Ce script nécessite les variables suivantes afin de pouvoir fonctionner :

c :
        Context de l'appel tel que défini dans le fichier /var/packages/Asterisk/target/etc/asterisk/extensions.conf pour Asterisk
        Exemple : alert
        
        Exemple de définition du context dans le fichier asterisk :
        [alert]
        exten => eeDomus,1,Answer()
        exten => eeDomus,n,Hangup()
F :
        Nom ou numéro du poste appelant : eeDomus dans l'exemple alert
T :
        Identifiant SIP du poste à appeler :
        Exemple : SIP/6000
f :
        Sous-dossier où sont stockés les fichiers vocaux générés dans /var/lib/asterisk/sounds
        Exemple : alert
t :
        Emplacement du fichier contenant les variables et phrases à énoncer par asterisk.
        Exemple : /volume1/asterisk/call.txt

        Exemple de contenu du fichier txt :
        {file1}Bonjour à tous.
        {file2}Il n'y a pas de fumée sans feu.
        {file3}Tu comprends ?
        {file4}La maison est en feu !
        {file5}Faut appeler les pompiers.
         
        Chaque phrase ne doit pas dépasser les 100 caractères (limitation de Google TTS)
        La variable entre accolade permet d'utiliser des extensions avec gestion de variable afin par exemple de définir l'ordre des phrases voir de mettre en place un IVR pour demander une action utilisateur

a :
        Action à faire exécuter par le script
        FILE : Générer les sons à partir d'un fichier
        CALL : Exécuter un appel à partir d'un fichier
        SOUND : Générer un son à partir d'une phrase
        WEATHER : Générer un fichier pour la météo
        LOAD : Récupérer le nom du son pour une variable spécifique d'un fichier
        RECOG : Exécuter la reconnaissance vocale sur un fichier son pour obtenir le texte correspondant et le pourcentage de fiabilité

o :
        Non Obligatoire, indique l'origine prioritaire de l'outil de conversion Text to Speech
        GOOGLE : Par défaut, utilise l'API Google pour générer la voix
        VOICERSS : Utilise l'API VoiceRSS pour générer la voix

Nous allons créer une extension dans le fichier d’Asterisk pour tester :

vi /var/packages/Asterisk/target/etc/asterisk/extensions.conf

Tapez i puis saisissez le texte suivant

[alert]
exten => eeDomus,1,Answer()
exten => eeDomus,2,Wait(1)
exten => eeDomus,3,Set(i=1);
exten => eeDomus,n,While($[${i} <= ${file_max}])
exten => eeDomus,n,Playback(${file${i}})
exten => eeDomus,n,Set(i=$[ ${i} + 1 ])
exten => eeDomus,n,EndWhile
exten => eeDomus,n,Wait(1)
exten => eeDomus,n,Hangup()

Tapez echappement et :wq puis entrée.

 

On va créer un fichier test.txt qui contiendra les données à lire par Asterisk :

vi call.txt

Tapez i puis saisissez le texte suivant :

{file1}Bonjour à tous.
{file2}Il n'y a pas de fumée sans feu.
{file3}Tu comprends ?
{file4}La maison est en feu !
{file5}Faut appeler les pompiers.

Tapez echappement et :wq puis entrée.

 

Les données entre crochets correspondent aux variables utilisées dans l’extension sous Asterisk et le texte correspond à ce que l’on veut faire dire. A noter que chaque ligne ne doit pas dépasser les 100 caractères (limite de Google pour son API).

 

  1. Utilisation

 

Pour essayer le script, il suffit de taper ceci :

/volume1/scripts/Asterisk/tts.sh -a CALL -F eeDomus -T SIP/6007 -c alert -f tts -t /volume1/scripts/Asterisk/call.txt

Je considère que votre utilisateur SIP/6007 est déjà existant et bien configure.

Il va alors recevoir un appel du numéro eeDomus et vous pourrez entendre une jolie voix vous dicter votre texte. :D

 

Que fait le script ?

Il va lire le fichier contenant les textes à traduire et va stocker chaque texte dans un fichier MP3 provenant de Google TTS. Ces MP3 sont transformés en WAV par mpg123 et son renommés par MD5Deep.

 

Pourquoi MD5Deep ?

Simplement que chaque texte identique aura la même signature et on limitera le nombre de fichiers stockés.

 

Pourquoi stocker les fichiers ?

La magie de ce système est que si un jour, le service Google ne marche plus, le TTS de VoiceRSS prend le relais.

Dans tous les cas, les fichiers déjà généré resteront opérationnels.

Il suffit juste de jouer chaque scénario à partir des fichiers textes une seule fois.

 

 

A noter que les extensions sous Asterisk permettent de faire, avec les variables, des IVR dynamiques, comme par exemple, déclencher une action de la eeDomus pour qu’elle nous demande quoi faire, et qu’en fonction de la réponse (touche 1 ou 2 du clavier du tel) de déclencher un AGI pour changer un état de la eeDomus.

Mais ça, ça sera un prochain tutorial.

 

 

 

 

P.S. : Si vous possédez comme moi des téléphones SIP Fixe de Type Alcatel Temporis IP600, ils peuvent accueillir jusqu'à 3 comptes SIP et on peut paramétrer les comptes séparément.

J'ai donc configuré un compte SIP propre pour chacun des tels avec l'option de décrochage automatique.

C'est ce compte là qui sera appelée par la eeDomus, pour donner le temps qu'il fait, ou avertir du prochain rendez-vous.

On a même pas besoin de décrocher pour entendre la eeDomus nous parler. B)

Modifié par Terrano
MAJ tts.sh
Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

terrano mp ! ;)

c'est sur c'est mieux car autrement dans le chroot faut reinstallé asterix alors que syno a un beau paquet

autant faire un paquet complementaire pour lui ajouter des fonction ;)

de plus une fois fait comme ca, on peux le remonter au mainteneur du paquet pour une possible integration pourquoi pas ;)

Modifié par Gaetan Cambier
Lien vers le commentaire
Partager sur d’autres sites

  • 5 mois après...

Bonjour et merci pour ce tutoriel très interessant. J'ai suivi ce tuto en détail et j'ai validé que tout marche, sauf la création du ficchier TTS. J'ai lu que google translate avait un peut évoluer qt qu'il fallait rajouter des élements.

J'ai complété la ligne

curl -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)'--data-urlencode "q=$TEXTTOSPEECH" "$GOOGLETTS" > $ASF$SOUNDFOLDER/$SOUND.mp3

 

et rajouter client=t dans GOOGLETTS="http://translate.google.com/translate_tts?ie=utf-8&tl=$LANG&client=t"

 

Lorsque je met en dur pour essais q=bonjour, mon message est bien créer et transformer en wav et ensuite lu par asterisk mais si j'utilise le script comme prévu le fichier créer est vide.

Merci pour votre aide

 

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

Google translate bloque en cas d'utilisation importante (mais qui est en fait une vingtaine d'utilsiation par IP), j'utilise maintenant voicerss qui a l'avantage de coder directement en wav au format utilisable par asterisk (don pas besoin de MPG123)

 

Autre solution fonctionnelle avec un AGI. dans le dial plan     exten=123,1,agi(c.agi,bonjour le monde)

il faut créer un compte gratuit sous voicerss et mettre a jour la clé dans le code AGI

le fichier AGI

#!/usr/bin/php -q
<?php
ob_implicit_flush(true);
set_time_limit(6);
$in = fopen("php://stdin","r");
$stdlog = fopen("volume1/scripts/Asterisk/my_agi.log", "w");
$debug = false;
function read() {
global $in, $debug, $stdlog;
$input = str_replace("\n", "", fgets($in, 4096));
if ($debug) fputs($stdlog, "read: $input\n");
return $input;
}
function errlog($line) {
global $err;
echo "VERBOSE \"$line\"\n";
}
function write($line) {
global $debug, $stdlog;
if ($debug) fputs($stdlog, "write: $line\n");
echo $line."\n";
}
// parse agi headers into array
while ($env=read()) {
$s = split(": ",$env);
$agi[str_replace("agi_","",$s[0])] = trim($s[1]);
if (($env == "") || ($env == "\n")) {
break;
}
}
$tt = $_SERVER['argv'][1];
$soun = exec('echo -n '.$tt.' | /opt/bin/md5deep');
$sound = $soun.".wav";
$fichier = "/volume1/scripts/wav/".$soun;
if (file_exists($fichier)) {
    echo "Le fichier $filename existe.";
    } else {
$tts = '"https://api.voicerss.org?key=xxxxxxxxxxxxxxxsrc='.urlencode($tt).'&hl=fr-fr&c=wav&f=8khz_16bit_mono"';
$cmd= ' curl '.$tts.'  > /volume1/scripts/wav/'.$sound;
exec ($cmd);
}
$file = "/volume1/scripts/wav/".$soun;

echo "VERBOSE \"Here we go!\" 2\n";
read();
errlog("Call from ".$agi['channel']." - Calling phone");
read();


write("EXEC PLAYBACK $file "); // X is the escape digit. since X is not DTMF, no exit is possible
read();

// clean up file handlers etc.
fclose($in);
fclose($stdlog);

exit;
?>

 

Lien vers le commentaire
Partager sur d’autres sites

  • 2 ans après...

Bonjour

 

J'ai essaye de mettre en place ce tutorial . Le téléphone sonne mais pas de son 

Merci de votre aide

voila le résultat quand j'execute le script

pi@raspberrypi:~/scripts/Asterisk $ sudo bash tts.sh -a CALL -F eeDomus -T SIP/6005 -c alert  -t /home/pi/scripts/Asterisk/call.txt -o GOOGLE -f tts
-a was triggered, Parameter: CALL
-F was triggered, Parameter: eeDomus
-T was triggered, Parameter: SIP/6005
-c was triggered, Parameter: alert
-t was triggered, Parameter: /home/pi/scripts/Asterisk/call.txt
-o was triggered, Parameter: GOOGLE
-f was triggered, Parameter: tts
20171119114322.call

 

Lien vers le commentaire
Partager sur d’autres sites

Rejoindre la conversation

Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.