Sélectionner une révision Git
lkt.js 17,25 Kio
const logger = require.main.require('./common/logger.js'),
net = require('net'),
{ finished } = require('stream'),
{ cli } = require('winston/lib/winston/config');
var config = require.main.require('./common/config.js');
class LktClient {
/***************************************
* Not static methods, do not use them *
***************************************/
/* The constructor
* - host: String
* - port: String
*
* Private members
* - m_socket: net.socket
*
* Node: You should not use that directly, prefere the use of static
* methods */
constructor() {
this.m_online = false;
this.m_socket = new net.Socket();
this.m_closed = true;
const sockopt = {
port: config.content.lektord.port,
host: config.content.lektord.host,
readable: true,
writable: true,
};
logger.debug('lkt', 'Creating the lektor client');
this.m_socket.setTimeout(3000);
this.m_socket.setEncoding('utf8');
this.m_socket.on('timeout', () => {
logger.error('lkt', `Got timeout while connecting to localhost:${config.content.lektord.port}`);
this.m_socket.end();
});
this.m_socket.on('ready', () => {
logger.debug('lkt', `Ready to use socket with localhost:${config.content.lektord.port}`);
this.m_online = true;
});
this.m_socket.on('end', () => {
logger.info('lkt', `Disconnected from server localhost:${config.content.lektord.port}`);
this.m_online = false;
});
this.m_socket.on('error', err => {
logger.error('lkt', `${err}`);
if (this.m_online) {
this.m_socket.destroy();
this.m_online = false;
}
});
this.m_socket.on('close', () => {
logger.info('lkt', `Socket localhost:${config.content.lektord.port} closed`);
this.m_online = false;
});
this.m_socket.connect(sockopt, () => {
logger.info('lkt', `Socket connected to localhost:${config.content.lektord.port}`);
this.m_online = true;
});
return this;
}
/* Close the client.
* Note: Prefere using the static methods. */
close() {
if (this.m_online) {
logger.debug('lkt', 'Requesting socket shutdown');
this.m_socket.destroy();
} else {
logger.debug('lkt', 'Socket already closed');
}
this.m_closed = true;
}
/*****************************************
* Static methods, to be used by clients *
*****************************************/
/* The status command */
static commandStatus() {
return this.__execGetResult('status');
}
/* The current command */
static commandCurrent() {
return this.__execGetResult('currentsong');
}
/* Arguments:
* - command: The command to execute
* Result:
* - A promize with one argument: the dict of the result */
static __execGetResult(command) {
var client = new this();
var once = false;
var result = {};
function __getResult(client) {
return new Promise(resolv => {
client.m_socket.setTimeout(0);
client.m_socket.on('data', data => {
if (!once) {
client.m_socket.write(`${command}\n`);
once = true;
return null;
} else {
client.close();
result = __mpdToObject(data);
resolv(result);
}
});
});
}
return __getResult(client);
}
/* Arguments:
* - command: The command to execute
* Result:
* - Returns the status of the command */
static __execSimple(command) {
var client = new this();
var once = false;
var result = {};
function __getResult(client) {
return new Promise(resolv => {
client.m_socket.on('data', data => {
if (!once) {
client.m_socket.write(`${command}\n`);
once = true;
return null;
} else {
client.close();
result = __mpdStatusToBool(data);
resolv(result);
}
});
});
}
return __getResult(client);
}
static reloadState() {
LktClient.commandStatus().then(data => {
LktClient.__status = data;
LktClient.status_updated = true;
logger.debug('lkt', `Got update in status ${JSON.stringify(data)}`);
});
LktClient.commandCurrent().then(data => {
LktClient.__current = data;
LktClient.status_updated = true;
logger.debug('lkt', `Got update in current ${JSON.stringify(data)}`);
});
}
static idleActualisation() {
var client = new this();
client.m_socket.setTimeout(0);
function __getResult(client) {
return new Promise((resolve, reject) => {
client.m_socket.on('data', data => {
if (String(data).includes('playlist')) {
LktClient.setQueueUpdated(true);
}
if (String(data).includes(' stored_playlist')) {
LktClient.setPlaylistsUpdated(true);
}
if (String(data).includes('player')) {
LktClient.reloadState();
}
if (String(data).includes('database')) {
LktClient.setDBUpdated(true);
}
client.m_socket.write(`idle\n`);
return null;
});
});
}
return __getResult(client);
}
static statusActualisation() {
var client = new this();
var dataObj;
function __getResult(client) {
return new Promise(resolv => {
client.m_socket.setTimeout(0);
setInterval(() => client.m_socket.write(`status\n`), 100);
client.m_socket.on('data', data => {
dataObj = __mpdToObject(data);
if (dataObj.elapsed && dataObj.duration && dataObj.state && dataObj.song) {
LktClient.setSongTimeData(
parseInt(dataObj.elapsed, 10),
parseInt(dataObj.duration, 10),
dataObj.state,
parseInt(dataObj.song, 10)
);
}
});
});
}
return __getResult(client);
}
static commandPlay() {
return LktClient.commandStatus().then(LktClient.changePlayStatus, LktClient.errorStatus);
}
static changePlayStatus(status) {
switch (status.state) {
case 'play':
return LktClient.__execSimple('pause 1');
break;
case 'pause':
return LktClient.__execSimple('pause 0');
break;
case 'stop':
return LktClient.__execSimple('play');
break;
default:
logger.info('Unknown play state' + status.state);
}
LktClient.setPlayState(status.state);
}
static commandPlaylistsList() {
var client = new this();
var once = false;
var result = [];
var dataObj;
var prevcont = 0;
function __getResult(client) {
return new Promise(resolv => {
client.m_socket.setTimeout(0);
client.m_socket.on('data', data => {
if (!once) {
client.m_socket.write('listplaylists\n');
once = true;
return null;
} else {
dataObj = __mpdToObject(data);
if (dataObj.name) {
Array.prototype.push.apply(result, dataObj.name.split(' '));
}
if (dataObj.continue) {
if (prevcont == dataObj.continue) {
client.close();
resolv(result);
}
prevcont = dataObj.continue;
client.m_socket.write(`${dataObj.continue} listplaylists\n`);
}
}
});
});
}
return __getResult(client);
}
static commandPlaylistListKaras(playlist) {
var client = new this();
var once = false;
var result = [];
var matches;
var dataObj;
var karaList;
var prevcont = 0;
const regex = /([0-9]+) (vo|va|amv|cdg|vocaloid|autres|vtuber) - (jp|fr|en|ru|sp|it|ch|latin|heb|por|pol|kor|fin|ara|swe|de|multi|undefined) \/ (.+) - (OP|ED|IS|AMV|PV|MV|LIVE)([0-9]*) - (.+) \[(.+)\]( \(U\))?/;
var reg = new RegExp(regex);
function __getResult(client) {
return new Promise(resolv => {
client.m_socket.setTimeout(0);
client.m_socket.on('data', data => {
if (!once) {
client.m_socket.write(`listplaylist ${playlist}\n`);
once = true;
return null;
} else {
dataObj = __mpdToObject(data);
karaList = data.split('\n');
if (dataObj.continue) {
karaList.splice(-3);
} else {
karaList.splice(-1);
}
if (karaList[0] == 'OK') {
client.close();
return null;
}
karaList.forEach(kara => {
matches = reg.exec(kara);
result.push({
id: matches[1],
cat: matches[2],
language: matches[3],
source: matches[4],
type: matches[5] + matches[6],
title: matches[7],
author: matches[8],
});
//logger.info("kara",matches[1]);
});
if (dataObj.continue && prevcont != dataObj.continue) {
client.m_socket.write(`${dataObj.continue} listplaylist ${playlist}\n`);
prevcont = dataObj.continue;
} else if (dataObj.continue) {
client.close();
resolv(result);
}
}
});
});
}
return __getResult(client);
}
static commandPlayPos(position) {
return LktClient.__execSimple(`play ${position}`);
}
static commandStop() {
return LktClient.__execSimple('stop');
}
static commandPause() {
return LktClient.__execSimple('pause 1');
}
static commandUnpause() {
return LktClient.__execSimple('pause 0');
}
static commandPrev() {
return LktClient.__execSimple('previous');
}
static commandNext() {
return LktClient.__execSimple('next');
}
static commandShuffle() {
return LktClient.__execSimple('shuffle');
}
static commandClear() {
return LktClient.__execSimple('clear');
}
static commandMove(from, to) {
return LktClient.__execSimple(`move ${from} ${to}`);
}
static commandQueueAddId(id) {
return LktClient.__execSimple(`add id://${id}`);
}
static commandQueueInsertId(id) {
return LktClient.__execSimple(`__insert id://${id}`);
}
static commandQueueDelPos(position) {
return LktClient.__execSimple(`delete ${position}`);
}
static commandQueueDelId(id) {
return LktClient.__execSimple(`deleteid ${id}`);
}
static commandPlaylistAddId(playlist, id) {
return LktClient.__execSimple(`playlistadd ${playlist} id://${id}`);
}
static commandPlaylistRemoveId(playlist, id) {
return LktClient.__execSimple(`playlistdelete ${playlist} ${id}`);
}
static commandPlaylistClear(playlist) {
return LktClient.__execSimple(`playlistclear ${playlist}`);
}
static commandAddPlaylistToQueue(playlist) {
return LktClient.__execSimple(`add playlist://${playlist}`);
}
static commandPlaylistCreate(playlist) {
return LktClient.__execSimple(`playlistadd ${playlist}`);
}
static commandPlaylistDelete(playlist) {
return LktClient.__execSimple(`playlistdelete ${playlist}`);
}
static commandUpdateDatabase() {
return LktClient.__execSimple(`password hashire\nupdate`);
}
static commandDryUpdateDatabase() {
return LktClient.__execSimple('password hashire\n__dry_update');
}
static commandDownloadId(id) {
logger.info(`password hashire\nupdate id://${id}`);
return LktClient.__execSimple(`password hashire\nupdate id://${id}`);
}
static commandQueueAddSearch(search) {
//search = search.replace(/ /g,"%");
return LktClient.__execSimple(`add query://%${search}%`);
}
static errorStatus(error) {
logger.error('Unable to access lektor status:' + error);
}
static queue_updated = false;
static setQueueUpdated(state) {
this.queue_updated = state;
}
static isQueueUpdated() {
return this.queue_updated;
}
static isStatusUpdated() {
return this.status_updated;
}
static playlists_updated = true;
static setPlaylistsUpdated(state) {
this.playlists_updated = state;
}
static isPlaylistsUpdated() {
return this.playlists_updated;
}
static isStatusUpdated() {
return this.status_updated;
}
static timeData = { elapsed: 0, total: 100, state: 'stop', song: 0 };
static setPlayState(state) {
this.timeData.state = state;
}
static getCurrent() {
return this.__current;
}
static getCurrent() {
LktClient.status_updated = false;
return this.__current;
}
static getStatus() {
LktClient.status_updated = false;
return this.__status;
}
static setSongTimeData(elapsed, total, state, song) {
this.timeData = {
elapsed: elapsed,
total: total,
state: state,
song: song,
};
}
static getSongTimeData() {
return this.timeData;
}
static DBUpdated = false;
static setDBUpdated(state) {
this.DBUpdated = state;
}
static isDBUpdated() {
return this.DBUpdated;
}
static ping() {
var socket = new net.Socket();
var result = {};
function __getResult(socket) {
return new Promise(resolv => {
const sockopt = {
port: config.content.lektord.port,
host: config.content.lektord.host,
readable: true,
writable: true,
};
logger.debug('lkt', 'Try to ping');
socket.setTimeout(3000);
socket.setEncoding('utf8');
socket.on('timeout', () => {
logger.error('lkt', `Got timeout while ping to localhost:${config.content.lektord.port}`);
result = false;
resolv(result);
});
socket.on('ready', () => {
logger.debug('lkt', `Ping success with localhost:${config.content.lektord.port}`);
result = true;
resolv(result);
});
socket.on('error', err => {
logger.error('lkt', `${err}`);
result = false;
resolv(result);
});
socket.connect(sockopt, () => {
logger.info('lkt', `Pinged localhost:${config.content.lektord.port}`);
socket.destroy();
result = true;
resolv(result);
});
});
}
return __getResult(socket);
}
}
function __mpdToObject(string) {
var ret = {};
string.split('\n').forEach(line => {
if (line.length <= 1) return;
var couple = line.split(/: (.+)/).slice(0, 2);
if (!ret[couple[0]]) {
ret[couple[0]] = couple[1];
} else {
ret[couple[0]] += ' ' + couple[1];
}
});
return ret;
}
function __mpdStatusToBool(string) {
string = string.split('\n');
string = string[string.length - 1];
return string.split(/ /) == 'OK' ? true : false;
}
module.exports = LktClient;