aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.php125
-rw-r--r--index.php4
-rw-r--r--lib/helper.php174
-rw-r--r--lib/program.php168
-rw-r--r--model/Relive.php24
-rw-r--r--model/Room.php193
-rw-r--r--model/RoomSelection.php52
-rw-r--r--model/RoomTab.php34
-rw-r--r--model/Schedule.php173
-rw-r--r--model/Stream.php174
-rw-r--r--model/StreamList.php55
-rw-r--r--template/assemblies/chat.phtml13
-rw-r--r--template/assemblies/player/audio.phtml26
-rw-r--r--template/assemblies/player/music.phtml26
-rw-r--r--template/assemblies/player/slides.phtml20
-rw-r--r--template/assemblies/player/video.phtml42
-rw-r--r--template/assemblies/switcher/audio.phtml33
-rw-r--r--template/assemblies/switcher/music.phtml23
-rw-r--r--template/assemblies/switcher/slides.phtml52
-rw-r--r--template/assemblies/switcher/video.phtml36
-rw-r--r--template/page.phtml2
-rw-r--r--template/room.phtml36
-rw-r--r--view/room.php118
23 files changed, 833 insertions, 770 deletions
diff --git a/config.php b/config.php
index 1cf3891..2ae2aca 100644
--- a/config.php
+++ b/config.php
@@ -130,20 +130,6 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
'DISPLAY' => 'Saal 1',
/**
- * Vefügbare Streaming-Formate
- * Die Formate müssen in $GLOBALS['CONFIG']['FORMATS'] benannt sein, es
- * können jedoch über die Config keine neuen erfunden werden; dazu sind
- * Änderungen am Code erforderlich.
- */
- 'FORMATS' => array(
- 'rtmp-sd', 'rtmp-hd',
- 'hls-sd', 'hls-hd',
- 'webm-sd', 'webm-hd',
- 'audio-mp3', 'audio-opus',
- 'slides',
- ),
-
- /**
* ID des Video/Audio-Streams. Die Stream-ID ist davon abhängig, welches
* Event-Case in welchem Raum aufgebaut wird und wird üblicherweise von
* s1 bis s5 durchnummeriert.
@@ -163,14 +149,15 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
* Wenn diese Zeile auskommentiert oder auf false gesetzt ist werden nur
* die native-Streams verwendet, andernfalls wird native und translated
* angeboten und auch für beide Tonspuren eine Player-Seite angezeigt.
- *
- * Der Spezialwert 'stereo' (oder ein beliebiger anderer String) kann
- * verwendet werden, um statt s1_native_sd Streamnamen in der Art von
- * s1_<string>_sd, also z.B. s1_stereo_sd zu benutzen. Abgesehen von den
- * anderen Streamnamen verhält sich die Seite, als wäre false gesetzt.
*/
'TRANSLATION' => true,
+ //'STEREO' => true,
+ 'SD_VIDEO' => true,
+ 'HD_VIDEO' => true,
+ 'AUDIO' => true,
+ 'SLIDES' => true,
+
/**
* Fahrplan-Ansicht auf der Raum-Seite aktivieren (boolean)
*
@@ -271,16 +258,16 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
'saal2' => array(
'DISPLAY' => 'Saal 2',
- 'FORMATS' => array(
- 'rtmp-sd', 'rtmp-hd',
- 'hls-sd', 'hls-hd',
- 'webm-sd', 'webm-hd',
- 'audio-mp3', 'audio-opus',
- 'slides',
- ),
'STREAM' => 's2',
'PREVIEW' => true,
+
'TRANSLATION' => true,
+ //'STEREO' => true,
+ 'SD_VIDEO' => true,
+ 'HD_VIDEO' => true,
+ 'AUDIO' => true,
+ 'SLIDES' => true,
+
'SCHEDULE' => true,
'SCHEDULE_NAME' => 'Saal 2',
'FEEDBACK' => true,
@@ -299,16 +286,16 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
'saalg' => array(
'DISPLAY' => 'Saal G',
- 'FORMATS' => array(
- 'rtmp-sd', 'rtmp-hd',
- 'hls-sd', 'hls-hd',
- 'webm-sd',
- 'audio-mp3', 'audio-opus',
- 'slides',
- ),
'STREAM' => 's3',
'PREVIEW' => true,
+
'TRANSLATION' => true,
+ //'STEREO' => true,
+ 'SD_VIDEO' => true,
+ 'HD_VIDEO' => true,
+ 'AUDIO' => true,
+ 'SLIDES' => true,
+
'SCHEDULE' => true,
'SCHEDULE_NAME' => 'Saal G',
'FEEDBACK' => true,
@@ -327,16 +314,16 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
'saal6' => array(
'DISPLAY' => 'Saal 6',
- 'FORMATS' => array(
- 'rtmp-sd', 'rtmp-hd',
- 'hls-sd', 'hls-hd',
- 'webm-sd', 'webm-hd',
- 'audio-mp3', 'audio-opus',
- 'slides',
- ),
'STREAM' => 's4',
'PREVIEW' => true,
+
'TRANSLATION' => true,
+ //'STEREO' => true,
+ 'SD_VIDEO' => true,
+ 'HD_VIDEO' => true,
+ 'AUDIO' => true,
+ 'SLIDES' => true,
+
'SCHEDULE' => true,
'SCHEDULE_NAME' => 'Saal 6',
'FEEDBACK' => true,
@@ -356,28 +343,23 @@ $GLOBALS['CONFIG']['ROOMS'] = array(
'lounge' => array(
'DISPLAY' => 'Lounge',
- 'FORMATS' => array(
- 'music-mp3', 'music-opus',
- ),
+ 'MUSIC' => true,
),
'ambient' => array(
'DISPLAY' => 'Ambient',
- 'FORMATS' => array(
- 'music-mp3', 'music-opus',
- ),
+ 'MUSIC' => true,
),
'sendezentrum' => array(
'DISPLAY' => 'Sendezentrum',
- 'FORMATS' => array(
- 'rtmp-sd', 'rtmp-hd',
- 'hls-sd', 'hls-hd',
- 'webm-sd', 'webm-hd',
- 'audio-mp3', 'audio-opus',
- ),
'STREAM' => 's5',
- 'TRANSLATION' => false,
+
+ //'STEREO' => true,
+ 'SD_VIDEO' => true,
+ 'HD_VIDEO' => true,
+ 'AUDIO' => true,
+
'SCHEDULE' => true,
'FEEDBACK' => true,
'SUBTITLES' => false,
@@ -489,8 +471,11 @@ $GLOBALS['CONFIG']['IRC'] = array(
/**
* URL für die IRC-Links.
+ * Hierbei kann sowohl ein irc://-Link als auch ein Link zu einem
+ * WebIrc-Provider wie z.B. 'https://kiwiirc.com/client/irc.hackint.eu/#31C3-%s'
+ * verwendet werden.
*
- * %s wird durch den Raum-Slug ersetzt.
+ * %s wird durch den urlencodeten Raum-Slug ersetzt.
* Eine Anpassung kann ebenfalls in der Raum-Konfiguration vorgenommen werden.
*/
'URL' => 'irc://irc.hackint.eu:6667/31C3-%s',
@@ -523,35 +508,3 @@ $GLOBALS['CONFIG']['TWITTER'] = array(
*/
'TEXT' => '#31C3 #%s',
);
-
-
-
-
-/**
- * Beschreibung der Streaming-Formate
- *
- * Achtung: Über diese Sektion können keine zusätzlichen Formate erstellt werden -- dazu
- * sind Code-Anpassungen erforderlich.
- *
- * In diesem Abschnitt können ausschließlich die Anzeigetexte für die verschiedenen
- * Streaming-Formate bearbeitet werden. Für jedes Streamingformat das in einem Raum
- * verwendet wird müssen hier Texte hinterlegt sein.
- */
-$GLOBALS['CONFIG']['FORMAT'] = array(
- 'rtmp-sd' => '1024x576, h264+AAC im FLV-Container via RTMP, 800 kBit/s',
- 'rtmp-hd' => '1920x1080, h264+AAC im FLV-Container via RTMP, 3 MBit/s',
-
- 'hls-sd' => '1024x576, h264+AAC im MPEG-TS-Container via HTTP, 800 kBit/s',
- 'hls-hd' => '1920x1080, h264+AAC im MPEG-TS-Container via HTTP, 3 MBit/s',
-
- 'webm-sd' => '1024x576, VP8+Vorbis in WebM, 800 kBit/s',
- 'webm-hd' => '1920x1080, VP8+Vorbis in WebM, 3 MBit/s',
-
- 'audio-mp3' => 'MP3-Audio, 96 kBit/s',
- 'audio-opus' => 'Opus-Audio, 64 kBit/s',
-
- 'music-mp3' => 'MP3-Audio, 320 kBit/s',
- 'music-opus' => 'Opus-Audio, 128 kBit/s',
-
- 'slides' => '1024x576, h264+AAC, <500 kBit/s',
-);
diff --git a/index.php b/index.php
index 02a1f79..a00efc3 100644
--- a/index.php
+++ b/index.php
@@ -12,6 +12,9 @@ require_once('model/Feedback.php');
require_once('model/Schedule.php');
require_once('model/Overview.php');
require_once('model/Room.php');
+require_once('model/RoomTab.php');
+require_once('model/RoomSelection.php');
+require_once('model/Stream.php');
$route = @$_GET['route'];
$route = rtrim($route, '/');
@@ -20,6 +23,7 @@ $route = rtrim($route, '/');
$tpl = new PhpTemplate('template/page.phtml');
$tpl->set(array(
'baseurl' => baseurl(),
+ 'route' => $route,
'assemblies' => './template/assemblies/',
'conference' => new Conference(),
diff --git a/lib/helper.php b/lib/helper.php
index 640651b..7423a9c 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -1,46 +1,5 @@
<?php
-require_once('program.php');
-
-function link_player($room, $format = 'video', $translated = false)
-{
- $defaultformat = room_has_hd($room) ? 'hd' : 'sd';
-
- return rawurlencode($room).'/'.(($defaultformat == $format || 'video' == $format) ? '' : rawurlencode($format).'/').($translated ? 'translated/' : '');
-}
-
-function link_stream($protocol, $room, $format, $translated = false)
-{
- $language = $translated ? 'translated' : 'native';
-
- switch ($protocol) {
- case 'rtmp':
- return 'rtmp://cdn.c3voc.de/stream/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'_'.rawurlencode($language).'_'.rawurlencode($format);
-
- case 'hls':
- return 'http://cdn.c3voc.de/hls/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'_'.rawurlencode($language).($format == 'auto' ? '' : '_'.rawurlencode($format)).'.m3u8';
-
- case 'webm':
- return 'http://cdn.c3voc.de/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'_'.rawurlencode($language).'_'.rawurlencode($format).'.webm';
-
- case 'music':
- return 'http://cdn.c3voc.de/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'.'.rawurlencode($format);
-
- case 'audio':
- return 'http://cdn.c3voc.de/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'_'.rawurlencode($language).'.'.rawurlencode($format);
-
- case 'slide':
- return 'http://cdn.c3voc.de/slides/'.rawurlencode(get("ROOMS.$room.STREAM", $room)).'/current.png';
- }
-
- return '#';
-}
-
-function link_vod($id)
-{
- return 'relive/'.rawurlencode($id).'/';
-}
-
function baseurl()
{
if(isset($GLOBALS['CONFIG']['baseurl']))
@@ -62,12 +21,6 @@ function forceslash($url)
return $url;
}
-function strtoduration($str)
-{
- $parts = explode(':', $str);
- return ((int)$parts[0] * 60 + (int)$parts[1]) * 60;
-}
-
function has($keychain)
{
return _has($GLOBALS['CONFIG'], $keychain);
@@ -106,134 +59,7 @@ function _get($array, $keychain, $default)
return _get($array[$key], array_slice($keychain, 1), $default);
}
-
-
-function room_has_hd($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('rtmp-hd', 'hls-hd', 'webm-hd'), $formats)) > 0;
-}
-
-function room_has_sd($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('rtmp-sd', 'hls-sd', 'webm-sd'), $formats)) > 0;
-}
-
-function room_has_video($room)
-{
- return room_has_hd($room) || room_has_sd($room);
-}
-
-function room_has_audio($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('audio-mp3', 'audio-opus', 'audio-ogg'), $formats)) > 0;
-}
-
-function room_has_music($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('music-mp3', 'music-opus', 'music-ogg'), $formats)) > 0;
-}
-
-function room_has_slides($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('slides'), $formats)) > 0;
-}
-
-function room_get_possible_selections($room)
-{
- $selections = array();
-
- if(room_has_hd($room)) $selections[] = 'hd';
- if(room_has_sd($room)) $selections[] = 'sd';
- if(room_has_audio($room)) $selections[] = 'audio';
- if(room_has_music($room)) $selections[] = 'music';
- if(room_has_slides($room)) $selections[] = 'slides';
-
- return $selections;
-}
-
-function room_has_rtmp($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('rtmp-hd', 'rtmp-sd'), $formats)) > 0;
-}
-
-function room_has_webm($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('webm-hd', 'webm-sd'), $formats)) > 0;
-}
-
-function room_has_hls($room)
-{
- $formats = get("ROOMS.$room.FORMATS");
- return count(array_intersect(array('hls-hd', 'hls-sd'), $formats)) > 0;
-}
-
-function room_has_irc($room)
-{
- return get("ROOMS.$room.IRC") && has("IRC");
-}
-
-function room_has_twitter($room)
-{
- return get("ROOMS.$room.TWITTER") && has("TWITTER");
-}
-
-function room_has_chat($room)
-{
- return room_has_irc($room) || room_has_twitter($room);
-}
-
-function room_get_irc_url($room)
-{
- $cfg = get("ROOMS.$room.IRC_CONFIG", get("IRC"));
- return sprintf($cfg['URL'], rawurlencode($room));
-}
-
-function room_get_irc_display($room)
-{
- $cfg = get("ROOMS.$room.IRC_CONFIG", get("IRC"));
- return sprintf($cfg['DISPLAY'], $room);
-}
-
-function room_get_twitter_hashtag($room)
-{
- $cfg = get("ROOMS.$room.TWITTER_CONFIG", get("TWITTER"));
- return sprintf($cfg['TEXT'], $room);
-}
-
-function room_get_twitter_display($room)
-{
- $cfg = get("ROOMS.$room.TWITTER_CONFIG", get("TWITTER"));
- return sprintf($cfg['DISPLAY'], $room);
-}
-
function startswith($needle, $haystack)
{
return substr($haystack, 0, strlen($needle)) == $needle;
}
-
-function relive_talks()
-{
- $talks = @file_get_contents(get('OVERVIEW.RELIVE_JSON'));
- $talks = utf8_decode($talks);
- $talks = (array)json_decode($talks, true);
-
- usort($talks, function($a, $b) {
- $sort = array('live', 'recorded', 'released');
- return array_search($a['status'], $sort) > array_search($b['status'], $sort);
- });
-
- $talks_by_id = array();
- foreach ($talks as $value)
- {
- $talks_by_id[$value['id']] = $value;
- }
-
- return $talks_by_id;
-}
diff --git a/lib/program.php b/lib/program.php
deleted file mode 100644
index 79ce91d..0000000
--- a/lib/program.php
+++ /dev/null
@@ -1,168 +0,0 @@
-<?php
-
-function program()
-{
- if(!has('SCHEDULE'))
- return;
-
- if(has('SCHEDULE.CACHE') && function_exists('apc_fetch'))
- {
- $program = apc_fetch('SCHEDULE.CACHE');
- if($program) return $program;
- }
-
-
- $program = array();
- $opts = array(
- 'http' => array(
- 'timeout' => 2,
- 'user_agent' => 'C3Voc Universal Streaming-Website Backend @ '.$_SERVER['HTTP_HOST'],
- )
- );
- $context = stream_context_create($opts);
- $schedule = file_get_contents(get('SCHEDULE.URL'), false, $context);
-
- // failed, give up
- if(!$schedule)
- return array();
-
- $schedule = simplexml_load_string($schedule);
-
- // re-calculate day-ends
- // some schedules have long gaps before the first talk or talks that expand beyond the dayend
- // (fiffkon, i look at you)
- // so to be on the safer side we calculate our own daystart/end here
- foreach($schedule->day as $day)
- {
- $daystart = PHP_INT_MAX;
- $dayend = 0;
-
- foreach($day->room as $room)
- {
- foreach($room->event as $event)
- {
- $start = strtotime((string)$event->date);
- $duration = strtoduration((string)$event->duration);
- $end = $start + $duration;
-
- $daystart = min($daystart, $start);
- $dayend = max($dayend, $end);
- }
- }
-
- $day['start'] = $daystart;
- $day['end'] = $dayend;
- }
-
- $dayidx = 0;
- foreach($schedule->day as $day)
- {
- $dayidx++;
- $daystart = (int)$day['start'];
- $dayend = (int)$day['end'];
-
- $roomidx = 0;
- foreach($day->room as $room)
- {
- $roomidx++;
- $lastend = false;
- $name = (string)$room['name'];
- if(isset($GLOBALS['CONFIG']['FAHRPLAN_ROOM_MAPPING'][$name]))
- $name = $GLOBALS['CONFIG']['FAHRPLAN_ROOM_MAPPING'][$name];
-
- foreach($room->event as $event)
- {
- $start = strtotime((string)$event->date);
- $duration = strtoduration((string)$event->duration);
- $end = $start + $duration;
-
- if($lastend && $lastend < $start)
- {
- // synthesize pause event
- $pauseduration = $start - $lastend;
- $program[$name][] = array(
- 'special' => 'pause',
- 'title' => round($pauseduration / 60).' minutes pause',
-
- 'fstart' => date('c', $lastend),
- 'fend' => date('c', $start),
-
- 'start' => $lastend,
- 'end' => $start,
- 'duration' => $pauseduration,
- );
- }
- else if(!$lastend && $daystart < $start)
- {
- $program[$name][] = array(
- 'special' => 'gap',
-
- 'fstart' => date('c', $daystart),
- 'fend' => date('c', $start),
-
- 'start' => $daystart,
- 'end' => $start,
- 'duration' => $start - $daystart,
- );
- }
-
- $personnames = array();
- foreach($event->persons->person as $person)
- $personnames[] = (string)$person;
-
- $program[$name][] = array(
- 'title' => (string)$event->title,
- 'speaker' => implode(', ', $personnames),
-
- 'fstart' => date('c', $start),
- 'fend' => date('c', $end),
-
- 'start' => $start,
- 'end' => $end,
- 'duration' => $duration,
- );
-
- $lastend = $end;
- }
-
- // synthesize daychange event
- if(!$lastend) $lastend = $daystart;
- if($lastend < $dayend)
- {
- $program[$name][] = array(
- 'special' => 'gap',
-
- 'fstart' => date('c', $lastend),
- 'fend' => date('c', $dayend),
-
- 'start' => $lastend,
- 'end' => $dayend,
- 'duration' => $dayend - $lastend,
- );
- }
-
- if($dayidx < count($schedule->day))
- {
- $program[$name][] = array(
- 'special' => 'daychange',
- 'title' => 'Daychange from Day '.$dayidx.' to '.($dayidx+1),
-
- 'start' => $dayend,
- 'end' => (int)$schedule->day[$dayidx]['start'],
- 'duration' => 60*60,
- );
- }
- }
- }
-
- if(has('SCHEDULE.CACHE') && function_exists('apc_store'))
- {
- apc_store(
- 'SCHEDULE.CACHE',
- $program,
- get('SCHEDULE.CACHE')
- );
- }
-
- return $program;
-}
diff --git a/model/Relive.php b/model/Relive.php
new file mode 100644
index 0000000..3ffdc1b
--- /dev/null
+++ b/model/Relive.php
@@ -0,0 +1,24 @@
+<?php
+
+class Relive extends ModelBase
+{
+ function relive_talks()
+ {
+ $talks = @file_get_contents(get('OVERVIEW.RELIVE_JSON'));
+ $talks = utf8_decode($talks);
+ $talks = (array)json_decode($talks, true);
+
+ usort($talks, function($a, $b) {
+ $sort = array('live', 'recorded', 'released');
+ return array_search($a['status'], $sort) > array_search($b['status'], $sort);
+ });
+
+ $talks_by_id = array();
+ foreach ($talks as $value)
+ {
+ $talks_by_id[$value['id']] = $value;
+ }
+
+ return $talks_by_id;
+ }
+}
diff --git a/model/Room.php b/model/Room.php
index c7e51f9..f428d87 100644
--- a/model/Room.php
+++ b/model/Room.php
@@ -35,11 +35,202 @@ class Room extends ModelBase
+ public function hasStereo() {
+ return $this->get('ROOMS.'.$this->getSlug().'.STEREO');
+ }
+
public function hasPreview() {
- return get('ROOMS.'.$this->getSlug().'.PREVIEW');
+ return $this->get('ROOMS.'.$this->getSlug().'.PREVIEW');
}
public function hasSchedule() {
return $this->get('ROOMS.'.$this->getSlug().'.SCHEDULE') && $this->has('SCHEDULE');
}
+
+ public function hasFeedback() {
+ return $this->get('ROOMS.'.$this->getSlug().'.FEEDBACK') && $this->has('FEEDBACK');
+ }
+
+
+ public function hasTwitter() {
+ return $this->get('ROOMS.'.$this->getSlug().'.TWITTER') && $this->has('TWITTER');
+ }
+
+ public function getTwitterDisplay() {
+ return sprintf(
+ $this->get('ROOMS.'.$this->getSlug().'.TWITTER_CONFIG.DISPLAY', $this->get('TWITTER.DISPLAY')),
+ $this->getSlug()
+ );
+ }
+
+ public function getTwitterUrl() {
+ return sprintf(
+ 'https://twitter.com/intent/tweet?text=%s',
+ rawurlencode($this->getTwitterText())
+ );
+ }
+
+ public function getTwitterText() {
+ return sprintf(
+ $this->get('ROOMS.'.$this->getSlug().'.TWITTER_CONFIG.TEXT', $this->get('TWITTER.TEXT')),
+ $this->getSlug()
+ );
+ }
+
+
+ public function hasIrc() {
+ return $this->get('ROOMS.'.$this->getSlug().'.IRC') && $this->has('IRC');
+ }
+
+ public function getIrcDisplay() {
+ return sprintf(
+ $this->get('ROOMS.'.$this->getSlug().'.IRC_CONFIG.DISPLAY', $this->get('IRC.DISPLAY')),
+ $this->getSlug()
+ );
+ }
+
+ public function getIrcUrl() {
+ return sprintf(
+ $this->get('ROOMS.'.$this->getSlug().'.IRC_CONFIG.URL', $this->get('IRC.URL')),
+ rawurlencode($this->getSlug())
+ );
+ }
+
+
+ public function hasChat() {
+ return $this->hasTwitter() || $this->hasIrc();
+ }
+
+
+ public function hasSdVideo() {
+ return $this->get('ROOMS.'.$this->getSlug().'.SD_VIDEO');
+ }
+
+ public function hasHdVideo() {
+ return $this->get('ROOMS.'.$this->getSlug().'.HD_VIDEO');
+ }
+
+ public function hasVideo() {
+ return $this->hasSdVideo() || $this->hasHdVideo();
+ }
+
+ public function hasAudio() {
+ return $this->get('ROOMS.'.$this->getSlug().'.AUDIO');
+ }
+
+ public function hasSlides() {
+ return $this->get('ROOMS.'.$this->getSlug().'.SLIDES');
+ }
+
+ public function hasMusic() {
+ return $this->get('ROOMS.'.$this->getSlug().'.MUSIC');
+ }
+
+ public function hasTranslation() {
+ return $this->get('ROOMS.'.$this->getSlug().'.TRANSLATION');
+ }
+
+ public function getSelectionNames()
+ {
+ $selections = array();
+ if($this->hasHdVideo())
+ $selections[] = 'hd';
+
+ if($this->hasSdVideo())
+ $selections[] = 'sd';
+
+ if($this->hasSlides())
+ $selections[] = 'slides';
+
+ if($this->hasAudio())
+ $selections[] = 'audio';
+
+ if($this->hasMusic())
+ $selections[] = 'music';
+
+ return $selections;
+ }
+
+ public function getTabNames()
+ {
+ $tabs = array();
+ if($this->hasVideo())
+ $tabs[] = 'video';
+
+ if($this->hasSlides())
+ $tabs[] = 'slides';
+
+ if($this->hasAudio())
+ $tabs[] = 'audio';
+
+ if($this->hasMusic())
+ $tabs[] = 'music';
+
+ return $tabs;
+ }
+
+ public function getSelections()
+ {
+ $selections = array();
+ foreach($this->getSelectionNames() as $selection)
+ $selections[$tab] = $this->createSelectionObject($selection);
+
+ return $selections;
+ }
+
+ public function createSelectionObject($selection)
+ {
+ return new RoomSelection($this, $selection);
+ }
+
+ public function getTabs()
+ {
+ $tabs = array();
+ foreach($this->getTabNames() as $tab)
+ $tabs[$tab] = $this->createTabObject($tab);
+
+ return $tabs;
+ }
+
+ public function createTabObject($tab)
+ {
+ return new RoomTab($this, $tab);
+ }
+
+ public function getVideoResolutions()
+ {
+ $res = array();
+ if($this->hasHdVideo())
+ $res[] = 'hd';
+
+ if($this->hasSdVideo())
+ $res[] = 'sd';
+
+ return $res;
+ }
+
+ public function selectStream($selection, $language = 'native')
+ {
+ $selections = $this->getSelectionNames();
+
+ // default page
+ if(!$selection)
+ $selection = $selections[0];
+
+ if(!in_array($selection, $selections))
+ throw new NotFoundException('Selection '.$selection.' in Room '.$this->getSlug());
+
+ if($language == 'translated' && !$this->hasTranslation())
+ throw new NotFoundException('Translated Streams of Room '.$this->getSlug());
+
+ return $this->createStreamObject($selection, $language);
+ }
+
+ public function createStreamObject($selection, $language = 'native')
+ {
+ if($language == 'native' && $this->hasStereo())
+ $language = 'stereo';
+
+ return new Stream($this, $selection, $language);
+ }
}
diff --git a/model/RoomSelection.php b/model/RoomSelection.php
new file mode 100644
index 0000000..c163321
--- /dev/null
+++ b/model/RoomSelection.php
@@ -0,0 +1,52 @@
+<?php
+
+class RoomSelection
+{
+ public function __construct(Room $room, $selection)
+ {
+ $this->room = $room;
+ $this->selection = $selection;
+ }
+
+ public function getRoom()
+ {
+ return $this->room;
+ }
+
+ public function getSelection()
+ {
+ return $this->selection;
+ }
+
+ public function getLink()
+ {
+ $selection = $this->getRoom()->getSelectionNames();
+ if($selection[0] == $this->getSelection())
+ return rawurlencode($this->getRoom()->getSlug()).'/';
+
+ return rawurlencode($this->getRoom()->getSlug()).'/'.rawurlencode($this->getSelection()).'/';
+ }
+
+ public function getTranslatedLink()
+ {
+ return $this->getLink().'translated/';
+ }
+
+ public function getDisplay()
+ {
+ switch($this->getSelection())
+ {
+ case 'sd':
+ case 'hd':
+ return strtoupper($this->getSelection());
+
+ default:
+ return ucfirst($this->getSelection());
+ }
+ }
+
+ public function getTech()
+ {
+ return $this->getSelection().'-tech';
+ }
+}
diff --git a/model/RoomTab.php b/model/RoomTab.php
new file mode 100644
index 0000000..d4f781b
--- /dev/null
+++ b/model/RoomTab.php
@@ -0,0 +1,34 @@
+<?php
+
+class RoomTab
+{
+ public function __construct(Room $room, $tab)
+ {
+ $this->room = $room;
+ $this->tab = $tab;
+ }
+
+ public function getRoom()
+ {
+ return $this->room;
+ }
+
+ public function getTab()
+ {
+ return $this->tab;
+ }
+
+ public function getLink()
+ {
+ $tabs = $this->getRoom()->getTabNames();
+ if($tabs[0] == $this->getTab())
+ return rawurlencode($this->getRoom()->getSlug()).'/';
+
+ return rawurlencode($this->getRoom()->getSlug()).'/'.rawurlencode($this->getTab()).'/';
+ }
+
+ public function getDisplay()
+ {
+ return ucfirst($this->getTab());
+ }
+}
diff --git a/model/Schedule.php b/model/Schedule.php
index db940ce..ca4881d 100644
--- a/model/Schedule.php
+++ b/model/Schedule.php
@@ -5,4 +5,177 @@ class Schedule extends ModelBase
public function getSimulationOffset() {
return $this->get('SCHEDULE.SIMULATE_OFFSET', 0);
}
+
+ private function strtoduration($str)
+ {
+ $parts = explode(':', $str);
+ return ((int)$parts[0] * 60 + (int)$parts[1]) * 60;
+ }
+
+ function program()
+ {
+ if(!has('SCHEDULE'))
+ return;
+
+ if(has('SCHEDULE.CACHE') && function_exists('apc_fetch'))
+ {
+ $program = apc_fetch('SCHEDULE.CACHE');
+ if($program) return $program;
+ }
+
+
+ $program = array();
+ $opts = array(
+ 'http' => array(
+ 'timeout' => 2,
+ 'user_agent' => 'C3Voc Universal Streaming-Website Backend @ '.$_SERVER['HTTP_HOST'],
+ )
+ );
+ $context = stream_context_create($opts);
+ $schedule = file_get_contents(get('SCHEDULE.URL'), false, $context);
+
+ // failed, give up
+ if(!$schedule)
+ return array();
+
+ $schedule = simplexml_load_string($schedule);
+
+ // re-calculate day-ends
+ // some schedules have long gaps before the first talk or talks that expand beyond the dayend
+ // (fiffkon, i look at you)
+ // so to be on the safer side we calculate our own daystart/end here
+ foreach($schedule->day as $day)
+ {
+ $daystart = PHP_INT_MAX;
+ $dayend = 0;
+
+ foreach($day->room as $room)
+ {
+ foreach($room->event as $event)
+ {
+ $start = strtotime((string)$event->date);
+ $duration = strtoduration((string)$event->duration);
+ $end = $start + $duration;
+
+ $daystart = min($daystart, $start);
+ $dayend = max($dayend, $end);
+ }
+ }
+
+ $day['start'] = $daystart;
+ $day['end'] = $dayend;
+ }
+
+ $dayidx = 0;
+ foreach($schedule->day as $day)
+ {
+ $dayidx++;
+ $daystart = (int)$day['start'];
+ $dayend = (int)$day['end'];
+
+ $roomidx = 0;
+ foreach($day->room as $room)
+ {
+ $roomidx++;
+ $lastend = false;
+ $name = (string)$room['name'];
+ if(isset($GLOBALS['CONFIG']['FAHRPLAN_ROOM_MAPPING'][$name]))
+ $name = $GLOBALS['CONFIG']['FAHRPLAN_ROOM_MAPPING'][$name];
+
+ foreach($room->event as $event)
+ {
+ $start = strtotime((string)$event->date);
+ $duration = strtoduration((string)$event->duration);
+ $end = $start + $duration;
+
+ if($lastend && $lastend < $start)
+ {
+ // synthesize pause event
+ $pauseduration = $start - $lastend;
+ $program[$name][] = array(
+ 'special' => 'pause',
+ 'title' => round($pauseduration / 60).' minutes pause',
+
+ 'fstart' => date('c', $lastend),
+ 'fend' => date('c', $start),
+
+ 'start' => $lastend,
+ 'end' => $start,
+ 'duration' => $pauseduration,
+ );
+ }
+ else if(!$lastend && $daystart < $start)
+ {
+ $program[$name][] = array(
+ 'special' => 'gap',
+
+ 'fstart' => date('c', $daystart),
+ 'fend' => date('c', $start),
+
+ 'start' => $daystart,
+ 'end' => $start,
+ 'duration' => $start - $daystart,
+ );
+ }
+
+ $personnames = array();
+ foreach($event->persons->person as $person)
+ $personnames[] = (string)$person;
+
+ $program[$name][] = array(
+ 'title' => (string)$event->title,
+ 'speaker' => implode(', ', $personnames),
+
+ 'fstart' => date('c', $start),
+ 'fend' => date('c', $end),
+
+ 'start' => $start,
+ 'end' => $end,
+ 'duration' => $duration,
+ );
+
+ $lastend = $end;
+ }
+
+ // synthesize daychange event
+ if(!$lastend) $lastend = $daystart;
+ if($lastend < $dayend)
+ {
+ $program[$name][] = array(
+ 'special' => 'gap',
+
+ 'fstart' => date('c', $lastend),
+ 'fend' => date('c', $dayend),
+
+ 'start' => $lastend,
+ 'end' => $dayend,
+ 'duration' => $dayend - $lastend,
+ );
+ }
+
+ if($dayidx < count($schedule->day))
+ {
+ $program[$name][] = array(
+ 'special' => 'daychange',
+ 'title' => 'Daychange from Day '.$dayidx.' to '.($dayidx+1),
+
+ 'start' => $dayend,
+ 'end' => (int)$schedule->day[$dayidx]['start'],
+ 'duration' => 60*60,
+ );
+ }
+ }
+ }
+
+ if(has('SCHEDULE.CACHE') && function_exists('apc_store'))
+ {
+ apc_store(
+ 'SCHEDULE.CACHE',
+ $program,
+ get('SCHEDULE.CACHE')
+ );
+ }
+
+ return $program;
+ }
}
diff --git a/model/Stream.php b/model/Stream.php
index a60284a..402dfff 100644
--- a/model/Stream.php
+++ b/model/Stream.php
@@ -1,5 +1,177 @@
<?php
-class Room {
+class Stream
+{
+ public function __construct(Room $room, $selection, $language)
+ {
+ $this->room = $room;
+ $this->selection = $selection;
+ $this->language = $language;
+ }
+ public function getRoom()
+ {
+ return $this->room;
+ }
+
+ public function getSelection()
+ {
+ return $this->selection;
+ }
+
+ public function getLanguage()
+ {
+ return $this->language;
+ }
+
+ public function isTranslated()
+ {
+ return $this->getLanguage() == 'translated';
+ }
+
+ public function getVideoSize()
+ {
+ switch($this->getSelection())
+ {
+ case 'sd':
+ case 'slides':
+ return array(1024, 576);
+
+ case 'hd':
+ return array(1920, 1080);
+
+ default:
+ return null;
+ }
+ }
+
+ public function getVideoWidth()
+ {
+ $sz = $this->getVideoSize();
+ return $sz[0];
+ }
+
+ public function getVideoHeight()
+ {
+ $sz = $this->getVideoSize();
+ return $sz[1];
+ }
+
+ public function getTab()
+ {
+ switch($this->getSelection())
+ {
+ case 'sd':
+ case 'hd':
+ return 'video';
+
+ default:
+ return $this->getSelection();
+ }
+ }
+
+ public function getPlayerType()
+ {
+ return $this->getTab();
+ }
+
+ public function getDisplay()
+ {
+ $display = $this->getRoom()->getDisplay().' ';
+ switch($this->getSelection())
+ {
+ case 'hd':
+ $display .= 'FullHD Video';
+ break;
+
+ case 'sd':
+ $display .= 'SD Video';
+ break;
+
+ default:
+ $display .= ucfirst($this->getSelection());
+ break;
+ }
+
+ if($this->isTranslated())
+ $display .= ' (Translation)';
+
+ return $display;
+ }
+
+ public function getVideoUrl($proto)
+ {
+ switch($proto)
+ {
+ case 'webm':
+ return 'http://cdn.c3voc.de/'.rawurlencode($this->getRoom()->getStream()).'_'.rawurlencode($this->getLanguage()).'_'.rawurlencode($this->getSelection()).'.webm';
+
+ case 'hls':
+ return 'http://cdn.c3voc.de/hls/'.rawurlencode($this->getRoom()->getStream()).'_'.rawurlencode($this->getLanguage()).'_'.rawurlencode($this->getSelection()).'.m3u8';
+
+ default:
+ return null;
+ }
+ }
+ public static function getVideoProtos()
+ {
+ return array(
+ 'webm' => 'WebM',
+ 'hls' => 'HLS',
+ );
+ }
+
+ public function getSlidesUrl($proto)
+ {
+ return $this->getVideoUrl($proto);
+ }
+ public static function getSlidesProtos()
+ {
+ return Stream::getVideoProtos();
+ }
+
+
+ public function getAudioUrl($proto)
+ {
+ switch($proto)
+ {
+ case 'mp3':
+ return 'http://cdn.c3voc.de/'.rawurlencode($this->getRoom()->getStream()).'_'.rawurlencode($this->getLanguage()).'.mp3';
+
+ case 'opus':
+ return 'http://cdn.c3voc.de/'.rawurlencode($this->getRoom()->getStream()).'_'.rawurlencode($this->getLanguage()).'.opus';
+
+ default:
+ return null;
+ }
+ }
+ public static function getAudioProtos()
+ {
+ return array(
+ 'mp3' => 'MP3',
+ 'opus' => 'Opus',
+ );
+ }
+
+ public function getMusicUrl($proto)
+ {
+ switch($proto)
+ {
+ case 'mp3':
+ return 'http://cdn.c3voc.de/'.rawurlencode($this->getRoom()->getStream()).'.mp3';
+
+ case 'opus':
+ return 'http://cdn.c3voc.de/'.rawurlencode($this->getRoom()->getStream()).'.opus';
+
+ default:
+ return null;
+ }
+ }
+ public static function getMusicProtos()
+ {
+ return array(
+ 'mp3' => 'MP3',
+ 'opus' => 'Opus',
+ );
+ }
}
diff --git a/model/StreamList.php b/model/StreamList.php
deleted file mode 100644
index d203a52..0000000
--- a/model/StreamList.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-
-class StreamList extends ModelBase implements IteratorAggregate
-{
- private $streams = array();
-
- public function __construct($slug)
- {
- if(! $this->has('ROOMS.'.$slug))
- throw new NotFoundException('Room '.$slug);
-
- $this->slug = $slug;
- $this->streams = array();
-
- $streams = $this->get("ROOMS.$slug.STREAMS");
- foreach((array)$streams as $stream) {
- $this->streams[$stream] = explode('-', $stream);
- }
- }
-
- public function getRoomSlug() {
- return $this->slug;
- }
-
- public function getRoom() {
- return new Room($this->getRoomSlug());
- }
-
- public function getStreams() {
- return array_keys($this->streams);
- }
-
- public function getIterator() {
- return new ArrayIterator($this->streams);
- }
-
-
- public function hasTranslation() {
- }
-
- public function hasRTMP() {
- }
-
- public function hasHLS() {
- }
-
- public function hasWebM() {
- }
-
- public function hasHD() {
- }
-
- public function hasSD() {
- }
-}
diff --git a/template/assemblies/chat.phtml b/template/assemblies/chat.phtml
index 85245b2..8498c45 100644
--- a/template/assemblies/chat.phtml
+++ b/template/assemblies/chat.phtml
@@ -1,14 +1,15 @@
-<? if(room_has_irc($room)): ?>
+<? if($room->hasIrc()): ?>
<div>
- <a class="btn btn-primary irclink" href="<?=h(room_get_irc_url($room))?>" target="_blank">
- <span class="fa fa-comment"></span> <?=h(room_get_irc_display($room))?>
+ <a class="btn btn-primary irclink" href="<?=h($room->getIrcUrl())?>" target="_blank">
+ <span class="fa fa-comment"></span> <?=h($room->getIrcDisplay())?>
</a>
</div>
<? endif ?>
-<? if(room_has_twitter($room)): ?>
+
+<? if($room->hasTwitter($room)): ?>
<div>
- <a class="btn twitterlink" href="https://twitter.com/intent/tweet?text=<?=h(rawurlencode(room_get_twitter_hashtag($room)))?>" target="_blank">
- <span class="fa fa-twitter"></span> <?=h(room_get_twitter_display($room))?>
+ <a class="btn twitterlink" href="<?=h($room->getTwitterUrl())?>" target="_blank">
+ <span class="fa fa-twitter"></span> <?=h($room->getTwitterDisplay())?>
</a>
</div>
<? endif ?>
diff --git a/template/assemblies/player/audio.phtml b/template/assemblies/player/audio.phtml
index e007ab3..f8ed579 100644
--- a/template/assemblies/player/audio.phtml
+++ b/template/assemblies/player/audio.phtml
@@ -3,22 +3,12 @@
preload="auto"
style="width: 230px;"
>
- <? if(in_array("audio-mp3", $formats)): ?>
- <source
- src="<?=h(link_stream('audio', $room, 'mp3', @$translated))?>"
- type="audio/mp3"
- />
- <? endif ?>
- <? if(in_array("audio-opus", $formats)): ?>
- <source
- src="<?=h(link_stream('audio', $room, 'opus', @$translated))?>"
- type="audio/opus"
- />
- <? endif ?>
- <? if(in_array("audio-ogg", $formats)): ?>
- <source
- src="<?=h(link_stream('audio', $room, 'ogg', @$translated))?>"
- type="audio/ogg"
- />
- <? endif ?>
+ <source
+ src="<?=h($stream->getAudioUrl('mp3'))?>"
+ type="audio/mp3"
+ />
+ <source
+ src="<?=h($stream->getAudioUrl('opus'))?>"
+ type="audio/opus"
+ />
</audio>
diff --git a/template/assemblies/player/music.phtml b/template/assemblies/player/music.phtml
index 587d2d2..b1c804a 100644
--- a/template/assemblies/player/music.phtml
+++ b/template/assemblies/player/music.phtml
@@ -3,22 +3,12 @@
preload="auto"
style="width: 230px;"
>
- <? if(in_array("music-mp3", $formats)): ?>
- <source
- src="<?=h(link_stream('music', $room, 'mp3', @$translated))?>"
- type="audio/mp3"
- />
- <? endif ?>
- <? if(in_array("music-opus", $formats)): ?>
- <source
- src="<?=h(link_stream('music', $room, 'opus', @$translated))?>"
- type="audio/opus"
- />
- <? endif ?>
- <? if(in_array("music-ogg", $formats)): ?>
- <source
- src="<?=h(link_stream('music', $room, 'ogg', @$translated))?>"
- type="audio/ogg"
- />
- <? endif ?>
+ <source
+ src="<?=h($stream->getMusicUrl('mp3'))?>"
+ type="audio/mp3"
+ />
+ <source
+ src="<?=h($stream->getMusicUrl('opus'))?>"
+ type="audio/opus"
+ />
</audio>
diff --git a/template/assemblies/player/slides.phtml b/template/assemblies/player/slides.phtml
index c2720d6..7887aa0 100644
--- a/template/assemblies/player/slides.phtml
+++ b/template/assemblies/player/slides.phtml
@@ -1,28 +1,22 @@
-<div style="width: 100%; height: 100%; max-width: <?=h($width)?>px; margin: 0 auto;">
+<div style="max-width: <?=h($stream->getVideoWidth())?>px; max-height: <?=h($stream->getVideoHeight())?>px;" class="video-wrap">
<video
autoplay="autoplay"
preload="auto"
- width="<?=h($width)?>"
- height="<?=h($height)?>"
+ width="<?=h($stream->getVideoWidth())?>"
+ height="<?=h($stream->getVideoHeight())?>"
style="width: 100%; height: 100%;"
>
- <!--source
+ <source
data-plugin-type="native"
- src="<?=h(link_stream('webm', $room, 'webm_slides', $translated))?>"
+ src="<?=h($stream->getSlidesUrl('webm'))?>"
title="WebM (Icecast)"
type="video/webm"
- /-->
- <source
- data-plugin-type="flash"
- src="<?=h(link_stream('rtmp', $room, 'slides', $translated))?>"
- title="h.264 (RTMP)"
- type="video/rtmp"
/>
<source
data-plugin-type="native"
- src="<?=h(link_stream('hls', $room, 'slides', $translated))?>"
+ src="<?=h($stream->getSlidesUrl('hls'))?>"
title="h.264 (HLS)"
type="application/vnd.apple.mpegURL"
/>
</video>
-</div> \ No newline at end of file
+</div>
diff --git a/template/assemblies/player/video.phtml b/template/assemblies/player/video.phtml
index 0861cf8..3ffc333 100644
--- a/template/assemblies/player/video.phtml
+++ b/template/assemblies/player/video.phtml
@@ -1,34 +1,22 @@
-<div style="max-width: <?=h($width)?>px; max-height: <?=h($height)?>px;" class="video-wrap">
+<div style="max-width: <?=h($stream->getVideoWidth())?>px; max-height: <?=h($stream->getVideoHeight())?>px;" class="video-wrap">
<video
autoplay="autoplay"
preload="auto"
- width="<?=h($width)?>"
- height="<?=h($height)?>"
+ width="<?=h($stream->getVideoWidth())?>"
+ height="<?=h($stream->getVideoHeight())?>"
style="width: 100%; height: 100%;"
>
- <? if(in_array("webm-$selection", $formats)): ?>
- <source
- data-plugin-type="native"
- src="<?=h(link_stream('webm', $room, $selection, $translated))?>"
- title="WebM (Icecast)"
- type="video/webm"
- />
- <? endif ?>
- <? if(in_array("hls-$selection", $formats)): ?>
- <source
- data-plugin-type="native"
- src="<?=h(link_stream('hls', $room, $hlsformat, $translated))?>"
- title="h.264 (HLS)"
- type="application/vnd.apple.mpegURL"
- />
- <? endif ?>
- <? if(in_array("rtmp-$selection", $formats)): ?>
- <source
- data-plugin-type="flash"
- src="<?=h(link_stream('rtmp', $room, $selection, $translated))?>"
- title="h.264 (RTMP)"
- type="video/rtmp"
- />
- <? endif ?>
+ <source
+ data-plugin-type="native"
+ src="<?=h($stream->getVideoUrl('webm'))?>"
+ title="WebM (Icecast)"
+ type="video/webm"
+ />
+ <source
+ data-plugin-type="native"
+ src="<?=h($stream->getVideoUrl('hls'))?>"
+ title="h.264 (HLS)"
+ type="application/vnd.apple.mpegURL"
+ />
</video>
</div>
diff --git a/template/assemblies/switcher/audio.phtml b/template/assemblies/switcher/audio.phtml
index 53131d3..9f3ba76 100644
--- a/template/assemblies/switcher/audio.phtml
+++ b/template/assemblies/switcher/audio.phtml
@@ -1,5 +1,6 @@
<div class="container-fluid">
- <? if($has_translation): ?>
+ <? $selection = $room->createSelectionObject('audio') ?>
+ <? if($room->hasTranslation()): ?>
<h3>Audio</h3>
<div class="formats row">
@@ -7,11 +8,11 @@
<div class="btn-group" role="group">
<div class="btn btn-primary" disabled>Audio</div>
- <a href="<?=h(link_player($room, 'audio'))?>" class="btn btn-default">
+ <a href="<?=h($selection->getLink())?>" class="btn btn-default">
<span class="fa fa-flag-o"></span>
native
</a>
- <a href="<?=h(link_player($room, 'audio', true))?>" class="btn btn-default">
+ <a href="<?=h($selection->getTranslatedLink())?>" class="btn btn-default">
<span class="fa fa-flag"></span>
translated
</a>
@@ -23,35 +24,35 @@
<? endif ?>
- <h3>Directlinks</h3>
- <div class="formats row">
- <? foreach(array_intersect($formats, array('audio-mp3', 'audio-opus', 'audio-ogg')) as $format): ?>
- <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
- <? $proto = substr($format, 6) ?>
- <div class="btn-group" role="group" title="<?=h(get("FORMAT.$format"))?>">
- <div class="btn btn-primary" disabled><?=h(strtoupper($proto))?></div>
+ <div class="directlinks">
- <? if($has_translation): ?>
+ <? foreach(Stream::getAudioProtos() as $proto => $display): ?>
+ <h3>Directlinks (<?=h($display)?>)</h3>
+ <div class="row">
+ <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
+ <div class="btn-group" role="group">
+ <div class="btn btn-primary" disabled><?=h($selection->getDisplay())?></div>
+ <? if($room->hasTranslation()): ?>
- <a href="<?=h(link_stream('audio', $room, $proto))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject('audio', 'native')->getAudioUrl($proto))?>" class="btn btn-default">
<span class="fa fa-flag-o"></span>
native
</a>
- <a href="<?=h(link_stream('audio', $room, $proto, true))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject('audio', 'translated')->getAudioUrl($proto))?>" class="btn btn-default">
<span class="fa fa-flag"></span>
translated
</a>
<? else: ?>
- <a href="<?=h(link_stream('audio', $room, $proto))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject('audio')->getAudioUrl($proto))?>" class="btn btn-default">
<span class="fa fa-volume-up"></span>
- audio
+ video
</a>
<? endif ?>
-
+ </div>
</div>
</div>
<? endforeach ?>
diff --git a/template/assemblies/switcher/music.phtml b/template/assemblies/switcher/music.phtml
index df1fbf2..a6b3ffc 100644
--- a/template/assemblies/switcher/music.phtml
+++ b/template/assemblies/switcher/music.phtml
@@ -1,21 +1,20 @@
<div class="container-fluid">
<h3>Directlinks</h3>
- <div class="formats row">
+ <div class="directlinks">
+ <div class="row">
+ <? foreach(Stream::getMusicProtos() as $proto => $display): ?>
+ <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
+ <div class="btn-group" role="group">
+ <div class="btn btn-primary" disabled><?=h($display)?></div>
- <? foreach(array_intersect($formats, array('music-mp3', 'music-opus', 'music-ogg')) as $format): ?>
- <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
- <? $proto = substr($format, 6) ?>
- <div class="btn-group" role="group" title="<?=h(get("FORMAT.$format"))?>">
- <div class="btn btn-primary" disabled><?=h(strtoupper($proto))?></div>
-
- <a href="<?=h(link_stream('music', $room, $proto))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject('music')->getMusicUrl($proto))?>" class="btn btn-default">
<span class="fa fa-music"></span>
- music
+ live music
</a>
+ </div>
</div>
- </div>
- <? endforeach ?>
-
+ <? endforeach ?>
+ </div>
</div>
</div>
diff --git a/template/assemblies/switcher/slides.phtml b/template/assemblies/switcher/slides.phtml
index 7355da0..a5f5082 100644
--- a/template/assemblies/switcher/slides.phtml
+++ b/template/assemblies/switcher/slides.phtml
@@ -1,5 +1,6 @@
<div class="container-fluid">
- <? if($has_translation): ?>
+ <? $selection = $room->createSelectionObject('audio') ?>
+ <? if($room->hasTranslation()): ?>
<h3>Slides</h3>
<div class="formats row">
@@ -7,11 +8,11 @@
<div class="btn-group" role="group">
<div class="btn btn-primary" disabled>Slides</div>
- <a href="<?=h(link_player($room, 'slides'))?>" class="btn btn-default">
+ <a href="<?=h($selection->getLink())?>" class="btn btn-default">
<span class="fa fa-flag-o"></span>
native
</a>
- <a href="<?=h(link_player($room, 'slides', true))?>" class="btn btn-default">
+ <a href="<?=h($selection->getTranslatedLink())?>" class="btn btn-default">
<span class="fa fa-flag"></span>
translated
</a>
@@ -22,38 +23,39 @@
</div>
<? endif ?>
- <h3>Directlinks</h3>
- <div class="formats row">
- <? foreach(array_intersect($protos, array('rtmp', 'hls')) as $proto): ?>
- <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
- <div class="btn-group" role="group" title="<?=h(get("FORMAT.slides"))?>">
- <div class="btn btn-primary" disabled><?=h(strtoupper($proto))?></div>
- <? if($has_translation): ?>
+ <div class="directlinks">
- <a href="<?=h(link_stream($proto, $room, 'slides'))?>" class="btn btn-default">
- <span class="fa fa-flag-o"></span>
- native
- </a>
- <a href="<?=h(link_stream($proto, $room, 'slides', true))?>" class="btn btn-default">
- <span class="fa fa-flag"></span>
- translated
- </a>
+ <? foreach(Stream::getSlidesProtos() as $proto => $display): ?>
+ <h3>Directlinks (<?=h($display)?>)</h3>
+ <div class="row">
+ <div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
+ <div class="btn-group" role="group" title="<?=h(get("FORMAT.slides"))?>">
+ <div class="btn btn-primary" disabled><?=h($selection->getDisplay())?></div>
+ <? if($room->hasTranslation()): ?>
- <? else: ?>
+ <a href="<?=h($room->createStreamObject('slides', 'native')->getSlidesUrl($proto))?>" class="btn btn-default">
+ <span class="fa fa-flag-o"></span>
+ native
+ </a>
+ <a href="<?=h($room->createStreamObject('slides', 'translated')->getSlidesUrl($proto))?>" class="btn btn-default">
+ <span class="fa fa-flag"></span>
+ translated
+ </a>
- <a href="<?=h(link_stream($proto, $room, 'slides'))?>" class="btn btn-default">
- <span class="fa fa-picture-o"></span>
- slides
- </a>
+ <? else: ?>
- <? endif ?>
+ <a href="<?=h($room->createStreamObject('slides')->getSlidesUrl($proto))?>" class="btn btn-default">
+ <span class="fa fa-picture-o"></span>
+ slides
+ </a>
+ <? endif ?>
+ </div>
</div>
</div>
<? endforeach ?>
</div>
-
</div> \ No newline at end of file
diff --git a/template/assemblies/switcher/video.phtml b/template/assemblies/switcher/video.phtml
index 5a35657..c0429d3 100644
--- a/template/assemblies/switcher/video.phtml
+++ b/template/assemblies/switcher/video.phtml
@@ -2,25 +2,26 @@
<h3>Video</h3>
<div class="formats row">
- <? foreach($videores as $iter): ?>
+ <? foreach($room->getVideoResolutions() as $res): ?>
+ <? $selection = $room->createSelectionObject($res) ?>
<div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
<div class="btn-group" role="group">
- <div class="btn btn-primary" disabled><?=h(strtoupper($iter))?></div>
+ <div class="btn btn-primary" disabled><?=h($selection->getDisplay())?></div>
- <? if($has_translation): ?>
+ <? if($room->hasTranslation()): ?>
- <a href="<?=h(link_player($room, $iter))?>" class="btn btn-default">
+ <a href="<?=h($selection->getLink())?>" class="btn btn-default">
<span class="fa fa-flag-o"></span>
native
</a>
- <a href="<?=h(link_player($room, $iter, true))?>" class="btn btn-default">
+ <a href="<?=h($selection->getTranslatedLink())?>" class="btn btn-default">
<span class="fa fa-flag"></span>
translated
</a>
<? else: ?>
- <a href="<?=h(link_player($room, $iter))?>" class="btn btn-default">
+ <a href="<?=h($selection->getLink())?>" class="btn btn-default">
<span class="fa fa-video-camera"></span>
video
</a>
@@ -37,30 +38,28 @@
</div>
<div class="directlinks">
-
- <? foreach($protos as $proto): ?>
- <h3>Directlinks (<?=h(strtoupper($proto))?>)</h3>
+ <? foreach(Stream::getVideoProtos() as $proto => $display): ?>
+ <h3>Directlinks (<?=h($display)?>)</h3>
<div class="row">
- <? foreach($formats as $format): ?>
- <? if(!startswith($proto, $format)) continue ?>
- <? $res = substr($format, -2) ?>
+ <? foreach($room->getVideoResolutions() as $res): ?>
+ <? $selection = $room->createSelectionObject($res) ?>
<div class="col-lg-3 col-md-4 col-lg-5 col-xs-12">
- <div class="btn-group" role="group" title="<?=h(get("FORMAT.$format"))?>">
- <div class="btn btn-primary" disabled><?=h(strtoupper($res))?></div>
- <? if($has_translation): ?>
+ <div class="btn-group" role="group">
+ <div class="btn btn-primary" disabled><?=h($selection->getDisplay())?></div>
+ <? if($room->hasTranslation()): ?>
- <a href="<?=h(link_stream($proto, $room, $res))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject($res, 'native')->getVideoUrl($proto))?>" class="btn btn-default">
<span class="fa fa-flag-o"></span>
native
</a>
- <a href="<?=h(link_stream($proto, $room, $res, true))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject($res, 'translated')->getVideoUrl($proto))?>" class="btn btn-default">
<span class="fa fa-flag"></span>
translated
</a>
<? else: ?>
- <a href="<?=h(link_stream($proto, $room, $res))?>" class="btn btn-default">
+ <a href="<?=h($room->createStreamObject($res)->getVideoUrl($proto))?>" class="btn btn-default">
<span class="fa fa-video-camera"></span>
video
</a>
@@ -71,6 +70,5 @@
<? endforeach ?>
</div>
<? endforeach ?>
-
</div>
</div>
diff --git a/template/page.phtml b/template/page.phtml
index 58f502c..cb79c16 100644
--- a/template/page.phtml
+++ b/template/page.phtml
@@ -27,7 +27,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="<?=h($baseurl)?>" />
- <link href="<?=h($baseurl.forceslash($GLOBALS['ROUTE']))?>" rel="canonical" />
+ <link href="<?=h($baseurl.forceslash($route))?>" rel="canonical" />
<link href="assets/img/apple-touch-icon/76x76.png" rel="apple-touch-icon" />
<link href="assets/img/apple-touch-icon/76x76.png" rel="apple-touch-icon" sizes="76x76" />
diff --git a/template/room.phtml b/template/room.phtml
index 416629b..25a7255 100644
--- a/template/room.phtml
+++ b/template/room.phtml
@@ -1,17 +1,17 @@
-<div class="container <?=h($tab)?> <?=h($selection)?> <?=h($language)?>">
+<div class="container <?=h($stream->getTab())?> <?=h($stream->getSelection())?> <?=h($stream->getLanguage())?>">
<div class="row headline">
<div class="col-xs-12">
- <h1 data-room="<?=h(get("ROOMS.$room.DISPLAY"))?>"><?=h($title)?></h1>
+ <h1 data-room="<?=h($room->getDisplay())?>"><?=h($stream->getDisplay())?></h1>
</div>
</div>
<ul class="nav nav-player nav-tabs nav-justified">
- <? foreach($tabs as $iter): ?>
+ <? foreach($room->getTabs() as $tab): ?>
<li
- <? if($tab == $iter):?>class="active"<? endif ?>
+ <? if($tab->getTab() == $stream->getTab()): ?>class="active"<? endif ?>
>
- <a href="<?=h(link_player($room, $iter))?>">
- <?=h(ucfirst($iter))?>
+ <a href="<?=h($tab->getLink())?>">
+ <?=h($tab->getDisplay())?>
</a>
</li>
<? endforeach ?>
@@ -19,7 +19,7 @@
<div class="player-wrap tab-content">
<div role="tabpanel" class="tab-pane active">
- <? include("$assemblies/player/$tab.phtml") ?>
+ <? require("$assemblies/player/".$stream->getPlayerType().".phtml") ?>
</div>
</div>
@@ -27,17 +27,17 @@
<li class="active">
<a href="#switcher" role="tab" data-toggle="tab">Formats</a>
</li>
- <? if(room_has_chat($room)): ?>
+ <? if($room->hasChat()): ?>
<li>
<a href="#chat" role="tab" data-toggle="tab">Chat</a>
</li>
<? endif ?>
- <? if(get("ROOMS.$room.SCHEDULE") && has("SCHEDULE")): ?>
+ <? if($room->hasSchedule()): ?>
<li>
- <a href="#program" role="tab" data-toggle="tab">Program</a>
+ <a href="#schedule" role="tab" data-toggle="tab">Schedule</a>
</li>
<? endif ?>
- <? if(get("ROOMS.$room.FEEDBACK") && has("FEEDBACK")): ?>
+ <? if($room->hasFeedback()): ?>
<li>
<a href="#feedback" role="tab" data-toggle="tab">Feedback</a>
</li>
@@ -46,21 +46,21 @@
<div class="functions-wrap tab-content">
<div role="tabpanel" class="tab-pane active" id="switcher">
- <? include("$assemblies/switcher/$tab.phtml") ?>
+ <? require("$assemblies/switcher/".$stream->getPlayerType().".phtml") ?>
</div>
- <? if(room_has_chat($room)): ?>
+ <? if($room->hasChat()): ?>
<div role="tabpanel" class="tab-pane" id="chat">
- <? include("$assemblies/chat.phtml") ?>
+ <? require("$assemblies/chat.phtml") ?>
</div>
<? endif ?>
- <? if(get("ROOMS.$room.SCHEDULE") && has("SCHEDULE")): ?>
+ <? if($room->hasSchedule()): ?>
<div role="tabpanel" class="tab-pane" id="program">
- <? include("$assemblies/program.phtml") ?>
+ <? require("$assemblies/program.phtml") ?>
</div>
<? endif ?>
- <? if(get("ROOMS.$room.FEEDBACK") && has("FEEDBACK")): ?>
+ <? if($room->hasFeedback()): ?>
<div role="tabpanel" class="tab-pane" id="feedback">
- <? include("$assemblies/feedback.phtml") ?>
+ <? require("$assemblies/feedback.phtml") ?>
</div>
<? endif ?>
</div>
diff --git a/view/room.php b/view/room.php
index 4484a14..505be95 100644
--- a/view/room.php
+++ b/view/room.php
@@ -1,121 +1,15 @@
<?php
-$room = $_GET['room'];
-$language = $_GET['language'];
-$selection = $_GET['selection'];
-
-if(!has("ROOMS.$room"))
- return include('pages/404.php');
-
-$formats = get("ROOMS.$room.FORMATS");
-$has_translation = get("ROOMS.$room.TRANSLATION");
-
-$protos = array();
-$selections = array();
-$tabs = array();
-$videores = array();
-
-if(room_has_hd($room))
- $selections[] = $videores[] = 'hd';
-
-if(room_has_sd($room))
- $selections[] = $videores[] = 'sd';
-
-if(room_has_video($room))
- $tabs[] = 'video';
-
-
-if(room_has_audio($room))
- $selections[] = $tabs[] = 'audio';
-
-if(room_has_music($room))
- $selections[] = $tabs[] = 'music';
-
-if(room_has_slides($room))
- $selections[] = $tabs[] = 'slides';
-
-
-if(room_has_rtmp($room))
- $protos[] = 'rtmp';
-
-if(room_has_webm($room))
- $protos[] = 'webm';
-
-if(room_has_hls($room))
- $protos[] = 'hls';
-
-
-
-// default page
-if(!$selection)
- $selection = $selections[0];
-
-if(!in_array($selection, $selections))
- return include('pages/404.php');
-
-
-
-switch($selection) {
- case 'audio':
- $tab = 'audio';
- $title = 'Audio';
- break;
-
- case 'music':
- $tab = 'music';
- $title = 'Music';
- break;
-
- case 'slides':
- $tab = 'slides';
- $title = 'Slides';
- $width = 1024;
- $height = 576;
- break;
-
- case 'hd':
- $tab = 'video';
- $title = 'FullHD Video';
- $width = 1920;
- $height = 1080;
- break;
-
- case 'sd':
- $tab = 'video';
- $title = 'SD Video';
- $width = 1024;
- $height = 576;
- break;
-}
-
-if($language == 'translated')
-{
- if(!$has_translation)
- return include('pages/404.php');
-
- $title = 'Translated '.$title;
-}
+$room = new Room($_GET['room']);
+$stream = $room->selectStream(
+ $_GET['selection'], $_GET['language']);
echo $tpl->render(array(
'page' => 'room',
- 'title' => get("ROOMS.$room.DISPLAY").' – '.$title,
+ 'title' => $stream->getDisplay(),
'room' => $room,
+ 'stream' => $stream,
- 'program' => program(),
-
- 'tab' => $tab,
- 'tabs' => $tabs,
-
- 'width' => @$width,
- 'height' => @$height,
- 'language' => $language,
- 'translated' => ($language == 'translated'),
- 'selection' => $selection,
- 'hlsformat' => ($selection == 'hd' ? 'auto' : $selection),
-
- 'has_translation' => $has_translation,
- 'formats' => $formats,
- 'protos' => $protos,
- 'videores' => $videores,
+ 'schedule' => new Schedule(),
));