feat: setup proper channel api

This commit is contained in:
Ante Brähler
2024-11-13 20:11:43 +00:00
parent 0696dad1da
commit dc38222cb3
5 changed files with 96 additions and 36 deletions

View File

@@ -0,0 +1,66 @@
const ffmpegService = require('../services/FFmpegService');
const storageService = require('../services/StorageService');
const Channel = require('../models/Channel');
let channels = [new Channel('DEFAULT_CHANNEL', process.env.DEFAULT_CHANNEL_URL)];
let currentChannel = channels[0];
function setCurrent(req, res) {
const { channelName } = req.body || {};
if (!channelName) {
return res.status(400).json({ status: 'error', message: 'channelName is required' });
}
const nextChannel = channels.find(channel => channel.name === channelName);
if (!nextChannel) {
res.status(400).json({ status: 'error', message: 'Channel does not exist' });
}
if (currentChannel !== nextChannel) {
const segmentNumber = storageService.getNextSegmentNumber();
storageService.clearStorage();
currentChannel = nextChannel;
ffmpegService.startFFmpeg(nextChannel.url, segmentNumber);
}
res.status(200).json({ status: 'success', channelUrl: currentChannel.url });
}
function getCurrent(_, res) {
if (currentChannel) {
res.status(200).json({ channelName: currentChannel.name, channelUrl: currentChannel.url });
} else {
res.status(404).json({ status: 'error', message: 'No channel active' });
}
}
function getChannels(_, res) {
res.status(200).json({ channels });
}
function addChannel(req, res) {
const { name, url } = req.body;
if (!name || !url) {
return res.status(400).json({ status: 'error', message: 'Channel name and URL are required' });
}
const channelExists = channels.some(channel => channel.url === url);
if (channelExists) {
return res.status(409).json({ status: 'error', message: 'Channel already exists' });
}
const newChannel = new Channel(name, url);
channels.push(newChannel);
res.status(201).json({ status: 'success', message: 'Channel added', channel: newChannel });
}
module.exports = {
setCurrent,
getCurrent,
getChannels,
addChannel
};

View File

@@ -1,41 +1,22 @@
const ffmpegService = require('../services/FFmpegService');
const storageService = require('../services/StorageService');
let currentChannelId = process.env.DEFAULT_CHANNEL_ID;
function setChannel(req, res) {
const { id: channelId } = req.params;
if (channelId && currentChannelId != channelId) {
function start() {
if (!ffmpegService.isFFmpegRunning()) {
const segmentNumber = storageService.getNextSegmentNumber();
storageService.clearStorage();
currentChannelId = channelId;
ffmpegService.startFFmpeg(channelId, segmentNumber);
res.status(200).json({ status: 'success', channelId: currentChannelId });
} else {
res.status(400).json({ status: 'error', message: 'No channel set' });
ffmpegService.startFFmpeg(process.env.DEFAULT_CHANNEL_URL, segmentNumber);
}
}
function getChannel(_, res) {
if (currentChannelId) {
res.status(200).json({ channelId: currentChannelId });
} else {
res.status(404).json({ status: 'error', message: 'No channel set' });
}
}
function stop(req, res) {
function stop() {
if (ffmpegService.isFFmpegRunning()) {
ffmpegService.stopFFmpeg();
res.status(200).json({ status: 'success', message: 'ffmpeg-Process terminated' });
} else {
res.status(400).json({ status: 'error', message: 'No ffmpeg-process running' });
}
}
module.exports = {
setChannel,
getChannel,
start,
stop
};

View File

@@ -1,21 +1,27 @@
const express = require('express');
const dotenv = require('dotenv');
const channelController = require('./controllers/ChannelController');
const streamController = require('./controllers/StreamController');
dotenv.config();
const app = express();
app.use(express.json());
const apiRouter = express.Router();
apiRouter.post('/current', channelController.setCurrent);
apiRouter.get('/current', channelController.getCurrent);
apiRouter.post('/set-channel/:id', streamController.setChannel);
apiRouter.get('/get-channel', streamController.getChannel);
apiRouter.post('/stop', streamController.stop);
apiRouter.get('/', channelController.getChannels);
apiRouter.post('/add', channelController.addChannel);
app.use('/api', apiRouter);
app.use('/channels', apiRouter);
const PORT = 5000;
app.listen(PORT, () => {
console.log(`Server listening on Port ${PORT}`);
streamController.setChannel({ params: { id: process.env.DEFAULT_CHANNEL_ID } }, { status: () => ({ json: () => {} }) });
streamController.start();
});

8
models/Channel.js Normal file
View File

@@ -0,0 +1,8 @@
class Channel {
constructor(name, url) {
this.name = name;
this.url = url;
}
}
module.exports = Channel;

View File

@@ -2,26 +2,25 @@ const { spawn } = require('child_process');
require('dotenv').config();
let currentFFmpegProcess = null;
const BASE_URL = process.env.BASE_URL;
const STORAGE_PATH = process.env.STORAGE_PATH;
function startFFmpeg(channelId, startNumber) {
function startFFmpeg(channelUrl, startNumber) {
if (currentFFmpegProcess) {
console.log('Terminate previous ffmpeg-Prozess...');
currentFFmpegProcess.kill('SIGTERM');
}
const streamUrl = `${BASE_URL}${channelId}`;
console.log(`Start ffmpeg with URL: ${streamUrl}`);
console.log(`Start ffmpeg with URL: ${channelUrl}`);
currentFFmpegProcess = spawn('ffmpeg', [
'-i', streamUrl,
'-i', channelUrl,
'-c', 'copy',
'-f', 'hls',
'-hls_time', '8',
'-hls_list_size', '5',
'-hls_flags', 'delete_segments',
'-hls_flags', 'delete_segments+program_date_time',
'-start_number', startNumber,
'/mnt/streams/recordings/playlist.m3u8'
`${STORAGE_PATH}/playlist.m3u8`
]);
currentFFmpegProcess.stdout.on('data', (data) => {