Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions backendControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
const blessed = require('blessed');

module.exports = function blessedUI(io,MediaPlayer) {
require('dotenv').config();
const playlistUrl = process.env.URL || 'http://localhost:3000';
let repeat = process.env.REPEAT;
const argv = require('yargs-parser')(process.argv);
let manualOverride = false;

// Start mediaPlayer
let mediaPlayer = new MediaPlayer(io);
mediaPlayer.init();

const screen = blessed.screen();
const body = blessed.box({
top: 0,
left: 0,
height: '100%-1',
width: '100%',
keys: true,
mouse: true,
alwaysScroll: true,
scrollable: true,
scrollbar: {
ch: ' ',
bg: 'red'
}
});
const inputBar = blessed.textbox({
bottom: 0,
left: 0,
height: 1,
width: '100%',
keys: true,
mouse: true,
inputOnFocus: true,
style: {
fg: 'white',
bg: 'blue' // Blue background so you see this is different from body
}
});

function log(text) {
body.pushLine(text);
screen.render();
}

screen.append(body);
screen.append(inputBar);

screen.key(['escape', 'q', 'C-c'], (ch, key) => {
process.exit(0);
});
screen.key(['left'], (ch, key) => {
manualOverride = true;
mediaPlayer.previous();
});
screen.key(['right'], (ch, key) => {
manualOverride = true;
mediaPlayer.next();
});
inputBar.on('submit', (text) => {
log(text);
inputBar.clearValue();
});
screen.key('enter', (ch, key) => {
inputBar.focus();
});

io.on('connection', (client) => {
let index = mediaPlayer.mediaIndex;
let url = `${playlistUrl}${mediaPlayer.playlist[index]}`;
if (argv.m3u) {
//if the url is remote, don't append the project root url
if (url.startsWith('http')) {
url = `${mediaPlayer.playlist[index]['url']}`;
}
else {
url = `${playlistUrl}${mediaPlayer.playlist[index]['url']}`;
}
}
else url = `${playlistUrl}${mediaPlayer.playlist[index]}`;
const timestamp = mediaPlayer.getTimestamp();
const mediaType = mediaPlayer.mediaTypes[index];
const duration = mediaPlayer.mediaLengths[index];
console.log(`Client connected! Now playing ${mediaType} file ${url}. Timestamp: ${timestamp}`);
client.emit('updateClient', {
mediaType: mediaType,
timestamp: timestamp,
duration: duration,
url: url
});
});

// Stop server depending on value given from REPEAT constant
function checkRepeat(repeat, count) {
if (manualOverride) {return;}
if (repeat == count) {
console.log('we have played through the list '+count+' times');
process.exit('bye bye!');
}
else if (repeat==='false' && count == 1) {
console.log('we have played through the list');
process.exit('bye bye!');
}
//if there's no repeat count or repeat is anything other than false, repeat ad infinitum
}

setInterval(() => {
let index = mediaPlayer.mediaIndex;
let total = mediaPlayer.playlist.length;
let timestamp = mediaPlayer.getTimestamp();
let mediaType = mediaPlayer.mediaTypes[index];
let playlistCount = mediaPlayer.playlistCount;
let data = {
humanReadableIndex: index + 1,
mediaType: mediaType,
timestamp: timestamp,
totalFiles: total
};
checkRepeat(repeat,playlistCount);
io.sockets.emit('timestamp', data);
}, 3000);

setInterval(()=>{
mediaPlayer.tick();
},500);

};
155 changes: 77 additions & 78 deletions media-player.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const videoTypes = new Set(['.ogv', '.mp4']);
const audioTypes = new Set(['.mp3', '.flac', '.oga', '.wav']);
const ambiguousTypes = new Set(['.webm', '.ogg']); // These can be either audio or video

let count = 0;

//import m3u files into sync. atm files will need to be located in the project directory.
function importM3U(file) {
Expand All @@ -21,15 +20,14 @@ function importM3U(file) {
return parser.manifest.segments;
}



class MediaPlayer {

constructor(io) {
this.io = io;
this.mediaIndex = 0;
this.mediaTypes = [];
this.startTime = null;
this.elapsedTime = null;
this.filesProcessed = 0;
this.playlistCount = 0;

Expand Down Expand Up @@ -64,6 +62,19 @@ class MediaPlayer {
console.warn(`Weird. Somehow one of your files in your playlist is missing a path`);
}
else {
if (file.uri) {
//get the name of the file which will be the title of the media
let name = path.parse(file.uri).name;
const shellCommand = 'ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1';
const execute = require('child_process').execSync;
let duration = execute(`${shellCommand} "./public${file.uri}"`).toString();
//return an object with relevant information
return {
duration: parseFloat(duration),
url: file.uri,
name: name,
};
}
console.warn(`one of your files in your playlist ${file.uri} is missing a duration`);
}
}
Expand Down Expand Up @@ -123,66 +134,60 @@ class MediaPlayer {
}

// Compute video end times
setBreakpoints() {
let totalTime = 0;
this.breakpoints = this.mediaLengths.map((currentVal) => {
return totalTime += currentVal;
});
previous(){
console.log("previous");
this.mediaIndex--;
if(this.mediaIndex < 0){
this.mediaIndex = this.playlist.length - 1;
}

this.emitNewMediaEvent() ;
}
next(){
console.log("next");
this.mediaIndex++;
if(this.mediaIndex >= this.playlist.length){
this.mediaIndex = 0;
this.playlistCount++;
}
this.emitNewMediaEvent() ;
}
emitNewMediaEvent() {
this.startTime = new Date();
let url = `${playlistUrl}${this.playlist[this.mediaIndex]}`;
//if were in m3u mode were passing an object so we have to fetch the url from the object
if (argv.m3u) {
//check the url for a remote http string
if (this.playlist[this.mediaIndex]['url'].startsWith('http')) {
url = `${this.playlist[this.mediaIndex]['url']}`;
}
else {
//else its a local file
url = `${playlistUrl}${this.playlist[this.mediaIndex]['url']}`;
}

}
const mediaType = this.mediaTypes[this.mediaIndex];
const duration = this.mediaLengths[this.mediaIndex];
const data = {
url: url,
duration: duration,
mediaType: mediaType
};

this.io.sockets.emit('newMedia', data);
}

startTimers() {
this.startTime = new Date(); // Start main timer
}

for (let index = 0; index < this.breakpoints.length; index++) {
let breakpointMillisecs = this.breakpoints[index] * 1000;

// Set timers to update mediaIndex and notify users of next URL in playlist
if (index === (this.breakpoints.length - 1)) {
setTimeout(() => {
// Emit socket event here
this.mediaIndex = 0;
emitNewMediaEvent();
this.restartTimers();
}, breakpointMillisecs);
} else {
setTimeout(() => {
// Emit socket event here
this.mediaIndex++;
emitNewMediaEvent();
}, breakpointMillisecs);
}
tick() {
this.elapsedTime = (new Date() - this.startTime)/1000;
if (this.elapsedTime >= this.mediaLengths[this.mediaIndex]) {
this.startTime = new Date();
this.next();
}

const emitNewMediaEvent = () => {

let url = `${playlistUrl}${this.playlist[this.mediaIndex]}`;
//if were in m3u mode were passing an object so we have to fetch the url from the object
if (argv.m3u) {
//check the url for a remote http string
if (this.playlist[this.mediaIndex]['url'].startsWith('http')) {
url = `${this.playlist[this.mediaIndex]['url']}`;
}
else {
//else its a local file
url = `${playlistUrl}${this.playlist[this.mediaIndex]['url']}`;
}

}
const mediaType = this.mediaTypes[this.mediaIndex];
const duration = this.mediaLengths[this.mediaIndex];
const data = {
url: url,
duration: duration,
mediaType: mediaType
};

//on new media event, count each time the index is at zero.
if (this.mediaIndex == 0) {
this.playlistCount++;
}
this.io.sockets.emit('newMedia', data);
};
}

restartTimers() {
Expand All @@ -199,7 +204,6 @@ class MediaPlayer {
this.mediaLengths[index] = parseFloat(duration);
this.filesProcessed++;
if (this.filesProcessed === this.mediaLengths.length) {
this.setBreakpoints();
this.startTimers();
}
});
Expand All @@ -209,9 +213,8 @@ class MediaPlayer {
this.mediaLengths[index] = file.duration;
this.filesProcessed++;
if (this.filesProcessed === this.mediaLengths.length) {
this.setBreakpoints();
this.startTimers();
}
this.startTimers();
}
}

// Initialize by parsing media
Expand All @@ -231,27 +234,23 @@ class MediaPlayer {
}

getTimestamp() {
let timePassed = (new Date() - this.startTime)/1000;
for (let index = 0; index < this.breakpoints.length; index++) {
if (timePassed <= this.breakpoints[index]) {
let videoStartTime = this.breakpoints[index - 1] || 0;
let timestamp = timePassed - videoStartTime;
//if were in m3u mode were passing an object so we have to fetch the url from the object
if (argv.m3u) {
//check if the url is remote
if (this.playlist[index]['url'].startsWith('http')) {
console.log(`watching file ${this.playlist[index]['url']}; ${timestamp}s`);
}
//else include localhost for the person watching the backend of this app.
else console.log(`watching file ${playlistUrl}${this.playlist[index]['url']}; ${timestamp}s`);
}
else {
console.log(`watching file ${playlistUrl}${this.playlist[index]}; ${timestamp}s`);
}
this.elapsedTime = (new Date() - this.startTime)/1000;

return timestamp;
let timestamp = this.elapsedTime;
//if were in m3u mode were passing an object so we have to fetch the url from the object
if (argv.m3u) {
//check if the url is remote
if (this.playlist[this.mediaIndex]['url'].startsWith('http')) {
console.log(`watching file ${this.playlist[this.mediaIndex]['url']}; ${timestamp}s`);
}
//else include localhost for the person watching the backend of this app.
else console.log(`watching file ${playlistUrl}${this.playlist[this.mediaIndex]['url']}; ${timestamp}s`);
}
else {
console.log(`watching file ${playlistUrl}${this.playlist[this.mediaIndex]}; ${timestamp}s`);
}

return timestamp;
}


Expand Down
Loading