logger moved to App::shutdown

This commit is contained in:
shimon
2022-07-11 11:22:43 +03:00
parent ec8eaa1ddd
commit 9f4ebcf208
10 changed files with 457 additions and 6366 deletions
+1
View File
@@ -12,4 +12,5 @@ app/sdks
dev/yasd_init.php
/tests/resources/disk-a/very-large-file-1.mov
/tests/resources/disk-a/very-big-file-2.mov
/tests/resources/disk-a/video-srt.*
/tests/tmp/
+85 -1
View File
@@ -3339,7 +3339,7 @@ $collections = [
],
'indexes' => [
[
'$id' => '_key_bucket_file_stream',
'$id' => '_key_video_stream',
'type' => Database::INDEX_KEY,
'attributes' => ['videoId', 'stream'],
'lengths' => [Database::LENGTH_KEY],
@@ -3429,6 +3429,90 @@ $collections = [
],
]
],
'video_subtitles' => [
'$collection' => Database::METADATA,
'$id' => 'video_subtitles',
'$name' => 'Video_subtitles',
'attributes' => [
[
'$id' => 'videoId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'bucketId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => 0,
'array' => false,
'filters' => [],
],
[
'$id' => 'fileId',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => 0,
'array' => false,
'filters' => [],
],
[
'$id' => 'name',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'code',
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => 'default',
'type' => Database::VAR_BOOLEAN,
'format' => '',
'size' => 0,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
],
'indexes' => [
[
'$id' => '_key_bucket_video_subtitle',
'type' => Database::INDEX_KEY,
'attributes' => ['videoId'],
'lengths' => [Database::LENGTH_KEY],
'orders' => [Database::ORDER_ASC],
],
]
],
];
return $collections;
+3 -3
View File
@@ -8,7 +8,7 @@ return [
'audioBitrate' => 64, //audio bitrate in Kbps
'width' => 640, //width resolution in px
'height' => 360, //height resolution in px
'stream' => 'mpeg-dash'
'stream' => 'hls'
],
[
'name' => '576p',
@@ -16,7 +16,7 @@ return [
'audioBitrate' => 128,
'width' => 1024,
'height' => 576,
'stream' => 'mpeg-dash'
'stream' => 'hls'
],
[
'name' => '720p',
@@ -24,7 +24,7 @@ return [
'audioBitrate' => 128,
'width' => 1280,
'height' => 720,
'stream' => 'mpeg-dash'
'stream' => 'hls'
],
];
+74 -7
View File
@@ -132,6 +132,60 @@ App::get('/v1/video/profiles')
});
App::post('/v1/video/:videoId/subtitles')
->alias('/v1/video/:videoId/subtitles', [])
->desc('Link a subtitle file to a video')
->groups(['api', 'storage'])
->label('scope', 'files.write')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('bucketId', '', new CustomId(), 'Subtitle bucket unique ID.')
->param('fileId', '', new CustomId(), 'Subtitle file unique ID.')
->param('name', '', new Text(128), 'Subtitle name.')
->param('code', '', new Text(128), 'Subtitle code name.')
->param('read', null, new Permissions(), 'An array of strings with read permissions. By default only the current user is granted with read permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
->param('write', null, new Permissions(), 'An array of strings with write permissions. By default only the current user is granted with write permissions. [learn more about permissions](https://appwrite.io/docs/permissions) and get a full list of available permissions.', true)
->inject('request')
->inject('response')
->inject('dbForProject')
->inject('project')
->inject('user')
->inject('audits')
->inject('usage')
->inject('events')
->inject('mode')
->inject('deviceFiles')
->inject('deviceLocal')
->action(action: function (string $videoId, string $bucketId, string $fileId, string $name, string $code, ?array $read, ?array $write, Request $request, Response $response, Database $dbForProject, $project, Document $user, Audit $audits, Stats $usage, Event $events, string $mode, Device $deviceFiles, Device $deviceLocal) {
/** @var Utopia\Database\Document $project */
/** @var Utopia\Database\Document $user */
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$videoId])]));
if ($video->isEmpty()) {
throw new Exception('Video not found', 400, Exception::VIDEO_NOT_FOUND);
}
validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode, $read, $write);
validateFilePermissions($dbForProject, $bucketId, $fileId, $mode, $read, $write);
try {
$subtitle = Authorization::skip(function () use ($dbForProject, $videoId, $bucketId, $fileId, $name, $code) {
return $dbForProject->createDocument('video_subtitles', new Document([
'videoId' => $videoId,
'bucketId' => $bucketId,
'fileId' => $fileId,
'name' => $name,
'code' => $code,
]));
});
} catch (StructureException $exception) {
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
}
$response->json(['result' => 'ok']);
});
App::post('/v1/video/buckets/:bucketId/files/:fileId')
->alias('/v1/video/files', ['bucketId' => 'default'])
->desc('Create video')
@@ -278,6 +332,7 @@ App::get('/v1/video/:videoId/:stream/:profile/:fileName')
->alias('/v1/video/:videoId/:stream/:profile/:fileName', [])
->desc('Get video playlist manifests')
->groups(['api', 'storage'])
#->label('sdk.auth', [APP_AUTH_TYPE_SESSION])
->label('scope', 'files.read')
->param('videoId', null, new UID(), 'Video unique ID.')
->param('stream', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
@@ -323,19 +378,31 @@ App::get('/v1/video/:videoId/:stream/:profile/:fileName')
$ext = pathinfo($fileName, PATHINFO_EXTENSION);
$baseUrl = 'http://127.0.0.1/v1/video/' . $videoId . '/' . $stream . '/' ;
if ($profile === 'master') {
if ($stream === 'hls') {
$subtitles = Authorization::skip(fn () => $dbForProject->find('video_subtitles', [new Query('videoId', Query::TYPE_EQUAL, [$video->getId()])], 12, 0, [], ['ASC']));
$paramsSubtitles = [];
foreach ($subtitles as $subtitle) {
$paramsSubtitles[] = [
'name' => $subtitle->getAttribute('name'),
'code' => $subtitle->getAttribute('code'),
'uri' => $baseUrl . $videoId . '_subtitles_' . $subtitle->getAttribute('code') . '.m3u8',
];
}
$paramsRenditions = [];
foreach ($renditions as $rendition) {
$t['bandwidth'] = $rendition->getAttribute('videoBitrate') + $rendition->getAttribute('audioBitrate');
$t['resolution'] = $rendition->getAttribute('width') . 'X' . $rendition->getAttribute('height');
$t['name'] = $rendition->getAttribute('name');
$t['path'] = $baseUrl . $rendition->getAttribute('name') . '/' . $rendition->getAttribute('videoId') . '_' . $rendition->getAttribute('name') . '.m3u8';
$params[] = $t;
$paramsRenditions[] = [
'bandwidth' => $rendition->getAttribute('videoBitrate') + $rendition->getAttribute('audioBitrate'),
'resolution' => $rendition->getAttribute('width') . 'X' . $rendition->getAttribute('height'),
'name' => $rendition->getAttribute('name'),
'uri' => $baseUrl . $rendition->getAttribute('name') . '/' . $rendition->getAttribute('videoId') . '_' . $rendition->getAttribute('name') . '.m3u8',
'subs' => !empty($paramsSubtitles) ? ' SUBTITLES="subs"' : '',
];
}
$template = new View(__DIR__ . '/../../views/video/hls.phtml');
$template->setParam('params', $params);
$template->setParam('paramsSubtitles', $paramsSubtitles);
$template->setParam('paramsRenditions', $paramsRenditions);
$output = $template->render();
} else {
$adaptations = [];
+7 -3
View File
@@ -1,7 +1,11 @@
#EXTM3U
#EXT-X-VERSION:3
<?php foreach ($this->getParam('params', []) as $param): ?>
#EXT-X-STREAM-INF:BANDWIDTH="<?php echo $param['bandwidth']; ?>" ,RESOLUTION="<?php echo $param['resolution']; ?>" ,NAME="<?php echo $param['name']; ?>"<?php echo PHP_EOL?>
<?php echo $param['path'] ?>
<?php foreach ($this->getParam('paramsSubtitles', []) as $subtitle): ?>
#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="subs",NAME="<?php echo $subtitle['name']; ?>",DEFAULT=YES,AUTOSELECT=NO,FORCED=NO,LANGUAGE="<?php echo $subtitle['code']; ?>",URI="<?php echo $subtitle['uri']; ?>"<?php echo PHP_EOL?>
<?php endforeach; ?>
<?php foreach ($this->getParam('paramsRenditions', []) as $rendition): ?>
#EXT-X-STREAM-INF:BANDWIDTH="<?php echo $rendition['bandwidth']; ?>" ,RESOLUTION="<?php echo $rendition['resolution']; ?>" ,NAME="<?php echo $rendition['name']; ?>" <?php if($rendition['subs'] !== null): echo $rendition['subs']; endif?><?php echo PHP_EOL?>
<?php echo $rendition['uri'] ?>
<?php endforeach; ?>
}
+87 -19
View File
@@ -4,6 +4,7 @@ use Appwrite\Extend\Exception;
use Appwrite\OpenSSL\OpenSSL;
use Appwrite\Resque\Worker;
use Streaming\Format\StreamFormat;
use Streaming\HLSSubtitle;
use Streaming\Media;
use Streaming\Metadata;
use Streaming\Representation;
@@ -15,6 +16,8 @@ use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use FFMpeg\FFProbe\DataMapping\StreamCollection;
use Utopia\Storage\Compression\Algorithms\GZIP;
use Captioning\Format\SubripFile;
use Captioning\Format\WebvttFile;
require_once __DIR__ . '/../init.php';
@@ -81,12 +84,7 @@ class TranscodingV1 extends Worker
}
$bucket = Authorization::skip(fn() => $this->database->getDocument('buckets', $sourceVideo['bucketId']));
if ($bucket->getAttribute('permission') === 'bucket') {
$file = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo['fileId']));
} else {
$file = $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo['fileId']);
}
$file = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo['fileId']));
$data = $this->getFilesDevice($project->getId())->read($file->getAttribute('path'));
$fileName = basename($file->getAttribute('path'));
$inPath = $this->inDir . $fileName;
@@ -149,6 +147,43 @@ class TranscodingV1 extends Worker
$video = $ffmpeg->open($inPath);
$this->setRenditionName($profile);
$subs = [];
$subtitles = Authorization::skip(fn () => $this->database->find('video_subtitles', [new Query('videoId', Query::TYPE_EQUAL, [$this->args['videoId']])], 12, 0, [], ['ASC']));
foreach ($subtitles as $subtitle) {
$subtitleBucket = Authorization::skip(fn() => $this->database->getDocument('buckets', $subtitle->getAttribute('bucketId')));
$subtitleFile = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $subtitleBucket->getInternalId(), $subtitle->getAttribute('fileId')));
$subtitleData = $this->getFilesDevice($project->getId())->read($subtitleFile->getAttribute('path'));
$subtitleFileName = basename($subtitleFile->getAttribute('path'));
if (!empty($subtitleFile->getAttribute('openSSLCipher'))) { // Decrypt
$subtitleData = OpenSSL::decrypt(
$subtitleData,
$subtitleFile->getAttribute('openSSLCipher'),
App::getEnv('_APP_OPENSSL_KEY_V' . $subtitleFile->getAttribute('openSSLVersion')),
0,
\hex2bin($subtitleFile->getAttribute('openSSLIV')),
\hex2bin($subtitleFile->getAttribute('openSSLTag'))
);
}
if (!empty($subtitleFile->getAttribute('algorithm', ''))) {
$compressor = new GZIP();
$subtitleData = $compressor->decompress($subtitleData);
}
$this->getFilesDevice($project->getId())->write($this->inDir . $subtitleFileName, $subtitleData, $subtitleFile->getAttribute('mimeType'));
$ext = pathinfo($subtitleFileName, PATHINFO_EXTENSION);
if ($ext === 'srt') {
$srt = new SubripFile($this->inDir . $subtitleFileName);
$srt->convertTo('webvtt')->save($this->inDir . $this->args['videoId'] . '.vtt');
}
$subs[] = [
'name' => $subtitle->getAttribute('name'),
'code' => $subtitle->getAttribute('code'),
'path' => $this->inDir . $this->args['videoId'] . '.vtt',
];
}
$query = Authorization::skip(function () use ($collection, $profile) {
return $this->database->createDocument($collection, new Document([
'videoId' => $this->args['videoId'],
@@ -179,7 +214,7 @@ class TranscodingV1 extends Worker
});
list($general, $metadata) = $this->transcode($profile['stream'], $video, $format, $representation);
list($general, $metadata) = $this->transcode($profile['stream'], $video, $format, $representation, $subs);
if (!empty($metadata)) {
$query->setAttribute('metadata', json_encode($metadata));
}
@@ -214,11 +249,15 @@ class TranscodingV1 extends Worker
$deviceFiles = $this->getVideoDevice($project->getId());
$devicePath = $deviceFiles->getPath($this->args['videoId']);
$data = $this->getFilesDevice($project->getId())->read($this->outDir . $fileName);
$renditionPath = $devicePath . DIRECTORY_SEPARATOR . $this->getRenditionName();
$this->getVideoDevice($project->getId())->write($renditionPath . DIRECTORY_SEPARATOR . $fileName, $data, \mime_content_type($this->outDir . $fileName));
$to = $devicePath . '/' . $this->getRenditionName() . '/';
if (str_contains($fileName, "_subtitles_") || str_contains($fileName, ".vtt")) {
$to = $devicePath . '/';
}
$this->getVideoDevice($project->getId())->write($to . $fileName, $data, \mime_content_type($this->outDir . $fileName));
if ($start === 0) {
$query->setAttribute('status', self::STATUS_UPLOADING);
$query->setAttribute('path', $renditionPath);
$query->setAttribute('path', $devicePath . '/' . $this->getRenditionName());
Authorization::skip(fn() => $this->database->updateDocument(
$collection,
$query->getId(),
@@ -266,7 +305,7 @@ class TranscodingV1 extends Worker
* @param $representation Representation
* @return array
*/
private function transcode(string $stream, Media $video, StreamFormat $format, Representation $representation): string | array
private function transcode(string $stream, Media $video, StreamFormat $format, Representation $representation, array $subtitles): string | array
{
$additionalParams = [
@@ -299,25 +338,52 @@ class TranscodingV1 extends Worker
}
$hls = $video->hls()
->setFormat($format)
$hls = $video->hls();
foreach ($subtitles as $subtitle) {
$sub = new HLSSubtitle($subtitle['path'], $subtitle['name'], $subtitle['code']);
$sub->default();
$sub->setM3u8Uri($this->getHlsBaseUri(false) . $this->args['videoId'] . '_subtitles_' . $subtitle['code'] . '.m3u8');
$hls->subtitle($sub);
}
$hls->setFormat($format)
->setHlsTime($segementSize)
->addRepresentation($representation)
->setAdditionalParams($additionalParams)
->setHlsBaseUrl('http://127.0.0.1/v1/video/' . $this->args['videoId'] . '/' . self::STREAM_HLS . '/' . $this->getRenditionName() . '/')
->setHlsBaseUrl($this->getHlsBaseUri())
->save($this->outPath);
$general = $this->getVideoInfo($hls->metadata()->getVideoStreams());
$general['width'] = $representation->getWidth();
$general['height'] = $representation->getHeight();
//$this->rewriteHlsLines($this->outPath . '_' . $this->getRenditionName() . '.m3u8');
foreach ($subtitles as $subtitle) {
$this->rewriteHlsLines($this->outPath . '_subtitles_' . $subtitle['code'] . '.m3u8');
}
return [
$general, []
];
}
/**
* @param bool $nest
* @return string
*/
private function getHlsBaseUri(bool $nest = true): string
{
$uri = 'http://127.0.0.1/v1/video/' . $this->args['videoId'] . '/' . self::STREAM_HLS . '/';
if (empty($nest)) {
return $uri;
}
return $uri . $this->getRenditionName() . '/';
}
private function rewriteHlsLines($path)
{
$handle = fopen($path, "r");
@@ -325,13 +391,15 @@ class TranscodingV1 extends Worker
if ($handle) {
while (($line = fgets($handle)) !== false) {
$newLine = str_replace(array("\r","\n"), "", $line);
if (str_contains($line, ".ts")) {
$newLine = 'http://127.0.0.1/v1/video/' . $this->args['videoId'] . '/' . self::STREAM_HLS . '/' . $this->getRenditionName() . '/' . $newLine;
var_dump($newLine);
if (
str_contains($line, ".ts") ||
str_contains($line, ".vtt") ||
str_contains($line, ".m3u8")
) {
$newLine = $this->getHlsBaseUri(str_contains($line, ".vtt") ?? false) . $newLine;
}
fwrite($destination, $newLine . PHP_EOL);
}
var_dump($path . '_tmp -> ' . $path);
rename($path . '_tmp', $path);
fclose($handle);
fclose($destination);
+1
View File
@@ -64,6 +64,7 @@
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "3.1.0",
"aminyazdanpanah/php-ffmpeg-video-streaming": "^1.2",
"captioning/captioning": "2.*",
"squizlabs/php_codesniffer": "^3.6",
"ext-simplexml": "*"
},
Generated
-6267
View File
File diff suppressed because it is too large Load Diff
+124
View File
@@ -0,0 +1,124 @@
<?php
namespace Tests\E2E\Scopes;
use Tests\E2E\Client;
trait VideoCustom
{
use ProjectCustom;
/**
* @var array
*/
protected static $bucket = [];
protected static $video = [];
protected static $subtitle = [];
/**
* @return array
*/
public function getBucket(): array
{
if (!empty(self::$bucket)) {
return self::$bucket;
}
$_bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => 'unique()',
'name' => 'Test Bucket 2',
'permission' => 'file',
'read' => ['role:all'],
'write' => ['role:all']
]);
self::$bucket = [
'$id' => $_bucket['body']['$id'],
];
return self::$bucket;
}
/**
* @return array
*/
public function getVideo(): array
{
if (!empty(self::$video)) {
return self::$video;
}
$source = __DIR__ . "/../../resources/disk-a/video-srt.mp4";
$totalSize = \filesize($source);
$chunkSize = 5 * 1024 * 1024;
$handle = @fopen($source, "rb");
$fileId = 'unique()';
$mimeType = mime_content_type($source);
$counter = 0;
$size = filesize($source);
$headers = [
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id']
];
$id = '';
while (!feof($handle)) {
$curlFile = new \CURLFile('data:' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'video-srt.mp4');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size) . '/' . $size;
if (!empty($id)) {
$headers['x-appwrite-id'] = $id;
}
$_file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $this->getBucket()['$id'] . '/files', array_merge($headers, $this->getHeaders()), [
'fileId' => $fileId,
'file' => $curlFile,
'read' => ['role:all'],
'write' => ['role:all'],
]);
$counter++;
$id = $_file['body']['$id'];
}
@fclose($handle);
self::$video = [
'$id' => $_file['body']['$id'],
];
return self::$video;
}
/**
* @return array
*/
public function getSubtitle(): array
{
if (!empty(self::$subtitle)) {
return self::$subtitle;
}
$res = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $this->getBucket()['$id'] . '/files', array_merge([
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'fileId' => 'unique()',
'file' => new \CURLFile(realpath(__DIR__ . '/../../resources/disk-a//../../resources/disk-a/video-srt.srt'), 'text/plain', 'video-srt.srt'),
'read' => ['role:all'],
'write' => ['role:all'],
]);
self::$subtitle = [
'$id' => $res['body']['$id'],
];
return self::$subtitle;
}
}
@@ -4,6 +4,7 @@ namespace Tests\E2E\Services\Storage;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\VideoCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideServer;
@@ -11,71 +12,77 @@ class VideoCustomServerTest extends Scope
{
use StorageBase;
use ProjectCustom;
use VideoCustom;
use SideServer;
public function testCreateBucketFile(): array
public function testTranscodeWithSubs() :array
{
$bucket = $this->client->call(Client::METHOD_POST, '/storage/buckets', [
$response = $this->client->call(Client::METHOD_POST, '/video/buckets/' . $this->getBucket()['$id'] . '/files/' . $this->getVideo()['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => 'unique()',
'name' => 'Test Bucket 2',
'permission' => 'file',
'read' => ['role:all'],
'write' => ['role:all']
]);
//$source = __DIR__ . "/../../../resources/disk-a/large-file.mp4";
$source = __DIR__ . "/../../../resources/disk-a/very-big-file-2.mov";
$totalSize = \filesize($source);
$chunkSize = 5 * 1024 * 1024;
$handle = @fopen($source, "rb");
$fileId = 'unique()';
$mimeType = mime_content_type($source);
$counter = 0;
$size = filesize($source);
$headers = [
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id']
];
$id = '';
$videoId = $response['body']['$id'];
while (!feof($handle)) {
$curlFile = new \CURLFile('data:' . $mimeType . ';base64,' . base64_encode(@fread($handle, $chunkSize)), $mimeType, 'very-large-file-1.mov');
$headers['content-range'] = 'bytes ' . ($counter * $chunkSize) . '-' . min(((($counter * $chunkSize) + $chunkSize) - 1), $size) . '/' . $size;
$response = $this->client->call(Client::METHOD_POST, '/video/' . $videoId . '/subtitles', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => $this->getBucket()['$id'],
'fileId' => $this->getSubtitle()['$id'],
'name' => 'hebrew',
'code' => 'heb',
'read' => ['role:all'],
'write' => ['role:all']
]);
if (!empty($id)) {
$headers['x-appwrite-id'] = $id;
}
$response = $this->client->call(Client::METHOD_POST, '/video/' . $videoId . '/subtitles', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'bucketId' => $this->getBucket()['$id'],
'fileId' => $this->getSubtitle()['$id'],
'name' => 'english',
'code' => 'eng',
'read' => ['role:all'],
'write' => ['role:all']
]);
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucket['body']['$id'] . '/files', array_merge($headers, $this->getHeaders()), [
'fileId' => $fileId,
'file' => $curlFile,
'read' => ['role:all'],
'write' => ['role:all'],
]);
$counter++;
$response = $this->client->call(Client::METHOD_GET, '/video/profiles', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertNotEmpty($file['body']['$id']);
$id = $file['body']['$id'];
}
@fclose($handle);
$profileId = $response['body']['profiles'][0]['$id'];
$response = $this->client->call(Client::METHOD_POST, '/video/' . $videoId . '/rendition/' . $profileId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'read' => ['role:all'],
'write' => ['role:all']
]);
return [
'bucketId' => $bucket['body']['$id'],
'fileId' => $id,
];
'videoId' => $videoId,
'stream' => ''
];
}
/**
* @depends testCreateBucketFile
*/
public function testTranscodingRendition($data): array
public function testTranscodingRendition(): array
{
$response = $this->client->call(Client::METHOD_POST, '/video/buckets/' . $data['bucketId'] . '/files/' . $data['fileId'], [
$response = $this->client->call(Client::METHOD_POST, '/video/buckets/' . $this->getBucket()['$id'] . '/files/' . $this->getVideo()['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -114,7 +121,7 @@ class VideoCustomServerTest extends Scope
}
/**
* @depends testTranscodingRendition
* @depends testTranscodeWithSubs
*/
public function testGetRendition(array $data): array
{
@@ -130,8 +137,6 @@ class VideoCustomServerTest extends Scope
'write' => ['role:all']
]);
$this->assertNotEmpty($response['body']['renditions']);
$videoId = $response['body']['renditions'][0]['videoId'];
@@ -139,6 +144,7 @@ class VideoCustomServerTest extends Scope
$profileName = $response['body']['renditions'][0]['name'];
$stream = $response['body']['renditions'][0]['stream'];
var_dump($response['body']);
return [
'videoId' => $videoId,
@@ -164,6 +170,8 @@ class VideoCustomServerTest extends Scope
'write' => ['role:all']
]);
var_dump($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/' . $data['stream'] . '/' . $data['profileName'] . '/' . $data['videoId'] . '_360p.m3u8', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
@@ -175,7 +183,7 @@ class VideoCustomServerTest extends Scope
var_dump($response['body']);
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/hls/' . $data['profileName'] . '/' . $data['videoId'] . '_360p_0000.ts', [
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/' . $data['stream'] . '/' . $data['profileName'] . '/' . $data['videoId'] . '_360p_0000.ts', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
@@ -185,24 +193,25 @@ class VideoCustomServerTest extends Scope
]);
var_dump($response['body']);
}
/**
* @depends testTranscodingRendition
*/
public function testDashStreamRender($data): void
{
sleep(20);
$response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/mpeg-dash/master/' . $data['videoId'] . '.mpd', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'read' => ['role:all'],
'write' => ['role:all']
]);
var_dump($response['body']);
}
// /**
// * @depends testTranscodingRendition
// */
// public function testDashStreamRender($data): void
// {
// sleep(20);
//
// $response = $this->client->call(Client::METHOD_GET, '/video/' . $data['videoId'] . '/mpeg-dash/master/' . $data['videoId'] . '.mpd', [
// 'content-type' => 'application/json',
// 'x-appwrite-project' => $this->getProject()['$id'],
// 'x-appwrite-key' => $this->getProject()['apiKey'],
// ], [
// 'read' => ['role:all'],
// 'write' => ['role:all']
// ]);
//
// var_dump($response['body']);
// }
}