mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
subtitles crud
This commit is contained in:
@@ -195,7 +195,7 @@ App::get('/v1/videos/profiles/:profileId')
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('Video profile not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
throw new Exception('Video profile not found', 404, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic($profile, Response::MODEL_VIDEO_PROFILE);
|
||||
@@ -219,7 +219,7 @@ App::get('/v1/videos/profiles')
|
||||
$profiles = Authorization::skip(fn () => $dbForProject->find('videos_profiles', [], 12, 0, [], ['ASC']));
|
||||
|
||||
if (empty($profiles)) {
|
||||
throw new Exception('Video profiles where not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
throw new Exception('Video profiles where not found', 404, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
@@ -246,7 +246,7 @@ App::delete('/v1/videos/profiles/:profileId')
|
||||
$profile = Authorization::skip(fn() => $dbForProject->getDocument('videos_profiles', $profileId));
|
||||
|
||||
if ($profile->isEmpty()) {
|
||||
throw new Exception('Video profile not found', 404, Exception::PROFILES_NOT_FOUND);
|
||||
throw new Exception('Video profile not found', 404, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$deleted = $dbForProject->deleteDocument('videos_profiles', $profileId);
|
||||
@@ -260,8 +260,7 @@ App::delete('/v1/videos/profiles/:profileId')
|
||||
|
||||
|
||||
App::post('/v1/videos/:videoId/subtitles')
|
||||
->alias('/v1/videos/:videoId/subtitles', [])
|
||||
->desc('Attach a subtitle file to a video')
|
||||
->desc('Add subtitle to video')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
@@ -299,7 +298,7 @@ App::post('/v1/videos/:videoId/subtitles')
|
||||
validateFilePermissions($dbForProject, $bucketId, $fileId, $mode, $user);
|
||||
|
||||
try {
|
||||
Authorization::skip(function () use ($dbForProject, $videoId, $bucketId, $fileId, $name, $code, $default) {
|
||||
$subtitle = Authorization::skip(function () use ($dbForProject, $videoId, $bucketId, $fileId, $name, $code, $default) {
|
||||
return $dbForProject->createDocument('videos_subtitles', new Document([
|
||||
'videoId' => $videoId,
|
||||
'bucketId' => $bucketId,
|
||||
@@ -313,9 +312,37 @@ App::post('/v1/videos/:videoId/subtitles')
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
|
||||
$response->json(['result' => 'ok']);
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic($subtitle, Response::MODEL_VIDEO_SUBTITLE);
|
||||
});
|
||||
|
||||
App::get('/v1/videos/:videoId/subtitles')
|
||||
->desc('Get all video subtitles')
|
||||
->groups(['api', 'video'])
|
||||
->label('scope', 'files.read')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_KEY])
|
||||
->label('sdk.namespace', 'video')
|
||||
->label('sdk.method', 'getSubtitles')
|
||||
->label('sdk.description', '/docs/references/videos/get-subtitles.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_SUBTITLE_LIST)
|
||||
->param('videoId', null, new UID(), 'Video unique ID.')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->action(function ($videoId, Response $response, Database $dbForProject) {
|
||||
|
||||
$subtitles = Authorization::skip(fn () => $dbForProject->find('videos_subtitles', [new Query('videoId', Query::TYPE_EQUAL, [$videoId])], 12, 0, [], ['ASC']));
|
||||
|
||||
if (empty($subtitles)) {
|
||||
throw new Exception('Video subtitles not found', 404, Exception::VIDEO_SUBTITLE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'total' => $dbForProject->count('videos_subtitles', [], APP_LIMIT_COUNT),
|
||||
'subtitles' => $subtitles,
|
||||
]), Response::MODEL_VIDEO_SUBTITLE_LIST);
|
||||
});
|
||||
|
||||
App::post('/v1/video')
|
||||
->desc('Create Video')
|
||||
@@ -344,19 +371,15 @@ App::post('/v1/video')
|
||||
/** @var Utopia\Database\Document $project */
|
||||
|
||||
$file = validateFilePermissions($dbForProject, $bucketId, $fileId, $mode, $user);
|
||||
|
||||
try {
|
||||
$video = Authorization::skip(function () use ($dbForProject, $bucketId, $file) {
|
||||
$video = Authorization::skip(function () use ($dbForProject, $bucketId, $file) {
|
||||
return $dbForProject->createDocument('videos', new Document([
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $file->getId(),
|
||||
'size' => $file->getAttribute('sizeOriginal'),
|
||||
]));
|
||||
});
|
||||
} catch (StructureException $exception) {
|
||||
throw new Exception($exception->getMessage(), 400, Exception::DOCUMENT_INVALID_STRUCTURE);
|
||||
}
|
||||
});
|
||||
|
||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||
$response->dynamic(new Document([
|
||||
'$id' => $video->getId(),
|
||||
'fileId' => $video['fileId'],
|
||||
@@ -404,7 +427,7 @@ App::post('/v1/videos/:videoId/rendition')
|
||||
$profile = Authorization::skip(fn() => $dbForProject->findOne('videos_profiles', [new Query('_uid', Query::TYPE_EQUAL, [$profileId])]));
|
||||
|
||||
if (!$profile) {
|
||||
throw new Exception('Video profile not found', 400, Exception::PROFILES_NOT_FOUND);
|
||||
throw new Exception('Video profile not found', 400, Exception::VIDEO_PROFILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$transcoder = new Transcoding();
|
||||
@@ -430,7 +453,7 @@ App::get('/v1/videos/:videoId/:stream/renditions')
|
||||
->label('sdk.description', '/docs/references/videos/get-renditions.md') // TODO: Create markdown
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_RENDITIONS_LIST)
|
||||
->label('sdk.response.model', Response::MODEL_VIDEO_RENDITION_LIST)
|
||||
->param('videoId', null, new UID(), 'Video unique ID.')
|
||||
->param('stream', '', new WhiteList(['hls', 'mpeg-dash']), 'stream protocol name')
|
||||
->inject('response')
|
||||
@@ -460,7 +483,7 @@ App::get('/v1/videos/:videoId/:stream/renditions')
|
||||
$response->dynamic(new Document([
|
||||
'total' => $dbForProject->count('videos_renditions', $queries, APP_LIMIT_COUNT),
|
||||
'renditions' => $renditions,
|
||||
]), Response::MODEL_VIDEO_RENDITIONS_LIST);
|
||||
]), Response::MODEL_VIDEO_RENDITION_LIST);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -171,8 +171,9 @@ class Exception extends \Exception
|
||||
public const DOMAIN_VERIFICATION_FAILED = 'domain_verification_failed';
|
||||
|
||||
/** Video */
|
||||
public const PROFILES_NOT_FOUND = 'profiles_not_found';
|
||||
public const VIDEO_NOT_FOUND = 'video_not_found';
|
||||
public const VIDEO_PROFILE_NOT_FOUND = 'profile_not_found';
|
||||
public const VIDEO_NOT_FOUND = 'video_not_found';
|
||||
public const VIDEO_SUBTITLE_NOT_FOUND = 'subtitle_not_found';
|
||||
|
||||
|
||||
private $type = '';
|
||||
|
||||
@@ -70,9 +70,10 @@ use Appwrite\Utopia\Response\Model\UsageFunctions;
|
||||
use Appwrite\Utopia\Response\Model\UsageProject;
|
||||
use Appwrite\Utopia\Response\Model\UsageStorage;
|
||||
use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use Appwrite\Utopia\Response\Model\VideoRendition;
|
||||
use Appwrite\Utopia\Response\Model\Video;
|
||||
use Appwrite\Utopia\Response\Model\VideoProfile;
|
||||
use Appwrite\Utopia\Response\Model\VideoRendition;
|
||||
use Appwrite\Utopia\Response\Model\VideoSubtitle;
|
||||
|
||||
/**
|
||||
* @method Response setStatusCode(int $code = 200)
|
||||
@@ -140,7 +141,9 @@ class Response extends SwooleResponse
|
||||
public const MODEL_VIDEO_PROFILE = 'videoProfile';
|
||||
public const MODEL_VIDEO_PROFILE_LIST = 'videoProfileList';
|
||||
public const MODEL_VIDEO_RENDITION = 'videoRendition';
|
||||
public const MODEL_VIDEO_RENDITIONS_LIST = 'videoRenditionsList';
|
||||
public const MODEL_VIDEO_RENDITION_LIST = 'videoRenditionList';
|
||||
public const MODEL_VIDEO_SUBTITLE = 'videoSubtitle';
|
||||
public const MODEL_VIDEO_SUBTITLE_LIST = 'videoSubtitleList';
|
||||
|
||||
// Locale
|
||||
public const MODEL_LOCALE = 'locale';
|
||||
@@ -252,9 +255,9 @@ class Response extends SwooleResponse
|
||||
->setModel(new BaseList('Currencies List', self::MODEL_CURRENCY_LIST, 'currencies', self::MODEL_CURRENCY))
|
||||
->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE))
|
||||
->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false))
|
||||
->setModel(new BaseList('Video Renditions List', self::MODEL_VIDEO_RENDITIONS_LIST, 'renditions', self::MODEL_VIDEO_RENDITION))
|
||||
->setModel(new BaseList('video profile List', self::MODEL_VIDEO_PROFILE_LIST, 'profiles', self::MODEL_VIDEO_PROFILE))
|
||||
|
||||
->setModel(new BaseList('Video Rendition List', self::MODEL_VIDEO_RENDITION_LIST, 'renditions', self::MODEL_VIDEO_RENDITION))
|
||||
->setModel(new BaseList('Video Subtitle List', self::MODEL_VIDEO_SUBTITLE_LIST, 'subtitles', self::MODEL_VIDEO_SUBTITLE))
|
||||
// Entities
|
||||
->setModel(new Database())
|
||||
->setModel(new Collection())
|
||||
@@ -310,9 +313,10 @@ class Response extends SwooleResponse
|
||||
->setModel(new UsageBuckets())
|
||||
->setModel(new UsageFunctions())
|
||||
->setModel(new UsageProject())
|
||||
->setModel(new VideoRendition())
|
||||
->setModel(new Video())
|
||||
->setModel(new VideoProfile())
|
||||
->setModel(new VideoRendition())
|
||||
->setModel(new VideoSubtitle())
|
||||
|
||||
// Verification
|
||||
// Recovery
|
||||
|
||||
@@ -74,7 +74,7 @@ class VideoRendition extends Model
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'File rendition';
|
||||
return 'Video rendition';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class VideoSubtitle extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('$id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('videoId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Video ID.',
|
||||
'default' => '',
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('bucketId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Bucket ID.',
|
||||
'default' => '',
|
||||
'example' => 'd5fg5ehg1c168g7c',
|
||||
])
|
||||
->addRule('fileId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'file ID.',
|
||||
'default' => '',
|
||||
'example' => 'c5fg5emg1c168grr',
|
||||
])
|
||||
->addRule('path', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Subtitle path.',
|
||||
'default' => '',
|
||||
'example' => '640x360@500',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Subtitle name.',
|
||||
'default' => '',
|
||||
'example' => 'English',
|
||||
])
|
||||
->addRule('code', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Subtitle code.',
|
||||
'default' => '',
|
||||
'example' => 'Eng',
|
||||
])
|
||||
->addRule('default', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Subtitle default',
|
||||
'default' => '',
|
||||
'example' => false,
|
||||
])
|
||||
->addRule('status', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Subtitle packaging status',
|
||||
'default' => '',
|
||||
'example' => 'ready',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Video subtitle';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_VIDEO_SUBTITLE;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ class VideoCustomServerTest extends Scope
|
||||
use VideoCustom;
|
||||
use SideServer;
|
||||
|
||||
|
||||
public function testCreateVideoProfile()
|
||||
{
|
||||
|
||||
@@ -95,9 +94,70 @@ class VideoCustomServerTest extends Scope
|
||||
}
|
||||
|
||||
|
||||
public function testCreateVideo(): string
|
||||
{
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/videos', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
], [
|
||||
'bucketId' => $this->getBucket()['$id'],
|
||||
'fileId' => $this->getVideo()['$id']
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
return $response['body']['$id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCreateVideo
|
||||
*/
|
||||
public function testCreateVideoSubtitle($videoId)
|
||||
{
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/videos/' . $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',
|
||||
'default' => true,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertNotEmpty($response['body']['$id']);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_GET, '/videos/'. $videoId . '/subtitles' , [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals(1, $response['body']['total']);
|
||||
$this->assertNotEmpty($response['body']['subtitles']);
|
||||
$this->assertNotEmpty($response['body']['subtitles'][0]['$id']);
|
||||
$this->assertEquals('Eng', $response['body']['subtitles'][0]['code']);
|
||||
|
||||
//
|
||||
//// $this->assertEquals(404, $response['headers']['status-code']);
|
||||
//// $this->assertNotEmpty($response['body']);
|
||||
//// $this->assertEquals('Video profile not found', $response['body']['message']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @depends testCreateVideo
|
||||
*/
|
||||
public function testTranscodeWithSubs(): array
|
||||
{
|
||||
|
||||
|
||||
Reference in New Issue
Block a user