|
|
- const express = require('express');
- const http = require('http');
- const socketIo = require('socket.io');
- const multer = require('multer');
- const fs = require('fs');
- const path = require('path');
- const { OBSWebSocket } = require('obs-websocket-js');
-
- const app = express();
- const server = http.createServer(app);
- const io = socketIo(server);
- const obs = new OBSWebSocket();
-
- const OBS_HOST = 'localhost'; // If OBS is running on the same machine
- const OBS_PORT = 4455; // Default WebSocket port
- const OBS_PASSWORD = 'jBHD5lLvKtHIjIwC'; // Add your WebSocket password here if set
-
- // Set up file storage for uploaded speeches
- const upload = multer({ dest: 'uploads/' });
-
- let speechText = [];
- let currentPosition = 0;
-
- // File to store speech lines
- const SPEECH_LINES_FILE = 'speechLines.txt';
- const SRT_FILE_NAME = 'captions.srt';
-
- // Serve static files (HTML views)
- app.use(express.static(path.join(__dirname, 'public')));
-
- // Connect to OBS WebSocket
- async function connectToOBS() {
- try {
- await obs.connect(`ws://${OBS_HOST}:${OBS_PORT}`, OBS_PASSWORD);
- console.log('Connected to OBS WebSocket');
- } catch (error) {
- console.error('Failed to connect to OBS WebSocket:', error);
- }
- }
-
- connectToOBS();
-
- // Load speech lines from file
- function loadSpeechLines() {
- if (fs.existsSync(SPEECH_LINES_FILE)) {
- const fileContents = fs.readFileSync(SPEECH_LINES_FILE, 'utf-8');
- speechText = fileContents.split('\n').map(line => line.trim()).filter(line => line.length > 0);
- currentPosition = 0; // Reset the position to the start
- console.log('Loaded speech lines from file.');
- }
- }
-
- // Load speech lines when the server starts
- loadSpeechLines();
-
- // Serve speaker view
- app.get('/speaker', (req, res) => {
- res.sendFile(path.join(__dirname, 'public', 'speaker.html'));
- });
-
- // Serve audience/projector view
- app.get('/audience', (req, res) => {
- res.sendFile(path.join(__dirname, 'public', 'audience.html'));
- });
-
- // Endpoint to handle file upload
- app.post('/upload', upload.single('speech'), (req, res) => {
- const filePath = path.join(process.cwd(), req.file.path);
- const fileContents = fs.readFileSync(filePath, 'utf-8');
-
- speechText = fileContents.split('\n').map(line => line.trim()).filter(line => line.length > 0);
- currentPosition = 0;
-
- // Save the loaded speech lines to a file
- fs.writeFileSync(SPEECH_LINES_FILE, speechText.join('\n'));
-
- io.emit('load_speech', speechText);
- res.send('File uploaded and speech loaded.');
- });
-
- // Handle WebSocket connections
- io.on('connection', (socket) => {
- console.log('Client connected');
-
- // Send the full speech to any newly connected client
- if (speechText.length > 0) {
- socket.emit('load_speech', speechText);
- }
-
- // Handle position updates from the speaker view
- socket.on('update_position', (newPosition) => {
- currentPosition = newPosition;
- io.emit('update_caption', currentPosition); // Send to all clients
-
- const currentLine = speechText[currentPosition];
- updateOBSSubtitle(currentLine);
- generateSRT(currentLine);
- });
- });
-
- async function updateOBSSubtitle(captionText) {
- try {
- await obs.call('SendStreamCaption', {
- captionText: captionText
- });
- console.log('Updated OBS Text Source:', captionText);
- } catch (error) {
- console.error('Error updating OBS Text Source:', error);
- }0
- }
-
- async function generateSRT(captionText) {
- try {
- // Check if recording is enabled
- const recordStatus = await obs.call('GetRecordStatus');
- if (recordStatus && recordStatus.outputActive) {
- // Get the recording timecode
- const seconds = recordStatus.outputDuration / 1000; // Assuming this returns a time in seconds
-
- // Format timecode for SRT (HH:MM:SS,ms)
- const startTime = formatTimecode(seconds);
- const endTime = formatTimecode(seconds + 5); // Assume each line is displayed for 5 seconds
-
- // Create SRT entry
- const srtEntry = `${currentPosition + 1}\n${startTime} --> ${endTime}\n${captionText}\n\n`;
- fs.appendFileSync(SRT_FILE_NAME, srtEntry); // Append to SRT file
- console.log('Updated SRT file:', SRT_FILE_NAME);
- }
- } catch (error) {
- console.error('Error generating SRT:', error);
- }
- }
-
- function formatTimecode(seconds) {
- const date = new Date(0);
- date.setSeconds(seconds);
- const hours = String(date.getUTCHours()).padStart(2, '0');
- const minutes = String(date.getUTCMinutes()).padStart(2, '0');
- const secs = String(date.getUTCSeconds()).padStart(2, '0');
- const millis = String((seconds % 1) * 1000).padStart(3, '0');
- return `${hours}:${minutes}:${secs},${millis}`;
- }
-
- const PORT = process.env.PORT || 3000;
- server.listen(PORT, () => {
- console.log(`Server running on port ${PORT}`);
- });
-
- const ngrok = require("@ngrok/ngrok");
-
- async function startTunnel() {
- const listener = await ngrok.forward({
- addr: PORT,
- authtoken: "2nCZjA9FOMFVdHAhIDyI0Tn8y0A_5oFkSL7kXve8RcCeJMXKU",
- domain: "explicitly-trusty-javelin.ngrok-free.app",
- proto: "http"
- });
-
- console.log(`Ingress established at: ${listener.url()}`);
- }
-
- startTunnel();
|