fix(sequences): coerce NUMERIC frame_rate to float in all API responses
node-postgres returns NUMERIC columns as strings by default. Add a mapSeq() helper that parses frame_rate to a JS float before any response is sent. Affected routes: GET /, POST /, PUT /:id, GET /:id.
This commit is contained in:
parent
bfc2649909
commit
4d0e715982
1 changed files with 16 additions and 7 deletions
|
|
@ -7,6 +7,15 @@ import { requireAuth } from '../middleware/auth.js';
|
|||
const router = express.Router();
|
||||
router.use(requireAuth);
|
||||
|
||||
// ── Row mapper ────────────────────────────────────────────────────────────────
|
||||
// node-postgres returns NUMERIC columns as strings. Coerce frame_rate to a
|
||||
// JS float before sending any sequence object to clients.
|
||||
|
||||
function mapSeq(row) {
|
||||
if (!row) return row;
|
||||
return { ...row, frame_rate: parseFloat(row.frame_rate) || 59.94 };
|
||||
}
|
||||
|
||||
// ── Timecode helpers ──────────────────────────────────────────────────────────
|
||||
//
|
||||
// generateEDL emits CMX3600 timecode using the sequence's frame_rate.
|
||||
|
|
@ -19,7 +28,7 @@ router.use(requireAuth);
|
|||
function pad2(n) { return String(Math.floor(n)).padStart(2, '0'); }
|
||||
|
||||
function framesToTC(totalFrames, fps) {
|
||||
fps = fps || 59.94;
|
||||
fps = parseFloat(fps) || 59.94;
|
||||
const fc = Math.max(0, Math.round(totalFrames));
|
||||
|
||||
// 29.97 DF ─ drop 2 frames per minute except every 10th
|
||||
|
|
@ -77,7 +86,7 @@ function framesToTC(totalFrames, fps) {
|
|||
}
|
||||
|
||||
function generateEDL(seqName, clips, fps) {
|
||||
fps = fps || 59.94;
|
||||
fps = parseFloat(fps) || 59.94;
|
||||
const lines = [`TITLE: ${seqName}`, ''];
|
||||
clips.forEach((c, i) => {
|
||||
const num = String(i + 1).padStart(3, '0');
|
||||
|
|
@ -105,7 +114,7 @@ router.get('/', async (req, res, next) => {
|
|||
`SELECT * FROM sequences WHERE project_id = $1 ORDER BY updated_at DESC`,
|
||||
[project_id]
|
||||
);
|
||||
res.json(r.rows);
|
||||
res.json(r.rows.map(mapSeq));
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
|
|
@ -125,7 +134,7 @@ router.post('/', async (req, res, next) => {
|
|||
VALUES ($1, $2, $3, $4, $5) RETURNING *`,
|
||||
[project_id, name, frame_rate, width, height]
|
||||
);
|
||||
res.status(201).json(r.rows[0]);
|
||||
res.status(201).json(mapSeq(r.rows[0]));
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
|
|
@ -160,7 +169,7 @@ router.get('/:id', async (req, res, next) => {
|
|||
})
|
||||
);
|
||||
|
||||
res.json({ ...seqR.rows[0], clips });
|
||||
res.json({ ...mapSeq(seqR.rows[0]), clips });
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
|
|
@ -183,7 +192,7 @@ router.put('/:id', async (req, res, next) => {
|
|||
params
|
||||
);
|
||||
if (!r.rows.length) return res.status(404).json({ error: 'Sequence not found' });
|
||||
res.json(r.rows[0]);
|
||||
res.json(mapSeq(r.rows[0]));
|
||||
} catch (e) { next(e); }
|
||||
});
|
||||
|
||||
|
|
@ -254,7 +263,7 @@ router.post('/:id/export/edl', async (req, res, next) => {
|
|||
try {
|
||||
const seqR = await pool.query(`SELECT * FROM sequences WHERE id = $1`, [req.params.id]);
|
||||
if (!seqR.rows.length) return res.status(404).json({ error: 'Sequence not found' });
|
||||
const seq = seqR.rows[0];
|
||||
const seq = mapSeq(seqR.rows[0]);
|
||||
|
||||
// Export V1 clips only (primary video track) sorted by position
|
||||
const clipsR = await pool.query(
|
||||
|
|
|
|||
Loading…
Reference in a new issue