Pony.fm/app/Http/Controllers/Api/Web/AlexaController.php

309 lines
9 KiB
PHP
Raw Normal View History

2016-09-30 03:36:44 +02:00
<?php
2021-02-14 03:34:58 +01:00
namespace App\Http\Controllers\Api\Web;
2016-09-30 03:36:44 +02:00
2021-02-14 03:34:58 +01:00
use App\Http\Controllers\Controller;
use App\Models\AlexaSession;
use App\Models\Track;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Session\Store;
2016-09-30 03:36:44 +02:00
use Psr\Log\LoggerInterface;
class AlexaController extends Controller
{
2016-09-30 23:21:17 +02:00
/**
* @var AlexaSession
*/
protected $session;
2016-09-30 03:36:44 +02:00
public function handle(Request $request, LoggerInterface $logger)
{
$type = $request->json('request.type');
$intent = $request->json('request.intent.name');
2016-09-30 23:21:17 +02:00
$sessId = $request->json('session.user.userId', $request->json('context.System.user.userId'));
if ($sessId) {
$this->session = AlexaSession::find($sessId);
if (! $this->session) {
2016-09-30 23:21:17 +02:00
$this->session = new AlexaSession();
$this->session->id = $sessId;
}
}
2016-09-30 03:36:44 +02:00
$logger->debug('Incoming Alexa Request', [
'type' => $type,
'intent' => $intent,
2016-09-30 03:36:44 +02:00
]);
2016-09-30 23:21:17 +02:00
$logger->debug('Incoming Alexa Full Request', [
'json' => json_encode($request->json()->all(), JSON_PRETTY_PRINT),
2016-09-30 23:21:17 +02:00
]);
/** @var JsonResponse $response */
$response = $this->handleType($request);
if ($response instanceof JsonResponse) {
$logger->debug('Alexa Response', ['json' => $response->getContent()]);
}
if ($this->session) {
$this->session->save();
}
return $response;
}
public function handleType(Request $request)
{
$type = $request->json('request.type');
2016-09-30 03:36:44 +02:00
switch ($type) {
case 'LaunchRequest':
return $this->launch();
case 'PlayAudio':
2016-09-30 03:36:44 +02:00
return $this->play();
2016-09-30 23:21:17 +02:00
case 'AudioPlayer.PlaybackNearlyFinished':
return $this->queueNextTrack();
2016-09-30 03:36:44 +02:00
case 'IntentRequest':
return $this->handleIntent($request);
default:
return response()->make('', 204);
}
}
public function handleIntent(Request $request)
{
$intent = $request->json('request.intent.name');
switch ($intent) {
case 'AMAZON.PauseIntent':
return $this->stop();
2016-09-30 23:21:17 +02:00
case 'PlayAudio':
2016-09-30 03:36:44 +02:00
case 'AMAZON.ResumeIntent':
return $this->play();
2016-09-30 23:21:17 +02:00
case 'AMAZON.NextIntent':
return $this->queueNextTrack(true);
case 'AMAZON.PreviousIntent':
return $this->previousTrack();
2016-09-30 03:36:44 +02:00
case 'Author':
return $this->author();
default:
return response()->make('', 204);
}
}
public function launch()
{
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'outputSpeech' => [
'type' => 'SSML',
'ssml' => "<speak>If you want to play music, say 'Alexa, ask pony fm to play'</speak>",
2016-09-30 03:36:44 +02:00
],
'shouldEndSession' => true,
],
];
}
public function unknown()
{
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'outputSpeech' => [
'type' => 'SSML',
'ssml' => "<speak>Sorry, I don't recognise that command.</speak>",
2016-09-30 03:36:44 +02:00
],
'shouldEndSession' => true,
],
];
}
public function author()
{
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'outputSpeech' => [
'type' => 'SSML',
'ssml' => '
2016-09-30 03:36:44 +02:00
<speak>
Pony.fm was built by Pixel Wavelength for Viola to keep all her music in one place.
</speak>
',
2016-09-30 03:36:44 +02:00
],
'shouldEndSession' => true,
],
];
}
public function play()
{
2016-09-30 23:21:17 +02:00
$track = array_first(Track::popular(1));
$this->session->put('current_position', 1);
$this->session->put('track_id', $track['id']);
2016-09-30 03:36:44 +02:00
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'directives' => [
[
'type' => 'AudioPlayer.Play',
'playBehavior' => 'REPLACE_ALL',
'audioItem' => [
'stream' => [
2016-09-30 23:21:17 +02:00
'url' => $track['streams']['mp3'],
'token' => '1',
2016-09-30 03:36:44 +02:00
'offsetInMilliseconds' => 0,
],
],
],
],
'shouldEndSession' => true,
],
];
}
2016-09-30 23:21:17 +02:00
public function queueNextTrack($replace = false)
2016-09-30 03:36:44 +02:00
{
2016-09-30 23:21:17 +02:00
$trackId = $this->session->get('track_id');
$position = $this->session->get('current_position', 1);
$trackHistory = $this->session->get('track_history', []);
$playlist = $this->session->get('playlist', []);
$playlistNum = $this->session->get('playlist-num', 1);
if (count($playlist) === 0) {
$playlist = Track::popular(30);
$this->session->put('playlist', $playlist);
}
if ($position === 30) {
$playlist = Track::popular(30, false, $playlistNum * 30);
$position = 1;
$playlistNum++;
}
if (count($playlist) === 0) {
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 23:21:17 +02:00
'response' => [
'outputSpeech' => [
'type' => 'SSML',
'ssml' => "
2016-09-30 23:21:17 +02:00
<speak>
You've reached the end of the popular tracks today. To start from the beginning say 'Alexa, ask pony fm to play'
</speak>
", ],
2016-09-30 23:21:17 +02:00
'directives' => [
[
'type' => 'AudioPlayer.Stop',
2016-09-30 23:21:17 +02:00
],
],
'shouldEndSession' => true,
],
];
}
$track = $playlist[$position - 1];
2016-09-30 23:21:17 +02:00
$trackHistory[] = $trackId;
$this->session->put('current_position', $position + 1);
$this->session->put('track_id', $track['id']);
$this->session->put('track_history', $trackHistory);
$this->session->put('playlist-num', $playlistNum);
$stream = [
'url' => $track['streams']['mp3'],
'token' => $track['id'],
'offsetInMilliseconds' => 0,
];
if (! $replace) {
2016-09-30 23:21:17 +02:00
$stream['expectedPreviousToken'] = $trackId;
}
2016-09-30 03:36:44 +02:00
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'directives' => [
[
'type' => 'AudioPlayer.Play',
2016-09-30 23:21:17 +02:00
'playBehavior' => $replace ? 'REPLACE_ALL' : 'ENQUEUE',
2016-09-30 03:36:44 +02:00
'audioItem' => [
2016-09-30 23:21:17 +02:00
'stream' => $stream,
],
],
],
2016-09-30 23:21:17 +02:00
],
];
}
public function previousTrack()
{
$trackId = $this->session->get('track_id');
$position = $this->session->get('current_position', 1);
$trackHistory = $this->session->get('track_history', []);
$playlist = $this->session->get('playlist', []);
$track = $playlist[$position - 2];
2016-09-30 23:21:17 +02:00
$trackHistory[] = $trackId;
$this->session->put('current_position', $position - 1);
$this->session->put('track_id', $track['id']);
$this->session->put('track_history', $trackHistory);
$stream = [
'url' => $track['streams']['mp3'],
'token' => $track['id'],
'offsetInMilliseconds' => 0,
];
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 23:21:17 +02:00
'response' => [
'directives' => [
[
'type' => 'AudioPlayer.Play',
'playBehavior' => 'REPLACE_ALL',
'audioItem' => [
'stream' => $stream,
2016-09-30 03:36:44 +02:00
],
],
],
2016-09-30 03:36:44 +02:00
],
];
}
public function stop()
{
return [
'version' => '1.0',
'sessionAttributes' => (object) [],
2016-09-30 03:36:44 +02:00
'response' => [
'directives' => [
[
'type' => 'AudioPlayer.Stop',
2016-09-30 03:36:44 +02:00
],
],
'shouldEndSession' => true,
],
];
}
}