/podcast/{overzicht,stream,download} toegevoegd

This commit is contained in:
2017-06-11 22:58:53 +02:00
parent f2ae355e72
commit 7ede0532ac
8 changed files with 1660 additions and 211 deletions

View File

@@ -2,6 +2,8 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
error_reporting(E_ALL);
ini_set('display_errors', true);
@@ -37,9 +39,13 @@ QUERY;
/**
* Lijst van alle nieuwsberichten
*/
public function list(int $count = 15, int $page = 1) {
if((int)$count <= 0) { $count = 15; }
if((int)$page <= 0) { $page = 1; }
public function list(Request $request) {
$count = (int)$request->get('aantal', 15);
$page = (int)$request->get('pagina', 1);
if($count <= 0 || $page <= 0) {
return abort(400);
}
$start = ($page - 1) * $count;
$newsItems = app('db')->select(self::$BASE_SQL
. ' ORDER BY `published` DESC'

View File

@@ -0,0 +1,133 @@
<?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 list(Request $request) {
$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
. ' ORDER BY `podcast_meta`.`creationdt` DESC, `podcast_meta`.`id` DESC'
. ' LIMIT ' . (int)$start . ', ' . (int)$count);
$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, int $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);
}
return response()->download($podcast->getSoundfile(),
'6FM Gemist - ' . $podcast->title . '.mp3');
}
public function stream(Request $request, int $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);
}
// 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();
}
}

View File

@@ -1,216 +1,170 @@
swagger: "2.0"
swagger: '2.0'
info:
description: "Dit is de publieke alleen-lezen interface van 6FM RES (Radio Extranet Systeem)."
version: "1.0.0"
title: "6FM RES"
# termsOfService: "http://swagger.io/terms/"
description: 'Dit is de publieke alleen-lezen interface van 6FM RES (Radio Extranet Systeem).'
version: '1.0.0'
title: '6FM RES'
# termsOfService: 'http://swagger.io/terms/'
contact:
email: "mischa.spelt@6fm.nl"
email: 'mischa.spelt@6fm.nl'
#license:
# name: "Apache 2.0"
# url: "http://www.apache.org/licenses/LICENSE-2.0.html"
host: "api.6fm.nl"
basePath: "/"
# name: 'Apache 2.0'
# url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
host: 'api.6fm.nl'
basePath: '/'
tags:
- name: "nieuws"
description: "Nieuwsberichten"
- name: "agenda"
description: "Regioagenda-items"
- name: 'nieuws'
description: 'Nieuwsberichten'
- name: 'agenda'
description: 'Regioagenda-items'
- name: 'podcast'
description: 'Podcasts'
#externalDocs:
# description: "Find out more"
# url: "http://swagger.io"
#- name: "store"
#description: "Access to Petstore orders"
#- name: "user"
#description: "Operations about user"
# description: 'Find out more'
# url: 'http://swagger.io'
#- name: 'store'
#description: 'Access to Petstore orders'
#- name: 'user'
#description: 'Operations about user'
#externalDocs:
# description: "Find out more about our store"
# url: "http://swagger.io"
# description: 'Find out more about our store'
# url: 'http://swagger.io'
schemes:
- "http"
- 'http'
paths:
'/nieuws/overzicht':
get:
tags:
- "nieuws"
summary: "Overzicht van nieuwsberichten"
description: "Geeft een overzicht van de 15 meest recente nieuwsberichten. Equivalent aan /nieuws/overzicht/15/1."
- 'nieuws'
summary: 'Overzicht van nieuwsberichten'
description: 'Geeft een overzicht van {aantal} recente nieuwsberichten, de meest recente {pagina} pagina''s overslaand. Met andere woorden, geeft de nieuwsberichten ({pagina} - 1) * {aantal} + 1 tot en met {pagina} * {aantal} terug, waarbij 1 het meest recent toegevoegde bericht is. '
produces:
- "application/json"
responses:
200:
description: "Success"
schema:
type: "object"
properties:
page:
type: "integer"
count:
type: "integer"
news:
type: "array"
items:
$ref: "#/definitions/NewsItem"
'/nieuws/overzicht/{aantal}':
get:
tags:
- "nieuws"
summary: "Overzicht van nieuwsberichten"
description: "Geeft een overzicht van de {aantal} meest recente nieuwsberichten. Equivalent aan /nieuws/overzicht/{aantal}/1."
produces:
- "application/json"
- 'application/json'
parameters:
- name: aantal
in: path
description: "Het aantal nieuwsberichten per resultaatpagina."
required: true
default: 15
type: string
responses:
200:
description: "Success"
schema:
type: "object"
properties:
page:
type: "integer"
count:
type: "integer"
news:
type: "array"
items:
$ref: "#/definitions/NewsItem"
'/nieuws/overzicht/{aantal}/{pagina}':
get:
tags:
- "nieuws"
summary: "Overzicht van nieuwsberichten"
description: "Geeft een overzicht van {aantal} recente nieuwsberichten, de meest recente {pagina} pagina's overslaand"
produces:
- "application/json"
parameters:
- name: aantal
in: path
description: "Het aantal nieuwsberichten per resultaatpagina."
required: true
in: query
description: 'Het aantal nieuwsberichten per resultaatpagina.'
required: false
default: 15
type: string
- name: pagina
in: path
description: "Het paginanummer."
required: true
in: query
description: 'Het paginanummer.'
required: false
default: 1
type: string
responses:
200:
description: "Success"
description: 'Success'
schema:
type: "object"
type: 'object'
properties:
page:
type: "integer"
type: integer
count:
type: "integer"
type: integer
news:
type: "array"
type: array
items:
$ref: "#/definitions/NewsItem"
$ref: '#/definitions/NewsItem'
400:
description: 'Parameter ''aantal'' of ''pagina'' heeft geen geldige waarde.'
'/nieuws/bericht/{id}':
get:
tags:
- "nieuws"
summary: "Details van een specifiek nieuwsbericht"
description: "Geeft de details van een specifiek nieuwsbericht"
- 'nieuws'
summary: 'Details van een specifiek nieuwsbericht'
description: 'Geeft de details van een specifiek nieuwsbericht'
produces:
- "application/json"
- 'application/json'
parameters:
- name: id
in: path
description: "Het unieke ID van het nieuwsbericht"
description: 'Het unieke ID van het nieuwsbericht'
required: true
type: "integer"
type: integer
responses:
200:
description: "Success"
description: 'Success'
schema:
$ref: '#/definitions/NewsItem'
404:
description: "ID is ongeldig"
description: 'ID is ongeldig'
'/agenda/overzicht[/week]':
get:
tags:
- "agenda"
summary: "Overzicht van alle agendaberichten in de komende 7 dagen"
description: "Geeft een overzicht van alle agendaberichten in de komende week"
- 'agenda'
summary: 'Overzicht van alle agendaberichten in de komende 7 dagen'
description: 'Geeft een overzicht van alle agendaberichten in de komende week'
produces:
- "application/json"
- 'application/json'
responses:
200:
description: "Success"
description: 'Success'
schema:
type: "array"
type: array
items:
$ref: '#/definitions/AgendaItem'
'/agenda/overzicht/maand':
get:
tags:
- "agenda"
summary: "Overzicht van alle agendaberichten in de komende 30 dagen"
description: "Geeft een overzicht van alle agendaberichten in de komende maand"
- 'agenda'
summary: 'Overzicht van alle agendaberichten in de komende 30 dagen'
description: 'Geeft een overzicht van alle agendaberichten in de komende maand'
produces:
- "application/json"
- 'application/json'
responses:
200:
description: "Success"
description: 'Success'
schema:
type: "array"
type: array
items:
$ref: '#/definitions/AgendaItem'
'/agenda/overzicht/alles':
get:
tags:
- "agenda"
summary: "Overzicht van alle agendaberichten in de toekomst"
description: "Geeft een overzicht van alle agendaberichten in de toekomst"
- 'agenda'
summary: 'Overzicht van alle agendaberichten in de toekomst'
description: 'Geeft een overzicht van alle agendaberichten in de toekomst'
produces:
- "application/json"
- 'application/json'
responses:
200:
description: "Success"
description: 'Success'
schema:
type: "array"
type: array
items:
$ref: '#/definitions/AgendaItem'
'/agenda/kalender':
get:
tags:
- "agenda"
summary: "Haalt de agenda op in kalender-formaat voor de huidige maand"
description: "Geeft alle agendaitems voor de huidige kalendermaand gegroepeerd op dag van de maand."
- 'agenda'
summary: 'Haalt de agenda op in kalender-formaat voor de huidige maand'
description: 'Geeft alle agendaitems voor de huidige kalendermaand gegroepeerd op dag van de maand.'
produces:
- "application/json"
- 'application/json'
responses:
200:
description: "Success"
description: 'Success'
schema:
type: "object"
type: 'object'
properties:
items:
type: "array"
type: array
items:
$ref: '#/definitions/AgendaItem'
days:
type: "object"
description: "Eigenschapnamen zijn datum binnen gegeven maand in yyyy-mm-dd formaat"
type: 'object'
description: 'Eigenschapnamen zijn datum binnen gegeven maand in yyyy-mm-dd formaat'
additionalProperties:
type: 'array'
description: "ID's van agenda-items op deze datum"
type: array
description: 'ID''s van agenda-items op deze datum'
items:
type: 'integer'
type: integer
example:
'2017-01-20': [ 40234, 48398 ]
'2017-01-21': [ 40234, 47239 ]
@@ -219,42 +173,42 @@ paths:
'/agenda/kalender/{jaar}/{maand}':
get:
tags:
- "agenda"
summary: "Haalt de agenda op in kalender-formaat voor de gegeven maand"
description: "Geeft alle agendaitems voor de gegeven kalendermaand gegroepeerd op dag van de maand."
- 'agenda'
summary: 'Haalt de agenda op in kalender-formaat voor de gegeven maand'
description: 'Geeft alle agendaitems voor de gegeven kalendermaand gegroepeerd op dag van de maand.'
produces:
- "application/json"
- 'application/json'
parameters:
- name: jaar
in: path
description: "Het jaartal"
description: 'Het jaartal'
required: true
type: "integer"
type: integer
- name: maand
in: path
description: "De maand van het jaar (1 - 12)"
description: 'De maand van het jaar (1 - 12)'
required: true
type: "integer"
type: integer
responses:
400:
description: "Maand of jaartal ongeldig. Maand moet 1, 2, ..., 12 zijn."
description: 'Maand of jaartal ongeldig. Maand moet 1, 2, ..., 12 zijn.'
200:
description: "Success"
description: 'Success'
schema:
type: "object"
type: 'object'
properties:
items:
type: "array"
type: array
items:
$ref: '#/definitions/AgendaItem'
days:
type: "object"
description: "Eigenschapnamen zijn datum binnen gegeven maand in yyyy-mm-dd formaat"
type: 'object'
description: 'Eigenschapnamen zijn datum binnen gegeven maand in yyyy-mm-dd formaat'
additionalProperties:
type: 'array'
description: "ID's van agenda-items op deze datum"
type: array
description: 'ID''s van agenda-items op deze datum'
items:
type: 'integer'
type: integer
example:
'2017-01-20': [ 40234, 48398 ]
'2017-01-21': [ 40234, 47239 ]
@@ -263,129 +217,265 @@ paths:
'/agenda/details/{id}':
get:
tags:
- "agenda"
summary: "Details van een specifiek agendaitem"
description: "Geeft de details van een specifiek agendaitem"
- 'agenda'
summary: 'Details van een specifiek agendaitem'
description: 'Geeft de details van een specifiek agendaitem'
produces:
- "application/json"
- 'application/json'
parameters:
- name: id
in: path
description: "Het unieke ID van het agendabericht"
description: 'Het unieke ID van het agendabericht'
required: true
type: "integer"
type: integer
responses:
200:
description: "Success"
description: 'Success'
schema:
$ref: '#/definitions/AgendaItem'
404:
description: "ID is ongeldig"
description: 'ID is ongeldig'
'/podcast/overzicht':
get:
tags:
- 'podcast'
summary: 'Overzicht van meest recente podcasts'
description: 'Geeft een overzicht van {aantal} recente podcasts, de meest recente {pagina} pagina''s overslaand. Met andere woorden, geeft de podcasts ({pagina} - 1) * {aantal} + 1 tot en met {pagina} * {aantal} terug, waarbij 1 de meest recent toegevoegde podcast is. '
parameters:
- name: aantal
in: query
description: 'Het aantal podcasts per resultaatpagina.'
required: false
default: 15
type: string
- name: pagina
in: query
description: 'Het paginanummer.'
required: false
default: 1
type: string
responses:
200:
description: 'Success'
schema:
type: 'object'
properties:
page:
type: integer
count:
type: integer
podcasts:
type: array
items:
$ref: '#/definitions/Podcast'
400:
description: 'Parameter ''aantal'' of ''pagina'' heeft geen geldige waarde.'
'/podcast/download/{id}/{title}':
get:
tags:
- 'podcast'
summary: 'Download een specifieke podcast'
description: 'Geeft een MP3-bestand terug waarvan de headers de browser forceren het bestand te downloaden.'
produces:
- 'audio/mpeg'
parameters:
- name: id
in: path
description: 'Het unieke ID van de podcast'
required: true
type: integer
- name: title
in: path
description: 'De titel van de podcast'
required: true
type: string
- name: auth
in: query
description: 'De authorisatiecode voor het downloaden van de podcast. Deze verandert per gebruikerssessie. (Dit is onder andere nodig om te voorkomen dat uitzendingen ouder dan twee weken kunnen worden gedownload door de URL aan te passen.) Deze sleutel is beschikbaar via de ''url'' eigenschap van de podcast.'
required: true
type: string
404:
description: 'Podcast ID of authorisatiesleutel is ongeldig'
'/podcast/stream/{id}/{title}':
get:
tags:
- 'podcast'
summary: 'Stream een specifieke podcast'
description: 'Geeft een MP3-bestand terug voor live streaming'
produces:
- 'audio/mpeg'
parameters:
- name: id
in: path
description: 'Het unieke ID van de podcast'
required: true
type: integer
- name: title
in: path
description: 'De titel van de podcast'
required: true
type: string
- name: auth
in: query
description: 'De authorisatiecode voor het streamen van de podcast. Deze verandert per gebruikerssessie. (Dit is onder andere nodig om te voorkomen dat uitzendingen ouder dan twee weken kunnen worden gestreamd door de URL aan te passen.) Deze sleutel is beschikbaar via de ''url'' eigenschap van de podcast.'
required: true
type: string
404:
description: 'Podcast ID of authorisatiesleutel is ongeldig'
#securityDefinitions:
#petstore_auth:
# type: "oauth2"
# authorizationUrl: "http://petstore.swagger.io/oauth/dialog"
# flow: "implicit"
# type: 'oauth2'
# authorizationUrl: 'http://petstore.swagger.io/oauth/dialog'
# flow: 'implicit'
# scopes:
# write:pets: "modify pets in your account"
# read:pets: "read your pets"
# write:pets: 'modify pets in your account'
# read:pets: 'read your pets'
#api_key:
# type: "apiKey"
# name: "api_key"
# in: "header"
# type: 'apiKey'
# name: 'api_key'
# in: 'header'
definitions:
DateTime:
type: "object"
type: 'object'
properties:
date:
type: "string"
format: "yyyy-mm-dd hh:mm:ss.zzzzzz"
example: "2017-07-12 15:23:59.000000"
type: string
format: 'yyyy-mm-dd hh:mm:ss.zzzzzz'
example: '2017-07-12 15:23:59.000000'
timezone_type:
type: "integer"
type: integer
example: 4
timezone:
type: "string"
example: "Europe/Amsterdam"
type: string
example: 'Europe/Amsterdam'
NewsSource:
type: "object"
type: 'object'
properties:
title:
type: "string"
type: string
url:
type: "string"
type: string
show:
type: "boolean"
type: 'boolean'
NewsImage:
type: "object"
type: 'object'
properties:
id:
type: "integer"
type: integer
title:
type: "string"
type: string
url:
type: "string"
type: string
NewsItem:
type: "object"
type: 'object'
properties:
id:
type: "integer"
type: integer
title:
type: "string"
type: string
content:
type: "string"
type: string
published:
$ref: "#/definitions/DateTime"
$ref: '#/definitions/DateTime'
edited:
$ref: "#/definitions/DateTime"
$ref: '#/definitions/DateTime'
keywords:
type: "array"
type: array
items:
type: "string"
type: string
source:
type: "array"
type: array
items:
$ref: "#/definitions/NewsSource"
$ref: '#/definitions/NewsSource'
theme:
type: "string"
type: string
region:
type: "string"
type: string
podcast:
type: "string"
type: string
images:
type: "array"
type: array
items:
$ref: "#/definitions/NewsImage"
$ref: '#/definitions/NewsImage'
video:
type: "string"
type: string
url:
type: "string"
type: string
AgendaItem:
type: "object"
type: 'object'
properties:
id:
type: "integer"
type: integer
title:
type: "string"
type: string
region:
type: "string"
type: string
content:
type: "string"
type: string
starts:
$ref: "#/definitions/DateTime"
$ref: '#/definitions/DateTime'
ends:
$ref: "#/definitions/DateTime"
$ref: '#/definitions/DateTime'
images:
type: "array"
type: array
items:
$ref: "#/definitions/NewsImage"
$ref: '#/definitions/NewsImage'
url:
type: "string"
type: string
Podcast:
type: 'object'
properties:
id:
type: integer
title:
type: string
content:
type: string
created:
$ref: '#/definitions/DateTime'
program:
$ref: '#/definitions/Program'
description: 'Alleen de {name}, {description} en {id} van het programma worden ingevuld, {hosts}, {schedule} en {podcasts} zijn leeg. Gebruik GET /programma om meer informatie hierover te krijgen.'
url:
type: string
description: 'Link om de podcast als MP3 te streamen of te downloaden. Voeg hiervoor /podcast/stream/ of /podcast/download/ toe voor de url, bijvoorbeeld: /podcast/stream/213723/6fm-podcast-titel-slug?auth=15ff823563323fe3342812937b4013984218'
Program:
type: 'object'
properties:
id:
type: integer
name:
type: string
description:
type: string
hosts:
type: array
items:
type: string # Voor nu
description: 'NOT IMPLEMENTED YET!'
required: false
schedule:
type: array
description: 'NOT IMPLEMENTED YET!'
required: false
podcasts:
type: array
items:
$ref: '#/definitions/Podcast'
description: 'Podcasts in deze lijst hebben geen {programma} ingevuld.'
required: false
#externalDocs:
# description: "Find out more about Swagger"
# url: "http://swagger.io"
# description: 'Find out more about Swagger'
# url: 'http://swagger.io'

View File

@@ -16,8 +16,6 @@ $app->get('/', function () use ($app) {
});
$app->get('nieuws/overzicht', 'NewsController@list' );
$app->get('nieuws/overzicht/{count:\d+}', 'NewsController@list' );
$app->get('nieuws/overzicht/{count:\d+}/{page:\d+}', 'NewsController@list' );
$app->get('nieuws/bericht/{id:\d+}', 'NewsController@item' );
$app->get('agenda/overzicht[/week]', 'AgendaController@listWeek' );
@@ -25,3 +23,15 @@ $app->get('agenda/overzicht/maand', 'AgendaController@listMonth' );
$app->get('agenda/overzicht/alles', 'AgendaController@list' );
$app->get('agenda/kalender[/{year:\d\d\d\d}/{month:\d\d?}]', 'AgendaController@calendar' );
$app->get('agenda/details/{id:\d+}', 'AgendaController@item' );
$app->get('podcast/overzicht', 'PodcastController@list' );
// podcast/programma/1234[?aantal=&pagina=]
$app->get('podcast/download/{id:\d+}/[{title}]', 'PodcastController@download' );
$app->get('podcast/stream/{id:\d+}/[{title}]', 'PodcastController@stream' );
// programma/nustraks
// programma/schema
// programma/details/{id:\d+}
// live/onair
// live/stream

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,7 @@ class Model {
$text = str_replace($search, $replace, $text);
// Verwijder alle woorden van 3 letters, behalve BEL (BEL-combinatie etc)
$text = preg_replace('/\b(?!bel)([a-z]{1,3})\b/u', '', $text);
$text = preg_replace('/\b(?!bel|fm)([a-z]{1,3})\b/u', '', $text);
// Vervang alles dat niet een woord-karakter is (letter, cijfer), een streepje of spatie
$text = preg_replace('/[^\w_\-\s]/', '', $text);

View File

@@ -0,0 +1,46 @@
<?php
namespace Model;
require "Program.php";
class Podcast extends Model {
public $id;
public $title;
public $content;
protected $soundfilename;
public $created;
public $program;
public $url;
public $download;
private $key;
public function __construct($data) {
parent::__construct($data);
parent::ConvertToDateTime($this->created);
$this->key = sha1($this->id . ':' . session_id() . ':' . $this->soundfilename);
$this->url = $this->id . '/' . parent::url_slug($this->title) . '?auth=' . $this->key;
if($this->program != 0) {
$this->program = new \Model\Program(['id' => $this->program, 'name' => $data->program_name, 'description' => $data->program_description]);
}
}
public function isValidAuth($key) {
return ($key == $this->key);
}
public function getSoundfile() {
return '/tmp/podcast.mp3';
}
public function excerpt() {
$hasImages = count($this->images) > 0;
$maxLength = $hasImages ? 200 : 500;
return '<p class="news-excerpt ' . ($hasImages ? 'short' : 'long') . '">' .
substr($this->content, 0, $maxLength) .
(strlen($this->content) > $maxLength ? '...' : '') .
'</p>';
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Model;
class Program extends Model {
public $id;
public $name;
public $description;
// TODO: Implementeren
public $hosts;
public $schedule;
public $podcasts;
public function __construct($data) {
parent::__construct($data);
}
}