From 20199d996195acd4f9f1c364e3ef793612a739b7 Mon Sep 17 00:00:00 2001 From: data Date: Sat, 28 Dec 2019 12:03:13 +0000 Subject: [PATCH] add bot to announce playlist and current track --- src/playlistbot.js | 140 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/playlistbot.js diff --git a/src/playlistbot.js b/src/playlistbot.js new file mode 100644 index 0000000..c5b57ab --- /dev/null +++ b/src/playlistbot.js @@ -0,0 +1,140 @@ +const icy = require('icy') +const devnull = require('dev-null') +const IRC = require('irc-framework') +const bot = new IRC.Client() +const chalk = require('chalk') + +const radioUrl = 'https://radio.anarchyplanet.org/live' +const owners = ['data', 'notnull'] +var channels = ['#traumschule', '#apradio', '#anarchyplanet'] +var announcing = ['#apradio'] +const host = process.env.HOST || 'irc.anarchyplanet.org' +const port = process.env.PORT || 6667 +const nick = process.env.NICK || 'playlist' + +var currentTrack = {} +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' + +// TODO on new streams to /live w/o metadata !np will give outdated data + +const log = message => { + console.log(chalk.magenta(message)) +} + +const announceTrack = msg => { + announcing.map(channel => bot.say(channel, msg)) +} + +const connectRadio = () => { + log('[ICY] Connecting') + try { + icy.get(radioUrl, function(res) { + console.error(res.headers) + + res.on('metadata', metadata => { + const parsed = icy.parse(metadata) + const track = parsed.StreamTitle + currentTrack = { track } + console.error(track) + announceTrack(track) + }) + + res.pipe(devnull()) + }) + } catch (e) { + log(`[ICY] Failed to connect: $(e.message)`) + } +} + +const connectIRC = () => { + log(`[IRC] Connecting to ${host}`) + try { + bot.connect({ host, port, nick }) + bot.on('connected', () => { + log(`[IRC] Joining ${channels.join(', ')}`) + channels.map(c => bot.join(c)) + connectRadio() + }) + bot.on('socket close', () => { + log('[IRC] Reconnecting ..') + bot.connect({ host, port, nick }) + }) + + // handle commands + bot.matchMessage(/^\?np/, event => sendCurrentTrack(event)) + bot.matchMessage(/^\?help/, event => sendHelp(event)) + bot.matchMessage(/^\?join/, event => handleJoin(event)) + bot.matchMessage(/^\?part/, event => handlePart(event)) + bot.matchMessage(/^\?quit/, event => handleQuit(event)) + bot.matchMessage(/^\?announce/, event => handleAnnounce(event)) + bot.matchMessage(/^\?unannounce/, event => handleUnannounce(event)) + bot.matchMessage(/^\?channels/, event => sendChannels(event)) + } catch (e) { + log(`[IRC] Failed to connect: ${e.message}`) + } +} + +const sendHelp = event => { + const chans = announcing.join(', ') + const helpMsg = `Announcing radio playlist in ${chans} | ?np shows current track.` + const adminMsg = + ' ?[un]announce [OPTIONAL #chan] shows playlist in current or supplied channel. Other comamnds: ?channels ?join ?part ?quit' + if (owners.includes(event.nick)) return event.reply(helpMsg + adminMsg) + event.reply(helpMsg) +} + +const sendCurrentTrack = event => { + const { error, track } = currentTrack + if (error) return event.reply('Something went wrong.') + if (track.length === 0) return event.reply('Nothing is currently playing.') + event.reply(track) +} + +const sendChannels = event => { + if (!owners.includes(event.nick)) return + const str = [announcing.join(' '), channels.join(' ')] + event.reply(`Announcing radio playlist in ${str[0]}. Joined ${str[1]}.`) +} + +const handleJoin = event => { + if (!owners.includes(event.nick)) return + const channel = event.message.split(' ')[1] + log(`Joining ${channel} (${event.nick})`) + bot.join(channel) + channels.concat(channel) +} + +const handlePart = event => { + if (!owners.includes(event.nick)) return + const channel = event.message.split(' ')[1] + log(`Parting ${channel} (${event.nick})`) + bot.part(channel) + channels.filter(c => c !== channel) +} + +const handleQuit = event => { + if (!owners.includes(event.nick)) return + log(`${event.nick} requested to quit.`) + bot.quit('time to die') + process.exit() +} + +const handleAnnounce = event => { + console.log(event) + if (!owners.includes(event.nick)) return + const arg = event.message.split(' ')[1] + const channel = arg ? arg : event.target + log(`Announcing in ${channel} (${event.nick})`) + announcing = announcing.concat(channel) + if (!arg) sendCurrentTrack(event) +} + +const handleUnannounce = event => { + if (!owners.includes(event.nick)) return + const arg = event.message.split(' ')[1] + const channel = arg ? arg : event.target + log(`Unannouncing in ${channel} (${event.nick})`) + announcing = announcing.filter(c => c !== channel) +} + +connectIRC() -- 2.46.1