Skip to content

Commit

Permalink
Update environment variables in Docker Compose, enhance Clip componen…
Browse files Browse the repository at this point in the history
…t to fetch session rendering progress, and increase file upload size limit. Refactor session handling in server controllers and add new API endpoint for session rendering progress. Clean up code by removing unused imports and console logs.
  • Loading branch information
pblvrt committed Jan 19, 2025
1 parent ca96edf commit 265f4ce
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 47 deletions.
4 changes: 2 additions & 2 deletions docker-compose-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ services:
dockerfile: packages/server/workers/clips/Dockerfile.dev
environment:
<<: *common-environment
REMOTION_WEBHOOK_URL: ${REMOTION_WEBHOOK_URL}
REMOTION_WEBHOOK_URL: https://kodiak-feasible-distinctly.ngrok-free.app/webhook/remotion

reel-creator:
build:
Expand All @@ -90,7 +90,7 @@ services:
- /app/packages/reel-creator/node_modules
environment:
NODE_ENV: ${NODE_ENV}
SERVER_WEBHOOK_URL: https://6c5a-83-38-191-227.ngrok-free.app/webhook/remotion
SERVER_WEBHOOK_URL: https://kodiak-feasible-distinctly.ngrok-free.app/webhook/remotion
SERVER_WEBHOOK_SECRET_FILE: ${LIVEPEER_WEBHOOK_SECRET_FILE}
AWS_ACCESS_KEY_ID_FILE: ${AWS_ACCESS_KEY_ID_FILE}
AWS_SECRET_ACCESS_KEY_FILE: ${AWS_SECRET_ACCESS_KEY_FILE}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,42 @@
'use client';
import Thumbnail from '@/components/misc/VideoCard/thumbnail';
import { Card, CardContent } from '@/components/ui/card';
import { fetchAsset } from '@/lib/services/sessionService';
import { fetchSessionRenderingProgress } from '@/lib/services/sessionService';
import { IExtendedSession } from '@/lib/types';
import { formatDate } from '@/lib/utils/time';
import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import { ProcessingStatus } from 'streameth-new-server/src/interfaces/session.interface';
import Preview from './Preview';
import { Asset } from 'livepeer/models/components/asset';
export default function Clip({ session }: { session: IExtendedSession }) {
const { name, coverImage, assetId } = session;
const [asset, setAsset] = useState<Asset | null>(null);
const [progress, setProgress] = useState<{
type: 'progress' | 'done';
progress: number;
} | null>(null);
const [isOpen, setIsOpen] = useState(false);
const router = useRouter();
const getAsset = async () => {
if (assetId) {
const asset = await fetchAsset({
assetId: assetId,
});
setAsset(asset);
}
};

useEffect(() => {
getAsset();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [assetId]);

useEffect(() => {
if (asset?.status?.phase === 'processing') {
const interval = setInterval(() => {
const getAsset = async () => {
const progress = await fetchSessionRenderingProgress({
sessionId: session._id,
});
setProgress(progress);
};
setInterval(() => {
if (
session.processingStatus === ProcessingStatus.rendering ||
session.processingStatus === ProcessingStatus.pending
) {
getAsset();
}, 10000);
return () => clearInterval(interval);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [asset?.status?.phase]);
}
}, 20000);
}, [session.processingStatus, session._id]);

return (
<>
<div>
{asset?.status?.phase === 'processing' ||
session.processingStatus === ProcessingStatus.pending ||
{session.processingStatus === ProcessingStatus.pending ||
session.processingStatus === ProcessingStatus.rendering ? (
<Card className="w-full cursor-not-allowed animate-pulse max-w-2xl overflow-hidden px-2 py-1 shadow-none bg-muted">
<div className="flex justify-center items-center">
Expand All @@ -57,9 +51,9 @@ export default function Clip({ session }: { session: IExtendedSession }) {
: 'Video is processing...'}
</p>
<div className="flex items-center justify-between gap-2">
{asset?.status?.phase === 'processing' && (
{session.processingStatus === ProcessingStatus.rendering && (
<p className="text-sm text-gray-500 mt-1">
{Math.round(Number(asset?.status?.progress ?? 0) * 100)}%
{Math.round(Number(progress?.progress ?? 0) * 100)}%
complete.
</p>
)}
Expand Down Expand Up @@ -120,7 +114,7 @@ export default function Clip({ session }: { session: IExtendedSession }) {
)}
</div>

{isOpen && asset && (
{isOpen && (
<Preview
isOpen={isOpen}
// asset={asset}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const SelectAnimation = ({
path={`organizations/${organizationId}/animations`}
options={{
placeholder: 'Upload animation video (max 15MB)',
maxSize: 15 * 1024 * 1024, // 15MB
maxSize: 20 * 1024 * 1024, // 15MB
}}
onChange={(e) => {
// Store the S3 URL directly
Expand Down
1 change: 0 additions & 1 deletion packages/app/components/misc/SearchBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export default function SearchBar({
})
.then((data) => {
const items = data.data.slice(0, 10);
console.log(data.data);
setSearchResults(items);
setIsLoading(false);
});
Expand Down
14 changes: 13 additions & 1 deletion packages/app/lib/services/sessionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,26 @@ export const fetchSessionMetrics = async ({
}
};

export const fetchSessionRenderingProgress = async ({
sessionId,
}: {
sessionId: string;
}): Promise<{ type: 'progress' | 'done'; progress: number }> => {
const response = await fetch(`${apiUrl()}/sessions/${sessionId}/progress`, {
cache: 'no-store',
});
return (await response.json()).data;
};


export const fetchAsset = async ({
assetId,
}: {
assetId: string;
}): Promise<Asset | null> => {
try {
const response = await fetch(`${apiUrl()}/streams/asset/${assetId}`, {
cache: 'no-store',
next: { revalidate: 100 },
});
if (!response.ok) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/controllers/index.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ export class IndexController extends Controller {
end: session.end,
organizationId: session.organizationId,
type: session.type,
processingStatus: ProcessingStatus.completed,
processingStatus: ProcessingStatus.pending,
}),
clipEditor.updateOne({
status: ClipEditorStatus.uploading,
Expand Down
34 changes: 33 additions & 1 deletion packages/server/src/controllers/session.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { CreateSessionDto } from '@dtos/session/create-session.dto';
import { UpdateSessionDto } from '@dtos/session/update-session.dto';
import { UploadSessionDto } from '@dtos/session/upload-session.dto';
import { IMarker } from '@interfaces/marker.interface';
import { ISession } from '@interfaces/session.interface';
import { ISession, ProcessingStatus } from '@interfaces/session.interface';
import clipEditorService from '@services/clipEditor.service';
import SessionServcie from '@services/session.service';
import { IStandardResponse, SendApiResponse } from '@utils/api.response';
import {
Expand All @@ -20,6 +21,7 @@ import {
SuccessResponse,
Tags,
} from 'tsoa';
import { getAsset } from '@utils/livepeer';

@Tags('Session')
@Route('sessions')
Expand Down Expand Up @@ -217,4 +219,34 @@ export class SessionController extends Controller {
);
return SendApiResponse('highlights extracted', highlights);
}
/**
* @summary get session rendeing progress
*/
@SuccessResponse('200')
@Get('{sessionId}/progress')
async getSessionRenderingProgress(@Path() sessionId: string): Promise<
IStandardResponse<{
type: 'progress' | 'done';
progress: number;
}>
> {
const session = await this.sessionService.get(sessionId);
if (session.processingStatus === ProcessingStatus.rendering) {
const progress =
await clipEditorService.getSessionRenderingProgress(sessionId);
return SendApiResponse('session rendering progress', progress);
}
if (session.processingStatus === ProcessingStatus.pending) {
const asset = await getAsset(session.assetId);
return SendApiResponse('session rendering progress', {
type: 'done',
progress: asset.status.progress,
});
}

return SendApiResponse('session rendering progress', {
type: 'done',
progress: 100,
});
}
}
1 change: 1 addition & 0 deletions packages/server/src/controllers/stream.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export class StreamController extends Controller {
}
}


/**
* @summary Generate thumbnail
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/middlewares/multer.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import multer from 'multer';
export const multerConfig = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 15 * 1024 * 1024, // 15MB limit
fileSize: 20 * 1024 * 1024, // 15MB limit
},
});
40 changes: 40 additions & 0 deletions packages/server/src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,16 @@ const models: TsoaRoute.Models = {
"additionalProperties": false,
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"IStandardResponse__type-progress-or-done--progress-number__": {
"dataType": "refObject",
"properties": {
"status": {"dataType":"string","required":true},
"message": {"dataType":"string","required":true},
"data": {"dataType":"nestedObjectLiteral","nestedProperties":{"progress":{"dataType":"double","required":true},"type":{"dataType":"union","subSchemas":[{"dataType":"enum","enums":["progress"]},{"dataType":"enum","enums":["done"]}],"required":true}}},
},
"additionalProperties": false,
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"ImportType": {
"dataType": "refEnum",
"enums": ["gsheet","pretalx"],
Expand Down Expand Up @@ -2827,6 +2837,36 @@ export function RegisterRoutes(app: Router,opts?:{multer?:ReturnType<typeof mult
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.get('/sessions/:sessionId/progress',
...(fetchMiddlewares<RequestHandler>(SessionController)),
...(fetchMiddlewares<RequestHandler>(SessionController.prototype.getSessionRenderingProgress)),

async function SessionController_getSessionRenderingProgress(request: ExRequest, response: ExResponse, next: any) {
const args: Record<string, TsoaRoute.ParameterSchema> = {
sessionId: {"in":"path","name":"sessionId","required":true,"dataType":"string"},
};

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args, request, response });

const controller = new SessionController();

await templateService.apiHandler({
methodName: 'getSessionRenderingProgress',
controller,
response,
next,
validatedArgs,
successStatus: 200,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.post('/schedule/import',
authenticateMiddleware([{"jwt":["org"]}]),
...(fetchMiddlewares<RequestHandler>(ScheduleImporterController)),
Expand Down
69 changes: 61 additions & 8 deletions packages/server/src/services/clipEditor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ import {
IClipEditor,
} from '@interfaces/clip.editor.interface';
import { clipsQueue } from '@utils/redis';

interface RemotionProgressResponse {
type: 'success';
data:
| {
type: 'progress';
progress: number;
}
| {
type: 'done';
url: string;
size: number;
};
}

export class ClipEditorService extends SessionService {
constructor(
private readonly livepeer: Livepeer,
Expand Down Expand Up @@ -73,9 +88,9 @@ export class ClipEditorService extends SessionService {
async launchRemotionRender(clipEditor: IClipEditor) {
// get all event session data based on event session ids
const sessionIds = clipEditor.events
.filter(e => e.sessionId)
.map(e => e.sessionId);
.filter((e) => e.sessionId)
.map((e) => e.sessionId);

// Get all sessions in one query
const eventSessions = await Session.find({
_id: { $in: sessionIds },
Expand Down Expand Up @@ -110,7 +125,9 @@ export class ClipEditorService extends SessionService {
}

// Otherwise, look up the session from our map
const session = e.sessionId ? sessionsMap[e.sessionId.toString()] : null;
const session = e.sessionId
? sessionsMap[e.sessionId.toString()]
: null;

if (!session?.source?.streamUrl) {
console.log(
Expand All @@ -126,15 +143,19 @@ export class ClipEditorService extends SessionService {
url: session?.source?.streamUrl || '', // Always provide empty string as fallback
};

if (e.label === 'main' && clipEditor.captionEnabled && session?.transcripts?.chunks) {
if (
e.label === 'main' &&
clipEditor.captionEnabled &&
session?.transcripts?.chunks
) {
eventData.transcript = {
language: 'en',
text: session.transcripts.text || '',
words: session.transcripts.chunks.map(chunk => ({
words: session.transcripts.chunks.map((chunk) => ({
word: chunk.word,
start: chunk.start,
end: chunk.end || chunk.start + 1, // Fallback end time if not provided
}))
})),
};
}

Expand Down Expand Up @@ -180,6 +201,38 @@ export class ClipEditorService extends SessionService {
);
return data;
}

async getSessionRenderingProgress(sessionId: string) {
const session = await this.findByClipSessionId(sessionId);

const response = await fetch(
`${config.remotion.host}/api/lambda/progress`,
{
method: 'POST',
body: JSON.stringify({
id: session.renderId,
bucketName: 'remotionlambda-useast2-w6uye0gtql',
}),
headers: {
'Content-Type': 'application/json',
},
},
);

const data = (await response.json()) as RemotionProgressResponse;
if (data.data.type === 'progress') {
return data.data;
}

if (data.data.type === 'done') {
return {
type: 'done' as const,
progress: 1,
};
}

return data.data;
}
}

const clipEditorService = new ClipEditorService(
Expand All @@ -189,4 +242,4 @@ const clipEditorService = new ClipEditorService(
new StateService(),
);

export default clipEditorService;
export default clipEditorService;
Loading

0 comments on commit 265f4ce

Please sign in to comment.