mirror of
https://github.com/voc/streaming-website
synced 2024-11-10 06:34:17 +00:00
487 lines
12 KiB
PHP
487 lines
12 KiB
PHP
<?php
|
|
|
|
class Room
|
|
{
|
|
private $guid;
|
|
private $slug;
|
|
private $conference;
|
|
private $talks;
|
|
|
|
public function __construct(Conference $conference, $slug)
|
|
{
|
|
$this->conference = $conference;
|
|
|
|
if(preg_match('/[^a-z0-9_\-]/i', $slug))
|
|
throw new Exception('Room Slug contains invalid Characters: "'.$slug.'"');
|
|
|
|
if(!$this->getConference()->hasRoom($slug))
|
|
throw new NotFoundException('Room '.$slug);
|
|
|
|
$this->slug = $slug;
|
|
$this->guid = $this->get('GUID');
|
|
|
|
$schedule = $conference->getSchedule();
|
|
$talksPerRoom = $schedule->getSchedule();
|
|
$scheduleName = $this->getScheduleName();
|
|
|
|
$this->talks = isset($talksPerRoom[$scheduleName]) ? $talksPerRoom[$scheduleName] : [];
|
|
}
|
|
|
|
public function getCurrentTalk($now)
|
|
{
|
|
return array_filter_last($this->talks, function($talk) use ($now) {
|
|
return $talk['start'] < $now && $talk['end'] > $now;
|
|
});
|
|
}
|
|
|
|
public function getNextTalk($now)
|
|
{
|
|
return array_filter_first($this->talks, function($talk) use ($now) {
|
|
return !isset($talk['special']) && $talk['start'] > $now;
|
|
});
|
|
}
|
|
|
|
public function getConference() {
|
|
return $this->conference;
|
|
}
|
|
|
|
public function getId() {
|
|
return $this->guid;
|
|
}
|
|
|
|
public function getSlug() {
|
|
if ($this->slug != NULL) {
|
|
return $this->slug;
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
private function get($key, $fallbackValue = null) {
|
|
$keychain = 'ROOMS.'.$this->getSlug().'.'.$key;
|
|
$fallback = null;
|
|
if (isset($GLOBALS['CONFIG']['ROOM_DEFAULTS'][$key])) {
|
|
$fallback = $GLOBALS['CONFIG']['ROOM_DEFAULTS'][$key];
|
|
}
|
|
return $this->conference->get($keychain, $fallbackValue ?: $fallback);
|
|
}
|
|
|
|
private function has($key) {
|
|
return $this->conference->has('ROOMS.'.$this->getSlug().'.'.$key);
|
|
}
|
|
|
|
public function getThumb() {
|
|
if ($this->conference->has('cdn.thumbnail_url')) {
|
|
return str_replace('{streamId}', $this->getStream(), $this->conference->get('cdn.thumbnail_url'));
|
|
}
|
|
return proto().'://'.joinpath([$GLOBALS['CONFIG']['CDN'], 'thumbnail', $this->getStream(), 'thumb.jpeg']);
|
|
}
|
|
|
|
public function getPoster() {
|
|
if ($this->conference->has('cdn.poster_url')) {
|
|
return str_replace('{streamId}', $this->getStream(), $this->conference->get('cdn.poster_url'));
|
|
}
|
|
return proto().'://'.joinpath([$GLOBALS['CONFIG']['CDN'], 'thumbnail', $this->getStream(), 'poster.jpeg']);
|
|
}
|
|
|
|
public function getLink() {
|
|
return joinpath([$this->getConference()->getSlug(), $this->getSlug()]).url_params();
|
|
}
|
|
|
|
public function getStream() {
|
|
return $this->get('STREAM') ?: $this->get('streamId') ?: $this->getSlug();
|
|
}
|
|
|
|
public function getScheduleName() {
|
|
return $this->get('SCHEDULE_NAME') ?: $this->get('name') ?: $this->getDisplay();
|
|
}
|
|
|
|
public function getDisplay() {
|
|
return $this->get('DISPLAY') ?: $this->get('name') ?: $this->getSlug();
|
|
}
|
|
|
|
public function getDisplayShort() {
|
|
$display_short = $this->get('DISPLAY_SHORT', '');
|
|
if (empty($display_short)) {
|
|
return $this->getDisplay(); // getDisplay() falls back to slug
|
|
}
|
|
else {
|
|
return $display_short;
|
|
}
|
|
}
|
|
|
|
public function h264Only() {
|
|
return $this->get('H264_ONLY');
|
|
}
|
|
|
|
public function hasStereo() {
|
|
return $this->get('STEREO');
|
|
}
|
|
|
|
public function hasPreview() {
|
|
return $this->get('PREVIEW', true);
|
|
}
|
|
|
|
public function requestsWide() {
|
|
return $this->get('WIDE');
|
|
}
|
|
|
|
public function hasSchedule() {
|
|
return $this->get('SCHEDULE', true) && $this->getConference()->has('SCHEDULE');
|
|
}
|
|
|
|
public function hasSubtitles() {
|
|
return
|
|
$this->get('SUBTITLES') &&
|
|
$this->has('SUBTITLES_ROOM_ID') &&
|
|
$this->getConference()->has('SUBTITLES');
|
|
}
|
|
public function getSubtitlesRoomId() {
|
|
return $this->get('SUBTITLES_ROOM_ID');
|
|
}
|
|
|
|
public function hasFeedback() {
|
|
return $this->get('FEEDBACK') && $this->getConference()->hasFeedback();
|
|
}
|
|
|
|
|
|
public function hasTwitter() {
|
|
return $this->get('TWITTER') && $this->getConference()->has('TWITTER');
|
|
}
|
|
|
|
public function getTwitterDisplay() {
|
|
return sprintf(
|
|
$this->get('TWITTER_CONFIG.DISPLAY', $this->getConference()->get('TWITTER.DISPLAY')),
|
|
$this->getSlug()
|
|
);
|
|
}
|
|
|
|
public function getTwitterUrl() {
|
|
return sprintf(
|
|
'https://twitter.com/search?f=tweets&q=%s',
|
|
rawurlencode($this->getTwitterText())
|
|
);
|
|
}
|
|
|
|
public function getTwitterText() {
|
|
return sprintf(
|
|
$this->get('TWITTER_CONFIG.TEXT') ?: $this->getConference()->get('TWITTER.TEXT') ?: $this->getHashtag(),
|
|
$this->getSlug()
|
|
);
|
|
}
|
|
|
|
public function hasMastodon() {
|
|
return $this->get('social.mastodon') && $this->getConference()->get('social') !== false;
|
|
}
|
|
|
|
public function getMastodonUrl() {
|
|
return sprintf(
|
|
'https://chaos.social/tags/%s',
|
|
substr($this->getHashtag(), 1)
|
|
);
|
|
}
|
|
|
|
public function getHashtag() {
|
|
return sprintf(
|
|
$this->get('social.hashtag') ?: $this->getConference()->get('social.hashtag'),
|
|
$this->getSlug()
|
|
);
|
|
}
|
|
|
|
public function hasMatrix() {
|
|
return $this->get('chat.matrix') && $this->getConference()->has('chat');
|
|
}
|
|
|
|
public function getMatrixDisplay() {
|
|
return sprintf(
|
|
$this->get('chat.matrix.display') ?: $this->getConference()->get('chat.matrix.display'),
|
|
$this->getSlug()
|
|
);
|
|
}
|
|
|
|
public function getMatrixUrl() {
|
|
return sprintf(
|
|
$this->get('chat.matrix.url') ?: $this->getConference()->get('chat.matrix.url'),
|
|
rawurlencode($this->getSlug())
|
|
);
|
|
}
|
|
|
|
|
|
public function hasIrc() {
|
|
$irc = $this->get('IRC');
|
|
return $this->getConference()->has('IRC') && (is_array($irc) ? count($irc) : $irc);
|
|
}
|
|
|
|
public function getIrcDisplay() {
|
|
return sprintf(
|
|
$this->get('IRC_CONFIG.DISPLAY') ?: $this->get('irc.display') ?: $this->getConference()->get('IRC.DISPLAY'),
|
|
$this->getSlug()
|
|
);
|
|
}
|
|
|
|
public function getIrcUrl() {
|
|
return sprintf(
|
|
$this->get('IRC_CONFIG.URL') ?: $this->get('irc.url') ?: $this->getConference()->get('IRC.URL'),
|
|
rawurlencode($this->getSlug())
|
|
);
|
|
}
|
|
|
|
public function hasWebchat() {
|
|
return $this->get('WEBCHAT') && $this->getConference()->has('WEBCHAT_URL');
|
|
}
|
|
|
|
public function getWebchatUrl() {
|
|
return sprintf(
|
|
$this->get('WEBCHAT_URL', $this->getConference()->get('WEBCHAT_URL')),
|
|
rawurlencode($this->getSlug())
|
|
);
|
|
}
|
|
|
|
public function hasChat() {
|
|
$chat = $this->get('CHAT');
|
|
return ((is_array($chat) ? count($chat) : $chat) && $this->getConference()->has('CHAT'))
|
|
|| $this->hasIrc() || $this->hasWebchat() || $this->hasTwitter();
|
|
}
|
|
|
|
public function hasEmbed() {
|
|
return $this->get('EMBED') && $this->getConference()->get('EMBED');
|
|
}
|
|
|
|
public function hasInfo() {
|
|
return $this->get('INFO') && $this->getConference()->get('INFO');
|
|
}
|
|
|
|
public function getInfo() {
|
|
return $this->get('INFO');
|
|
}
|
|
|
|
public function hasSdVideo() {
|
|
return $this->get('SD_VIDEO');
|
|
}
|
|
|
|
public function hasHdVideo() {
|
|
return $this->get('HD_VIDEO');
|
|
}
|
|
|
|
public function hasAudio() {
|
|
return $this->get('AUDIO') && $this->getConference()->get('AUDIO') !== FALSE;
|
|
}
|
|
|
|
public function hasSlides() {
|
|
return $this->get('SLIDES');
|
|
}
|
|
|
|
public function hasMusic() {
|
|
return $this->get('MUSIC');
|
|
}
|
|
|
|
public function hasDash() {
|
|
return $this->get('DASH', true);
|
|
}
|
|
|
|
public function hasCustomStreamingUrl() {
|
|
return $this->conference->has('cdn.hls_playlist_url');
|
|
}
|
|
|
|
public function getHLSPlaylistUrl() {
|
|
if ($this->conference->has('cdn.hls_playlist_url')) {
|
|
return str_replace('{streamId}', rawurlencode($this->getStream()), $this->conference->get('cdn.hls_playlist_url'));
|
|
}
|
|
return proto().'://'.joinpath([$GLOBALS['CONFIG']['CDN'], 'hls', rawurlencode($this->getStream()).'/native_hd.m3u8']);
|
|
}
|
|
|
|
public function getDashManifestUrl() {
|
|
if ($this->conference->has('cdn.dash_manifest_url')) {
|
|
return str_replace('{streamId}', rawurlencode($this->getStream()), $this->conference->get('cdn.dash_manifest_url'));
|
|
}
|
|
return proto().'://'.joinpath([$GLOBALS['CONFIG']['CDN'], 'dash', rawurlencode($this->getStream()).'/manifest.mpd']);
|
|
}
|
|
|
|
public function getDashTech() {
|
|
return 'Adaptive multi-format-multi-bitrate-Stream to rule the World!!1elf';
|
|
}
|
|
|
|
public function getTranslations() {
|
|
return $this->get('TRANSLATION') ?: [];
|
|
}
|
|
|
|
private function getTranslationEndpoints() {
|
|
return array_map(
|
|
function ($translation) {
|
|
return $translation['endpoint'];
|
|
},
|
|
$this->getTranslations()
|
|
);
|
|
}
|
|
|
|
private function isTranslationEndpoint($endpoint) {
|
|
return in_array($endpoint, $this->getTranslationEndpoints());
|
|
}
|
|
|
|
private function findTranslationLabel($language) {
|
|
foreach($this->getTranslations() as $translation) {
|
|
if ($translation['endpoint'] === $language) {
|
|
return $translation['label'];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function hasTranslation() {
|
|
return count($this->getTranslations()) > 0;
|
|
}
|
|
|
|
public function isValidLanguage($language) {
|
|
return ($language === 'native' || $this->isTranslationEndpoint($language));
|
|
}
|
|
|
|
public function getSelectionNames()
|
|
{
|
|
$selections = array();
|
|
if($this->hasDash())
|
|
if($this->h264Only())
|
|
$selections[] = 'hls';
|
|
else
|
|
$selections[] = 'dash';
|
|
|
|
if($this->hasAudio())
|
|
$selections[] = 'audio';
|
|
|
|
if($this->hasMusic())
|
|
$selections[] = 'music';
|
|
|
|
if($this->hasSlides())
|
|
$selections[] = 'slides';
|
|
|
|
return $selections;
|
|
}
|
|
|
|
public function isSelectionTranslated($selection) {
|
|
# dash is special, has langs included
|
|
return $selection !== 'dash' && $selection !== 'music';
|
|
}
|
|
|
|
public function getTabNames()
|
|
{
|
|
$tabs = array();
|
|
if($this->hasDash())
|
|
$tabs[] = 'dash';
|
|
|
|
if($this->hasAudio())
|
|
$tabs[] = 'audio';
|
|
|
|
if($this->hasMusic())
|
|
$tabs[] = 'music';
|
|
|
|
if($this->hasSlides())
|
|
$tabs[] = 'slides';
|
|
|
|
return $tabs;
|
|
}
|
|
|
|
public function getSelections()
|
|
{
|
|
$selections = array();
|
|
foreach($this->getSelectionNames() as $selection)
|
|
$selections[$selection] = $this->createSelectionObject($selection);
|
|
|
|
return $selections;
|
|
}
|
|
|
|
public function createSelectionObject($selection = null)
|
|
{
|
|
if(!$selection)
|
|
{
|
|
$selections = $this->getSelectionNames();
|
|
$selection = $selections[0];
|
|
}
|
|
|
|
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 = null)
|
|
{
|
|
if(!$tab)
|
|
{
|
|
$tabs = $this->getTabNames();
|
|
$tab = $tabs[0];
|
|
}
|
|
|
|
return new RoomTab($this, $tab);
|
|
}
|
|
|
|
public function getVideoResolutions()
|
|
{
|
|
$res = array();
|
|
if($this->hasHdVideo())
|
|
$res[] = 'hd';
|
|
|
|
if($this->hasSdVideo())
|
|
$res[] = 'sd';
|
|
|
|
return $res;
|
|
}
|
|
|
|
public function getStreams()
|
|
{
|
|
$selections = $this->getSelectionNames();
|
|
$selections[] = "hd";
|
|
$streams = array();
|
|
|
|
foreach ($selections as $selection) {
|
|
$streams[] = $this->createStreamObject($selection, 'native');
|
|
|
|
if ($this->isSelectionTranslated($selection)) {
|
|
foreach ($this->getTranslations() as $translation) {
|
|
$streams[] = $this->createStreamObject($selection, $translation['endpoint'], $translation['label']);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $streams;
|
|
}
|
|
|
|
public function selectStream($selection, $language = 'native')
|
|
{
|
|
if($selection == 'video') $selection = 'hd';
|
|
$selections = $this->getSelectionNames();
|
|
|
|
if(count($selections) == 0)
|
|
throw new NotFoundException('No Streams activated');
|
|
|
|
// default page
|
|
if(!$selection)
|
|
$selection = $selections[0];
|
|
|
|
if(!in_array($selection, $selections))
|
|
throw new NotFoundException('Selection '.$selection.' in Room '.$this->getSlug());
|
|
|
|
$translation_label = null;
|
|
if ($language !== 'native') {
|
|
if (! $this->hasTranslation()) {
|
|
throw new NotFoundException('Translated Streams of Room '. $this->getSlug());
|
|
}
|
|
if (! $this->isValidLanguage($language)) {
|
|
throw new NotFoundException('Selected translation');
|
|
}
|
|
|
|
$translation_label = $this->findTranslationLabel($language);
|
|
}
|
|
|
|
return $this->createStreamObject($selection, $language, $translation_label);
|
|
}
|
|
|
|
public function createStreamObject($selection, $language = 'native', $languageLabel = null)
|
|
{
|
|
return new Stream($this, $selection, $language, $languageLabel);
|
|
}
|
|
}
|