
Partager:
Aaron était défenseur des développeurs chez Nexmo. Ingénieur logiciel chevronné et artiste numérique en herbe, Aaron est souvent amené à créer des choses avec du code ou de l'électronique, parfois les deux. On peut généralement savoir qu'il travaille sur quelque chose de nouveau grâce à l'odeur de composants brûlés qui flotte dans l'air.
Streamer Last Christmas en un appel téléphonique avec Python
Temps de lecture : 6 minutes
Noël est une période coûteuse, mais je peux vous aider à économiser une fortune sur les cadeaux en m'assurant que personne ne vous parle le jour de Noël en les envoyant tous à Whamhalla !
Chaque année, mes amis et moi participons à la compétition Whamageddonles règles sont simples :
L'objectif est de passer le plus de temps possible sans entendre le classique de Noël de WHAM, "Last Christmas".
Le jeu commence le 1er décembre et se termine le 24 décembre à minuit.
Seule la version originale s'applique
Vous êtes exclu dès que vous reconnaissez la chanson.
Quiconque a déjà mis le pied dehors ou allumé la radio pendant la période de Noël peut attester qu'il est difficile d'éviter "Last Christmas". À partir d'une seconde après minuit le 1er décembre, c'est comme si tous les magasins la répétaient. La plupart des gens jouent le jeu de manière défensive, en évitant les endroits où la chanson est la plus susceptible d'être diffusée. Mais nous ne sommes pas comme les autres, nous allons passer à l'attaque.
Les principes de la guerre
Santa driving a tank
Saisir, conserver et exploiter l'initiative. L'action offensive est le moyen le plus efficace et le plus décisif pour atteindre un objectif commun clairement défini. Les opérations offensives sont les moyens par lesquels une force militaire saisit et conserve l'initiative tout en maintenant sa liberté d'action et en obtenant des résultats décisifs. Cela est fondamentalement vrai à tous les niveaux de la guerre.
Nous pouvons gagner le Whamageddon soit en évitant la chanson jusqu'au 25 décembre, soit en faisant en sorte que tous nos amis l'entendent avant nous, de sorte que nous soyons la dernière personne à rester debout. Nous devons trouver un moyen de leur faire entendre la chanson sans nous y exposer en même temps. Pas d'incident de tir ami, s'il vous plaît !
Le vecteur d'attaque évident est de leur envoyer un lien Youtube de la chanson, mais le Rickrolling a rendu tout le monde trop méfiant pour cliquer sur des liens Youtube inconnus. Nous avons besoin d'un canal qu'ils ne soupçonneraient pas.
Frapper l'ennemi à un moment, en un lieu ou d'une manière à laquelle il n'est pas préparé. La surprise peut modifier de manière décisive l'équilibre de la puissance de combat. En recherchant la surprise, les forces peuvent obtenir des succès bien disproportionnés par rapport à l'effort déployé. La surprise peut porter sur le rythme, la taille de la force, la direction ou l'emplacement de l'effort principal et le moment choisi. La tromperie peut augmenter la probabilité d'obtenir une surprise.
Streaming audio lors d'un appel téléphonique
Autant que Dernier Noël imprègne tout à cette époque de l'année, je ne pense pas avoir déjà répondu au téléphone et l'avoir entendu. Personne ne soupçonnerait Wham ! d'appeler.
Nous allons utiliser deux API pour y parvenir, l'API Voice de Nexmo Nexmo pour passer l'appel sortant et diffuser le mp3 à nos amis, et l'API Spotify Spotify pour fournir un court extrait de Last Christmas. Les deux API ont des wrappers Python pour les rendre plus faciles à utiliser, et nous allons envelopper le tout dans un CLI sympa pour que nous puissions éliminer nos amis avec une seule commande. Lorsque nous aurons terminé, cela ressemblera à ceci :
Screencast of our Voice Application CL
Pour commencer
Vous aurez besoin d'un peu d'expérience avec Python pour faire fonctionner cette application, et au moins la version 3.6 car nous utilisons des chaînes f (parce qu'elles sont géniales) ainsi que quelques autres choses :
Le code code source de GitHub
Un Account Spotify et votre propre application Spotify. Notez votre identifiant client et votre secret car vous devrez les ajouter à votre compte Spotify.
.envplus tardNgrok; si vous n'êtes pas sûr de savoir à quoi cela sert, vous devriez lire d'abord notre tutoriel ngrok
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Configuration
Il y a un fichier d'exemple .env.example dans le référentiel, renommez-le en .env et commencez à remplir les valeurs. Pour les valeurs NEXMO_APPLICATION_ID et NEXMO_PRIVATE_KEY vous devez créer une nouvelle Applications Nexmovous pouvez le faire via le tableau de bord, n'oubliez pas de sauvegarder l'application générée dans un endroit sûr et définissez la valeur de l'application dans le tableau de bord. private.key généré dans un endroit sûr et de définir la valeur de NEXMO_PRIVATE_KEY à l'emplacement de votre clé.
Le script a également plusieurs dépendances ; je recommande de les de les installer via pipenvmais vous pouvez utiliser un autre gestionnaire de dépendances Python si vous préférez.
pipenv install
Une fois que vous avez installé vos dépendances, assurez-vous d'avoir activé votre environnement virtuel (ce serait pipenv shell si vous utilisez pipenv) et que votre shell contient les variables environnementales du fichier .env dans votre shell. Enfin, nous devons être en mesure d'exposer notre script à l'internet public afin que les webhooks Nexmo puissent l'atteindre. Pour cela nous allons utiliser ngrok, ne vous souciez pas de configurer votre tunnel, assurez-vous simplement que ngrok est lancé.
ngrok http 80
Vous êtes maintenant prêt à exécuter le script.
python pvpwham.py NUMBER
Il existe quelques options supplémentaires que vous pouvez spécifier. python pvpwham.py --help pour plus d'informations.
Examinons plus en détail certaines des parties les plus intéressantes du code.
Validation du Numbers
Il est essentiel de s'assurer que nous disposons d'un numéro de téléphone valide à cibler, car rien d'autre ne fonctionne sans lui. Nous passons donc un peu de temps à valider le numéro et à le convertir dans le bon format. Cependant, les gens écrivent les numéros de téléphone de manière très bizarre et merveilleuse. Si nous ne pouvons pas le valider, nous les invitons à s'en tenir à E.164, et nous leur fournissons même un lien vers plus d'informations avant qu'ils ne soient invités à réessayer.
while e164_number == False:
insight_response = nexmo_client.get_basic_number_insight(number=number)
if insight_response["status"] == 3:
insight_response = nexmo_client.get_basic_number_insight(
number=number, country=country
)
if insight_response["status"] != 0:
click.clear()
click.secho(intro, bg="magenta", fg="green")
click.secho(
f"{number} does not appear to be a valid telephone number",
bg="magenta",
fg="white",
)
click.secho(
"It might work if you enter it in the E.164 format",
bg="magenta",
fg="white",
)
if click.confirm(wtf_e164_message):
click.launch(
"https://developer.nexmo.com/concepts/guides/glossary#e-164-format"
)
if click.confirm(try_number_again_message):
number = click.prompt("Ok, give it to me in E.164 this time")
else:
raise click.BadArgumentUsage(
click.style(
f"{number} does not appear to be a valid number. Try entering it in the E.164 format",
bg="red",
fg="white",
bold=True,
)
)
else:
e164_number = insight_response["international_format_number"] Trouver un MP3 de la chanson
Nous n'avons pas besoin de la chanson entière ; quelques secondes devraient suffire à envoyer quelqu'un à Whamhalla. L'aperçu de 30 secondes de Spotify est idéal. Le script utilise par défaut "Last Christmas", mais vous pouvez le configurer en utilisant l'option --track option.
spotify_client_credentials_manager = SpotifyClientCredentials(
client_id=os.environ["SPOTIFY_CLIENT_ID"],
client_secret=os.environ["SPOTIFY_CLIENT_SECRET"],
)
spotify_client = spotipy.Spotify(
client_credentials_manager=spotify_client_credentials_manager
)
tracks = spotify_client.search(track, limit=1, type="track")
if len(tracks["tracks"]["items"]) == 0:
raise click.BadOptionUsage(
track,
click.style(f"Can't find track: {track}", bg="red", fg="white", bold=True),
)
track = tracks["tracks"]["items"][0] Notre serveur
Nous avons plusieurs webhooks Nexmo différents à gérer.
URL de réponse - elle est appelée lorsque quelqu'un répond à l'appel et contient une liste d'actions à exécuter par Nexmo. Dans notre cas, nous allons dire à Nexmo d'enregistrer l'appel, d'utiliser la synthèse vocale pour lire un court avertissement à l'utilisateur (cette fonction est désactivée par défaut mais peut être activée à l'aide de l'option --delay )et enfin de diffuser notre aperçu Spotify dans l'appel.
@cherrypy.tools.json_out()
def index(self, **params):
ncco_file = [
{
"action": "record",
"eventUrl": [f"{self.ngrok_tunnel['public_url']}/recording"],
}
]
if delay == "short":
ncco_file.append({"action": "talk", "text": "whamageddon"})
elif delay == "long":
ncco_file.append(
{
"action": "talk",
"text": "hang up your phone or prepare to enter Whamhalla",
}
)
ncco_file.append(
{"action": "stream", "streamUrl": [f"{self.preview_url}?t=mp3"]}
)
return ncco_fileURL d'enregistrement - Une fois que l'utilisateur a raccroché le téléphone et que l'appel est terminé, Nexmo envoie à ce webhook les détails de l'enregistrement afin que nous puissions télécharger le mp3 et écouter le désarroi de notre ami lorsqu'il réalise ce qui s'est passé.
NB : Nous enregistrons tout, y compris l'audio que nous avons diffusé dans l'appel. Vous ne voulez pas non plus vous envoyer accidentellement à Whamhalla. Vous pouvez modifier le script pour utiliser enregistrements fractionnés pour éviter cela.
@cherrypy.expose
def fetch_recording():
data = cherrypy.request.json
click.secho("## Fetching Call Recording", bg="green", fg="black", bold=True)
recording_response = nexmo_client.get_recording(data["recording_url"])
recordingfile = f"/tmp/{data['recording_uuid']}.mp3"
os.makedirs(os.path.dirname(recordingfile), exist_ok=True)
with open(recordingfile, "wb") as f:
f.write(recording_response)
click.secho("## Call Recording Saved", bg="green", fg="black", bold=True)
if click.confirm(
click.style(
"## Listen to your friend's anguish now?", bg="magenta", fg="white"
)
):
click.launch(recordingfile)URL des événements - Cette URL est purement informative. Le script met à jour le terminal avec le dernier statut qu'il reçoit via le webhook des événements.
@cherrypy.expose
@cherrypy.tools.json_in()
def events(self):
data = cherrypy.request.json
click.secho(
f"## Status: {data['status']}", bg="blue", fg="white", bold=True
)
return "OK" Entretien ménager
Lorsque l'appel est terminé, nous disposons d'un on_end_request qui fait un peu de rangement. Nous fermons notre serveur Cherrypy et tuons notre tunnel Ngrok.
def quit_cherry():
cherrypy.engine.exit()
click.secho("## Exiting NCCO Server", bg="blue", fg="white", bold=True)
requests.delete("http://localhost:4040/api/tunnels/pvpwham")
click.secho("## Closing tunnel", bg="blue", fg="white", bold=True) Quelques autres commandes amusantes
Vous pouvez trouver des choses assez étranges sur Spotify si vous êtes assez créatif.
python pvpwham.py NUMBER --track='Rick Astley Never gonna give you up'
python pvpwham.py NUMBER --track='Sound Effects Animals Chimps, Apes'
python pvpwham.py NUMBER --track='Halloween Sound effects machine ghostly whispers'
Quelle est la prochaine étape ?
Diriger chaque opération militaire vers un objectif clairement défini, décisif et réalisable. Le but militaire ultime de la guerre est la destruction de la capacité et de la volonté de combattre de l'ennemi.
Même si vous ne parvenez pas à éliminer tous vos amis, il faut espérer que les survivants seront tellement angoissés chaque fois que le téléphone sonnera qu'ils se rendront. Ils iront s'asseoir dans leur centre commercial pour attendre l'inévitable.
Puis, après avoir écrasé l'opposition, jetez un coup d'œil à certaines utilisations moins militantes de l'API Voice :
Mise en place d'un système de Voice Broadcast pour les notifications critiques
Utilisation de l'IVR et de la Voice API pour créer un service d'assistance téléphonique aux familles
Déclencher des appels Voice à partir de wearables (pour échapper à un mauvais rendez-vous)
Création d'un service d'assistance téléphonique pour le code de conduite
Partager:
Aaron était défenseur des développeurs chez Nexmo. Ingénieur logiciel chevronné et artiste numérique en herbe, Aaron est souvent amené à créer des choses avec du code ou de l'électronique, parfois les deux. On peut généralement savoir qu'il travaille sur quelque chose de nouveau grâce à l'odeur de composants brûlés qui flotte dans l'air.
