mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
sync with 0.16
This commit is contained in:
@@ -3708,25 +3708,25 @@ $collections = [
|
||||
],
|
||||
[
|
||||
'$id' => 'startedAt',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
'filters' => ['datetime'],
|
||||
],
|
||||
[
|
||||
'$id' => 'endedAt',
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
'filters' => ['datetime'],
|
||||
],
|
||||
[
|
||||
'$id' => 'path',
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -38,36 +38,20 @@ function validateFilePermissions(Database $dbForProject, string $bucketId, strin
|
||||
$bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId));
|
||||
|
||||
if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && $mode !== APP_MODE_ADMIN)) {
|
||||
throw new Exception('Bucket not found', 404, Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND);
|
||||
}
|
||||
|
||||
// Check bucket permissions when enforced
|
||||
$permissionBucket = $bucket->getAttribute('permission') === 'bucket';
|
||||
if ($permissionBucket) {
|
||||
$validator = new Authorization('read');
|
||||
if (!$validator->isValid($bucket->getRead())) {
|
||||
throw new Exception('Unauthorized file permissions', 401, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$validator = new Authorization(Database::PERMISSION_READ);
|
||||
$valid = $validator->isValid($bucket->getRead());
|
||||
if (!$fileSecurity && !$valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$read = !$user->isEmpty() ? ['user:' . $user->getId()] : []; // By default set read permissions for user
|
||||
|
||||
// Users can only add their roles to files, API keys and Admin users can add any
|
||||
$roles = Authorization::getRoles();
|
||||
|
||||
if (!Auth::isAppUser($roles) && !Auth::isPrivilegedUser($roles)) {
|
||||
foreach ($read as $role) {
|
||||
if (!Authorization::isRole($role)) {
|
||||
throw new Exception('Read permissions must be one of: (' . \implode(', ', $roles) . ')', 400, Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bucket->getAttribute('permission') === 'bucket') {
|
||||
// skip authorization
|
||||
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
} else {
|
||||
if ($fileSecurity && !$valid) {
|
||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||
} else {
|
||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||
}
|
||||
|
||||
return $file;
|
||||
@@ -439,15 +423,20 @@ App::post('/v1/videos/:videoId/rendition')
|
||||
->inject('mode')
|
||||
->action(action: function (string $videoId, string $profileId, Request $request, Response $response, Database $dbForProject, Document $project, Document $user, string $mode) {
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$videoId])]));
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
Query::equal('_uid', [$videoId]),
|
||||
]));
|
||||
|
||||
if (empty($video)) {
|
||||
throw new Exception('Video not found', 404, Exception::VIDEO_NOT_FOUND);
|
||||
}
|
||||
|
||||
validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode, $user);
|
||||
validateFilePermissions($dbForProject, $video->getAttribute('bucketId'), $video->getAttribute('fileId'), $mode, $user);
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->findOne('videos_profiles', [
|
||||
Query::equal('_uid', [$profileId]),
|
||||
]));
|
||||
|
||||
$profile = Authorization::skip(fn() => $dbForProject->findOne('videos_profiles', [new Query('_uid', Query::TYPE_EQUAL, [$profileId])]));
|
||||
|
||||
if (empty($profile)) {
|
||||
throw new Exception('Video profile not found', 404, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
@@ -610,8 +599,8 @@ App::get('/v1/videos/:videoId/protocols/:protocolId')
|
||||
->inject('user')
|
||||
->action(function (string $videoId, string $protocolId, Response $response, Database $dbForProject, string $mode, Document $user) {
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$videoId])
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
Query::equal('_uid', [$videoId]),
|
||||
]));
|
||||
|
||||
if (empty($video)) {
|
||||
@@ -621,10 +610,9 @@ App::get('/v1/videos/:videoId/protocols/:protocolId')
|
||||
validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode, $user);
|
||||
|
||||
$renditions = Authorization::skip(fn () => $dbForProject->find('videos_renditions', [
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$video->getId()]),
|
||||
new Query('endedAt', Query::TYPE_GREATER, [0]),
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready']),
|
||||
new Query('protocol', Query::TYPE_EQUAL, [$protocolId]),
|
||||
Query::equal('videoId', [$video->getId()]),
|
||||
Query::equal('status', ['ready']),
|
||||
Query::equal('protocol', [$protocolId]),
|
||||
]));
|
||||
|
||||
if (empty($renditions)) {
|
||||
@@ -632,7 +620,10 @@ App::get('/v1/videos/:videoId/protocols/:protocolId')
|
||||
}
|
||||
|
||||
$baseUrl = 'http://127.0.0.1/v1/videos/' . $videoId . '/protocols/' . $protocolId;
|
||||
$subtitles = Authorization::skip(fn() => $dbForProject->find('videos_subtitles', [new Query('videoId', Query::TYPE_EQUAL, [$video->getId()])]));
|
||||
$subtitles = Authorization::skip(fn() => $dbForProject->find('videos_subtitles', [
|
||||
Query::equal('videoId', [$video->getId()]),
|
||||
]));
|
||||
|
||||
$_renditions = [];
|
||||
$_subtitles = [];
|
||||
|
||||
@@ -648,21 +639,20 @@ App::get('/v1/videos/:videoId/protocols/:protocolId')
|
||||
|
||||
foreach ($renditions as $rendition) {
|
||||
$uri = null;
|
||||
$metadata = $rendition->getAttribute('metadata');
|
||||
$manifest = $metadata['hls'];
|
||||
|
||||
$_audios = [];
|
||||
foreach ($manifest as $key => $value) {
|
||||
if ($value['type'] === 'audio') {
|
||||
$metadata = $rendition->getAttribute('metadata');
|
||||
$streams = $metadata['hls'];
|
||||
foreach ($streams as $i => $stream) {
|
||||
if ($stream['type'] === 'audio') {
|
||||
$_audios[] = [
|
||||
'type' => 'group_audio',
|
||||
'name' => $value['language'],
|
||||
'default' => ($key === 0) ? 'YES' : 'NO',
|
||||
'language' => $value['language'],
|
||||
'uri' => $baseUrl . '/renditions/' . $rendition->getId() . '/streams/' . $value['id'],
|
||||
'name' => $stream['language'],
|
||||
'default' => ($i === 0) ? 'YES' : 'NO',
|
||||
'language' => $stream['language'],
|
||||
'uri' => $baseUrl . '/renditions/' . $rendition->getId() . '/streams/' . $stream['id'],
|
||||
];
|
||||
} elseif ($value['type'] === 'video') {
|
||||
$uri = $baseUrl . '/renditions/' . $rendition->getId() . '/streams/' . $value['id'];
|
||||
} elseif ($stream['type'] === 'video') {
|
||||
$uri = $baseUrl . '/renditions/' . $rendition->getId() . '/streams/' . $stream['id'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,8 +765,8 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/stre
|
||||
->inject('user')
|
||||
->action(function (string $videoId, string $protocolId, string $renditionId, string $streamId, Response $response, Database $dbForProject, string $mode, Document $user) {
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$videoId])
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
Query::equal('_uid', [$videoId]),
|
||||
]));
|
||||
|
||||
if (empty($video)) {
|
||||
@@ -786,29 +776,28 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/stre
|
||||
validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode, $user);
|
||||
|
||||
$rendition = Authorization::skip(fn () => $dbForProject->findOne('videos_renditions', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$renditionId]),
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$video->getId()]),
|
||||
new Query('endedAt', Query::TYPE_GREATER, [0]),
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready']),
|
||||
new Query('protocol', Query::TYPE_EQUAL, [$protocolId]),
|
||||
Query::equal('_uid', [$renditionId]),
|
||||
Query::equal('videoId', [$video->getId()]),
|
||||
Query::equal('status', ['ready']),
|
||||
Query::equal('protocol', [$protocolId]),
|
||||
]));
|
||||
|
||||
if (empty($rendition)) {
|
||||
throw new Exception('Rendition not found', 404, Exception::VIDEO_RENDITION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$segments = Authorization::skip(fn() => $dbForProject->find('videos_renditions_segments', [
|
||||
new Query('renditionId', Query::TYPE_EQUAL, [$renditionId]),
|
||||
new Query('streamId', Query::TYPE_EQUAL, [$streamId]),
|
||||
], 5000));
|
||||
$segments = Authorization::skip(fn () => $dbForProject->find('videos_renditions_segments', [
|
||||
Query::equal('renditionId', [$renditionId]),
|
||||
Query::equal('streamId', [$streamId]),
|
||||
]));
|
||||
|
||||
if (empty($segments)) {
|
||||
throw new Exception('Rendition segments not found', 404, Exception::VIDEO_RENDITION_SEGMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$paramsSegments = [];
|
||||
$_segments = [];
|
||||
foreach ($segments as $segment) {
|
||||
$paramsSegments[] = [
|
||||
$_segments[] = [
|
||||
'duration' => $segment->getAttribute('duration'),
|
||||
'url' => 'http://127.0.0.1/v1/videos/' . $videoId . '/protocols/' . $protocolId . '/renditions/' . $renditionId . '/segments/' . $segment->getId(),
|
||||
];
|
||||
@@ -816,8 +805,9 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/stre
|
||||
|
||||
$template = new View(__DIR__ . '/../../views/videos/hls.phtml');
|
||||
$template->setParam('targetDuration', $rendition->getAttribute('targetDuration'));
|
||||
$template->setParam('paramsSegments', $paramsSegments);
|
||||
$response->setContentType('application/x-mpegurl')->send($template->render(false));
|
||||
$template->setParam('paramsSegments', $_segments);
|
||||
$response->setContentType('application/x-mpegurl')
|
||||
->send($template->render(false));
|
||||
});
|
||||
|
||||
|
||||
@@ -843,8 +833,8 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/segm
|
||||
->inject('user')
|
||||
->action(function (string $videoId, string $protocolId, string $renditionId, string $segmentId, Response $response, Database $dbForProject, Device $deviceVideos, string $mode, Document $user) {
|
||||
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$videoId])
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
Query::equal('_uid', [$videoId]),
|
||||
]));
|
||||
|
||||
if (empty($video)) {
|
||||
@@ -853,20 +843,24 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/segm
|
||||
|
||||
validateFilePermissions($dbForProject, $video['bucketId'], $video['fileId'], $mode, $user);
|
||||
|
||||
$rendition = Authorization::skip(fn() => $dbForProject->findOne('videos_renditions', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$renditionId]),
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$video->getId()]),
|
||||
new Query('endedAt', Query::TYPE_GREATER, [0]),
|
||||
new Query('status', Query::TYPE_EQUAL, ['ready']),
|
||||
new Query('protocol', Query::TYPE_EQUAL, [$protocolId]),
|
||||
$video = Authorization::skip(fn() => $dbForProject->findOne('videos', [
|
||||
Query::equal('_uid', [$videoId]),
|
||||
]));
|
||||
|
||||
$rendition = Authorization::skip(fn () => $dbForProject->findOne('videos_renditions', [
|
||||
Query::equal('_uid', [$renditionId]),
|
||||
Query::equal('videoId', [$video->getId()]),
|
||||
Query::equal('status', ['ready']),
|
||||
Query::equal('protocol', [$protocolId]),
|
||||
]));
|
||||
|
||||
if (empty($rendition)) {
|
||||
throw new Exception('Rendition not found', 404, Exception::VIDEO_RENDITION_NOT_FOUND);
|
||||
throw new Exception('Rendition not found', 404, Exception::VIDEO_RENDITION_NOT_FOUND);
|
||||
}
|
||||
|
||||
$segment = Authorization::skip(fn () => $dbForProject->findOne('videos_renditions_segments', [
|
||||
new Query('_uid', Query::TYPE_EQUAL, [$segmentId])]));
|
||||
Query::equal('_uid', [$segmentId]),
|
||||
]));
|
||||
|
||||
if (empty($segment)) {
|
||||
throw new Exception('Rendition segments not found', 404, Exception::VIDEO_RENDITION_SEGMENT_NOT_FOUND);
|
||||
@@ -875,9 +869,11 @@ App::get('/v1/videos/:videoId/protocols/:protocolId/renditions/:renditionId/segm
|
||||
$output = $deviceVideos->read($segment->getAttribute('path') . $segment->getAttribute('fileName'));
|
||||
|
||||
if ($protocolId === 'hls') {
|
||||
$response->setContentType('video/MP2T')->send($output);
|
||||
$response->setContentType('video/MP2T')
|
||||
->send($output);
|
||||
} else {
|
||||
$response->setContentType('video/iso.segment')->send($output);
|
||||
$response->setContentType('video/iso.segment')
|
||||
->send($output);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+106
-83
@@ -3,7 +3,6 @@
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Resque\Worker;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Streaming\Format\StreamFormat;
|
||||
use Streaming\HLSSubtitle;
|
||||
use Streaming\Media;
|
||||
@@ -12,10 +11,12 @@ use Streaming\RepresentationInterface;
|
||||
use Utopia\App;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Storage\Compression\Algorithms\GZIP;
|
||||
use Utopia\Storage\Compression\Algorithms\Zstd;
|
||||
use Captioning\Format\SubripFile;
|
||||
use Utopia\Storage\Device;
|
||||
|
||||
@@ -35,8 +36,8 @@ class TranscodingV1 extends Worker
|
||||
private const STATUS_READY = 'ready';
|
||||
private const STATUS_ERROR = 'error';
|
||||
|
||||
private const PROTOCOL_HLS = 'hls';
|
||||
private const PROTOCOL_MPEG_DASH = 'dash';
|
||||
private const PROTOCOL_HLS = 'hls';
|
||||
private const PROTOCOL_DASH = 'dash';
|
||||
|
||||
//private string $basePath = '/tmp/';
|
||||
private string $basePath = '/usr/src/code/tests/tmp/';
|
||||
@@ -74,46 +75,36 @@ class TranscodingV1 extends Worker
|
||||
$project = new Document($this->args['project']);
|
||||
$this->database = $this->getProjectDB($project->getId());
|
||||
|
||||
$sourceVideo = Authorization::skip(fn() => $this->database->findOne('videos', [new Query('_uid', Query::TYPE_EQUAL, [$this->args['videoId']])]));
|
||||
$sourceVideo = Authorization::skip(fn() => $this->database->findOne('videos', [
|
||||
Query::equal('_uid', [$this->args['videoId']]),
|
||||
]));
|
||||
|
||||
if (empty($sourceVideo)) {
|
||||
throw new Exception('Video not found', 404, Exception::VIDEO_NOT_FOUND);
|
||||
throw new Exception('Video not found', 400, Exception::VIDEO_NOT_FOUND);
|
||||
}
|
||||
|
||||
$profile = Authorization::skip(fn() => $this->database->findOne('videos_profiles', [new Query('_uid', Query::TYPE_EQUAL, [$this->args['profileId']])]));
|
||||
$profile = Authorization::skip(fn() => $this->database->findOne('videos_profiles', [
|
||||
Query::equal('_uid', [$this->args['profileId']]),
|
||||
]));
|
||||
|
||||
if (empty($profile)) {
|
||||
throw new Exception('Video profile not found', 404, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
throw new Exception('Video profile not found', 400, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$bucket = Authorization::skip(fn() => $this->database->getDocument('buckets', $sourceVideo['bucketId']));
|
||||
$file = Authorization::skip(fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo['fileId']));
|
||||
$fileName = basename($file->getAttribute('path'));
|
||||
$inPath = $this->inDir . $fileName;
|
||||
$collection = 'videos_renditions';
|
||||
$bucket = Authorization::skip(
|
||||
fn() => $this->database->getDocument('buckets', $sourceVideo->getAttribute('bucketId'))
|
||||
);
|
||||
|
||||
if (
|
||||
!empty($file->getAttribute('openSSLCipher')) ||
|
||||
!empty($file->getAttribute('algorithm', ''))
|
||||
) {
|
||||
$data = $this->getFilesDevice($project->getId())->read($file->getAttribute('path'));
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) {
|
||||
$data = OpenSSL::decrypt(
|
||||
$data,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
);
|
||||
}
|
||||
$file = Authorization::skip(
|
||||
fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $sourceVideo->getAttribute('fileId'))
|
||||
);
|
||||
|
||||
if (!empty($file->getAttribute('algorithm', ''))) {
|
||||
$compressor = new GZIP();
|
||||
$data = $compressor->decompress($data);
|
||||
}
|
||||
$path = basename($file->getAttribute('path'));
|
||||
$inPath = $this->inDir . $path;
|
||||
|
||||
$this->getFilesDevice($project->getId())->write($this->inDir . $fileName, $data, $file->getAttribute('mimeType'));
|
||||
} else {
|
||||
$this->getFilesDevice($project->getId())->transfer($file->getAttribute('path'), $this->inDir . $fileName, $this->getFilesDevice($project->getId()));
|
||||
$result = $this->writeData($project, $file);
|
||||
if (empty($result)) {
|
||||
throw new Exception('File write failed', 500, Exception::GENERAL_UNKNOWN);
|
||||
}
|
||||
|
||||
$ffprobe = FFMpeg\FFProbe::create();
|
||||
@@ -156,9 +147,9 @@ class TranscodingV1 extends Worker
|
||||
$this->setRenditionName($profile);
|
||||
|
||||
$subs = [];
|
||||
$subtitles = Authorization::skip(fn () => $this->database->find('videos_subtitles', [
|
||||
new Query('status', Query::TYPE_EQUAL, ['']),
|
||||
new Query('videoId', Query::TYPE_EQUAL, [$this->args['videoId']])
|
||||
$subtitles = Authorization::skip(fn() => $this->database->find('videos_subtitles', [
|
||||
Query::equal('videoId', [$this->args['videoId']]),
|
||||
Query::equal('status', ['']),
|
||||
]));
|
||||
|
||||
foreach ($subtitles as $subtitle) {
|
||||
@@ -169,42 +160,21 @@ class TranscodingV1 extends Worker
|
||||
$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')));
|
||||
$subtitleFileName = basename($subtitleFile->getAttribute('path'));
|
||||
$bucket = Authorization::skip(
|
||||
fn() => $this->database->getDocument('buckets', $subtitle->getAttribute('bucketId'))
|
||||
);
|
||||
|
||||
if (
|
||||
!empty($subtitleFile->getAttribute('openSSLCipher')) ||
|
||||
!empty($subtitleFile->getAttribute('algorithm', ''))
|
||||
) {
|
||||
$subtitleData = $this->getFilesDevice($project->getId())->read($subtitleFile->getAttribute('path'));
|
||||
$file = Authorization::skip(
|
||||
fn() => $this->database->getDocument('bucket_' . $bucket->getInternalId(), $subtitle->getAttribute('fileId'))
|
||||
);
|
||||
|
||||
if (!empty($subtitleFile->getAttribute('openSSLCipher'))) {
|
||||
$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'));
|
||||
} else {
|
||||
$this->getFilesDevice($project->getId())->transfer($subtitleFile->getAttribute('path'), $this->inDir . $subtitleFileName, $this->getFilesDevice($project->getId()));
|
||||
}
|
||||
|
||||
$ext = pathinfo($subtitleFileName, PATHINFO_EXTENSION);
|
||||
$path = basename($file->getAttribute('path'));
|
||||
$this->writeData($project, $file);
|
||||
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||||
$subtitlePath = $this->inDir . $subtitle->getId() . '.vtt';
|
||||
|
||||
if ($ext === 'srt') {
|
||||
$srt = new SubripFile($this->inDir . $subtitleFileName);
|
||||
$srt = new SubripFile($this->inDir . $path);
|
||||
$srt->convertTo('webvtt')->save($subtitlePath);
|
||||
}
|
||||
|
||||
@@ -215,14 +185,14 @@ class TranscodingV1 extends Worker
|
||||
];
|
||||
}
|
||||
|
||||
$query = Authorization::skip(function () use ($collection, $profile) {
|
||||
return $this->database->createDocument($collection, new Document([
|
||||
$query = Authorization::skip(function () use ($profile) {
|
||||
return $this->database->createDocument('videos_renditions', new Document([
|
||||
'videoId' => $this->args['videoId'],
|
||||
'profileId' => $profile->getId(),
|
||||
'name' => $this->getRenditionName(),
|
||||
'startedAt' => time(),
|
||||
'startedAt' => DateTime::now(),
|
||||
'status' => self::STATUS_START,
|
||||
'protocol' => $profile['protocol'],
|
||||
'protocol' => $profile->getAttribute('protocol'),
|
||||
]));
|
||||
});
|
||||
|
||||
@@ -237,25 +207,25 @@ class TranscodingV1 extends Worker
|
||||
;
|
||||
|
||||
$format = new Streaming\Format\X264();
|
||||
$format->on('progress', function ($video, $format, $percentage) use ($query, $collection) {
|
||||
$format->on('progress', function ($video, $format, $percentage) use ($query) {
|
||||
if ($percentage % 3 === 0) {
|
||||
$query->setAttribute('progress', (string)$percentage);
|
||||
Authorization::skip(fn() => $this->database->updateDocument(
|
||||
$collection,
|
||||
'videos_renditions',
|
||||
$query->getId(),
|
||||
$query
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
$general = $this->transcode($profile['protocol'], $video, $format, $representation, $subs);
|
||||
$general = $this->transcode($profile->getAttribute('protocol'), $video, $format, $representation, $subs);
|
||||
if (!empty($general)) {
|
||||
foreach ($general as $key => $value) {
|
||||
$query->setAttribute($key, (string)$value);
|
||||
}
|
||||
}
|
||||
|
||||
if ($profile['protocol'] === 'hls') {
|
||||
if ($profile->getAttribute('protocol') === self::PROTOCOL_HLS) {
|
||||
$streams = $this->getHlsSegmentsUrls($this->outDir . 'master.m3u8');
|
||||
foreach ($streams as $stream) {
|
||||
$m3u8 = $this->getHlsSegments($this->outDir . $stream['path']);
|
||||
@@ -298,11 +268,11 @@ class TranscodingV1 extends Worker
|
||||
}
|
||||
|
||||
$query->setAttribute('status', self::STATUS_END);
|
||||
$query->setAttribute('endedAt', time());
|
||||
Authorization::skip(fn() => $this->database->updateDocument($collection, $query->getId(), $query));
|
||||
$query->setAttribute('endedAt', DateTime::now());
|
||||
Authorization::skip(fn() => $this->database->updateDocument('videos_renditions', $query->getId(), $query));
|
||||
|
||||
foreach ($subtitles ?? [] as $subtitle) {
|
||||
if ($profile['protocol'] === 'hls') {
|
||||
if ($profile->getAttribute('protocol') === 'hls') {
|
||||
$m3u8 = $this->getHlsSegments($this->outPath . '_subtitles_' . $subtitle['code'] . '.m3u8');
|
||||
foreach ($m3u8['segments'] ?? [] as $segment) {
|
||||
Authorization::skip(function () use ($segment, $project, $subtitle, $renditionRootPath) {
|
||||
@@ -347,14 +317,14 @@ class TranscodingV1 extends Worker
|
||||
if ($start === 0) {
|
||||
$query->setAttribute('status', self::STATUS_UPLOADING);
|
||||
$query->setAttribute('path', $renditionPath);
|
||||
Authorization::skip(fn() => $this->database->updateDocument($collection, $query->getId(), $query));
|
||||
Authorization::skip(fn() => $this->database->updateDocument('videos_renditions', $query->getId(), $query));
|
||||
$start = 1;
|
||||
}
|
||||
//@unlink($this->outDir . $fileName);
|
||||
}
|
||||
|
||||
$query->setAttribute('status', self::STATUS_READY);
|
||||
Authorization::skip(fn() => $this->database->updateDocument($collection, $query->getId(), $query));
|
||||
Authorization::skip(fn() => $this->database->updateDocument('videos_renditions', $query->getId(), $query));
|
||||
} catch (\Throwable $th) {
|
||||
$query->setAttribute('metadata', json_encode([
|
||||
'code' => $th->getCode(),
|
||||
@@ -362,7 +332,7 @@ class TranscodingV1 extends Worker
|
||||
]));
|
||||
|
||||
$query->setAttribute('status', self::STATUS_ERROR);
|
||||
Authorization::skip(fn() => $this->database->updateDocument($collection, $query->getId(), $query));
|
||||
Authorization::skip(fn() => $this->database->updateDocument('videos_renditions', $query->getId(), $query));
|
||||
throw new Exception($th->getMessage(), 500, Exception::GENERAL_UNKNOWN);
|
||||
}
|
||||
}
|
||||
@@ -393,7 +363,7 @@ class TranscodingV1 extends Worker
|
||||
|
||||
$segmentSize = 8;
|
||||
|
||||
if ($protocol === 'dash') {
|
||||
if ($protocol === self::PROTOCOL_DASH) {
|
||||
$dash = $video->dash()
|
||||
->setFormat($format)
|
||||
->setSegDuration($segmentSize)
|
||||
@@ -570,6 +540,59 @@ class TranscodingV1 extends Worker
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project Document
|
||||
* @param $file Document
|
||||
* @return boolean
|
||||
*/
|
||||
private function writeData(Document $project, Document $file): bool
|
||||
{
|
||||
|
||||
|
||||
$fullPath = $file->getAttribute('path');
|
||||
$path = basename($file->getAttribute('path'));
|
||||
|
||||
if (
|
||||
!empty($file->getAttribute('openSSLCipher')) ||
|
||||
!empty($file->getAttribute('algorithm', ''))
|
||||
) {
|
||||
$data = $this->getFilesDevice($project->getId())->read($fullPath);
|
||||
|
||||
if (!empty($file->getAttribute('openSSLCipher'))) {
|
||||
$data = OpenSSL::decrypt(
|
||||
$data,
|
||||
$file->getAttribute('openSSLCipher'),
|
||||
App::getEnv('_APP_OPENSSL_KEY_V' . $file->getAttribute('openSSLVersion')),
|
||||
0,
|
||||
\hex2bin($file->getAttribute('openSSLIV')),
|
||||
\hex2bin($file->getAttribute('openSSLTag'))
|
||||
);
|
||||
}
|
||||
|
||||
$algorithm = $file->getAttribute('algorithm', 'none');
|
||||
switch ($algorithm) {
|
||||
case 'zstd':
|
||||
$compressor = new Zstd();
|
||||
$data = $compressor->decompress($data);
|
||||
break;
|
||||
case 'gzip':
|
||||
$compressor = new GZIP();
|
||||
$data = $compressor->decompress($data);
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $this->getFilesDevice(
|
||||
$project->getId()
|
||||
)->write($this->inDir . $path, $data, $file->getAttribute('mimeType'));
|
||||
} else {
|
||||
$result = $this->getFilesDevice(
|
||||
$project->getId()
|
||||
)->transfer($fullPath, $this->inDir . $path, $this->getFilesDevice($project->getId()));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function setRenditionName($profile)
|
||||
{
|
||||
$this->renditionName = $profile->getAttribute('width')
|
||||
|
||||
Generated
+41
-35
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1f5db249f522d57622076db6b9b76b9e",
|
||||
"content-hash": "8fb2378bd34d917dd54073e99593ab52",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -263,11 +263,11 @@
|
||||
},
|
||||
{
|
||||
"name": "appwrite/php-runtimes",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/runtimes.git",
|
||||
"reference": "09874846c6bdb7be58c97b12323d2b35ec995409"
|
||||
"reference": "547fc026e11c0946846a8ac690898f5bf53be101"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
@@ -302,7 +302,7 @@
|
||||
"php",
|
||||
"runtimes"
|
||||
],
|
||||
"time": "2022-06-28T05:26:20+00:00"
|
||||
"time": "2022-08-15T14:03:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "captioning/captioning",
|
||||
@@ -2846,22 +2846,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/abuse",
|
||||
"version": "0.7.0",
|
||||
"version": "0.12.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/abuse.git",
|
||||
"reference": "52fb20e39e2e9619948bc0a73b52e10caa71350d"
|
||||
"reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/52fb20e39e2e9619948bc0a73b52e10caa71350d",
|
||||
"reference": "52fb20e39e2e9619948bc0a73b52e10caa71350d",
|
||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/aa1e1aae163ecf8ea81d48857ff55c241dcb695f",
|
||||
"reference": "aa1e1aae163ecf8ea81d48857ff55c241dcb695f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": ">=0.11 <1.0"
|
||||
"utopia-php/database": "0.24.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.4",
|
||||
@@ -2893,9 +2894,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.7.0"
|
||||
"source": "https://github.com/utopia-php/abuse/tree/0.12.0"
|
||||
},
|
||||
"time": "2021-12-27T13:06:45+00:00"
|
||||
"time": "2022-08-27T09:50:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
@@ -2954,22 +2955,22 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "0.8.0",
|
||||
"version": "0.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "b46dc42614a69437c45eb229249b6a6d000122c1"
|
||||
"reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/b46dc42614a69437c45eb229249b6a6d000122c1",
|
||||
"reference": "b46dc42614a69437c45eb229249b6a6d000122c1",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b",
|
||||
"reference": "a2f30ccfba7a61b1718b9ebd4557ed0d8a4dcb5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": ">=0.11 <1.0"
|
||||
"utopia-php/database": "0.24.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.3",
|
||||
@@ -3001,9 +3002,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.8.0"
|
||||
"source": "https://github.com/utopia-php/audit/tree/0.13.0"
|
||||
},
|
||||
"time": "2021-12-27T13:05:56+00:00"
|
||||
"time": "2022-08-27T09:18:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/cache",
|
||||
@@ -3164,16 +3165,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.18.9",
|
||||
"version": "0.24.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "227b3ca919149b7b0d6556c8effe9ee46ed081e6"
|
||||
"reference": "7da841d65d87e9f2c242589e58c38880def44dd8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/227b3ca919149b7b0d6556c8effe9ee46ed081e6",
|
||||
"reference": "227b3ca919149b7b0d6556c8effe9ee46ed081e6",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/7da841d65d87e9f2c242589e58c38880def44dd8",
|
||||
"reference": "7da841d65d87e9f2c242589e58c38880def44dd8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3222,9 +3223,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.18.9"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.24.0"
|
||||
},
|
||||
"time": "2022-07-19T09:42:53+00:00"
|
||||
"time": "2022-08-27T09:16:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
@@ -3282,16 +3283,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.20.0",
|
||||
"version": "0.21.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/framework.git",
|
||||
"reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a"
|
||||
"reference": "5aa5431788460a782065e42b0e8a35e7f139af2f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/framework/zipball/beb5e861c7d0a6256a1272e6b9d70b060ca8629a",
|
||||
"reference": "beb5e861c7d0a6256a1272e6b9d70b060ca8629a",
|
||||
"url": "https://api.github.com/repos/utopia-php/framework/zipball/5aa5431788460a782065e42b0e8a35e7f139af2f",
|
||||
"reference": "5aa5431788460a782065e42b0e8a35e7f139af2f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3325,9 +3326,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/framework/issues",
|
||||
"source": "https://github.com/utopia-php/framework/tree/0.20.0"
|
||||
"source": "https://github.com/utopia-php/framework/tree/0.21.0"
|
||||
},
|
||||
"time": "2022-07-30T09:55:28+00:00"
|
||||
"time": "2022-08-12T11:37:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
@@ -3664,15 +3665,18 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/storage.git",
|
||||
"reference": "aa2bb18c7680632efd646efc1b9987591e822ec3"
|
||||
"reference": "a91b0f20180ebb90f3cc01c42a77c3bf7bc01f5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/aa2bb18c7680632efd646efc1b9987591e822ec3",
|
||||
"reference": "aa2bb18c7680632efd646efc1b9987591e822ec3",
|
||||
"url": "https://api.github.com/repos/utopia-php/storage/zipball/a91b0f20180ebb90f3cc01c42a77c3bf7bc01f5b",
|
||||
"reference": "a91b0f20180ebb90f3cc01c42a77c3bf7bc01f5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-fileinfo": "*",
|
||||
"ext-zlib": "*",
|
||||
"ext-zstd": "*",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/framework": "0.*.*"
|
||||
},
|
||||
@@ -3708,7 +3712,7 @@
|
||||
"issues": "https://github.com/utopia-php/storage/issues",
|
||||
"source": "https://github.com/utopia-php/storage/tree/feat-transfer"
|
||||
},
|
||||
"time": "2022-05-24T05:15:59+00:00"
|
||||
"time": "2022-09-06T13:37:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/swoole",
|
||||
@@ -6319,7 +6323,9 @@
|
||||
"ext-sockets": "*",
|
||||
"ext-simplexml": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {
|
||||
"ext-fileinfo": "*"
|
||||
},
|
||||
"platform-overrides": {
|
||||
"php": "8.0"
|
||||
},
|
||||
|
||||
@@ -7,6 +7,8 @@ use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\VideoCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideServer;
|
||||
use Utopia\Database\Permission;
|
||||
use Utopia\Database\Role;
|
||||
|
||||
class VideoCustomServerTest extends Scope
|
||||
{
|
||||
@@ -29,6 +31,16 @@ class VideoCustomServerTest extends Scope
|
||||
'protocol' => 'hls',
|
||||
]);
|
||||
|
||||
$x = [
|
||||
Permission::read(Role::any()),
|
||||
Permission::create(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
|
||||
];
|
||||
var_dump($x);
|
||||
exit;
|
||||
|
||||
$profileId = $response['body']['$id'];
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
|
||||
Reference in New Issue
Block a user