Files
api/api/app/Http/Controllers/PodcastController.php

208 lines
6.4 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;
error_reporting(E_ALL);
ini_set('display_errors', true);
class PodcastController extends Controller
{
// TODO: Include program
private static $BASE_SQL = <<<QUERY
SELECT `podcast`.`id`, `podcast`.`soundfilename`,
`podcast_meta`.`creationdt` AS `created`, `podcast_meta`.`title`, `podcast_meta`.`content`, `podcast_meta`.`program`,
`programs`.`longname` AS `program_name`, `programs`.`description` AS `program_description`
FROM `podcast`
INNER JOIN `podcast_meta` ON `podcast`.`id` = `podcast_meta`.`podcast`
LEFT JOIN `programs` ON `podcast_meta`.`program` = `programs`.`id`
WHERE `podcast_meta`.`active` = 1 AND `podcast_meta`.`title` <> '' AND `podcast_meta`.`content` <> ''
QUERY;
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Lijst van alle podcasts
*/
public function overview(Request $request) {
return $this->getPodcastList($request, null, []);
}
/**
* Lijst van alle podcasts voor een specifiek programma
*/
public function program(Request $request, $program) {
if((int)$program <= 0) {
return abort(404);
}
return $this->getPodcastList($request, '`podcast_meta`.`program` = :program', ['program' => (int)$program]);
}
/**
* Details over een specifieke podcast
*/
public function details(Request $request, $id) {
$podcasts = app('db')->select(self::$BASE_SQL . ' AND `podcast`.`id` = :podcast', ['podcast' => (int)$id]);
if(count($podcasts) != 1) {
return abort(404);
}
return response()->json(new \Model\Podcast($podcasts[0]));
}
private function getPodcastList(Request $request, $filter, $params)
{
$count = (int)$request->get('aantal', 15);
$page = (int)$request->get('pagina', 1);
if($count <= 0 || $page <= 0) {
return abort(400);
}
$start = ($page - 1) * $count;
$podcasts = app('db')->select(self::$BASE_SQL
. ($filter ? ' AND (' . $filter . ')' : '')
. ' ORDER BY `podcast_meta`.`creationdt` DESC, `podcast_meta`.`id` DESC'
. ' LIMIT ' . (int)$start . ', ' . (int)$count,
$params);
$result = array();
foreach($podcasts as $podcast) {
$result[] = new \Model\Podcast($podcast);
}
return response()->json(['page' => $page, 'count' => $count, 'podcasts' => $result]);
}
/**
* Download specifieke podcast
*/
public function download(Request $request, $id) {
$queryResult = app('db')->select(self::$BASE_SQL
. ' AND `podcast`.`id` = :id '
. ' LIMIT 0, 1',
['id' => (int)$id]);
if(count($queryResult) == 0) { return abort(404); }
$podcast = new \Model\Podcast($queryResult[0]);
if(!$podcast->isValidAuth($request->get('auth'))) {
return abort(404);
}
return response()->download($podcast->getSoundfile(),
'6FM Gemist - ' . $podcast->title . '.mp3');
}
/***
* Stream een specifieke podcast (niet voor uitzending)
*/
public function stream(Request $request, $id) {
$queryResult = app('db')->select(self::$BASE_SQL
. ' AND `podcast`.`id` = :id '
. ' LIMIT 0, 1',
['id' => $id]);
if(count($queryResult) == 0) { return abort(404); }
$podcast = new \Model\Podcast($queryResult[0]);
if(!$podcast->isValidAuth($request->get('auth'))) {
return abort(404);
}
$filename = $podcast->getSoundfile();
$file = fopen($filename, "rb");
$size = filesize($filename);
$content = fread($file, $size);
fclose($file);
self::streamFile($request, 'audio/mpeg', $content, $size);
}
/***
* Stream een specifieke uitzending
*/
public function complete(Request $r, $year, $month, $day, $hour, $duration) {
if($duration <= 0) {
return response()->abort(404);
}
$currentHour = new \DateTime();
$currentHour->setDate($year, $month, $day)->setTime($hour, 0, 0);
$files = [];
$size = 0;
while($duration--) {
$file = '/var/audio/uitzending/' . $currentHour->format('Ymd_Hi') . '.MP3';
if(!file_exists($file)) {
return response()->abort(404);
}
$size += filesize($file);
$files[] = $file;
$currentHour->add(\DateInterval::createFromDateString('1 hour'));
}
return new StreamedResponse(function() use($files) {
// Open output stream
$output = fopen('php://output', 'w');
foreach($files as $file) {
$fp = fopen($file, 'rb');
while ($buf = fread($fp, 1024)) {
fwrite($output, $buf);
}
fclose($fp);
}
fclose($output);
}, 200, [
'Content-Type' => 'audio/mpg',
'Content-Disposition' => sprintf(
'attachment; filename="Radio_6FM_Uitzending_%02d-%02d-%04d_%02du00.MP3"',
$day, $month, $year, $hour)
]);
}
// Provide a streaming file with support for scrubbing
// Source: https://gist.github.com/widnyana/cd2bdda07dc02e9fce71
private static function streamFile(Request $r, $contentType, $stream, $fullsize ) {
$size = $fullsize;
$response_code = 200;
$headers = array("Content-type" => $contentType);
// Check for request for part of the stream
$range = $r->header('Range');
if($range != null) {
$eqPos = strpos($range, "=");
$toPos = strpos($range, "-");
$unit = substr($range, 0, $eqPos);
$start = intval(substr($range, $eqPos+1, $toPos));
$success = fseek($stream, $start);
if($success == 0) {
$size = $fullsize - $start;
$response_code = 206;
$headers["Accept-Ranges"] = $unit;
$headers["Content-Range"] = $unit . " " . $start . "-" . ($fullsize-1) . "/" . $fullsize;
}
}
$headers["Content-Length"] = $size;
$response = new StreamedResponse(
function () use ($stream) {
$out = fopen('php://output', 'w');
fputs($out, $stream);
fclose($out);
}, 200, $headers);
$response->send();
}
}