everything
This commit is contained in:
218
server/index.js
Normal file
218
server/index.js
Normal file
@@ -0,0 +1,218 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import crypto from 'crypto';
|
||||
import sqlite3 from 'sqlite3';
|
||||
import { open } from 'sqlite';
|
||||
import multer from 'multer';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
|
||||
// Generate a unique link ID
|
||||
const generateUniqueId = () => {
|
||||
return crypto.randomBytes(8).toString('hex');
|
||||
};
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const app = express();
|
||||
const PORT = 3001;
|
||||
|
||||
// Middleware
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Ensure media directory exists
|
||||
const mediaDir = path.join(__dirname, '..', 'public', 'media');
|
||||
if (!fs.existsSync(mediaDir)) {
|
||||
fs.mkdirSync(mediaDir, { recursive: true });
|
||||
}
|
||||
|
||||
// Configure multer for video uploads
|
||||
const storage = multer.diskStorage({
|
||||
destination: (req, file, cb) => {
|
||||
cb(null, mediaDir);
|
||||
},
|
||||
filename: (req, file, cb) => {
|
||||
const timestamp = Date.now();
|
||||
const safeName = `recording_${timestamp}.webm`;
|
||||
cb(null, safeName);
|
||||
}
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage,
|
||||
limits: { fileSize: 100 * 1024 * 1024 }, // 100MB limit
|
||||
fileFilter: (req, file, cb) => {
|
||||
if (file.mimetype.startsWith('video/')) {
|
||||
cb(null, true);
|
||||
} else {
|
||||
cb(new Error('Only video files are allowed'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize SQLite database
|
||||
let db;
|
||||
|
||||
async function initializeDatabase() {
|
||||
db = await open({
|
||||
filename: path.join(__dirname, 'signsync.db'),
|
||||
driver: sqlite3.Database
|
||||
});
|
||||
|
||||
await db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS recordings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
unique_link TEXT UNIQUE NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
recorded_video_path TEXT NOT NULL,
|
||||
youtube_video_url TEXT NOT NULL,
|
||||
name_2 TEXT,
|
||||
email_2 TEXT,
|
||||
recorded_video_path_2 TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
console.log('Database initialized');
|
||||
}
|
||||
|
||||
// API Routes
|
||||
|
||||
// Save recording with user info
|
||||
app.post('/api/recordings', upload.single('video'), async (req, res) => {
|
||||
try {
|
||||
const { name, email, youtubeVideoUrl } = req.body;
|
||||
|
||||
if (!name || !email || !req.file) {
|
||||
return res.status(400).json({
|
||||
error: 'Name, email, and video file are required'
|
||||
});
|
||||
}
|
||||
|
||||
const recordedVideoPath = `/media/${req.file.filename}`;
|
||||
const uniqueLink = generateUniqueId();
|
||||
|
||||
const result = await db.run(
|
||||
`INSERT INTO recordings (unique_link, name, email, recorded_video_path, youtube_video_url)
|
||||
VALUES (?, ?, ?, ?, ?)`,
|
||||
[uniqueLink, name, email, recordedVideoPath, youtubeVideoUrl || '']
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
id: result.lastID,
|
||||
uniqueLink,
|
||||
recordedVideoPath,
|
||||
message: 'Recording saved successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving recording:', error);
|
||||
res.status(500).json({ error: 'Failed to save recording' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get all recordings
|
||||
app.get('/api/recordings', async (req, res) => {
|
||||
try {
|
||||
const recordings = await db.all(
|
||||
'SELECT * FROM recordings ORDER BY created_at DESC'
|
||||
);
|
||||
res.json(recordings);
|
||||
} catch (error) {
|
||||
console.error('Error fetching recordings:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch recordings' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get recording by ID
|
||||
app.get('/api/recordings/:id', async (req, res) => {
|
||||
try {
|
||||
const recording = await db.get(
|
||||
'SELECT * FROM recordings WHERE id = ?',
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
if (!recording) {
|
||||
return res.status(404).json({ error: 'Recording not found' });
|
||||
}
|
||||
|
||||
res.json(recording);
|
||||
} catch (error) {
|
||||
console.error('Error fetching recording:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch recording' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get recording by unique link
|
||||
app.get('/api/share/:uniqueLink', async (req, res) => {
|
||||
try {
|
||||
const recording = await db.get(
|
||||
'SELECT * FROM recordings WHERE unique_link = ?',
|
||||
[req.params.uniqueLink]
|
||||
);
|
||||
|
||||
if (!recording) {
|
||||
return res.status(404).json({ error: 'Recording not found' });
|
||||
}
|
||||
|
||||
res.json(recording);
|
||||
} catch (error) {
|
||||
console.error('Error fetching recording:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch recording' });
|
||||
}
|
||||
});
|
||||
|
||||
// Add second recording to an existing shared recording
|
||||
app.post('/api/share/:uniqueLink/second-video', upload.single('video'), async (req, res) => {
|
||||
try {
|
||||
const { name, email } = req.body;
|
||||
const { uniqueLink } = req.params;
|
||||
|
||||
if (!name || !email || !req.file) {
|
||||
return res.status(400).json({
|
||||
error: 'Name, email, and video file are required'
|
||||
});
|
||||
}
|
||||
|
||||
// Check if recording exists
|
||||
const recording = await db.get(
|
||||
'SELECT * FROM recordings WHERE unique_link = ?',
|
||||
[uniqueLink]
|
||||
);
|
||||
|
||||
if (!recording) {
|
||||
return res.status(404).json({ error: 'Recording not found' });
|
||||
}
|
||||
|
||||
if (recording.recorded_video_path_2) {
|
||||
return res.status(400).json({ error: 'Second video already recorded' });
|
||||
}
|
||||
|
||||
const recordedVideoPath2 = `/media/${req.file.filename}`;
|
||||
|
||||
await db.run(
|
||||
`UPDATE recordings SET name_2 = ?, email_2 = ?, recorded_video_path_2 = ? WHERE unique_link = ?`,
|
||||
[name, email, recordedVideoPath2, uniqueLink]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
recordedVideoPath2,
|
||||
message: 'Second recording saved successfully'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error saving second recording:', error);
|
||||
res.status(500).json({ error: 'Failed to save second recording' });
|
||||
}
|
||||
});
|
||||
|
||||
// Start server
|
||||
initializeDatabase().then(() => {
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on http://localhost:${PORT}`);
|
||||
});
|
||||
});
|
||||
BIN
server/signsync.db
Normal file
BIN
server/signsync.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user