'audio/ogg', 'ogg' => 'audio/ogg', 'mp3' => 'audio/mpeg', 'caf' => 'audio/x-caf', 'wav' => 'audio/wav', ]); header('X-Powered-By: Futami'); header('Cache-Control: max-age=86400, must-revalidate'); header('Access-Control-Allow-Origin: *'); $reqMethod = (string)filter_input(INPUT_SERVER, 'REQUEST_METHOD'); if($reqMethod === 'OPTIONS') { http_response_code(204); header('Access-Control-Allow-Methods: OPTIONS, GET'); header('Access-Control-Allow-Headers: Cache-Control'); return; } if($reqMethod !== 'HEAD' && $reqMethod !== 'GET') { http_response_code(405); return; } function json_out($data): void { header('Content-Type: application/json; charset=utf-8'); echo json_encode($data); exit; } function match_etag($eTag): void { if(filter_input(INPUT_SERVER, 'HTTP_IF_NONE_MATCH') === $eTag) { http_response_code(304); exit; } } function gen_etag(string $user, string $data): string { return sprintf('W/"%s-%s"', hash('sha1', $data), $user); } function gen_etag_file(string $user, string $path): string { return gen_etag($user, hash_file('sha1', $path)); } function etag(string $etag): void { match_etag($etag); header('ETag: ' . $etag); } function etag_data(string $user, string $data): void { etag(gen_etag($user, $data)); } function etag_file(string $user, string $path): void { etag(gen_etag_file($user, $path)); } $reqPath = '/' . trim(parse_url((string)filter_input(INPUT_SERVER, 'REQUEST_URI'), PHP_URL_PATH), '/'); if($reqPath === '/common.json') { $commonPath = FTM_PATH_PRV . '/common.ini'; etag_file('common', $commonPath); $common = parse_ini_file($commonPath, false, INI_SCANNER_TYPED); $colours = $common['colours']; $common['colours'] = []; foreach($colours as $n => $c) $common['colours'][] = compact('n', 'c'); json_out($common); } if($reqPath === '/sounds.json') { $sndLibData = file_get_contents(FTM_PATH_PRV . '/sound-library.ini'); $sndPackData = file_get_contents(FTM_PATH_PRV . '/sound-packs.ini'); etag_data('sounds', $sndLibData . $sndPackData); $sndLib = parse_ini_string($sndLibData, true, INI_SCANNER_TYPED); $sndPacks = parse_ini_string($sndPackData, true, INI_SCANNER_TYPED); $library = []; foreach($sndLib as $name => $info) { $sources = []; foreach($info['sources'] as $type => $path) { $sources[] = [ 'format' => FTM_LEGACY_SOUND_TYPE[$type], 'url' => $path, ]; } $library[] = [ 'id' => $name, 'name' => $info['title'], 'sources' => $sources, ]; } $packs = []; foreach($sndPacks as $name => $info) { $packs[] = [ 'id' => $name, 'name' => $info['title'], 'events' => $info['events'], ]; } json_out(compact('library', 'packs')); } if($reqPath === '/soundtriggers.json') { $textTriggersPath = FTM_PATH_PRV . '/text-triggers.ini'; etag_file('soundtriggers', $textTriggersPath); $textTriggers = parse_ini_file($textTriggersPath, true, INI_SCANNER_TYPED); $sndLib = parse_ini_file(FTM_PATH_PRV . '/sound-library.ini', true, INI_SCANNER_TYPED); $soundTrigs = []; foreach($textTriggers as $triggerInfo) { if($triggerInfo['type'] !== 'sound' && $triggerInfo['type'] !== 'alias') continue; $soundTrig = []; if($triggerInfo['type'] === 'sound') { $sounds = []; foreach($triggerInfo['sounds'] as $soundName) { if(!isset($sndLib[$soundName])) continue; $sound = []; $libSound = $sndLib[$soundName]; if(isset($libSound['sources']['mp3'])) $sound['m'] = $libSound['sources']['mp3']; if(isset($libSound['sources']['ogg'])) $sound['o'] = $libSound['sources']['ogg']; if(isset($libSound['sources']['opus'])) $sound['o'] = $libSound['sources']['opus']; if(isset($libSound['sources']['caf'])) $sound['c'] = $libSound['sources']['caf']; if(empty($sound)) continue; if(isset($triggerInfo['volume'])) { $sound['v'] = ceil(($triggerInfo['volume'] - 1) * 100); $sound['v2'] = $triggerInfo['volume']; } if(isset($triggerInfo['rate'])) $sound['r'] = $triggerInfo['rate']; $sounds[] = $sound; } $soundTrig['s'] = $sounds; } elseif($triggerInfo['type'] === 'alias') { $soundTrig['f'] = $triggerInfo['for']; } $matches = []; foreach($triggerInfo['match'] as $match) { $filters = []; $value = null; $notValue = null; $parts = explode(';', $match); foreach($parts as $part) { $part = explode(':', trim($part)); switch($part[0]) { case 'lc': $filters[] = 'lower'; break; case 'is': $filters[] = 'exact'; $value = trim($part[1]); break; case 'starts': $filters[] = 'starts'; $value = trim($part[1]); break; case 'has': $filters[] = 'contains'; $value = trim($part[1]); break; case 'hasnot': $notValue = trim($part[1]); break; default: $filters[] = 'missing:' . $part[0]; break; } } $matchNew = ['t' => implode(':', $filters)]; if($value !== null) $matchNew['m'] = $value; if($notValue !== null) $matchNew['n'] = $notValue; $matches[] = $matchNew; } $soundTrig['t'] = $matches; $soundTrigs[] = $soundTrig; } json_out([ 'meta' => [ 'baseUrl' => '', ], 'triggers' => $soundTrigs, ]); } if($reqPath === '/' || $reqPath === '/index.html' || $reqPath === '/index.php') { header('Content-Type: text/html; charset=utf-8'); echo << Data and settings shared between both chat clients is stored on this subdomain. HTML; return; } http_response_code(404);