diff --git a/stream/config.json b/stream/config.json new file mode 100644 index 0000000..d0812e1 --- /dev/null +++ b/stream/config.json @@ -0,0 +1,25 @@ +{ + "FFMPEG_PATH": "", + "STREAM_URL": "rtmp://localhost/live/opensourceradio", + + "FONT_SIZE": "10", + "FONT_COLOR": "#FFFFFF", + "FONT_BORDER": "#000000", + + "VIDEO_WIDTH": "1280", + "VIDEO_HEIGHT": "720", + "VIDEO_CODEC": "libx264", + "VIDEO_BIT_RATE": "2500k", + + "AUDIO_BIT_RATE": "128k", + "AUDIO_SAMPLE_RATE": "44100", + "AUDIO_CODEC": "aac", + + "NUM_THREADS": "2", + "PRESET": "superfast", + "CRF": "28", + "BUFFER_SIZE": "2500k", + "FRAMES_PER_SECOND": "24", + + "OVERLAY_TITLE": "opensourceradio" +} \ No newline at end of file diff --git a/stream/index.js b/stream/index.js index 0bd8496..7e0f218 100644 --- a/stream/index.js +++ b/stream/index.js @@ -4,10 +4,11 @@ const musicMetadata = require('music-metadata'); const stream = require('./src/stream'); const { findCurrentSchedule } = require('./src/schedule'); -const { printMetadata, printHeader, getNextSong, printSchedule, writeAppState, loadAppState } = require('./src/utils'); +const { printMetadata, printHeader, getNextSong, printSchedule, writeAppState, loadAppState, getConfig } = require('./src/utils'); + const videoPath = `${__dirname}/assets/video/dock.mp4`; const audioPath = `${__dirname}/assets/audio/`; -const STREAM_URL = 'rtmp://localhost/live/opensourceradio'; +const { STREAM_URL } = getConfig(); const appState = { currentSchedule: null, @@ -35,7 +36,7 @@ const playSong = () => { .then(metadata => { printMetadata(metadata); return stream(STREAM_URL, videoPath, currentAudioPath, metadata) - }); + }).catch(onSongError); } const onSongFinished = msg => { @@ -50,13 +51,14 @@ const onSongFinished = msg => { const onSongError = err => { console.log(chalk.red('ffmpeg stream error:'), err); + console.log('Quitting process...'); + process.exit(-1); - + //WRITE STATE TO FILE? const writeState = Object.create({}, appState); writeState.lastSongPlayed = getNextSong(writeState.playlist, writeState.lastSongPlayed); writeState.songCount++; - - //WRITE STATE TO FILE? + writeAppState(writeState) .then(() => { process.exit(-1); @@ -100,6 +102,7 @@ const radioInterval = () => { console.log(chalk.magenta(`Welcome to opensource radio. 📻`)); console.log(chalk.magenta('Starting server...')) + loadAppState() .then(state => { console.log(chalk.blue('Loaded app state from file.')); diff --git a/stream/src/stream/index.js b/stream/src/stream/index.js index f4ae29e..90c6475 100644 --- a/stream/src/stream/index.js +++ b/stream/src/stream/index.js @@ -2,10 +2,17 @@ const ffmpeg = require('fluent-ffmpeg'); const progress = require('cli-progress'); const chalk = require('chalk'); -const { printFfmpegHeader } = require('../utils'); +const { printFfmpegHeader, getConfig } = require('../utils'); const addOptions = require('./options'); const addFilters = require('./filters'); +const { FFMPEG_PATH } = getConfig(); + +if(FFMPEG_PATH && FFMPEG_PATH !== "") { + console.log(chalk.magenta('Setting custom ffmpeg path: ', FFMPEG_PATH)); + ffmpeg.setFfmpegPath(FFMPEG_PATH); +} + const makeProgressBar = () => { return new progress.Bar({ format: 'Audio Progress {bar} {percentage}% | Time Playing: {duration_formatted} |' }, progress.Presets.shades_classic); } diff --git a/stream/src/stream/options.js b/stream/src/stream/options.js index b98e794..5dfe15a 100644 --- a/stream/src/stream/options.js +++ b/stream/src/stream/options.js @@ -1,18 +1,21 @@ -const WIDTH = 1280; -const HEIGHT = 720; +const { getConfig } = require('../utils'); -const VIDEO_CODEC = 'libx264'; -const VIDEO_BIT_RATE = '2500k'; -const AUDIO_BIT_RATE = '128k'; +const { + VIDEO_WIDTH, + VIDEO_HEIGHT, + VIDEO_CODEC, + VIDEO_BIT_RATE, -const AUDIO_SAMPLE_RATE= '44100'; -const AUDIO_CODEC = 'aac' + AUDIO_BIT_RATE, + AUDIO_SAMPLE_RATE, + AUDIO_CODEC, -const NUM_THREADS = '2'; -const PRESET = 'superfast'; -const CRF = '28'; -const BUFFER_SIZE = '2500k'; -const FRAMES_PER_SECOND = '24'; + NUM_THREADS, + PRESET, + CRF, + BUFFER_SIZE, + FRAMES_PER_SECOND +} = getConfig(); const addOptions = (metadata) => { @@ -30,7 +33,7 @@ const addOptions = (metadata) => { `-pix_fmt yuv420p` ]; - outputOptions.push(`-s ${WIDTH}x${HEIGHT}`); + outputOptions.push(`-s ${VIDEO_WIDTH}x${VIDEO_HEIGHT}`); outputOptions.push(`-b:v ${VIDEO_BIT_RATE}`); outputOptions.push(`-minrate ${VIDEO_BIT_RATE}`); diff --git a/stream/src/stream/overlay.js b/stream/src/stream/overlay.js index a1f045f..325ca2a 100644 --- a/stream/src/stream/overlay.js +++ b/stream/src/stream/overlay.js @@ -1,7 +1,13 @@ +const { getConfig } = require('../utils'); + +const { + FONT_SIZE, + FONT_COLOR, + FONT_BORDER, + OVERLAY_TITLE +} = getConfig(); + const FONT_PATH = `${process.cwd()}/assets/font/scp.ttf`; -const FONT_SIZE = '10' -const FONT_COLOR = '#FFFFFF'; -const FONT_BORDER = "#000000"; const X_POSITION = 2; const sanitizeText = str => { @@ -28,7 +34,7 @@ const addOverlay = metadata => { const overlayTextItems = []; let yPosition = 5; - overlayTextItems.push(createOverlayText('opensourceradio', X_POSITION, yPosition)); + overlayTextItems.push(createOverlayText(OVERLAY_TITLE, X_POSITION, yPosition)); yPosition += 8; if(common.artist) { diff --git a/stream/src/utils.js b/stream/src/utils.js index 94e6bdb..dc12d2a 100644 --- a/stream/src/utils.js +++ b/stream/src/utils.js @@ -1,9 +1,9 @@ const fs = require('fs'); const moment = require('moment'); const chalk = require('chalk'); -const getFullPath = name => { return `${__dirname}/../assets/audio/${name}`; } -const pad = n => n < 10 ? `0${n}` : n; +const getConfig = () => require('../config.json'); +const pad = n => n < 10 ? `0${n}` : n; const TIME_FORMAT = 'MMM DD YYYY hh:mm a'; const printMetadata = metadata => { @@ -91,7 +91,6 @@ function loadAppState() { } module.exports = { - getFullPath, printHeader, printMetadata, printSchedule, @@ -101,4 +100,5 @@ module.exports = { writeAppState, loadAppState, TIME_FORMAT, + getConfig };