"use strict";
|
|
const fs = require("fs");
|
|
var clients = [];
|
|
var net = require('net');
|
|
try{
|
|
var request = require('request');
|
|
}
|
|
catch(err){
|
|
console.log(err);
|
|
console.log('Go read the damn readme. Run "npm install" or install the request module in some other way.');
|
|
process.exit()
|
|
}
|
|
|
|
var https = require('https');
|
|
var config = {};
|
|
var diff;
|
|
var fileSize;
|
|
var diffIndex;
|
|
var charIndex;
|
|
var diffFound = false;
|
|
var charFound = false;
|
|
var changesMade = false;
|
|
var downloadURL = "";
|
|
console.log("\n\n\n");
|
|
|
|
|
|
// Loading up json files and such that you need
|
|
try{
|
|
config = require('./config.json');
|
|
}
|
|
catch(err){
|
|
}
|
|
|
|
|
|
process.argv.shift();
|
|
process.argv.shift();
|
|
var type = "";
|
|
while(process.argv.length > 0)
|
|
{
|
|
var input = process.argv.shift()
|
|
if (input.startsWith("--"))
|
|
{
|
|
type = input.replace('--','');
|
|
}
|
|
else
|
|
{
|
|
if (type == "")
|
|
{
|
|
console.log('you fucked up');
|
|
process.exit()
|
|
}
|
|
else
|
|
{
|
|
config[type] = input;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Check and display relevant info
|
|
try{
|
|
if(config.folder !== "" && config.folder !== undefined){
|
|
console.log(' Song folder: ' + config.folder);
|
|
}
|
|
else{
|
|
console.log('\nError: Fill in folder field');
|
|
process.exit()
|
|
}
|
|
if(config.difficulty !== "" && config.characteristic !== undefined){
|
|
console.log(' Song characteristic: ' + config.characteristic);
|
|
}
|
|
else{
|
|
console.log(' Song characteristic: Standard');
|
|
}
|
|
if(config.difficulty !== "" && config.difficulty !== undefined){
|
|
console.log(' Song difficulty: ' + config.difficulty);
|
|
}
|
|
else{
|
|
console.log('\nError: Fill in difficulty field');
|
|
process.exit()
|
|
}
|
|
if(config.port !== "" && config.port !== undefined){
|
|
console.log(' Port: ' + config.port);
|
|
}
|
|
else{
|
|
console.log('\nError: Fill in port field');
|
|
process.exit()
|
|
}
|
|
if(config.password != "" && config.password !== undefined){
|
|
console.log(' Password: ' + config.password);
|
|
}
|
|
else{
|
|
config.password = "";
|
|
console.log(' Password: no password being used');
|
|
}
|
|
if(config.download !== "" && config.download !== undefined){
|
|
console.log(' Song download: ' + config.download);
|
|
downloadURL = config.download;
|
|
}
|
|
|
|
}
|
|
catch(err){
|
|
console.log('config file is not formatted correctly');
|
|
process.exit()
|
|
}
|
|
|
|
|
|
var data = fs.readFileSync('./Songs/' + config.folder + '/info.dat');
|
|
|
|
// Loading stuff
|
|
try{
|
|
var info = loadJSON('./Songs/' + config.folder + '/info.dat');
|
|
}
|
|
catch(err){
|
|
console.log('Could not find file: Songs/' + config.folder + '/info.dat');
|
|
process.exit()
|
|
}
|
|
if (!config.characteristic)
|
|
{
|
|
config.characteristic = "Standard";
|
|
}
|
|
for (var i = 0; i < info._difficultyBeatmapSets.length; i++)
|
|
{
|
|
if (info._difficultyBeatmapSets[i]._beatmapCharacteristicName == config.characteristic)
|
|
{
|
|
for(var j = 0; j < info._difficultyBeatmapSets[i]._difficultyBeatmaps.length; j++)
|
|
{
|
|
if (info._difficultyBeatmapSets[i]._difficultyBeatmaps[j]._difficulty == config.difficulty)
|
|
{
|
|
diff = loadJSON('./Songs/' + config.folder + '/' + info._difficultyBeatmapSets[i]._difficultyBeatmaps[j]._beatmapFilename);
|
|
try{
|
|
fileSize = fs.statSync('./Songs/' + config.folder + '/' + info._songFilename);
|
|
}catch(err)
|
|
{
|
|
//console.log('\nFailed to find '+info.difficultyLevels[i].audioPath+'. now using fileSize argument');
|
|
if(!config.hasOwnProperty('fileSize'))
|
|
{
|
|
//console.log('could not use fileSize argument, finding from download URL');
|
|
request({
|
|
url: downloadURL,
|
|
method: "HEAD"
|
|
}, function(err, response, body) {
|
|
|
|
var downloadResponse = response.headers;
|
|
|
|
if (downloadResponse.hasOwnProperty('content-length'))
|
|
{
|
|
fileSize = downloadResponse['content-length'];
|
|
}
|
|
else
|
|
{
|
|
console.log('Unable to get file size. Please specify fileSize in config.json or as an argument');
|
|
process.exit();
|
|
}
|
|
});
|
|
|
|
}
|
|
fileSize = config['content-length'];
|
|
|
|
}
|
|
|
|
diffIndex = j;
|
|
charIndex = i;
|
|
diffFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (diff === null)
|
|
{
|
|
console.log('No proper difficulty found.');
|
|
process.exit();
|
|
}
|
|
if (diffFound == false)
|
|
{
|
|
console.log('Difficulty/Characteristic not found');
|
|
process.exit();
|
|
}
|
|
setInterval(saveFile, 300000);//save every 5 minutes
|
|
// if(config.download === "")
|
|
// {
|
|
// config.download = 'none';
|
|
// }
|
|
|
|
var server = net.createServer(function(socket){
|
|
socket.name = "wait";
|
|
socket.send = false;
|
|
//add new client to the list
|
|
clients.push(socket);
|
|
|
|
// Handle incoming messages from clients.
|
|
socket.on('data', function (data) {
|
|
|
|
if(socket.name == "wait")
|
|
{
|
|
|
|
if (config.password !== "" && data.toString().includes(";|;"))
|
|
{
|
|
console.log("attempted connection: " + data.toString().split(";|;")[1] + "\nPassword: " +data.toString().split(";|;")[0]);
|
|
if (config.password == data.toString().split(";|;")[0])
|
|
{
|
|
for (var i = 0; i < clients.length; i++)
|
|
{
|
|
if (clients[i].name == data.toString().split(";|;")[1] || "wait" == data.toString().split(";|;")[1])
|
|
{
|
|
if (socket.address == clients[i].address)
|
|
{
|
|
console.log('duplicate from same client. Destroying old client.')
|
|
clients[i].destroy();
|
|
clients.splice(i, 1);
|
|
}
|
|
else
|
|
{
|
|
socket.write('dc:duplicate name');
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
socket.name = data.toString().split(";|;")[1];
|
|
// Send a nice welcome message and announce
|
|
|
|
socket.write(config.folder.split('/').pop()+"::"+diffIndex*100+ charIndex+";;;"); //0
|
|
socket.write(JSON.stringify(info)+";;;"); //1
|
|
socket.write(info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename+";;;"); //2
|
|
socket.write(JSON.stringify(diff)+";;;");//3
|
|
socket.write(info._songFilename+";;;"+fileSize+";;;");//4 & 5
|
|
socket.write(downloadURL +";;;" );//6
|
|
socket.send = true;
|
|
|
|
}
|
|
else
|
|
{
|
|
socket.write('dc:wrong password');
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
|
|
}
|
|
else if (config.password === "")
|
|
{
|
|
if(data.toString().includes(";|;"))
|
|
{
|
|
data = data.toString().split(";|;")[1];
|
|
}
|
|
console.log("attempted connection: " + data);
|
|
for (var i = 0; i < clients.length; i++)
|
|
{
|
|
if (clients[i].name == data || "wait" == data)
|
|
{
|
|
socket.write('dc:duplicate name');
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
}
|
|
socket.name = data.toString();
|
|
// Send a nice welcome message and announce
|
|
|
|
socket.write(config.folder.split('/').pop()+"::"+diffIndex*100+ charIndex+";;;"); //0
|
|
socket.write(JSON.stringify(info)+";;;"); //1
|
|
socket.write(info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename+";;;"); //2
|
|
socket.write(JSON.stringify(diff)+";;;");//3
|
|
socket.write(info._songFilename+";;;"+fileSize+";;;");//4 & 5
|
|
socket.write(downloadURL +";;;" );//6
|
|
socket.send = true;
|
|
}
|
|
else if (config.password !== "" && !data.toString().includes(";|;"))
|
|
{
|
|
socket.write('dc:password required');
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
socket.write('dc:uhhh something else');
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
console.log(socket.name + " joined the session.");
|
|
broadcast("System:,:sy:,:"+ socket.name + " joined the session.;:;");
|
|
}
|
|
else
|
|
{
|
|
|
|
broadcast(data.toString(), socket);
|
|
var commands = data.toString().split(";:;");
|
|
for (var i = 0; i < commands.length; i++)
|
|
{
|
|
readMessage(commands[i]);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
// Remove the client from the list when it leaves
|
|
socket.on('end', function () {
|
|
try
|
|
{
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
console.log(socket.name + " left the session.");
|
|
broadcast("System:,:sy:,:"+ socket.name + " left the session.;:;");
|
|
broadcast(socket.name + ":,:rc;:;");
|
|
}
|
|
catch(err)
|
|
{
|
|
console.log(err);
|
|
}
|
|
|
|
});
|
|
socket.on('error',function () {
|
|
try
|
|
{
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
broadcast("System:,:sy:,:"+ socket.name + " left the session.;:;");
|
|
broadcast(socket.name + ":,:rc;:;");
|
|
}
|
|
catch(err)
|
|
{
|
|
console.log(err);
|
|
}
|
|
|
|
});
|
|
// Send a message to all clients
|
|
function broadcast(message, sender) {
|
|
clients.forEach(function (client) {
|
|
// Don't want to send it to sender
|
|
if (client === sender)
|
|
{
|
|
return;
|
|
}
|
|
if (client.send == false)
|
|
{
|
|
return;
|
|
}
|
|
client.write(message);
|
|
});
|
|
}
|
|
});
|
|
|
|
//Get IP address
|
|
|
|
|
|
|
|
|
|
console.log('\n\n\n');
|
|
if (downloadURL === undefined || downloadURL === "")
|
|
{
|
|
var req = request.post('https://catbox.moe/user/api.php', function (err, resp, body) {
|
|
if (err) {
|
|
console.log(err);
|
|
} else {
|
|
// var downloadInfo = JSON.parse(body)
|
|
downloadURL = body;
|
|
console.log('Download URL generated: ' + body);
|
|
https.get('https://ifconfig.co/ip', function(res){
|
|
res.setEncoding('utf8');
|
|
|
|
res.on('data', function(chunk){
|
|
server.listen(config.port, '0.0.0.0');
|
|
process.stdout.write("Server Started on IP address: ")
|
|
console.log(chunk);
|
|
|
|
});
|
|
res.on('error', function(err) {
|
|
server.listen(config.port, '0.0.0.0');
|
|
process.stdout.write("Server Started");
|
|
});
|
|
});
|
|
|
|
}
|
|
});
|
|
var form = req.form();
|
|
form.append('reqtype', 'fileupload');
|
|
form.append('fileToUpload', fs.createReadStream('./Songs/'+config.folder+'/'+info._songFilename));
|
|
}else
|
|
{
|
|
|
|
https.get('https://ifconfig.co/ip', function(res){
|
|
res.setEncoding('utf8');
|
|
|
|
res.on('data', function(chunk){
|
|
server.listen(config.port, '0.0.0.0');
|
|
process.stdout.write("Server Started on IP address: ")
|
|
console.log(chunk);
|
|
|
|
});
|
|
res.on('error', function(err) {
|
|
server.listen(config.port, '0.0.0.0');
|
|
process.stdout.write("Server Started");
|
|
});
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
function readMessage(message)
|
|
{
|
|
changesMade = true;
|
|
var type = message.split(":,:")[1];
|
|
switch(type)
|
|
{
|
|
case 'an':
|
|
try{
|
|
addNote(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'rn':
|
|
try{
|
|
removeNote(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'ae':
|
|
try{
|
|
addEvent(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 're':
|
|
try{
|
|
removeEvent(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'aw':
|
|
try{
|
|
addWall(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'rw':
|
|
try{
|
|
removeWall(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'ab':
|
|
try{
|
|
addBookmark(message.split(':,:')[2].split("|||"));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
case 'rb':
|
|
try{
|
|
removeBookmark(message.split(':,:')[2].split(" "));
|
|
}
|
|
catch(err){
|
|
|
|
}
|
|
break;
|
|
default:
|
|
//console.log(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function addNote(data)
|
|
{
|
|
var note = stringToNote(data)
|
|
if (!hasNull(note))
|
|
{
|
|
diff._notes.push(note);
|
|
}
|
|
|
|
}
|
|
|
|
function removeNote(data)
|
|
{
|
|
for (var j = diff._notes.length -1 ; j >= 0; j--)
|
|
{
|
|
if (sameNote(diff._notes[j],stringToNote(data)))
|
|
{
|
|
diff._notes.splice(j,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
function stringToNote(data)
|
|
{
|
|
return {_time: parseFloat(data[0]),
|
|
_lineIndex: parseInt(data[1]),
|
|
_lineLayer: parseInt(data[2]),
|
|
_type: parseInt(data[3]),
|
|
_cutDirection: parseInt(data[4])};
|
|
}
|
|
function sameNote(note1,note2)
|
|
{
|
|
if (Math.abs(note1._time - note2._time) > 0.001)
|
|
return false;
|
|
if (note1._lineIndex != note2._lineIndex)
|
|
return false;
|
|
if (note1._lineLayer != note2._lineLayer)
|
|
return false;
|
|
if (note1._type != note2._type)
|
|
return false;
|
|
if (note1._cutDirection != note2._cutDirection)
|
|
return false;
|
|
return true;
|
|
}
|
|
function addEvent(data)
|
|
{
|
|
if (data.length == 3)
|
|
{
|
|
var event = stringToEvent(data)
|
|
if (!hasNull(event))
|
|
{
|
|
diff._events.push(event);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var event = stringToEvent(data)
|
|
if (!hasNull(event))
|
|
{
|
|
diff._BPMChanges.push(stringToBPM(data));
|
|
}
|
|
}
|
|
}
|
|
function removeEvent(data)
|
|
{
|
|
if (data.length == 3)
|
|
{
|
|
for (var j = diff._events.length -1 ; j >= 0; j--)
|
|
{
|
|
|
|
if (sameEvent(diff._events[j],stringToEvent(data)))
|
|
{
|
|
diff._events.splice(j,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var j = diff._BPMChanges.length -1 ; j >= 0; j--)
|
|
{
|
|
|
|
if (sameBPM(stringToBPM(data), diff._BPMChanges[j]))
|
|
{
|
|
diff._BPMChanges.splice(j,1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function sameEvent(event1,event2)
|
|
{
|
|
if (Math.abs(event1._time - event2._time) > 0.001)
|
|
return false;
|
|
if (event1._type != event2._type)
|
|
return false;
|
|
if (event1._value != event2._value)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
function sameBPM(event1,event2)
|
|
{
|
|
if (Math.abs(event1._BPM - event2._BPM) > 0.02)
|
|
return false;
|
|
if (Math.abs(event1._time - event2._time) > 0.001)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
function stringToEvent(data)
|
|
{
|
|
return {
|
|
_time: parseFloat(data[0]),
|
|
_type: parseInt(data[1]),
|
|
_value: parseInt(data[2])
|
|
};
|
|
}
|
|
function stringToBPM(data)
|
|
{
|
|
return {
|
|
_BPM:parseFloat(data[0]),
|
|
_time:parseFloat(data[1]),
|
|
_beatsPerBar:parseFloat(data[2]),
|
|
_metronomeOffset:parseFloat(data[3])}
|
|
}
|
|
function addWall(data)
|
|
{
|
|
var wall = stringToWall(data)
|
|
if (!hasNull(wall))
|
|
{
|
|
diff._obstacles.push(wall);
|
|
}
|
|
|
|
}
|
|
|
|
function removeWall(data)
|
|
{
|
|
for (var j = diff._obstacles.length -1 ; j >= 0; j--)
|
|
{
|
|
if (sameWall(diff._obstacles[j],stringToWall(data)))
|
|
{
|
|
diff._obstacles.splice(j,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function stringToWall(data)
|
|
{
|
|
return {_time: parseFloat(data[0]),
|
|
_lineIndex: parseInt(data[1]),
|
|
_type: parseInt(data[2]),
|
|
_duration: parseFloat(data[3]),
|
|
_width: parseInt(data[4])
|
|
};
|
|
}
|
|
|
|
function sameWall(wall1,wall2)
|
|
{
|
|
if (Math.abs(wall1._time - wall2._time) > 0.001)
|
|
return false;
|
|
if (wall1._lineIndex != wall2._lineIndex)
|
|
return false;
|
|
if (wall1._type != wall2._type)
|
|
return false;
|
|
if (Math.abs(wall1._duration - wall2._duration) > 0.001)
|
|
return false;
|
|
if (wall1._width != wall2._width)
|
|
return false;
|
|
return true;
|
|
}
|
|
function addBookmark(data)
|
|
{
|
|
diff._bookmarks.push(stringToBookmark(data));
|
|
}
|
|
|
|
function removeBookmark(data)
|
|
{
|
|
for (var j = diff._bookmarks.length - 1; j >= 0; j--)
|
|
{
|
|
if (Math.abs(diff._bookmarks[j]._time - stringToBookmark(data)._time) < 0.001)
|
|
{
|
|
diff._bookmarks.splice(j,1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function stringToBookmark(data)
|
|
{
|
|
return {
|
|
_time: parseFloat(data[0]),
|
|
_name: data[1]
|
|
};
|
|
}
|
|
|
|
function saveFile()
|
|
{
|
|
if (changesMade)
|
|
{
|
|
fs.writeFile('./Songs/' + config.folder + '/' + info._difficultyBeatmapSets[charIndex]._difficultyBeatmaps[diffIndex]._beatmapFilename, JSON.stringify(diff), function(err) {
|
|
if (err)
|
|
console.log(err);
|
|
else
|
|
{
|
|
console.log ("file successfully saved.\nNote Count: "+ diff._notes.length+"\nEvent Count: "+diff._events.length);
|
|
}
|
|
});
|
|
}
|
|
changesMade = false;
|
|
|
|
}
|
|
// server.getConnections(function(err,count){
|
|
// console.log(count);
|
|
// });
|
|
|
|
function disconnectSoon(socket)
|
|
{
|
|
if(socket.name == "wait" || socket.name.length > 30)
|
|
{
|
|
clients.splice(clients.indexOf(socket), 1);
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
}
|
|
|
|
function hasNull(object)
|
|
{
|
|
for(var key in object) {
|
|
if (object[key] === null)
|
|
{
|
|
try
|
|
{
|
|
console.log("null object detected at :" + object._time);
|
|
}
|
|
catch(err)
|
|
{
|
|
console.log("null object detected")
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
function loadJSON(file) {
|
|
var data = fs.readFileSync(file);
|
|
return JSON.parse(data);
|
|
}
|