add services/capture/src/routes/capture.js
This commit is contained in:
parent
dfffca879a
commit
7c7fcd2b0d
1 changed files with 140 additions and 0 deletions
140
services/capture/src/routes/capture.js
Normal file
140
services/capture/src/routes/capture.js
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
import express from 'express';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import captureManager from '../capture-manager.js';
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
const MAM_API_URL = process.env.MAM_API_URL || 'http://mam-api:3000';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /devices
|
||||||
|
* List available DeckLink devices
|
||||||
|
*/
|
||||||
|
router.get('/devices', (req, res) => {
|
||||||
|
try {
|
||||||
|
const devices = [];
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
output = execSync('ffmpeg -f decklink -list_devices 1 -i dummy 2>&1', {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// ffmpeg returns non-zero, but stderr is still captured
|
||||||
|
output = error.stderr ? error.stderr.toString() : error.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse ffmpeg output for DeckLink device names
|
||||||
|
// Format: [decklink @ ...] "DeckLink Quad 2" (input #0)
|
||||||
|
const lines = output.split('\n');
|
||||||
|
let deviceIndex = 0;
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const match = line.match(/^\s*\[decklink[^\]]*\]\s+"([^"]+)"/);
|
||||||
|
if (match) {
|
||||||
|
devices.push({
|
||||||
|
index: deviceIndex,
|
||||||
|
name: match[1],
|
||||||
|
});
|
||||||
|
deviceIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json({ devices });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error listing devices:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to list devices' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /status
|
||||||
|
* Get current capture status
|
||||||
|
*/
|
||||||
|
router.get('/status', (req, res) => {
|
||||||
|
try {
|
||||||
|
const status = captureManager.getStatus();
|
||||||
|
res.json(status);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting status:', error);
|
||||||
|
res.status(500).json({ error: 'Failed to get status' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /start
|
||||||
|
* Start a new capture session
|
||||||
|
* Body: { project_id, bin_id, clip_name, device }
|
||||||
|
*/
|
||||||
|
router.post('/start', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { project_id, bin_id, clip_name, device } = req.body;
|
||||||
|
|
||||||
|
if (!project_id || !bin_id || !clip_name || device === undefined) {
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'Missing required fields: project_id, bin_id, clip_name, device',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await captureManager.start({
|
||||||
|
projectId: project_id,
|
||||||
|
binId: bin_id,
|
||||||
|
clipName: clip_name,
|
||||||
|
device,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json(session);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error starting capture:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /stop
|
||||||
|
* Stop the current capture session
|
||||||
|
* Body: { session_id }
|
||||||
|
*/
|
||||||
|
router.post('/stop', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { session_id } = req.body;
|
||||||
|
|
||||||
|
if (!session_id) {
|
||||||
|
return res.status(400).json({ error: 'Missing required field: session_id' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const completedSession = await captureManager.stop(session_id);
|
||||||
|
|
||||||
|
// Register asset with mam-api
|
||||||
|
try {
|
||||||
|
const mamResponse = await fetch(`${MAM_API_URL}/api/v1/assets`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
projectId: completedSession.projectId,
|
||||||
|
binId: completedSession.binId,
|
||||||
|
clipName: completedSession.clipName,
|
||||||
|
hiresKey: completedSession.hiresKey,
|
||||||
|
proxyKey: completedSession.proxyKey,
|
||||||
|
duration: completedSession.duration,
|
||||||
|
capturedAt: completedSession.startedAt,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!mamResponse.ok) {
|
||||||
|
console.warn(
|
||||||
|
`MAM API registration returned ${mamResponse.status}: ${await mamResponse.text()}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (mamError) {
|
||||||
|
console.warn('Failed to register asset with MAM API:', mamError.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(completedSession);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error stopping capture:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
Loading…
Reference in a new issue