diff --git a/.env b/.env index 525e048e6e..26df94bba1 100644 --- a/.env +++ b/.env @@ -23,15 +23,15 @@ _APP_DB_SCHEMA=appwrite _APP_DB_USER=user _APP_DB_PASS=password _APP_DB_ROOT_PASS=rootsecretpassword -_APP_STORAGE_DEVICE=Local +_APP_STORAGE_DEVICE=DOSpaces _APP_STORAGE_S3_ACCESS_KEY= _APP_STORAGE_S3_SECRET= _APP_STORAGE_S3_REGION=us-east-1 -_APP_STORAGE_S3_BUCKET= -_APP_STORAGE_DO_SPACES_ACCESS_KEY= -_APP_STORAGE_DO_SPACES_SECRET= -_APP_STORAGE_DO_SPACES_REGION=us-east-1 -_APP_STORAGE_DO_SPACES_BUCKET= +_APP_STORAGE_S3_BUCKET=utopia-storage-tests +_APP_STORAGE_DO_SPACES_ACCESS_KEY=DO003UTVR9M3A7BM9G2R +_APP_STORAGE_DO_SPACES_SECRET=NPFdNiNfMFFwVjwOjO9r68TXqtut2huWTdDANBl8l5A +_APP_STORAGE_DO_SPACES_REGION=nyc3 +_APP_STORAGE_DO_SPACES_BUCKET=utopia-storage-tests _APP_STORAGE_BACKBLAZE_ACCESS_KEY= _APP_STORAGE_BACKBLAZE_SECRET= _APP_STORAGE_BACKBLAZE_REGION=us-west-004 diff --git a/app/config/collections.php b/app/config/collections.php index 081153cac2..a797a36050 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -3676,10 +3676,10 @@ $collections = [ ], [ '$id' => 'videoBitRate', - 'type' => Database::VAR_STRING, + 'type' => Database::VAR_INTEGER, 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, + 'size' => 0, + 'signed' => false, 'required' => false, 'default' => null, 'array' => false, @@ -3720,10 +3720,10 @@ $collections = [ ], [ '$id' => 'audioBitRate', - 'type' => Database::VAR_STRING, + 'type' => Database::VAR_INTEGER, 'format' => '', - 'size' => Database::LENGTH_KEY, - 'signed' => true, + 'size' => 0, + 'signed' => false, 'required' => false, 'default' => null, 'array' => false, diff --git a/app/controllers/api/videos.php b/app/controllers/api/videos.php index 58dbee6c93..06f73e28d8 100644 --- a/app/controllers/api/videos.php +++ b/app/controllers/api/videos.php @@ -812,6 +812,7 @@ App::get('/v1/videos/:videoId/outputs/:output') ->groups(['api', 'videos']) ->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT]) ->label('sdk.namespace', 'videos') + ->label('origin', '*') ->label('sdk.method', 'getMasterManifest') ->label('sdk.description', '/docs/references/videos/get-master-manifest.md') // TODO: Create markdown ->label('sdk.response.code', Response::STATUS_CODE_OK) @@ -862,7 +863,7 @@ App::get('/v1/videos/:videoId/outputs/:output') } foreach ($renditions as $rendition) { - $uri = null; + $uri = $codecs = $resolution = $bandwidth = null; $_audios = []; $metadata = $rendition->getAttribute('metadata'); $streams = $metadata['hls']; @@ -877,14 +878,18 @@ App::get('/v1/videos/:videoId/outputs/:output') ]; } elseif ($stream['type'] === 'video') { $uri = $baseUrl . '/renditions/' . $rendition->getId() . '/streams/' . $stream['id']; + $resolution = $stream['resolution'] ?? $rendition->getAttribute('width') . 'x' . $rendition->getAttribute('height'); + $bandwidth = $stream['bandwidth'] ?? ($rendition->getAttribute('videoBitRate') + $rendition->getAttribute('audioBitRate')) * 1024; + $codecs = $stream['codecs'] ?? null; } } $_renditions[] = [ - 'bandwidth' => ($rendition->getAttribute('videoBitRate') + $rendition->getAttribute('audioBitRate')), - 'resolution' => $rendition->getAttribute('width') . 'X' . $rendition->getAttribute('height'), + 'bandwidth' => $bandwidth, + 'resolution' => $resolution, + 'codecs' => $codecs, 'name' => $rendition->getAttribute('name'), - 'uri' => $uri, + 'uri' => rtrim($uri), 'subs' => !empty($_subtitles) ? 'subs' : null, 'audio' => !empty($_audios) ? 'group_audio' : null, ]; @@ -978,6 +983,7 @@ App::get('/v1/videos/:videoId/outputs/:output/renditions/:renditionId/streams/:s ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') + ->label('origin', '*') ->label('scope', 'videos.read') ->param('videoId', null, new UID(), 'Video unique ID.') ->param('output', '', new WhiteList(['hls']), 'Output name.') @@ -1041,6 +1047,7 @@ App::get('/v1/videos/:videoId/outputs/:output/renditions/:renditionId/segments/: ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') + ->label('origin', '*') ->label('scope', 'videos.read') ->param('videoId', null, new UID(), 'Video unique ID.') ->param('output', '', new WhiteList(['hls', 'dash']), 'Output name') @@ -1077,6 +1084,7 @@ App::get('/v1/videos/:videoId/outputs/:output/subtitles/:subtitleId') ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') + ->label('origin', '*') ->label('scope', 'videos.read') ->param('videoId', null, new UID(), 'Video unique ID.') ->param('output', '', new WhiteList(['hls', 'dash']), 'Protocol name') @@ -1142,6 +1150,7 @@ App::get('/v1/videos/:videoId/outputs/:output/subtitles/:subtitleId/segments/:se ->label('sdk.response.code', Response::STATUS_CODE_OK) ->label('sdk.response.type', '*/*') ->label('sdk.methodType', 'location') + ->label('origin', '*') ->label('scope', 'videos.read') ->param('videoId', null, new UID(), 'Video unique ID.') ->param('output', '', new WhiteList(['hls', 'dash']), 'output name') diff --git a/app/init.php b/app/init.php index 4338ecd813..eca26ecc8a 100644 --- a/app/init.php +++ b/app/init.php @@ -889,7 +889,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) { /** @var Utopia\Database\Document $console */ $projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', 'console')); - //$projectId = '6425c03a3ce2f21b2d1d'; + $projectId = '6434237946e602be6953'; if ($projectId === 'console') { return $console; diff --git a/app/views/videos/hls-master.phtml b/app/views/videos/hls-master.phtml index 557ccc8497..9db96b8c5e 100644 --- a/app/views/videos/hls-master.phtml +++ b/app/views/videos/hls-master.phtml @@ -4,9 +4,9 @@ #EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="group_audio",NAME="",DEFAULT=,LANGUAGE="",URI="" getParam('subtitles', []) as $subtitle):?> -#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="escape($subtitle['name']); ?>",DEFAULT=,AUTOSELECT=NO,FORCED=NO,LANGUAGE="escape($subtitle['code']); ?>",URI="" +#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="escape($subtitle['name']); ?>",DEFAULT=,AUTOSELECT=YES,FORCED=NO,LANGUAGE="escape($subtitle['code']); ?>",URI="" getParam('renditions', []) as $rendition):?> -#EXT-X-STREAM-INF:BANDWIDTH="",RESOLUTION="",NAME="",SUBTITLES="",AUDIO="" +#EXT-X-STREAM-INF:BANDWIDTH="",RESOLUTION="",CODECS="",NAME="",SUBTITLES="",AUDIO="" \ No newline at end of file diff --git a/app/workers/videos.php b/app/workers/videos.php index 5d89c059f1..bbbd511f57 100644 --- a/app/workers/videos.php +++ b/app/workers/videos.php @@ -136,14 +136,14 @@ class VideosV1 extends Worker ->setAttribute('videoFormatProfile', $video->has('format_profile') ? $video->get('format_profile') : '') ->setAttribute('videoFrameRate', $video->has('frame_rate') ? strval($video->get('frame_rate')->getAbsoluteValue()) : '') ->setAttribute('videoFrameRateMode', $video->has('frame_rate_mode') ? $video->get('frame_rate_mode')->getFullName() : '') - ->setAttribute('videoBitRate', $video->has('bit_rate') ? strval($video->get('bit_rate')->getAbsoluteValue()) : ''); + ->setAttribute('videoBitRate', $video->has('bit_rate') ? $video->get('bit_rate')->getAbsoluteValue() : 0); } foreach ($mediaInfoContainer->getAudios() ?? [] as $audio) { $this->video ->setAttribute('audioFormat', $audio->has('format') ? strval($audio->get('format')->getShortName()) : '') ->setAttribute('audioSampleRate', $audio->has('sampling_rate') ? strval($audio->get('sampling_rate')->getAbsoluteValue()) : '') - ->setAttribute('audioBitRate', $audio->has('bit_rate') ? strval($audio->get('bit_rate')->getAbsoluteValue()) : ''); + ->setAttribute('audioBitRate', $audio->has('bit_rate') ? $audio->get('bit_rate')->getAbsoluteValue() : 0); } console::info('Input video id: ' . $this->video->getId() . PHP_EOL . @@ -658,15 +658,27 @@ class VideosV1 extends Worker $handle = fopen($path, "r"); if ($handle) { while (($line = fgets($handle)) !== false) { - $line = str_replace(['"'], '', $line); + $tmp = []; + $line = str_replace(['"'], '', $line); $attributes = explode(',', $line); - $language = null; - foreach ($attributes as $attribute) { - if (str_contains($attribute, "LANGUAGE")) { - $parts = explode('=', $attribute); - $language = $parts[1]; + foreach ($attributes as $key => $attribute) { + $parts = explode('=', $attribute); + switch (true) { + case str_contains($parts[0], 'LANGUAGE'): + $attr['language'] = $parts[1]; + break; + case str_contains($parts[0], 'BANDWIDTH'): + $attr['bandwidth'] = $parts[1]; + break; + case str_contains($parts[0], 'RESOLUTION'): + $attr['resolution'] = $parts[1]; + break; + case str_contains($parts[0], 'CODECS'): + $attr['codecs'] = $parts[1] . ',' . $attributes[$key + 1]; + break; } } + $end = strpos($line, 'm3u8'); if ($end !== false) { $start = strpos($line, $this->video->getId()); @@ -675,16 +687,27 @@ class VideosV1 extends Worker $parts = explode('_', $path); $tmp = [ 'id' => $parts[1], - 'type' => str_contains($line, "TYPE=AUDIO") ? 'audio' : 'video', 'path' => $path ]; - - if (!empty($language)) { - $tmp ['language'] = $language; + if (str_contains($line, "TYPE=AUDIO")) { + $tmp['type'] = 'audio'; + if (!empty($attr['language'])) { + $tmp['language'] = $attr['language']; + } + } else { + $tmp['type'] = 'video'; + if (!empty($attr['resolution'])) { + $tmp['resolution'] = $attr['resolution']; + } + if (!empty($attr['bandwidth'])) { + $tmp['bandwidth'] = $attr['bandwidth']; + } + if (!empty($attr['codecs'])) { + $tmp['codecs'] = $attr['codecs']; + } } - - $files[] = $tmp; } + $files[] = $tmp; } } fclose($handle);