<commit_before>#!/usr/bin/env node

/* eslint-disable unicorn/no-process-exit */

const spawn = require('child_process').spawn;
const net = require('net');

const airtunes = require('airtunes');
const Mqtt = require('mqtt');
const log = require('yalm');

const pkg = require('./package.json');
const config = require('./config.js');

log.setLevel(config.verbosity);

if (typeof config.speaker === 'string') {
    config.speaker = [config.speaker];
}

const speakers = {};
let count = 0;
let connected = false;

log.info(pkg.name, pkg.version, 'starting');

const mqtt = Mqtt.connect(config.mqttUrl, {will: {topic: config.name + '/connected', payload: '0', retain: true}});

config.speaker.forEach(speaker => {
    let port;
    let [name, host, portStart, portEnd] = speaker.split(':');
    if (typeof portEnd === 'undefined') {
        port = portStart;
        portStart = undefined;
    }
    if (name && host && (port || (portStart && portEnd))) {
        speakers[name] = {host, port, portStart, portEnd};
        mqttPub(config.name + '/status/' + name + '/enable', '0', {retain: true});
    } else {
        console.error('invalid speaker config', speaker);
        process.exit(1);
    }
});

mqtt.on('connect', () => {
    log.info('mqtt connected', config.mqttUrl);

    mqttPub(config.name + '/connected', connected ? '2' : '1', {retain: true});

    const topic = config.name + '/set/#';
    log.info('mqtt subscribe ' + topic);
    mqtt.subscribe(topic);
});

mqtt.on('close', () => {
    log.info('mqtt closed ' + config.mqttUrl);
});

mqtt.on('error', err => {
    log.error('mqtt', err.toString());
});

mqtt.on('offline', () => {
    log.error('mqtt offline');
});

mqtt.on('reconnect', () => {
    log.info('mqtt reconnect');
});

mqtt.on('message', (topic, message) => {
    message = message.toString();
    log.debug('mqtt < ', topic, message);
    const [, , speaker, command] = topic.split('/');
    if (!speakers[speaker]) {
        log.info('unknown speaker', speaker);
        return;
    }

    let obj;

    switch (command) {
        case 'enable':
            if (message === 'false' || message === '0') {
                stop(speaker);
            } else if (message === 'true' || parseInt(message, 10) > 0) {
                add(speaker);
            } else {
                try {
                    obj = JSON.parse(message);
                    if (obj.val) {
                        add(speaker);
                    } else {
                        stop(speaker);
                    }
                } catch (err) {
                    add(speaker);
                }
            }
            break;
        case 'disable':
            stop(speaker);
            break;
        case 'volume':
            if (isNaN(message)) {
                try {
                    obj = JSON.parse(message);
                    setVolume(speaker, obj.val);
                } catch (err) {

                }
            } else {
                setVolume(speaker, parseInt(message, 10));
            }
            break;
        default:
    }
});

airtunes.on('buffer', status => {
    log.debug('buffer', status);
});

startPipe();

function add(speaker, volume, nosearch) {
    log.debug('add', speaker, {host: speakers[speaker].host, port: speakers[speaker].port, portStart: speakers[speaker].portStart, portEnd: speakers[speaker].portEnd});
    if (speakers[speaker].portStart && !nosearch) {
        findport(speakers[speaker].host, speakers[speaker].portStart, speakers[speaker].portEnd, p => {<commit_msg>format debug output on add()<commit_after>#!/usr/bin/env node

/* eslint-disable unicorn/no-process-exit */

const spawn = require('child_process').spawn;
const net = require('net');

const airtunes = require('airtunes');
const Mqtt = require('mqtt');
const log = require('yalm');

const pkg = require('./package.json');
const config = require('./config.js');

log.setLevel(config.verbosity);

if (typeof config.speaker === 'string') {
    config.speaker = [config.speaker];
}

const speakers = {};
let count = 0;
let connected = false;

log.info(pkg.name, pkg.version, 'starting');

const mqtt = Mqtt.connect(config.mqttUrl, {will: {topic: config.name + '/connected', payload: '0', retain: true}});

config.speaker.forEach(speaker => {
    let port;
    let [name, host, portStart, portEnd] = speaker.split(':');
    if (typeof portEnd === 'undefined') {
        port = portStart;
        portStart = undefined;
    }
    if (name && host && (port || (portStart && portEnd))) {
        speakers[name] = {host, port, portStart, portEnd};
        mqttPub(config.name + '/status/' + name + '/enable', '0', {retain: true});
    } else {
        console.error('invalid speaker config', speaker);
        process.exit(1);
    }
});

mqtt.on('connect', () => {
    log.info('mqtt connected', config.mqttUrl);

    mqttPub(config.name + '/connected', connected ? '2' : '1', {retain: true});

    const topic = config.name + '/set/#';
    log.info('mqtt subscribe ' + topic);
    mqtt.subscribe(topic);
});

mqtt.on('close', () => {
    log.info('mqtt closed ' + config.mqttUrl);
});

mqtt.on('error', err => {
    log.error('mqtt', err.toString());
});

mqtt.on('offline', () => {
    log.error('mqtt offline');
});

mqtt.on('reconnect', () => {
    log.info('mqtt reconnect');
});

mqtt.on('message', (topic, message) => {
    message = message.toString();
    log.debug('mqtt < ', topic, message);
    const [, , speaker, command] = topic.split('/');
    if (!speakers[speaker]) {
        log.info('unknown speaker', speaker);
        return;
    }

    let obj;

    switch (command) {
        case 'enable':
            if (message === 'false' || message === '0') {
                stop(speaker);
            } else if (message === 'true' || parseInt(message, 10) > 0) {
                add(speaker);
            } else {
                try {
                    obj = JSON.parse(message);
                    if (obj.val) {
                        add(speaker);
                    } else {
                        stop(speaker);
                    }
                } catch (err) {
                    add(speaker);
                }
            }
            break;
        case 'disable':
            stop(speaker);
            break;
        case 'volume':
            if (isNaN(message)) {
                try {
                    obj = JSON.parse(message);
                    setVolume(speaker, obj.val);
                } catch (err) {

                }
            } else {
                setVolume(speaker, parseInt(message, 10));
            }
            break;
        default:
    }
});

airtunes.on('buffer', status => {
    log.debug('buffer', status);
});

startPipe();

function add(speaker, volume, nosearch) {
    log.debug('add', speaker, JSON.stringify({host: speakers[speaker].host, port: speakers[speaker].port, portStart: speakers[speaker].portStart, portEnd: speakers[speaker].portEnd}));
    if (speakers[speaker].portStart && !nosearch) {
        findport(speakers[speaker].host, speakers[speaker].portStart, speakers[speaker].portEnd, p => {
{'fraction_non_alphanumeric': 0.1741391426563598, 'fraction_numerical': 0.0033731553056921995, 'mean_word_length': 2.1514614703277237, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '269481', 'n_tokens_mistral': 2230, 'n_tokens_neox': 2155, 'n_words': 456}