From f7d9d592745d1cb5cb2de76ed6ae99be974f1807 Mon Sep 17 00:00:00 2001 From: MaZderMind Date: Mon, 30 Mar 2015 16:20:30 +0200 Subject: Implement MVT Pattern based on simple Config options --- config.php | 125 ++++++------------- index.php | 4 + lib/helper.php | 174 --------------------------- lib/program.php | 168 -------------------------- model/Relive.php | 24 ++++ model/Room.php | 193 +++++++++++++++++++++++++++++- model/RoomSelection.php | 52 ++++++++ model/RoomTab.php | 34 ++++++ model/Schedule.php | 173 ++++++++++++++++++++++++++ model/Stream.php | 174 ++++++++++++++++++++++++++- model/StreamList.php | 55 --------- template/assemblies/chat.phtml | 13 +- template/assemblies/player/audio.phtml | 26 ++-- template/assemblies/player/music.phtml | 26 ++-- template/assemblies/player/slides.phtml | 20 ++-- template/assemblies/player/video.phtml | 42 +++---- template/assemblies/switcher/audio.phtml | 33 ++--- template/assemblies/switcher/music.phtml | 23 ++-- template/assemblies/switcher/slides.phtml | 52 ++++---- template/assemblies/switcher/video.phtml | 36 +++--- template/page.phtml | 2 +- template/room.phtml | 36 +++--- view/room.php | 118 +----------------- 23 files changed, 833 insertions(+), 770 deletions(-) delete mode 100644 lib/program.php create mode 100644 model/Relive.php create mode 100644 model/RoomSelection.php create mode 100644 model/RoomTab.php delete mode 100644 model/StreamList.php diff --git a/config.php b/config.php index 1cf3891..2ae2aca 100644 --- a/config.php +++ b/config.php @@ -129,20 +129,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 @@ -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__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 @@ 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 @@ - 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 @@ + 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 @@ +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 @@ +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 @@ 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 @@ -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 @@ - +hasIrc()): ?>
- - + + getIrcDisplay())?>
- + +hasTwitter($room)): ?>
-
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;" > - - - - - - - - - + + 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;" > - - - - - - - - - + + 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 @@ -
+
-
\ No newline at end of file +
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 @@ -
+
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 @@
- + createSelectionObject('audio') ?> + hasTranslation()): ?>

Audio

@@ -7,11 +8,11 @@
Audio
- + native - + translated @@ -23,35 +24,35 @@ -

Directlinks

-
- -
- -
"> -
+