Update media Postman collections and dashboard playback
هذا الالتزام موجود في:
1
.gitignore
مباع
1
.gitignore
مباع
@@ -2,6 +2,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
uploads
|
uploads
|
||||||
|
stream_*/
|
||||||
|
|
||||||
# Env files
|
# Env files
|
||||||
.env
|
.env
|
||||||
|
|||||||
@@ -30,15 +30,18 @@ export function PostPreviewCard({ post }: { post: ApiPost }) {
|
|||||||
const durationLabel = formatDuration(post.durationSeconds);
|
const durationLabel = formatDuration(post.durationSeconds);
|
||||||
const [imageFailed, setImageFailed] = useState(false);
|
const [imageFailed, setImageFailed] = useState(false);
|
||||||
const [sourceFailed, setSourceFailed] = useState(false);
|
const [sourceFailed, setSourceFailed] = useState(false);
|
||||||
|
const [isVideoPlaying, setIsVideoPlaying] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setImageFailed(false);
|
setImageFailed(false);
|
||||||
setSourceFailed(false);
|
setSourceFailed(false);
|
||||||
|
setIsVideoPlaying(false);
|
||||||
}, [media.url, media.sourceUrl]);
|
}, [media.url, media.sourceUrl]);
|
||||||
|
|
||||||
const showAudioPreview = media.kind === "audio" && !!media.sourceUrl && !sourceFailed;
|
const showAudioPreview = media.kind === "audio" && !!media.sourceUrl && !sourceFailed;
|
||||||
const showVideoPreview = media.kind === "video" && !!media.sourceUrl && !sourceFailed && (!media.url || imageFailed);
|
const showVideoPreview =
|
||||||
const showImagePreview = !!media.url && !imageFailed;
|
media.kind === "video" && !!media.sourceUrl && !sourceFailed && (isVideoPlaying || !media.url || imageFailed);
|
||||||
|
const showImagePreview = !!media.url && !imageFailed && !(media.kind === "video" && isVideoPlaying);
|
||||||
const showMediaShell = media.kind !== "text";
|
const showMediaShell = media.kind !== "text";
|
||||||
const showUnavailable = !showImagePreview && !showVideoPreview && !showAudioPreview;
|
const showUnavailable = !showImagePreview && !showVideoPreview && !showAudioPreview;
|
||||||
|
|
||||||
@@ -62,7 +65,9 @@ export function PostPreviewCard({ post }: { post: ApiPost }) {
|
|||||||
<video
|
<video
|
||||||
src={media.sourceUrl}
|
src={media.sourceUrl}
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
muted
|
controls={isVideoPlaying}
|
||||||
|
autoPlay={isVideoPlaying}
|
||||||
|
muted={!isVideoPlaying}
|
||||||
playsInline
|
playsInline
|
||||||
onError={() => setSourceFailed(true)}
|
onError={() => setSourceFailed(true)}
|
||||||
className="h-full w-full object-cover"
|
className="h-full w-full object-cover"
|
||||||
@@ -114,7 +119,17 @@ export function PostPreviewCard({ post }: { post: ApiPost }) {
|
|||||||
</Badge>
|
</Badge>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute bottom-3 right-3 rounded-full border border-border/60 bg-background/85 p-2 text-foreground">
|
{media.kind === "video" && media.sourceUrl && !isVideoPlaying && !sourceFailed ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label="Play video"
|
||||||
|
onClick={() => setIsVideoPlaying(true)}
|
||||||
|
className="absolute inset-0 z-10 cursor-pointer bg-transparent"
|
||||||
|
>
|
||||||
|
<span className="sr-only">Play video</span>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
<div className="pointer-events-none absolute bottom-3 right-3 z-20 rounded-full border border-border/60 bg-background/85 p-2 text-foreground">
|
||||||
{media.kind === "audio" ? <AudioLines className="h-4 w-4" /> : <PlayCircle className="h-4 w-4" />}
|
{media.kind === "audio" ? <AudioLines className="h-4 w-4" /> : <PlayCircle className="h-4 w-4" />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -722,6 +722,40 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Media",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Media Health",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Authorization",
|
||||||
|
"value": "Bearer {{accessToken}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": "{{baseUrl}}/media/health"
|
||||||
|
},
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"type": "text/javascript",
|
||||||
|
"exec": [
|
||||||
|
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||||
|
"const json = pm.response.json();",
|
||||||
|
"pm.expect(json.storage).to.be.an('object');",
|
||||||
|
"pm.expect(json.storage.provider).to.be.oneOf(['local', 's3']);",
|
||||||
|
"pm.expect(json.serving.rangeRequests).to.eql(true);",
|
||||||
|
"pm.expect(json.processing).to.be.an('object');"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Users",
|
"name": "Users",
|
||||||
"item": [
|
"item": [
|
||||||
@@ -1590,7 +1624,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('image');",
|
"pm.expect(json.postType).to.eql('image');",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.imageUrls).to.be.an('array');",
|
"pm.expect(json.imageUrls).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.images).to.be.an('array').that.is.not.empty;",
|
||||||
|
"pm.expect(json.media.images[0].url).to.be.a('string');",
|
||||||
"pm.expect(json.imageUrls.length).to.be.greaterThan(0);",
|
"pm.expect(json.imageUrls.length).to.be.greaterThan(0);",
|
||||||
"const pid = json._id || json.id;",
|
"const pid = json._id || json.id;",
|
||||||
"pm.environment.set('postId', pid);",
|
"pm.environment.set('postId', pid);",
|
||||||
@@ -1963,6 +2002,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('video');",
|
"pm.expect(json.postType).to.eql('video');",
|
||||||
|
"pm.expect(json.media.thumbnailUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.preferredPlaybackUrl).to.be.a('string');",
|
||||||
|
"if (json.hlsUrl) { pm.expect(json.media.preferredPlaybackUrl).to.eql(json.hlsUrl); }",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(42);",
|
"pm.expect(json.durationSeconds).to.eql(42);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -2050,6 +2095,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('video');",
|
"pm.expect(json.postType).to.eql('video');",
|
||||||
|
"pm.expect(json.media.thumbnailUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.preferredPlaybackUrl).to.be.a('string');",
|
||||||
|
"if (json.hlsUrl) { pm.expect(json.media.preferredPlaybackUrl).to.eql(json.hlsUrl); }",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(30);",
|
"pm.expect(json.durationSeconds).to.eql(30);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -2191,6 +2242,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('audio');",
|
"pm.expect(json.postType).to.eql('audio');",
|
||||||
|
"pm.expect(json.media.audioUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.waveformPeaks).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.durationSeconds).to.exist;",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(54);",
|
"pm.expect(json.durationSeconds).to.eql(54);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -2283,6 +2340,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('audio');",
|
"pm.expect(json.postType).to.eql('audio');",
|
||||||
|
"pm.expect(json.media.audioUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.waveformPeaks).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.durationSeconds).to.exist;",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.waveformPeaks).to.be.an('array');",
|
"pm.expect(json.waveformPeaks).to.be.an('array');",
|
||||||
"pm.expect(json.waveformPeaks.length).to.eql(6);",
|
"pm.expect(json.waveformPeaks.length).to.eql(6);",
|
||||||
"pm.expect(json.maqam).to.eql('Hijaz');",
|
"pm.expect(json.maqam).to.eql('Hijaz');",
|
||||||
|
|||||||
@@ -359,6 +359,40 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Media",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Media Health",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Authorization",
|
||||||
|
"value": "Bearer {{accessToken}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": "{{baseUrl}}/media/health"
|
||||||
|
},
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"type": "text/javascript",
|
||||||
|
"exec": [
|
||||||
|
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||||
|
"const json = pm.response.json();",
|
||||||
|
"pm.expect(json.storage).to.be.an('object');",
|
||||||
|
"pm.expect(json.storage.provider).to.be.oneOf(['local', 's3']);",
|
||||||
|
"pm.expect(json.serving.rangeRequests).to.eql(true);",
|
||||||
|
"pm.expect(json.processing).to.be.an('object');"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Users",
|
"name": "Users",
|
||||||
"item": [
|
"item": [
|
||||||
|
|||||||
@@ -573,6 +573,40 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Media",
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "Media Health",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Authorization",
|
||||||
|
"value": "Bearer {{accessToken}}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": "{{baseUrl}}/media/health"
|
||||||
|
},
|
||||||
|
"event": [
|
||||||
|
{
|
||||||
|
"listen": "test",
|
||||||
|
"script": {
|
||||||
|
"type": "text/javascript",
|
||||||
|
"exec": [
|
||||||
|
"pm.test('Status is 200', function () { pm.response.to.have.status(200); });",
|
||||||
|
"const json = pm.response.json();",
|
||||||
|
"pm.expect(json.storage).to.be.an('object');",
|
||||||
|
"pm.expect(json.storage.provider).to.be.oneOf(['local', 's3']);",
|
||||||
|
"pm.expect(json.serving.rangeRequests).to.eql(true);",
|
||||||
|
"pm.expect(json.processing).to.be.an('object');"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Users",
|
"name": "Users",
|
||||||
"item": [
|
"item": [
|
||||||
@@ -1051,7 +1085,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('image');",
|
"pm.expect(json.postType).to.eql('image');",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.imageUrls).to.be.an('array');",
|
"pm.expect(json.imageUrls).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.images).to.be.an('array').that.is.not.empty;",
|
||||||
|
"pm.expect(json.media.images[0].url).to.be.a('string');",
|
||||||
"pm.expect(json.imageUrls.length).to.be.greaterThan(0);",
|
"pm.expect(json.imageUrls.length).to.be.greaterThan(0);",
|
||||||
"const pid = json._id || json.id;",
|
"const pid = json._id || json.id;",
|
||||||
"pm.environment.set('postId', pid);",
|
"pm.environment.set('postId', pid);",
|
||||||
@@ -1424,6 +1463,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('video');",
|
"pm.expect(json.postType).to.eql('video');",
|
||||||
|
"pm.expect(json.media.thumbnailUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.preferredPlaybackUrl).to.be.a('string');",
|
||||||
|
"if (json.hlsUrl) { pm.expect(json.media.preferredPlaybackUrl).to.eql(json.hlsUrl); }",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(42);",
|
"pm.expect(json.durationSeconds).to.eql(42);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -1511,6 +1556,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('video');",
|
"pm.expect(json.postType).to.eql('video');",
|
||||||
|
"pm.expect(json.media.thumbnailUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.preferredPlaybackUrl).to.be.a('string');",
|
||||||
|
"if (json.hlsUrl) { pm.expect(json.media.preferredPlaybackUrl).to.eql(json.hlsUrl); }",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(30);",
|
"pm.expect(json.durationSeconds).to.eql(30);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -1652,6 +1703,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('audio');",
|
"pm.expect(json.postType).to.eql('audio');",
|
||||||
|
"pm.expect(json.media.audioUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.waveformPeaks).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.durationSeconds).to.exist;",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.durationSeconds).to.eql(54);",
|
"pm.expect(json.durationSeconds).to.eql(54);",
|
||||||
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
"if (json.thumbnailUrl) { pm.expect(json.thumbnailUrl).to.be.a('string'); }",
|
||||||
"pm.expect(json.style).to.eql('Sharqi');",
|
"pm.expect(json.style).to.eql('Sharqi');",
|
||||||
@@ -1744,6 +1801,12 @@
|
|||||||
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
"pm.test('Status is 201', function () { pm.response.to.have.status(201); });",
|
||||||
"const json = pm.response.json();",
|
"const json = pm.response.json();",
|
||||||
"pm.expect(json.postType).to.eql('audio');",
|
"pm.expect(json.postType).to.eql('audio');",
|
||||||
|
"pm.expect(json.media.audioUrl).to.be.a('string');",
|
||||||
|
"pm.expect(json.media.waveformPeaks).to.be.an('array');",
|
||||||
|
"pm.expect(json.media.durationSeconds).to.exist;",
|
||||||
|
"pm.expect(json.processingStatus).to.eql('ready');",
|
||||||
|
"pm.expect(json.media).to.be.an('object');",
|
||||||
|
"pm.expect(json.media.mediaType).to.eql(json.postType);",
|
||||||
"pm.expect(json.waveformPeaks).to.be.an('array');",
|
"pm.expect(json.waveformPeaks).to.be.an('array');",
|
||||||
"pm.expect(json.waveformPeaks.length).to.eql(6);",
|
"pm.expect(json.waveformPeaks.length).to.eql(6);",
|
||||||
"pm.expect(json.maqam).to.eql('Hijaz');",
|
"pm.expect(json.maqam).to.eql('Hijaz');",
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم