Update media Postman collections and dashboard playback

هذا الالتزام موجود في:
boutmoun123
2026-05-26 17:27:17 +03:00
الأصل acd8d0d8cf
التزام 377bebfb88
5 ملفات معدلة مع 181 إضافات و5 حذوفات

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');",