From 16ad72785445881b700100fc9468a4ff95d89fd1 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 11:55:30 +0100 Subject: [PATCH 01/77] renamed 'ported' to 'default-attached' --- {ported => default-attached}/README.md | 0 ported/01-advertising.js => default-attached/advertising.js | 0 ported/02-alonemode.js => default-attached/alonemode.js | 0 ported/03-bookmark.js => default-attached/bookmark.js | 0 ported/05-follow-me.js => default-attached/followme.js | 0 ported/04-no-recording.js => default-attached/norecording.js | 0 .../06-remember-channel.js => default-attached/rememberChannel.js | 0 ported/07-welcome.js => default-attached/welcome.js | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename {ported => default-attached}/README.md (100%) rename ported/01-advertising.js => default-attached/advertising.js (100%) rename ported/02-alonemode.js => default-attached/alonemode.js (100%) rename ported/03-bookmark.js => default-attached/bookmark.js (100%) rename ported/05-follow-me.js => default-attached/followme.js (100%) rename ported/04-no-recording.js => default-attached/norecording.js (100%) rename ported/06-remember-channel.js => default-attached/rememberChannel.js (100%) rename ported/07-welcome.js => default-attached/welcome.js (100%) diff --git a/ported/README.md b/default-attached/README.md similarity index 100% rename from ported/README.md rename to default-attached/README.md diff --git a/ported/01-advertising.js b/default-attached/advertising.js similarity index 100% rename from ported/01-advertising.js rename to default-attached/advertising.js diff --git a/ported/02-alonemode.js b/default-attached/alonemode.js similarity index 100% rename from ported/02-alonemode.js rename to default-attached/alonemode.js diff --git a/ported/03-bookmark.js b/default-attached/bookmark.js similarity index 100% rename from ported/03-bookmark.js rename to default-attached/bookmark.js diff --git a/ported/05-follow-me.js b/default-attached/followme.js similarity index 100% rename from ported/05-follow-me.js rename to default-attached/followme.js diff --git a/ported/04-no-recording.js b/default-attached/norecording.js similarity index 100% rename from ported/04-no-recording.js rename to default-attached/norecording.js diff --git a/ported/06-remember-channel.js b/default-attached/rememberChannel.js similarity index 100% rename from ported/06-remember-channel.js rename to default-attached/rememberChannel.js diff --git a/ported/07-welcome.js b/default-attached/welcome.js similarity index 100% rename from ported/07-welcome.js rename to default-attached/welcome.js From 94629306ecf22e6e6e15920613c0bd650b3ad5be Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 13:10:18 +0100 Subject: [PATCH 02/77] using now lf for *.js line endings --- .gitattributes | 1 + default-attached/advertising.js | 2 +- default-attached/alonemode.js | 2 +- default-attached/bookmark.js | 2 +- default-attached/followme.js | 2 +- default-attached/norecording.js | 2 +- default-attached/rememberChannel.js | 2 +- default-attached/welcome.js | 35 +++++------------------------ 8 files changed, 12 insertions(+), 36 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a5f23f8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.js eol=lf \ No newline at end of file diff --git a/default-attached/advertising.js b/default-attached/advertising.js index a78df56..63cd2ff 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Advertising (Text)', version: '2.0', description: 'This script will announce one of the configured lines every x seconds.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [{ name: 'ads', title: 'Ads (supports bbcode)', diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index 0fafeba..71b55ab 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'AloneMode', version: '2.0', description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [{ name: 'mode', title: 'Mode', diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index a03c35e..6e74140 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -36,4 +36,4 @@ registerPlugin({ backend.getCurrentChannel().chat('Resumed at ' + pos + 'ms.'); } }); -}); +}); \ No newline at end of file diff --git a/default-attached/followme.js b/default-attached/followme.js index 932df98..ff6a23b 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Follow Me', version: '2.0', description: 'The bot will follow the movements of any of the clients given', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [{ name: 'clientUids', title: 'Comma-separated list of client-ids that the bot should follow', diff --git a/default-attached/norecording.js b/default-attached/norecording.js index 0b799a0..f1a97bc 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'No Recording!', version: '2.0', description: 'This script will kick anyone who attempts to record.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [{ name: 'kickMessage', title: 'The optional kick message.', diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index d5267d6..e622ae7 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Remember Last Channel', version: '2.0', description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [] }, function (sinusbot, config) { var event = require('event'); diff --git a/default-attached/welcome.js b/default-attached/welcome.js index ae7cfbe..0dd1cff 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -1,8 +1,8 @@ registerPlugin({ name: 'Welcome!', - version: '2.1', + version: '2.0', description: 'This plugin will let the bot greet everyone.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese ', vars: [{ name: 'message', title: 'The message that should be displayed. (%n = nickname)', @@ -15,44 +15,19 @@ registerPlugin({ 'Private chat', 'Poke' ] - }, { - name: 'newline', - title: 'How new lines should be handled', - type: 'select', - options: [ - 'normal (one message with multiple lines)', - 'multiple messages (a new message for each line)' - ], - // only show this when private chat is selected - conditions: [{ - field: 'type', - value: 0 - }] }] }, function (sinusbot, config) { - var engine = require('engine'); var event = require('event'); - - config.type = config.type || 0; - config.newline = config.newline || 0; - engine.saveConfig(config); - event.on('clientMove', function (ev) { var msg = config.message; msg = msg.replace(/%n/g, ev.client.name()); - if (ev.fromChannel == undefined) { if (config.type == 0) { - if (config.newline == 0) { - ev.client.chat(msg); - } else { - msg.split('\n').forEach(function (line) { - ev.client.chat(line) - }); - } + ev.client.chat(msg); } else { ev.client.poke(msg); } + return; } }); -}); +}); \ No newline at end of file From 28d95f32d2cd3bc874bca623c0f61b1809f8a2c4 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 13:31:48 +0100 Subject: [PATCH 03/77] updated scripts to v8 engine --- default-attached/advertising.js | 31 ++++++------ default-attached/alonemode.js | 65 +++++++++++++------------ default-attached/bookmark.js | 74 +++++++++++++++++------------ default-attached/followme.js | 34 ++++++------- default-attached/norecording.js | 15 +++--- default-attached/rememberChannel.js | 19 ++++---- default-attached/welcome.js | 24 +++++----- 7 files changed, 139 insertions(+), 123 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 63cd2ff..50428a5 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -30,23 +30,24 @@ registerPlugin({ 'Server' ] }] -}, function (sinusbot, config) { - var backend = require('backend'); - var ads = (config && config.ads) ? config.ads.split('\n').map(function (e) { - return e.trim().replace(/\r/g, ''); - }) : []; - var ctr = -1; - setInterval(function () { - ctr++; - if (ads.length == 0 || config.Interval < 5) return; - var ad = ctr % ads.length; +}, (_, config) => { + const backend = require('backend') + const helpers = require('helpers') + + const ads = (config && config.ads) ? config.ads.split('\n').map(e => e.trim().replace(/\r/g, '')) : [] + let ctr = -1 + + setInterval(() => { + ctr++ + if (ads.length == 0 || config.Interval < 5) return + let ad = ctr % ads.length if (config.order == 1 && ads.length > 1) { - ad = sinusbot.getRand(ads.length - 1); + ad = helpers.getRandom(ads.length - 1) } if (config.type == 0) { - backend.getCurrentChannel().chat(ads[ad]); + backend.getCurrentChannel().chat(ads[ad]) } else { - backend.chat(ads[ad]); + backend.chat(ads[ad]) } - }, config.interval * 1000); -}); \ No newline at end of file + }, config.interval * 1000) +}) \ No newline at end of file diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index 71b55ab..c980ab7 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -12,42 +12,45 @@ registerPlugin({ 'stop playback' ] }] -}, function (sinusbot, config) { - var engine = require('engine'), - backend = require('backend'), - event = require('event'), - audio = require('audio'), - media = require('media'); +}, (_, { mode }) => { + const engine = require('engine') + const backend = require('backend') + const event = require('event') + const audio = require('audio') + const media = require('media') - var isMuted = false, - LastPosition = 0, - LastTitle; + let isMuted = false + let lastPosition = 0 + let lastTitle - audio.setMute(false); - event.on('clientMove', function (ev) { - if (backend.getCurrentChannel().getClientCount() > 1 && isMuted) { - isMuted = false; - engine.log('Ending AloneMode...'); - if (config.mode == 0) { - audio.setMute(false); + audio.setMute(false) + + event.on('clientMove', () => { + let currentChannelClientCount = backend.getCurrentChannel().getClientCount() + if (currentChannelClientCount > 1 && isMuted) { + isMuted = false + engine.log('Ending AloneMode...') + if (mode == 0) { + audio.setMute(false) } else { - LastTitle.play(); - audio.seek(LastPosition); - engine.log('Seeking to ' + LastPosition); + lastTitle.play() + audio.seek(lastPosition) + engine.log(`Seeking to ${lastPosition}`) + } - return; + return } - if (backend.getCurrentChannel().getClientCount() <= 1 && audio.isPlaying()) { - isMuted = true; - engine.log('Starting AloneMode...'); - if (config.mode == 0) { - audio.setMute(true); + if (currentChannelClientCount <= 1 && audio.isPlaying()) { + isMuted = true + engine.log('Starting AloneMode...') + if (mode == 0) { + audio.setMute(true) } else { - LastPosition = getPos(); - engine.log('Pos is ' + LastPosition); - LastTitle = media.getCurrentTrack(); - media.stop(); + lastPosition = getPos() + engine.log(`Pos is ${lastPosition}`) + lastTitle = media.getCurrentTrack() + media.stop() } } - }); -}); \ No newline at end of file + }) +}) \ No newline at end of file diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 6e74140..544cbf4 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -4,36 +4,50 @@ registerPlugin({ description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', author: 'Michael Friese & mxschmitt ', vars: [] -}, function (sinusbot, config) { +}, () => { + const store = require('store') + const media = require('media') + const audio = require('audio') + const event = require('event') - var store = require('store'), - media = require('media'), - backend = require('backend'), - audio = require('audio'); + const event = require("event") - var event = require('event'); + event.on("load", () => { + //try to load the library + const Command = require("command") + //check if the library has been loaded successfully + if (!Command) throw new Error("Command.js library not found! Please download Command.js and enable it to be able use this script!") - event.on('chat', function (ev) { - engine.log(ev.text); - if (ev.text == '.bookmark') { - engine.log("bookmark"); - var track = media.getCurrentTrack(); - if (!track) return; - var pos = audio.getTrackPosition(); - store.set(track.ID(), pos); - backend.getCurrentChannel().chat('Position saved for track ' + track.uuid + ' at ' + pos + 'ms.'); - } - if (ev.text == '.resume') { - engine.log("resume"); - var track = media.getCurrentTrack(); - if (!track) return; - var pos = store.get(track.ID()); - if (!pos) { - backend.getCurrentChannel().chat('No position found, sorry.'); - return; - } - audio.seek(pos); - backend.getCurrentChannel().chat('Resumed at ' + pos + 'ms.'); - } - }); -}); \ No newline at end of file + Command.createCommand("bookmark") + .help("saves the current position") + .manual("saves the current position") + .manual("can be resumed by the 'resume' command. (Seeks to the bookmarked position of the track)") + .exec((client, args, reply) => { + const track = media.getCurrentTrack() + if (!track) { + return + } + const pos = audio.getTrackPosition() + store.set(track.ID(), pos) + reply(`Position saved for track ${track.uuid} at ${pos}ms.`) + }) + + Command.createCommand("resume") + .help("resumes to the bookmarked position") + .manual("resumes to the bookmarked position") + .manual("by using the 'seek' command, it can be saved") + .exec((client, args, reply) => { + const track = media.getCurrentTrack() + if (!track) { + return + } + const pos = store.get(track.ID()) + if (!pos) { + reply('No position found, sorry.') + return + } + audio.seek(pos) + reply(`Resumed at ${pos}ms.`) + }) + }) +}) \ No newline at end of file diff --git a/default-attached/followme.js b/default-attached/followme.js index ff6a23b..5c23620 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -8,26 +8,22 @@ registerPlugin({ title: 'Comma-separated list of client-ids that the bot should follow', type: 'string' }] -}, function (sinusbot, config) { +}, (_, { clientUids }) => { + const engine = require('engine') + const backend = require('backend') + const event = require('event') - var engine = require('engine'), - backend = require('backend'), - event = require('event'); - - - if (!config.clientUids) { - engine.log('Invalid clientUids'); - return; + if (!clientUids) { + engine.log('Invalid clientUids') + return } - - var uids = config.clientUids.split(','); - event.on('clientMove', function (ev) { - if (uids.indexOf(ev.client.uniqueID()) >= 0 && ev.toChannel != null) { - engine.log('Following ' + ev.client.name()); - backend.getBotClient().moveTo(ev.toChannel); - return; + const uids = clientUids.split(',') + event.on('clientMove', ({ client, toChannel }) => { + if (uids.includes(client.uniqueID()) && toChannel) { + engine.log(`Following ${client.name()}`) + backend.getBotClient().moveTo(toChannel) } - }); + }) - engine.log('Follow Me initialized...'); -}); \ No newline at end of file + engine.log('Follow Me initialized...') +}) \ No newline at end of file diff --git a/default-attached/norecording.js b/default-attached/norecording.js index f1a97bc..0d3da06 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -8,11 +8,12 @@ registerPlugin({ title: 'The optional kick message.', type: 'string' }] -}, function (sinusbot, config) { - var engine = require('engine'); - var event = require('event'), - kickMessage = config.kickMessage ? config.kickMessage : 'No recording on our server!'; - event.on('clientRecord', function (ev) { +}, (_, config) => { + const event = require('event') + + const kickMessage = config.kickMessage || 'No recording on our server!' + + event.on('clientRecord', ev => { ev.kickFromServer(kickMessage) - }); -}); \ No newline at end of file + }) +}) \ No newline at end of file diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index e622ae7..46c51e4 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -4,13 +4,14 @@ registerPlugin({ description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', author: 'Michael Friese ', vars: [] -}, function (sinusbot, config) { - var event = require('event'); - var backend = require('backend'); - var engine = require('engine'); - event.on('clientMove', function (ev) { - if (ev.client.uniqueID() == backend.getBotClient().uniqueID()) { - engine.setDefaultChannelID(ev.toChannel.ID()); +}, () => { + const event = require('event') + const backend = require('backend') + const engine = require('engine') + + event.on('clientMove', ({ client, toChannel }) => { + if (client.uniqueID() == backend.getBotClient().uniqueID()) { + engine.setDefaultChannelID(toChannel.ID()) } - }); -}); \ No newline at end of file + }) +}) \ No newline at end of file diff --git a/default-attached/welcome.js b/default-attached/welcome.js index 0dd1cff..166288d 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -16,18 +16,18 @@ registerPlugin({ 'Poke' ] }] -}, function (sinusbot, config) { - var event = require('event'); - event.on('clientMove', function (ev) { - var msg = config.message; - msg = msg.replace(/%n/g, ev.client.name()); - if (ev.fromChannel == undefined) { - if (config.type == 0) { - ev.client.chat(msg); +}, (_, { message, type }) => { + const event = require('event') + + event.on('clientMove', ({ client, fromChannel }) => { + let msg = message + msg = msg.replace(/%n/g, client.name()) + if (!fromChannel) { + if (type == 0) { + client.chat(msg) } else { - ev.client.poke(msg); + client.poke(msg) } - return; } - }); -}); \ No newline at end of file + }) +}) \ No newline at end of file From c0a864c10b07fd76e030bf0c3b57b447830fa5e4 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 16:28:08 +0100 Subject: [PATCH 04/77] Reworked default attached scripts and fixed errors due testing --- default-attached/advertising.js | 35 ++++++++++++++++++++--------- default-attached/alonemode.js | 19 ++++++++-------- default-attached/bookmark.js | 12 +++++----- default-attached/followme.js | 5 +---- default-attached/norecording.js | 4 ++-- default-attached/rememberChannel.js | 4 ++-- default-attached/welcome.js | 5 ++--- 7 files changed, 46 insertions(+), 38 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 50428a5..22ea68d 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Advertising (Text)', version: '2.0', description: 'This script will announce one of the configured lines every x seconds.', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'ads', title: 'Ads (supports bbcode)', @@ -32,22 +32,35 @@ registerPlugin({ }] }, (_, config) => { const backend = require('backend') - const helpers = require('helpers') + const engine = require('engine') const ads = (config && config.ads) ? config.ads.split('\n').map(e => e.trim().replace(/\r/g, '')) : [] - let ctr = -1 + + let counter = 0 + if (ads.length === 0) { + engine.log("There were no ads configured.") + return + } + + if (config.Interval < 3) { + engine.log("The intervall is too small, use > 3 not to be banned from the server") + return + } setInterval(() => { - ctr++ - if (ads.length == 0 || config.Interval < 5) return - let ad = ctr % ads.length - if (config.order == 1 && ads.length > 1) { - ad = helpers.getRandom(ads.length - 1) + let adIdx = counter % ads.length + // prevent overflow of the counter + if (counter % ads.length === 0) { + adIdx = 0 + } + if (config.order === 1 && ads.length > 1) { + adIdx = Math.floor(Math.random() * ads.length) } - if (config.type == 0) { - backend.getCurrentChannel().chat(ads[ad]) + if (config.type === 0) { + backend.getCurrentChannel().chat(ads[adIdx]) } else { - backend.chat(ads[ad]) + backend.chat(ads[adIdx]) } + counter++ }, config.interval * 1000) }) \ No newline at end of file diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index c980ab7..daf8b8f 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'AloneMode', version: '2.0', description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'mode', title: 'Mode', @@ -21,7 +21,7 @@ registerPlugin({ let isMuted = false let lastPosition = 0 - let lastTitle + let lastTrack audio.setMute(false) @@ -33,10 +33,11 @@ registerPlugin({ if (mode == 0) { audio.setMute(false) } else { - lastTitle.play() - audio.seek(lastPosition) - engine.log(`Seeking to ${lastPosition}`) - + if (lastTrack) { + lastTrack.play() + audio.seek(lastPosition) + engine.log(`Seeking to ${lastPosition} of track '${lastTrack.title()}'`) + } } return } @@ -46,9 +47,9 @@ registerPlugin({ if (mode == 0) { audio.setMute(true) } else { - lastPosition = getPos() - engine.log(`Pos is ${lastPosition}`) - lastTitle = media.getCurrentTrack() + lastPosition = audio.getTrackPosition() + lastTrack = media.getCurrentTrack() + engine.log(`Position ${lastPosition} saved for track '${lastTrack.title()}'`) media.stop() } } diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 544cbf4..3135824 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -2,14 +2,12 @@ registerPlugin({ name: 'Bookmarks!', version: '2.0.1', description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', - author: 'Michael Friese & mxschmitt ', + author: 'Michael Friese , Max Schmitt & mxschmitt ', vars: [] }, () => { const store = require('store') const media = require('media') const audio = require('audio') - const event = require('event') - const event = require("event") event.on("load", () => { @@ -28,8 +26,8 @@ registerPlugin({ return } const pos = audio.getTrackPosition() - store.set(track.ID(), pos) - reply(`Position saved for track ${track.uuid} at ${pos}ms.`) + store.set(track.id(), pos) + reply(`Position saved for track '${track.title()}' at ${pos} ms`) }) Command.createCommand("resume") @@ -41,13 +39,13 @@ registerPlugin({ if (!track) { return } - const pos = store.get(track.ID()) + const pos = store.get(track.id()) if (!pos) { reply('No position found, sorry.') return } audio.seek(pos) - reply(`Resumed at ${pos}ms.`) + reply(`Resumed at ${pos} ms of track '${track.title()}'`) }) }) }) \ No newline at end of file diff --git a/default-attached/followme.js b/default-attached/followme.js index 5c23620..151a462 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Follow Me', version: '2.0', description: 'The bot will follow the movements of any of the clients given', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'clientUids', title: 'Comma-separated list of client-ids that the bot should follow', @@ -20,10 +20,7 @@ registerPlugin({ const uids = clientUids.split(',') event.on('clientMove', ({ client, toChannel }) => { if (uids.includes(client.uniqueID()) && toChannel) { - engine.log(`Following ${client.name()}`) backend.getBotClient().moveTo(toChannel) } }) - - engine.log('Follow Me initialized...') }) \ No newline at end of file diff --git a/default-attached/norecording.js b/default-attached/norecording.js index 0d3da06..75bf02b 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'No Recording!', version: '2.0', description: 'This script will kick anyone who attempts to record.', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'kickMessage', title: 'The optional kick message.', @@ -10,7 +10,7 @@ registerPlugin({ }] }, (_, config) => { const event = require('event') - + const kickMessage = config.kickMessage || 'No recording on our server!' event.on('clientRecord', ev => { diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index 46c51e4..203ef89 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Remember Last Channel', version: '2.0', description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [] }, () => { const event = require('event') @@ -11,7 +11,7 @@ registerPlugin({ event.on('clientMove', ({ client, toChannel }) => { if (client.uniqueID() == backend.getBotClient().uniqueID()) { - engine.setDefaultChannelID(toChannel.ID()) + engine.setDefaultChannelID(toChannel.id()) } }) }) \ No newline at end of file diff --git a/default-attached/welcome.js b/default-attached/welcome.js index 166288d..a12ce72 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Welcome!', version: '2.0', description: 'This plugin will let the bot greet everyone.', - author: 'Michael Friese ', + author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'message', title: 'The message that should be displayed. (%n = nickname)', @@ -20,8 +20,7 @@ registerPlugin({ const event = require('event') event.on('clientMove', ({ client, fromChannel }) => { - let msg = message - msg = msg.replace(/%n/g, client.name()) + let msg = message.replace("%n", client.name()) if (!fromChannel) { if (type == 0) { client.chat(msg) From 14eafef89bff9968f8118a4f95527ec4c56806d0 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 16:29:38 +0100 Subject: [PATCH 05/77] bumped version --- default-attached/advertising.js | 2 +- default-attached/alonemode.js | 2 +- default-attached/bookmark.js | 2 +- default-attached/followme.js | 2 +- default-attached/norecording.js | 2 +- default-attached/rememberChannel.js | 2 +- default-attached/welcome.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 22ea68d..a6982b0 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'Advertising (Text)', - version: '2.0', + version: '3.0', description: 'This script will announce one of the configured lines every x seconds.', author: 'Michael Friese , Max Schmitt ', vars: [{ diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index daf8b8f..04d8039 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'AloneMode', - version: '2.0', + version: '3.0', description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', author: 'Michael Friese , Max Schmitt ', vars: [{ diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 3135824..346602c 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'Bookmarks!', - version: '2.0.1', + version: '3.0', description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', author: 'Michael Friese , Max Schmitt & mxschmitt ', vars: [] diff --git a/default-attached/followme.js b/default-attached/followme.js index 151a462..2c6cda9 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'Follow Me', - version: '2.0', + version: '3.0', description: 'The bot will follow the movements of any of the clients given', author: 'Michael Friese , Max Schmitt ', vars: [{ diff --git a/default-attached/norecording.js b/default-attached/norecording.js index 75bf02b..ca39ab5 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'No Recording!', - version: '2.0', + version: '3.0', description: 'This script will kick anyone who attempts to record.', author: 'Michael Friese , Max Schmitt ', vars: [{ diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index 203ef89..6728523 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'Remember Last Channel', - version: '2.0', + version: '3.0', description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', author: 'Michael Friese , Max Schmitt ', vars: [] diff --git a/default-attached/welcome.js b/default-attached/welcome.js index a12ce72..82ba493 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'Welcome!', - version: '2.0', + version: '3.0', description: 'This plugin will let the bot greet everyone.', author: 'Michael Friese , Max Schmitt ', vars: [{ From 781f97ca521cad818404cd53b5f263e0d3e142c3 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 19 Jan 2019 16:53:11 +0100 Subject: [PATCH 06/77] enhanced readme --- README.md | 6 +++--- default-attached/README.md | 2 +- default-attached/advertising.js | 4 ++-- scripts/00-basic.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 11407f9..d742bd8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# sinusbot scripts +# SinusBot scripts -This repository contains a few scripts and snippets which demonstrate how the scripting engine of the [sinusbot](https://sinusbot.com) works. Scripts written in JavaScript. +This repository contains a few scripts and snippets which demonstrates how the scripting engine of the [sinusbot](https://sinusbot.com) works. Scripts are written in JavaScript. -The new scripting engine is documentated [here](https://www.sinusbot.com/docs/scripting/) and more details can be found in the [wiki](https://wiki.sinusbot.com/en:guides:features:scripts). +The new scripting engine is documentated [here](https://sinusbot.github.io/scripting-docs) and more details can be found in the [docs](https://sinusbot.github.io/docs). diff --git a/default-attached/README.md b/default-attached/README.md index fef258e..c6c651d 100644 --- a/default-attached/README.md +++ b/default-attached/README.md @@ -1 +1 @@ -### Default attached scripts of the SinusBot which are ported to the script engine v2 \ No newline at end of file +### Default attached scripts of the SinusBot which are ported to the v8 scripting engine \ No newline at end of file diff --git a/default-attached/advertising.js b/default-attached/advertising.js index a6982b0..7b70c3b 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -46,7 +46,7 @@ registerPlugin({ engine.log("The intervall is too small, use > 3 not to be banned from the server") return } - + setInterval(() => { let adIdx = counter % ads.length // prevent overflow of the counter @@ -56,7 +56,7 @@ registerPlugin({ if (config.order === 1 && ads.length > 1) { adIdx = Math.floor(Math.random() * ads.length) } - if (config.type === 0) { + if (config.type == 0) { backend.getCurrentChannel().chat(ads[adIdx]) } else { backend.chat(ads[adIdx]) diff --git a/scripts/00-basic.js b/scripts/00-basic.js index 1dec174..f4df773 100644 --- a/scripts/00-basic.js +++ b/scripts/00-basic.js @@ -10,9 +10,9 @@ registerPlugin({ // import modules const engine = require('engine'); const event = require('event'); - + // listen for chat event - event.on('chat', ({client, text}) => { + event.on('chat', ({ client, text }) => { engine.log(`${client.name()} wrote ${text}`); client.chat(`Hi ${client.name()}, you just wrote: ${text}`); }); From b38e513c121daef700b71991469b35a06ee26855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 14 Feb 2019 05:29:31 +0100 Subject: [PATCH 07/77] update type check config --- jsconfig.json | 4 ++-- package-lock.json | 14 ++++++++++++++ package.json | 2 +- scripts/00-basic.js | 1 - 4 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 package-lock.json diff --git a/jsconfig.json b/jsconfig.json index c14023d..8fe1aa7 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", - "module": "commonjs" + "target": "es2018", + "checkJs": true } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3fadc4c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,14 @@ +{ + "name": "scripts", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "sinusbot-scripting-engine": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.5.tgz", + "integrity": "sha512-Dz+ssGa10kcjPyViGvOVhqRIZoNi6qbhW4fw0b1bj9El/5+5sI06e6mOF2qohSe2U+Gq6tQsNJ3dss/dGsvAXw==", + "dev": true + } + } +} diff --git a/package.json b/package.json index f3ced24..95c6449 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.0" + "sinusbot-scripting-engine": "^1.0.5" } } diff --git a/scripts/00-basic.js b/scripts/00-basic.js index f4df773..77ded48 100644 --- a/scripts/00-basic.js +++ b/scripts/00-basic.js @@ -1,4 +1,3 @@ -// @ts-check registerPlugin({ name: 'Example script', version: '1.0.0', From 305f6ecf4a2e353ebeb37804a5975a707e05fc84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 14 Feb 2019 05:29:53 +0100 Subject: [PATCH 08/77] use speech recognition example from docs --- scripts/01-speech-recognition.js | 73 ++++++++------------------------ 1 file changed, 18 insertions(+), 55 deletions(-) diff --git a/scripts/01-speech-recognition.js b/scripts/01-speech-recognition.js index d0c5cc9..c17d939 100644 --- a/scripts/01-speech-recognition.js +++ b/scripts/01-speech-recognition.js @@ -1,61 +1,24 @@ registerPlugin({ - name: 'Chuck Norris Speech API', - version: '1.1', - backends: ["ts3"], - description: 'This is a simple script that will write you Chuck Norris jokes when you say "joke"', - author: 'mxschmitt & irgendwer ', - vars: [{ - name: 'msgtype', - title: 'message type', - type: 'select', - options: ['Poke', 'Private message', 'Channel message', 'Say it'] - }], - voiceCommands: ['joke'] -}, function (sinusbot, config) { - var engine = require('engine') - var event = require('event') - var audio = require('audio') - var backend = require('backend') + name: 'Speech Recognition Demo', + version: '1.0', + description: 'This is a simple script that will stop playback when you say "stop"', + author: 'Michael Friese ', + vars: [], + voiceCommands: ['stop'] +}, function(_, config) { + var event = require('event'); + var engine = require('engine'); + var audio = require('audio'); + var media = require('media'); - audio.setAudioReturnChannel(0x2); + audio.setAudioReturnChannel(2); - event.on('speech', function (ev) { - if (ev.text == 'joke') { - engine.log('Writes a joke to ' + ev.clientId); - sinusbot.http({ - "method": "GET", - "url": "http://api.icndb.com/jokes/random", - "timeout": 6000, - "headers": [{ - "Content-Type": "application/json" - },] - }, function (error, response) { - if (response.statusCode != 200) { - engine.log(error); - return; - } - var joke = unescape(JSON.parse(response.data).value.joke).replace('"', '\"'); - engine.log("received joke: " + joke); - switch (config.msgtype) { - case 0: - if (joke.length > 100) { - engine.log("over 100"); - var joke = joke.substring(0, 96) + '...'; - } - ev.client.poke(joke); - break; - case 1: - ev.client.chat(joke); - case 2: - backend.getCurrentChannel().chat(joke); - break; - default: - audio.say(joke); - break; - } - }); + event.on('speech', function(ev) { + if (ev.text == 'stop') { + engine.log('Stopping playback on behalf of client ' + ev.client.nick()); + media.stop(); } else { - engine.log('Client ' + ev.client.name() + ' just said ' + ev.text); + engine.log(ev.client.nick() + ' just said ' + ev.text); } }); -}); +}); \ No newline at end of file From 563bcde9b2255eac02e993c2c166c9a9a74b39a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 14 Feb 2019 06:17:39 +0100 Subject: [PATCH 09/77] minor improvements to default scripts --- default-attached/advertising.js | 57 ++++++++++++++++++--------------- default-attached/alonemode.js | 17 +++++----- default-attached/bookmark.js | 5 ++- default-attached/followme.js | 9 +++--- default-attached/norecording.js | 4 +-- default-attached/welcome.js | 4 +-- 6 files changed, 52 insertions(+), 44 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 7b70c3b..5a84a62 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -12,15 +12,17 @@ registerPlugin({ name: 'interval', title: 'Interval (in seconds)', type: 'number', - placeholder: '5' + placeholder: '5', + default: 5 }, { name: 'order', title: 'Order', type: 'select', options: [ - 'default (line by line)', + 'line by line (default)', 'random' - ] + ], + default: '0' }, { name: 'type', title: 'Broadcast-Type', @@ -28,39 +30,44 @@ registerPlugin({ options: [ 'Channel', 'Server' - ] + ], + default: '0' }] -}, (_, config) => { +}, (_, {ads, order, type, interval}) => { const backend = require('backend') const engine = require('engine') - const ads = (config && config.ads) ? config.ads.split('\n').map(e => e.trim().replace(/\r/g, '')) : [] + ads = ads ? ads.split('\n').map(line => line.trim().replace(/\r/g, '')) : [] - let counter = 0 if (ads.length === 0) { - engine.log("There were no ads configured.") + engine.log('There are no ads configured.') return } - - if (config.Interval < 3) { - engine.log("The intervall is too small, use > 3 not to be banned from the server") + if (interval <= 3) { + engine.log('The interval is too small, use a value bigger than 3 seconds.') return } - + + const RANDOM = '1'; + const SERVER = '1'; + + let index = -1 + setInterval(() => { - let adIdx = counter % ads.length - // prevent overflow of the counter - if (counter % ads.length === 0) { - adIdx = 0 - } - if (config.order === 1 && ads.length > 1) { - adIdx = Math.floor(Math.random() * ads.length) + switch (order) { + case RANDOM: + index = Math.floor(Math.random() * ads.length) + break + default: + index = (++index % ads.length) } - if (config.type == 0) { - backend.getCurrentChannel().chat(ads[adIdx]) - } else { - backend.chat(ads[adIdx]) + + switch (type) { + case SERVER: + backend.chat(ads[index]) + break + default: + backend.getCurrentChannel().chat(ads[index]) } - counter++ - }, config.interval * 1000) + }, interval * 1000) }) \ No newline at end of file diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index 04d8039..48997df 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -12,7 +12,7 @@ registerPlugin({ 'stop playback' ] }] -}, (_, { mode }) => { +}, (_, {mode}) => { const engine = require('engine') const backend = require('backend') const event = require('event') @@ -26,11 +26,13 @@ registerPlugin({ audio.setMute(false) event.on('clientMove', () => { - let currentChannelClientCount = backend.getCurrentChannel().getClientCount() - if (currentChannelClientCount > 1 && isMuted) { + let clients = backend.getCurrentChannel().getClientCount() + + if (clients > 1 && isMuted) { isMuted = false engine.log('Ending AloneMode...') - if (mode == 0) { + + if (mode == '0') { audio.setMute(false) } else { if (lastTrack) { @@ -39,12 +41,11 @@ registerPlugin({ engine.log(`Seeking to ${lastPosition} of track '${lastTrack.title()}'`) } } - return - } - if (currentChannelClientCount <= 1 && audio.isPlaying()) { + } else if (clients <= 1 && audio.isPlaying()) { isMuted = true engine.log('Starting AloneMode...') - if (mode == 0) { + + if (mode == '0') { audio.setMute(true) } else { lastPosition = audio.getTrackPosition() diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 346602c..23ff153 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -2,7 +2,7 @@ registerPlugin({ name: 'Bookmarks!', version: '3.0', description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', - author: 'Michael Friese , Max Schmitt & mxschmitt ', + author: 'Michael Friese , Max Schmitt ', vars: [] }, () => { const store = require('store') @@ -32,8 +32,7 @@ registerPlugin({ Command.createCommand("resume") .help("resumes to the bookmarked position") - .manual("resumes to the bookmarked position") - .manual("by using the 'seek' command, it can be saved") + .manual("resumes to the bookmarked position (use bookmark command to set)") .exec((client, args, reply) => { const track = media.getCurrentTrack() if (!track) { diff --git a/default-attached/followme.js b/default-attached/followme.js index 2c6cda9..8f611a2 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -5,19 +5,20 @@ registerPlugin({ author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'clientUids', - title: 'Comma-separated list of client-ids that the bot should follow', + title: 'Comma-separated list of client-UIDs that the bot should follow', type: 'string' }] -}, (_, { clientUids }) => { +}, (_, {clientUids}) => { const engine = require('engine') const backend = require('backend') const event = require('event') if (!clientUids) { - engine.log('Invalid clientUids') + engine.log('No client-UIDs set.') return } - const uids = clientUids.split(',') + + const uids = clientUids.replace(', ', ',').split(',') event.on('clientMove', ({ client, toChannel }) => { if (uids.includes(client.uniqueID()) && toChannel) { backend.getBotClient().moveTo(toChannel) diff --git a/default-attached/norecording.js b/default-attached/norecording.js index ca39ab5..d3e45ce 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -13,7 +13,7 @@ registerPlugin({ const kickMessage = config.kickMessage || 'No recording on our server!' - event.on('clientRecord', ev => { - ev.kickFromServer(kickMessage) + event.on('clientRecord', client => { + client.kickFromServer(kickMessage) }) }) \ No newline at end of file diff --git a/default-attached/welcome.js b/default-attached/welcome.js index 82ba493..049bd11 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -20,9 +20,9 @@ registerPlugin({ const event = require('event') event.on('clientMove', ({ client, fromChannel }) => { - let msg = message.replace("%n", client.name()) + let msg = message.replace('%n', client.name()) if (!fromChannel) { - if (type == 0) { + if (type == '0') { client.chat(msg) } else { client.poke(msg) From b5968b13a678be62a1c2e140b6d0e8b5c36abee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 18 Feb 2019 23:19:34 +0100 Subject: [PATCH 10/77] add requiredModules to http examples --- snippets/00-http.js | 96 +++++++++++++++++++++------------------ snippets/01-basic-http.js | 53 ++++++++++++--------- 2 files changed, 83 insertions(+), 66 deletions(-) diff --git a/snippets/00-http.js b/snippets/00-http.js index 036680c..7e0e420 100644 --- a/snippets/00-http.js +++ b/snippets/00-http.js @@ -1,46 +1,54 @@ -// import modules -var engine = require('engine'); -var http = require('http'); +registerPlugin({ + name: 'Demo http json Script', + version: '1.0.0', + description: 'This example actually does nothing', + author: 'Author ', + requiredModules: ['http'], // <-- don't forget this! + vars: [] +}, function(_, config, meta) { + // import modules + var engine = require('engine'); + var http = require('http'); -// define data that should be sent -var sendData = JSON.stringify({ foo: 'bar' }); + // define data that should be sent + var sendData = JSON.stringify({ foo: 'bar' }); -// send request -http.simpleRequest({ - 'method': 'POST', - 'url': 'https://example.com', - 'timeout': 6000, - 'maxSize': 1024 * 1024 * 5, - 'body': sendData, - 'headers': { - 'Content-Type': 'application/json', - 'Content-Length': sendData.length - } -}, function (error, response) { - if (error) { - engine.log("Error: " + error); - return; - } - - if (response.statusCode != 200) { - engine.log("HTTP Error: " + response.status); - return; - } - - // parse JSON response - var res; - try { - res = JSON.parse(response.data.toString()); - } catch (err) { - engine.log(err.message); - } - - // check if parsing was successfull - if (res === undefined) { - engine.log("Invalid JSON."); - return; - } - - // success! - engine.log(res); -}); + // send request + http.simpleRequest({ + 'method': 'POST', + 'url': 'https://example.com', + 'timeout': 6000, + 'body': sendData, + 'headers': { + 'Content-Type': 'application/json', + 'Content-Length': sendData.length + } + }, function (error, response) { + if (error) { + engine.log("Error: " + error); + return; + } + + if (response.statusCode != 200) { + engine.log("HTTP Error: " + response.status); + return; + } + + // parse JSON response + var res; + try { + res = JSON.parse(response.data.toString()); + } catch (err) { + engine.log(err.message); + } + + // check if parsing was successfull + if (res === undefined) { + engine.log("Invalid JSON."); + return; + } + + // success! + engine.log(res); + }); +}); \ No newline at end of file diff --git a/snippets/01-basic-http.js b/snippets/01-basic-http.js index d68566a..179f3e1 100644 --- a/snippets/01-basic-http.js +++ b/snippets/01-basic-http.js @@ -1,23 +1,32 @@ -// import modules -var engine = require('engine'); -var http = require('http'); +registerPlugin({ + name: 'Demo http basic Script', + version: '1.0.0', + description: 'This example actually does nothing', + author: 'Author ', + requiredModules: ['http'], // <-- don't forget this! + vars: [] +}, function(_, config, meta) { + // import modules + var engine = require('engine'); + var http = require('http'); -// send request -http.simpleRequest({ - 'method': 'GET', - 'url': 'https://example.com', - 'timeout': 6000, -}, function (error, response) { - if (error) { - engine.log("Error: " + error); - return; - } - - if (response.statusCode != 200) { - engine.log("HTTP Error: " + response.status); - return; - } - - // success! - engine.log("Response: " + response.data.toString()); -}); + // send request + http.simpleRequest({ + 'method': 'GET', + 'url': 'https://example.com', + 'timeout': 6000, + }, function (error, response) { + if (error) { + engine.log("Error: " + error); + return; + } + + if (response.statusCode != 200) { + engine.log("HTTP Error: " + response.status); + return; + } + + // success! + engine.log("Response: " + response.data.toString()); + }); +}); \ No newline at end of file From e9205c3d2437aa09146b5b5a2584c0d2af38c1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 22 Feb 2019 02:53:32 +0100 Subject: [PATCH 11/77] added discord support, minor improvements --- default-attached/advertising.js | 1 + default-attached/alonemode.js | 7 +++++-- default-attached/bookmark.js | 23 ++++++++++++----------- default-attached/followme.js | 5 +++-- default-attached/norecording.js | 4 +++- default-attached/rememberChannel.js | 4 ++-- default-attached/welcome.js | 1 + 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 5a84a62..1483729 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -1,6 +1,7 @@ registerPlugin({ name: 'Advertising (Text)', version: '3.0', + backends: ['ts3'], description: 'This script will announce one of the configured lines every x seconds.', author: 'Michael Friese , Max Schmitt ', vars: [{ diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index 48997df..b594228 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -1,6 +1,7 @@ registerPlugin({ name: 'AloneMode', version: '3.0', + backends: ['ts3', 'discord'], description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', author: 'Michael Friese , Max Schmitt ', vars: [{ @@ -19,6 +20,8 @@ registerPlugin({ const audio = require('audio') const media = require('media') + const MUTE_ONLY = '1' + let isMuted = false let lastPosition = 0 let lastTrack @@ -32,7 +35,7 @@ registerPlugin({ isMuted = false engine.log('Ending AloneMode...') - if (mode == '0') { + if (mode == MUTE_ONLY) { audio.setMute(false) } else { if (lastTrack) { @@ -45,7 +48,7 @@ registerPlugin({ isMuted = true engine.log('Starting AloneMode...') - if (mode == '0') { + if (mode == MUTE_ONLY) { audio.setMute(true) } else { lastPosition = audio.getTrackPosition() diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 23ff153..9cceebd 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -1,6 +1,7 @@ registerPlugin({ name: 'Bookmarks!', version: '3.0', + backends: ['ts3', 'discord'], description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', author: 'Michael Friese , Max Schmitt ', vars: [] @@ -8,18 +9,18 @@ registerPlugin({ const store = require('store') const media = require('media') const audio = require('audio') - const event = require("event") + const event = require('event') - event.on("load", () => { + event.on('load', () => { //try to load the library - const Command = require("command") + const Command = require('command') //check if the library has been loaded successfully - if (!Command) throw new Error("Command.js library not found! Please download Command.js and enable it to be able use this script!") + if (!Command) throw new Error('Command.js library not found! Please download Command.js and enable it to be able use this script!') - Command.createCommand("bookmark") - .help("saves the current position") - .manual("saves the current position") - .manual("can be resumed by the 'resume' command. (Seeks to the bookmarked position of the track)") + Command.createCommand('bookmark') + .help('saves the current position') + .manual('saves the current position') + .manual('can be resumed by the \'resume\' command. (Seeks to the bookmarked position of the track)') .exec((client, args, reply) => { const track = media.getCurrentTrack() if (!track) { @@ -30,9 +31,9 @@ registerPlugin({ reply(`Position saved for track '${track.title()}' at ${pos} ms`) }) - Command.createCommand("resume") - .help("resumes to the bookmarked position") - .manual("resumes to the bookmarked position (use bookmark command to set)") + Command.createCommand('resume') + .help('resumes to the bookmarked position') + .manual('resumes to the bookmarked position (use bookmark command to set)') .exec((client, args, reply) => { const track = media.getCurrentTrack() if (!track) { diff --git a/default-attached/followme.js b/default-attached/followme.js index 8f611a2..899d3b8 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -1,6 +1,7 @@ registerPlugin({ name: 'Follow Me', version: '3.0', + backends: ['ts3', 'discord'], description: 'The bot will follow the movements of any of the clients given', author: 'Michael Friese , Max Schmitt ', vars: [{ @@ -18,9 +19,9 @@ registerPlugin({ return } - const uids = clientUids.replace(', ', ',').split(',') + const uids = clientUids.trim().split(',') event.on('clientMove', ({ client, toChannel }) => { - if (uids.includes(client.uniqueID()) && toChannel) { + if (toChannel && uids.includes(client.uid())) { backend.getBotClient().moveTo(toChannel) } }) diff --git a/default-attached/norecording.js b/default-attached/norecording.js index d3e45ce..c65f654 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -1,12 +1,14 @@ registerPlugin({ name: 'No Recording!', version: '3.0', + backends: ['ts3'], description: 'This script will kick anyone who attempts to record.', author: 'Michael Friese , Max Schmitt ', vars: [{ name: 'kickMessage', title: 'The optional kick message.', - type: 'string' + type: 'string', + placeholder: 'No recording on our server!' }] }, (_, config) => { const event = require('event') diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index 6728523..f4821c0 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -1,16 +1,16 @@ registerPlugin({ name: 'Remember Last Channel', version: '3.0', + backends: ['ts3', 'discord'], description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', author: 'Michael Friese , Max Schmitt ', vars: [] }, () => { const event = require('event') - const backend = require('backend') const engine = require('engine') event.on('clientMove', ({ client, toChannel }) => { - if (client.uniqueID() == backend.getBotClient().uniqueID()) { + if (toChannel && client.isSelf()) { engine.setDefaultChannelID(toChannel.id()) } }) diff --git a/default-attached/welcome.js b/default-attached/welcome.js index 049bd11..9e694cf 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -1,6 +1,7 @@ registerPlugin({ name: 'Welcome!', version: '3.0', + backends: ['ts3'], description: 'This plugin will let the bot greet everyone.', author: 'Michael Friese , Max Schmitt ', vars: [{ From e1036db96935be187c6ab803f33a872318b414ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 22 Feb 2019 18:19:37 +0100 Subject: [PATCH 12/77] use new typings --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3fadc4c..d99c08b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.5.tgz", - "integrity": "sha512-Dz+ssGa10kcjPyViGvOVhqRIZoNi6qbhW4fw0b1bj9El/5+5sI06e6mOF2qohSe2U+Gq6tQsNJ3dss/dGsvAXw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.6.tgz", + "integrity": "sha512-VrD4hbI3EdrrWzK4UtEe0jzF/SNfjcbagEYoCdnxSq9BgtYRhF9NHRc0s6q8y+n2Xdr+lFXNF/1GkeEGeXRIdw==", "dev": true } } diff --git a/package.json b/package.json index 95c6449..cf90381 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.5" + "sinusbot-scripting-engine": "^1.0.6" } } From 0095e9b05886d088a12e54be633db35f1bf57af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 6 Oct 2019 18:53:57 +0200 Subject: [PATCH 13/77] add sinusbot-commands.js --- default-attached/sinusbot-commands.js | 1133 +++++++++++++++++++++++++ package-lock.json | 6 +- package.json | 2 +- 3 files changed, 1137 insertions(+), 4 deletions(-) create mode 100644 default-attached/sinusbot-commands.js diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js new file mode 100644 index 0000000..45ffeb1 --- /dev/null +++ b/default-attached/sinusbot-commands.js @@ -0,0 +1,1133 @@ +registerPlugin({ + name: 'SinusBot Commands', + version: '1.0.0', + description: 'Enables the default commands.', + author: 'Jonas Bögle (@irgendwr)', + engine: '>= 1.0.0', + backends: ['ts3', 'discord'], + requiredModules: ['discord-dangerous'], + autorun: true, + vars: [ + { + name: 'discord', + title: 'Show discord settings', + type: 'checkbox', + default: true, + }, + { + name: 'url', + title: 'URL to Webinterface (optional, for album covers in discord)', + type: 'string', + placeholder: 'i.e. https://sinusbot.example.com', + conditions: [{ field: 'discord', value: true }], + }, + { + name: 'songInStatus', + title: 'Show playing song in status.', + type: 'checkbox', + default: true, + conditions: [{ field: 'discord', value: true }], + }, + { + name: 'deleteOldMessages', + title: 'Delete previous responses if !playing command is used again', + type: 'checkbox', + default: true, + conditions: [{ field: 'discord', value: true }], + }, + { + name: 'createSuccessReaction', + title: 'Add a reaction to each command if it was successfull.', + type: 'checkbox', + default: false, + conditions: [{ field: 'discord', value: true }], + }, + ] +}, (_, config, meta) => { + const event = require('event') + const engine = require('engine') + const backend = require('backend') + const format = require('format') + const audio = require('audio') + const media = require('media') + const store = require('store') + + engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) + + /********* privileges *********/ + /* eslint-disable no-unused-vars */ + const LOGIN = 1 << 0; + const LIST_FILE = 1 << 1; + const UPLOAD_FILE = 1 << 2; + const DELETE_FILE = 1 << 3; + const EDIT_FILE = 1 << 4; + const CREATE_PLAYLIST = 1 << 5; + const DELETE_PLAYLIST = 1 << 6; + const ADDTO_PLAYLIST = 1 << 7; + const STARTSTOP = 1 << 8; + const EDITUSERS = 1 << 9; + const CHANGENICK = 1 << 10; + const BROADCAST = 1 << 11; + const PLAYBACK = 1 << 12; + const ENQUEUE = 1 << 13; + const ENQUEUENEXT = 1 << 14; + const EDITBOT = 1 << 15; + const EDITINSTANCE = 1 << 16; + /* eslint-enable no-unused-vars */ + + const ERROR_PREFIX = '❌ '; + const WARNING_PREFIX = '⚠ '; + const SUCCESS_PREFIX = '✔ '; + const USAGE_PREFIX = ERROR_PREFIX + 'Usage: '; + + const sinusbotURL = config.url; + const REACTION_PREV = '⏮'; + const REACTION_PLAYPAUSE = '⏯'; + const REACTION_NEXT = '⏭'; + + // for join/leave + const ERROR_BOT_NULL = 'Unable to change channel :frowning:\nTry to set a *Default Channel* in the webinterface and click save.' + let bot = backend.getBotClient(); + + // restore lastEmbeds + /** @type {object[]} */ + let lastEmbeds = store.get('lastEmbeds') || []; + + if (config.discord && engine.getBackend() != 'discord') { + // hide discord-only settings if backend is not discord + config.discord = false; + engine.saveConfig(config); + } + + event.on('load', () => { + const command = require('command'); + if (!command) { + engine.log('command.js library not found! Please download command.js and enable it to be able use this script!'); + return; + } + + command.createCommand('register') + .addArgument(command.createArgument('string').setName('username')) + .help('Register a new user') + .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!engine.registrationEnabled()) { + reply('Registration is disabled.'); + return; + } + + // print syntax if no username given + if (!args.username) { + reply(USAGE_PREFIX + 'register '); + return; + } + + if (engine.getUserByName(args.username)) { + reply(ERROR_PREFIX + 'This username already exists.'); + return; + } + + // check if client already has a user + let user = getUserByUid(client.uid()); + if (user) { + reply(ERROR_PREFIX + `You already have a user with the name "${user.name()}".`); + return; + } + + // create user + let newUser = engine.addUser(args.username); + if (!newUser) { + reply(ERROR_PREFIX + 'Unable to create user, try another username.'); + return; + } + // set uid + newUser.setTSUid(client.uid()); + + successReaction(ev); + }); + + command.createCommand('password') + .alias('pass') + .addArgument(command.createArgument('rest').setName('value')) + .help('Change your password') + .manual('Changes your password to .') + .checkPermission(client => { + return getUserByUid(client.uid()) != null; + }) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no value given + if (!args.value) { + reply(USAGE_PREFIX + 'password \n'+ WARNING_PREFIX + 'Don\'t use this command in a public channel.'); + return; + } + + if (ev.mode !== 1) { + reply(WARNING_PREFIX + 'Don\'t use this command in a public channel.'); + return; + } + + let user = getUserByUid(client.uid()); + if (!user) { + reply(ERROR_PREFIX + `You don't have a user-account. Use ${format.bold('!register')} to create one.`); + return; + } + + // set password + user.setPassword(args.value); + reply(SUCCESS_PREFIX + 'Changed your password.'); + successReaction(ev); + }); + + if (engine.getBackend() == 'discord') { + command.createCommand('playing') + .help('Show what\'s currantly playing') + .manual('Show what\'s currantly playing') + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!audio.isPlaying()) { + return reply('There is nothing playing at the moment.'); + } + + backend.extended().createMessage(ev.channel.id(), getPlayingEmbed(), (err, res) => { + if (err) return engine.log(err); + if (!res) return engine.log('Error: empty response'); + + const {id, channel_id} = JSON.parse(res); + + // messages that should be deleted + let deleteMsg = []; + const msgId = ev.message ? ev.message.ID() : null; + const index = lastEmbeds.findIndex(embed => embed.channelId == channel_id); + if (index !== -1) { + if (config.deleteOldMessages) { + // delete previous embed + deleteMsg.push(lastEmbeds[index].messageId); + // delete previous command from user + if (lastEmbeds[index].messageId) { + deleteMsg.push(lastEmbeds[index].invokeMessageId); + } + } + // save new embed + lastEmbeds[index].messageId = id; + lastEmbeds[index].invokeMessageId = msgId; + } else { + // save new embed + lastEmbeds.push({ + channelId: channel_id, + messageId: id, + invokeMessageId: msgId + }); + } + + deleteMessages(channel_id, deleteMsg); + + wait(1000) + // create reaction controls + .then(() => createReaction(channel_id, id, REACTION_PREV)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_NEXT)); + }); + successReaction(ev); + }); + } else { + command.createCommand('playing') + .help('Show what\'s currantly playing') + .manual('Show what\'s currantly playing') + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!audio.isPlaying()) { + return reply('There is nothing playing at the moment.'); + } + + reply(formatTrack(media.getCurrentTrack())); + }); + } + + command.createCommand('next') + .help('Play the next track') + .manual('Plays the next track (only when a playlist or queue is active).') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + media.playNext(); + successReaction(ev); + }); + + command.createCommand('prev') + .alias('previous') + .help('Play the previous track') + .manual('Plays the previous track (only when a playlistis active).') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + media.playPrevious(); + successReaction(ev); + }); + + command.createCommand('search') + .alias('s') + .addArgument(command.createArgument('rest').setName('searchstring')) + .help('Search for tracks') + .manual('Searches for tracks, returns 20 results at most.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no searchstring given + if (!args.searchstring) { + reply(USAGE_PREFIX + 'search '); + return; + } + + const tracks = media.search(args.searchstring); + if (tracks.length == 0) { + reply('Sorry, nothing found.'); + successReaction(ev); + return; + } + + const response = tracks.map(formatTrack).join("\n") + reply(response); + successReaction(ev); + }); + + command.createCommand('play') + .alias('p') + .addArgument(command.createArgument('rest').setName('idORsearchstring')) + .help('Play a track by its id or name') + .manual('Plays a track by its id or searches for a track and plays the first match.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no idORsearchstring given + if (!args.idORsearchstring) { + reply(USAGE_PREFIX + 'play '); + return; + } + + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + let tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } + + track.play(); + reply(`Playing ${formatTrack(track)}`); + successReaction(ev); + }); + + command.createCommand('queue') + .alias('q') + .addArgument(command.createArgument('rest').setName('idORsearchstring').optional(true)) + .help('Enqueue a track or resume queue') + .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!args.idORsearchstring) { + if (!audio.isPlaying()) { + media.playQueueNext(); + } + return; + } + + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + const tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } + + track.enqueue(); + reply(`Added ${formatTrack(track)} to the queue`); + successReaction(ev); + }); + + command.createCommand('queuenext') + .alias('qnext', 'qn') + .addArgument(command.createArgument('rest').setName('idORsearchstring')) + .help('Prepends a track to the queue') + .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') + .checkPermission(requirePrivileges(ENQUEUENEXT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no idORsearchstring given + if (!args.idORsearchstring) { + reply(USAGE_PREFIX + 'queuenext '); + return; + } + + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + const tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } + + track.enqueue(); + reply(`Added ${formatTrack(track)} to the queue`); + successReaction(ev); + }); + + command.createCommand('stop') + .help('Stop playback') + .manual('Stops playback.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + media.stop(); + successReaction(ev); + }); + + command.createCommand('!stop') + .help('Stop playback and remove idle-track') + .manual('Stops playback and removes idle-track.') + .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + media.stop(); + media.clearIdleTrack(); + successReaction(ev); + }); + + command.createCommand('volume') + .alias('vol') + .addArgument(command.createArgument('string').setName('value')) + .help('Change the volume') + .manual('Changes the volume.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + let value = args.value; + let volume = audio.getVolume(); + + switch (value) { + case 'up': + volume += 10; + break; + case 'dn': + case 'down': + volume -= 10; + break; + default: + value = parseInt(value, 10); + if (value >= 0 && value <= 100) { + volume = value; + } else { + reply(USAGE_PREFIX + 'volume '); + return; + } + } + + if (volume < 0) { + volume = 0; + } else if (volume > 100) { + volume = 100; + } + + audio.setVolume(volume); + successReaction(ev); + }); + + command.createCommand('stream') + .addArgument(command.createArgument('string').setName('url')) + .help('Stream a url') + .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'stream '); + return; + } + + if (!media.ytStream(args.url)) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev); + }); + + command.createCommand('say') + .addArgument(command.createArgument('rest').setName('text')) + .help('Say a text via TTS') + .manual('Uses text-to-speech (if configured) to say the given text.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no text given + if (!args.text) { + reply(USAGE_PREFIX + 'say '); + return; + } + + audio.say(args.text); + successReaction(ev); + }); + + command.createCommand('sayex') + .addArgument(command.createArgument('string').setName('locale')) + .addArgument(command.createArgument('rest').setName('text')) + .help('Say a text via TTS with given locale') + .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no locale/text given + if (!args.locale || !args.text) { + reply(USAGE_PREFIX + 'sayex '); + return; + } + + audio.say(args.text, args.locale); + successReaction(ev); + }); + + command.createCommand('ttsurl') + .addArgument(command.createArgument('string').setName('url')) + .help('Set the TTS url.') + .manual('Sets the TTS url.') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'ttsurl '); + return; + } + + audio.setTTSURL(args.url); + successReaction(ev); + }); + + command.createCommand('ttslocale') + .addArgument(command.createArgument('string').setName('locale')) + .help('Set the TTS locale.') + .manual('Sets the TTS locale.') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no locale given + if (!args.locale) { + reply(USAGE_PREFIX + 'ttslocale '); + return; + } + + audio.setTTSDefaultLocale(args.locale); + successReaction(ev); + }); + + command.createCommand('yt') + .addArgument(command.createArgument('string').setName('url')) + .help('Play via youtube-dl') + .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'yt '); + return; + } + + if (!media.yt(args.url)) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev); + }); + + command.createCommand('ytdl') + .addArgument(command.createArgument('string').setName('url')) + .help('Download and play via youtube-dl') + .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'ytdl '); + return; + } + + if (!media.ytdl(args.url, true)) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev); + }); + + command.createCommand('qyt') + .addArgument(command.createArgument('string').setName('url')) + .help('Enqueue via youtube-dl') + .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'qyt '); + return; + } + + if (!media.enqueueYt(args.url)) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev); + }); + + command.createCommand('qytdl') + .addArgument(command.createArgument('string').setName('url')) + .help('Download and enqueue via youtube-dl') + .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'qytdl '); + return; + } + + if (!media.enqueueYtdl(args.url)) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev); + }); + + command.createCommand('shuffle') + .help('Toggle shuffle') + .manual('Toggles shuffle.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + audio.setShuffle(!audio.isShuffle()); + reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); + successReaction(ev); + }); + + command.createCommand('repeat') + .help('Toggle repeat') + .manual('Toggles repeat.') + .checkPermission(requirePrivileges(PLAYBACK)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + audio.setRepeat(!audio.isRepeat()); + reply(SUCCESS_PREFIX + `Repeat is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); + successReaction(ev); + }); + + command.createCommand('registration') + .addArgument(command.createArgument('string').setName('value')) + .help('Change command prefix') + .manual('Changes the prefix for all core commands to , default is "!".') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + switch (args.value) { + case "enable": + engine.enableRegistration(); + reply(SUCCESS_PREFIX + 'Registration is now enabled.'); + successReaction(ev); + break; + case "disable": + engine.disableRegistration(); + reply(SUCCESS_PREFIX + 'Registration is now disabled.'); + successReaction(ev); + break; + default: + reply(`Registartion is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); + } + }); + + command.createCommand('prefix') + .addArgument(command.createArgument('string').setName('prefix')) + .help('Change command prefix') + .manual('Changes the prefix for all core commands to , default is "!".') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no url given + if (!args.prefix) { + reply(USAGE_PREFIX + 'prefix '); + return; + } + + engine.setCommandPrefix(args.prefix); + reply(SUCCESS_PREFIX + 'New prefix: ' + args.prefix); + successReaction(ev); + }); + + command.createCommand('ping') + .help('pong') + .manual('Responds with "PONG".') + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + reply(`PONG`); + successReaction(ev); + }); + + command.createCommand('version') + .help('Show version') + .manual('Shows the SinusBot version.') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + reply(`SinusBot v${engine.version()}\ncommand.js v${command.getVersion()}`); + successReaction(ev); + }); + + command.createCommand('reload') + .help('Reload scripts') + .manual('Reloads scripts.\nPlease Note: New scripts require a complete sinusbot restart.') + .checkPermission(requirePrivileges(EDITBOT)) + // eslint-disable-next-line no-unused-vars + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + let success = engine.reloadScripts(); + if (success) { + reply(SUCCESS_PREFIX + `Scripts reloaded.\nNew scripts require a complete sinusbot restart.`); + successReaction(ev); + } else { + reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); + } + }); + + + command.createCommand('join') + .help('Move the SinusBot to your channel') + .manual('Moves the SinusBot into your channel.') + .checkPermission(requirePrivileges(STARTSTOP)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(msg:string)=>void} */reply, /** @implements {Message} */ev) => { + var channel = client.getChannels()[0] + if (!channel) { + return reply('I\'m unable to join your channel :frowning:') + } + + bot = backend.getBotClient() || bot + if (!bot) { + return reply(ERROR_BOT_NULL) + } + bot.moveTo(channel) + successReaction(ev); + }); + + command.createCommand('leave') + .help('Disconnect the SinusBot') + .manual('Disconnects the SinusBot from the current voice channel.') + .checkPermission(requirePrivileges(STARTSTOP)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(msg:string)=>void} */reply, /** @implements {Message} */ev) => { + bot = backend.getBotClient() || bot + if (!bot) { + return reply(ERROR_BOT_NULL) + } + + // @ts-ignore + bot.moveTo('') + successReaction(ev); + }); + }); + + /********** !playing stuff for discord **********/ + if (engine.getBackend() == 'discord') { + event.on('unload', () => { + // save lastEmbeds + store.set('lastEmbeds', lastEmbeds); + }); + + event.on('discord:MESSAGE_REACTION_ADD', ev => { + const emoji = (ev.emoji.id || '') + ev.emoji.name; + + // ignore reactions that are not controls + if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; + // ignore reactions from the bot itself + if (backend.getBotClientID().endsWith(ev.user_id)) return; + + // get user via id + const client = backend.getClientByID((ev.guild_id ? ev.guild_id+'/' : '')+ev.user_id); + // check if user was found + if (client) { + // ignore reactions from the bot itself + if (client.isSelf()) return; + + // delete the rection + deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); + + // check if user has the 'playback' permission + if (requirePrivileges(PLAYBACK)(client)) { + const track = media.getCurrentTrack(); + + switch (emoji) { + case REACTION_PREV: + // ignore if nothing is playing + if (!audio.isPlaying()) return; + + if (media.getQueue().length !== 0) { + // start from beginning if we're playing queue + audio.seek(0); + } else { + // try prev (doesn't work for queue or folder) + media.playPrevious(); + + // fallback: start from beginning if there is no previous track + if (!audio.isPlaying()) { + if (track) track.play(); + } + } + break; + case REACTION_PLAYPAUSE: + if (audio.isPlaying()) { + media.stop(); + } else { + // is something in queue? try to resume + if (media.getQueue().length !== 0) { + media.resumeQueue(); + return; + } + if (!track) return; + + const pos = audio.getTrackPosition() + if (pos && pos < track.duration()) { + // continue playing at last pos + audio.setMute(true); + track.play(); + audio.seek(pos); + audio.setMute(false); + } else { + // or start from beginning if it already ended + track.play(); + } + } + break; + case REACTION_NEXT: + if (!audio.isPlaying()) { + // is something in queue? try to resume + if (media.getQueue().length !== 0) { + media.playQueueNext(); + } + // ignore if nothing is playing + return; + } + + media.playNext(); + } + } else { + engine.log(`${client.nick()} is missing playback permissions for reaction controls`); + client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); + } + } + }); + + /** + * Called when track or it's info changes + * @param {Track} track + */ + const onChange = track => { + if (config.songInStatus) { + const prefix = '🎵 '; + const suffix = ' 🎵'; + + // set track info as status + backend.extended().setStatus({ + game: { + name: prefix + formatTrack(track) + suffix, + type: 2, // => 0 (game), 1 (streaming), 2 (listening) + }, + status: "online", + afk: false + }); + } + + // update embeds + lastEmbeds.forEach(async embed => { + await editMessage(embed.channelId, embed.messageId, getPlayingEmbed()).then(() => wait(100)); + }); + }; + + event.on('track', onChange); + event.on('trackInfo', onChange); + event.on('trackEnd', () => { + if (!config.songInStatus) { + return; + } + backend.getBotClient().setDescription(''); + }); + } + + /** + * Returns embed for current track + */ + function getPlayingEmbed() { + let track = media.getCurrentTrack(); + let album = track.album(); + let duration = track.duration(); + + let fields = []; + fields.push({ + name: "Duration", + value: duration ? timestamp(duration) : 'stream', + inline: true + }); + if (album) { + fields.push({ + name: "Album", + value: album, + inline: true + }); + } + + return { + embed: { + title: formatTrack(track), + url: sinusbotURL ? sinusbotURL : null, + color: 0xe13438, + thumbnail: { + url: sinusbotURL && track.thumbnail() ? `${sinusbotURL}/cache/${track.thumbnail()}` : null + }, + fields: fields, + footer: { + icon_url: "https://sinusbot.github.io/logo.png", + text: "SinusBot" + } + } + }; + } + + + /********** helper functions **********/ + + /** + * Returns the first user with a given UID. + * + * @param {string} uid UID of the client + * @returns {User} first user with given uid + */ + function getUserByUid(uid) { + for (let user of engine.getUsers()) { + if (user.tsUid() == uid) { + return user; + } + } + + return null; + } + + /** + * Returns alls users that match the clients UID and ServerGroups. + * + * @param {Client} client + * @returns {User[]} Users that match the clients UID and ServerGroups. + */ + function getUsersByClient(client) { + return engine.getUsers().filter(user => + // does the UID match? + client.uid() == user.tsUid() || + // does a group ID match? + client.getServerGroups().map(group => group.id()).includes(user.tsGroupId()) + ); + } + + /** + * Returns a function that checks if a given user has all of the required privileges. + * @param {...number} privileges If at least one privilege matches the returned function will return true. + */ + function requirePrivileges(...privileges) { + return (/** @type {Client} */ client) => { + // check if at least one user has the required privileges + return getUsersByClient(client).some(user => { + // check if at least one privilege is found + return privileges.some(priv => { + return (user.privileges() & priv) === priv; + }); + }); + }; + } + + /** + * Returns a formatted string from a track. + * + * @param {Track} track + * @returns {string} formatted string + */ + function formatTrackWithID(track) { + return `${format.code(track.id())} ${formatTrack(track)}`; + } + + /** + * Returns a formatted string from a track. + * + * @param {Track} track + * @returns {string} formatted string + */ + function formatTrack(track) { + let title = track.tempTitle() || track.title(); + let artist = track.tempArtist() || track.artist(); + return artist ? `${artist} - ${title}` : title; + } + + /** + * Returns a more human readable timestamp (hours:minutes:secods) + * @param {number} milliseconds + */ + function timestamp(milliseconds) { + const SECOND = 1000; + const MINUTE = 60 * SECOND; + const HOUR = 60 * MINUTE; + + let seconds = Math.floor(milliseconds / SECOND); + let minutes = Math.floor(milliseconds / MINUTE); + let hours = Math.floor(milliseconds / HOUR); + + minutes = minutes % (HOUR/MINUTE); + seconds = seconds % (MINUTE/SECOND); + + let str = ''; + + if (hours !== 0) { + str += hours + ':'; + if (minutes <= 9) { + str += '0'; + } + } + str += minutes + ':'; + if (seconds <= 9) { + str += '0'; + } + str += seconds; + + return str; + } + + /** + * Gives the user feedback if a command was successfull. + * + * @param {Message} ev + */ + function successReaction(ev) { + if (!config.createSuccessReaction) { + return; + } + if (engine.getBackend() == 'discord') { + /** @type {DiscordMessage} */ + // @ts-ignore + let message = ev.message; + if (message) { + message.createReaction('✅'); + } + } + } + + /** + * Waits for given milliseconds. + * @param {number} ms Time to wait for in milliseconds. + * @return {Promise} + */ + function wait(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + /** + * Adds a reaction to a message. + * @param {string} channelID Channel ID + * @param {string} messageID Message ID + * @param {string} emoji Emoji + * @return {Promise} + */ + function createReaction(channelID, messageID, emoji) { + return discord('PUT', `/channels/${channelID}/messages/${messageID}/reactions/${emoji}/@me`, null, false); + } + + /** + * Removes a reaction from a message. + * @param {string} channelID Channel ID + * @param {string} messageID Message ID + * @param {string} userID User ID + * @param {string} emoji Emoji + * @return {Promise} + */ + function deleteUserReaction(channelID, messageID, userID, emoji) { + return discord('DELETE', `/channels/${channelID}/messages/${messageID}/reactions/${emoji}/${userID}`, null, false); + } + + /** + * Edits a message. + * @param {string} channelID Channel ID + * @param {string} messageID Message ID + * @param {object} message New message + * @return {Promise} + */ + function editMessage(channelID, messageID, message) { + return discord('PATCH', `/channels/${channelID}/messages/${messageID}`, message, true); + } + + /** + * Deletes a message. + * @param {string} channelID Channel ID + * @param {string} messageID Message ID + * @return {Promise} + */ + function deleteMessage(channelID, messageID) { + return discord('DELETE', `/channels/${channelID}/messages/${messageID}`, null, false); + } + + /** + * Deletes multiple messages. + * @param {string} channelID Channel ID + * @param {string[]} messageIDs Message IDs + * @return {Promise} + */ + function deleteMessages(channelID, messageIDs) { + switch (messageIDs.length) { + case 0: return Promise.resolve(); + case 1: return deleteMessage(channelID, messageIDs[0]); + default: return discord('POST', `/channels/${channelID}/messages/bulk-delete`, {messages: messageIDs}, false); + } + } + + /** + * Executes a discord API call + * @param {string} method http method + * @param {string} path path + * @param {object} [data] json data + * @param {boolean} [repsonse] `true` if you're expecting a json response, `false` otherwise + * @return {Promise} + */ + function discord(method, path, data, repsonse=true) { + return new Promise((resolve, reject) => { + backend.extended().rawCommand(method, path, data, (err, data) => { + if (err) return reject(err); + if (repsonse) { + let res; + try { + res = JSON.parse(data); + } catch (err) { + return reject(err); + } + + if (res === undefined) { + return reject('Invalid Response'); + } + + return resolve(res); + } + resolve(); + }); + }); + } +}) \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d99c08b..4c82699 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.6.tgz", - "integrity": "sha512-VrD4hbI3EdrrWzK4UtEe0jzF/SNfjcbagEYoCdnxSq9BgtYRhF9NHRc0s6q8y+n2Xdr+lFXNF/1GkeEGeXRIdw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.13.tgz", + "integrity": "sha512-0sydynVSmWFGC2aY8Ns07lYBc0VUK643vEY6zdVPHhDGH+d1FdVSNG892NYR8oQUGKkNw7bmyOKaXFSHybyWhA==", "dev": true } } diff --git a/package.json b/package.json index cf90381..531e1b5 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.6" + "sinusbot-scripting-engine": "^1.0.13" } } From 022492c06442086a41550c7372fc0f329d7a6280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 6 Oct 2019 19:51:58 +0200 Subject: [PATCH 14/77] chore: MIT License --- LICENSE | 9 +++++++++ default-attached/sinusbot-commands.js | 27 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eaa84a0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2019 Michael Friese, Max Schmitt, Jonas Bögle + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 45ffeb1..c06cb9b 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1,3 +1,30 @@ +/** + * @author Jonas Bögle + * @license MIT + * + * MIT License + * + * Copyright (c) 2019 Michael Friese, Jonas Bögle + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * @ignore + */ registerPlugin({ name: 'SinusBot Commands', version: '1.0.0', From 49fbbffd4650ccc6f3bbbe659cb98200d3885ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 13 Oct 2019 19:53:05 +0200 Subject: [PATCH 15/77] registration: fix description --- default-attached/sinusbot-commands.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index c06cb9b..6d4fc87 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -663,8 +663,8 @@ registerPlugin({ command.createCommand('registration') .addArgument(command.createArgument('string').setName('value')) - .help('Change command prefix') - .manual('Changes the prefix for all core commands to , default is "!".') + .help('Enable / disable user registration via chat') + .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') .checkPermission(requirePrivileges(EDITBOT)) // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { From 8711035877b737e7a09567997ad6c5704ec5fd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 14 Oct 2019 21:45:42 +0200 Subject: [PATCH 16/77] chore: remove unused eslint commants --- .gitignore | 3 ++- default-attached/sinusbot-commands.js | 26 -------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index b512c09..ad13fa8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +default-attached/command.js \ No newline at end of file diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 6d4fc87..6f8ca48 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -137,7 +137,6 @@ registerPlugin({ .addArgument(command.createArgument('string').setName('username')) .help('Register a new user') .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { if (!engine.registrationEnabled()) { reply('Registration is disabled.'); @@ -276,7 +275,6 @@ registerPlugin({ .help('Play the next track') .manual('Plays the next track (only when a playlist or queue is active).') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { media.playNext(); successReaction(ev); @@ -287,7 +285,6 @@ registerPlugin({ .help('Play the previous track') .manual('Plays the previous track (only when a playlistis active).') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { media.playPrevious(); successReaction(ev); @@ -299,7 +296,6 @@ registerPlugin({ .help('Search for tracks') .manual('Searches for tracks, returns 20 results at most.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no searchstring given if (!args.searchstring) { @@ -325,7 +321,6 @@ registerPlugin({ .help('Play a track by its id or name') .manual('Plays a track by its id or searches for a track and plays the first match.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no idORsearchstring given if (!args.idORsearchstring) { @@ -355,7 +350,6 @@ registerPlugin({ .help('Enqueue a track or resume queue') .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { if (!args.idORsearchstring) { if (!audio.isPlaying()) { @@ -386,7 +380,6 @@ registerPlugin({ .help('Prepends a track to the queue') .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') .checkPermission(requirePrivileges(ENQUEUENEXT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no idORsearchstring given if (!args.idORsearchstring) { @@ -414,7 +407,6 @@ registerPlugin({ .help('Stop playback') .manual('Stops playback.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { media.stop(); successReaction(ev); @@ -424,7 +416,6 @@ registerPlugin({ .help('Stop playback and remove idle-track') .manual('Stops playback and removes idle-track.') .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { media.stop(); media.clearIdleTrack(); @@ -437,7 +428,6 @@ registerPlugin({ .help('Change the volume') .manual('Changes the volume.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { let value = args.value; let volume = audio.getVolume(); @@ -475,7 +465,6 @@ registerPlugin({ .help('Stream a url') .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -495,7 +484,6 @@ registerPlugin({ .help('Say a text via TTS') .manual('Uses text-to-speech (if configured) to say the given text.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no text given if (!args.text) { @@ -513,7 +501,6 @@ registerPlugin({ .help('Say a text via TTS with given locale') .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no locale/text given if (!args.locale || !args.text) { @@ -530,7 +517,6 @@ registerPlugin({ .help('Set the TTS url.') .manual('Sets the TTS url.') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -547,7 +533,6 @@ registerPlugin({ .help('Set the TTS locale.') .manual('Sets the TTS locale.') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no locale given if (!args.locale) { @@ -564,7 +549,6 @@ registerPlugin({ .help('Play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -584,7 +568,6 @@ registerPlugin({ .help('Download and play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -604,7 +587,6 @@ registerPlugin({ .help('Enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -624,7 +606,6 @@ registerPlugin({ .help('Download and enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.url) { @@ -643,7 +624,6 @@ registerPlugin({ .help('Toggle shuffle') .manual('Toggles shuffle.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { audio.setShuffle(!audio.isShuffle()); reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); @@ -654,7 +634,6 @@ registerPlugin({ .help('Toggle repeat') .manual('Toggles repeat.') .checkPermission(requirePrivileges(PLAYBACK)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { audio.setRepeat(!audio.isRepeat()); reply(SUCCESS_PREFIX + `Repeat is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); @@ -666,7 +645,6 @@ registerPlugin({ .help('Enable / disable user registration via chat') .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { switch (args.value) { case "enable": @@ -689,7 +667,6 @@ registerPlugin({ .help('Change command prefix') .manual('Changes the prefix for all core commands to , default is "!".') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { // print syntax if no url given if (!args.prefix) { @@ -705,7 +682,6 @@ registerPlugin({ command.createCommand('ping') .help('pong') .manual('Responds with "PONG".') - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { reply(`PONG`); successReaction(ev); @@ -715,7 +691,6 @@ registerPlugin({ .help('Show version') .manual('Shows the SinusBot version.') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { reply(`SinusBot v${engine.version()}\ncommand.js v${command.getVersion()}`); successReaction(ev); @@ -725,7 +700,6 @@ registerPlugin({ .help('Reload scripts') .manual('Reloads scripts.\nPlease Note: New scripts require a complete sinusbot restart.') .checkPermission(requirePrivileges(EDITBOT)) - // eslint-disable-next-line no-unused-vars .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { let success = engine.reloadScripts(); if (success) { From a59241b7c33f09e655193be563a5f3b7c760cc77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 14 Oct 2019 21:54:21 +0200 Subject: [PATCH 17/77] replace discord emojis --- default-attached/sinusbot-commands.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 6f8ca48..9c8dacb 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -111,9 +111,10 @@ registerPlugin({ const REACTION_PREV = '⏮'; const REACTION_PLAYPAUSE = '⏯'; const REACTION_NEXT = '⏭'; + const REACTION_SUCCESS = '✅'; // for join/leave - const ERROR_BOT_NULL = 'Unable to change channel :frowning:\nTry to set a *Default Channel* in the webinterface and click save.' + const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' let bot = backend.getBotClient(); // restore lastEmbeds @@ -718,7 +719,7 @@ registerPlugin({ .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(msg:string)=>void} */reply, /** @implements {Message} */ev) => { var channel = client.getChannels()[0] if (!channel) { - return reply('I\'m unable to join your channel :frowning:') + return reply(ERROR_PREFIX+'I\'m unable to join your channel :(') } bot = backend.getBotClient() || bot @@ -1029,7 +1030,7 @@ registerPlugin({ // @ts-ignore let message = ev.message; if (message) { - message.createReaction('✅'); + message.createReaction(REACTION_SUCCESS); } } } From 61c68a1fe4c37c020b04cb15eb0ed8aedf880587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 16 Oct 2019 13:55:02 +0200 Subject: [PATCH 18/77] add playlist command --- default-attached/sinusbot-commands.js | 40 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 9c8dacb..2945d1d 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -255,6 +255,9 @@ registerPlugin({ .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) .then(() => wait(150)) .then(() => createReaction(channel_id, id, REACTION_NEXT)); + + // store lastEmbeds + store.set('lastEmbeds', lastEmbeds); }); successReaction(ev); }); @@ -345,6 +348,34 @@ registerPlugin({ successReaction(ev); }); + command.createCommand('playlist') + .addArgument(command.createArgument('rest').setName('playlistname')) + .help('Start playing back the playlist ') + .manual('starts playing back the playlist .') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + // print syntax if no playlistname given + if (!args.playlistname) { + reply(USAGE_PREFIX + 'playlist '); + return; + } + + const match = media.getPlaylists().find(playlist => { + // case insensitive equals + return playlist.name() == args.playlistname || playlist.name().localeCompare(args.playlistname, undefined, { sensitivity: 'accent' }) === 0 + }); + + if (!match) { + reply('Sorry, no matching playlist found.'); + successReaction(ev); + return; + } + + media.playlistPlayById(match, 0); + + successReaction(ev); + }); + command.createCommand('queue') .alias('q') .addArgument(command.createArgument('rest').setName('idORsearchstring').optional(true)) @@ -702,6 +733,7 @@ registerPlugin({ .manual('Reloads scripts.\nPlease Note: New scripts require a complete sinusbot restart.') .checkPermission(requirePrivileges(EDITBOT)) .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + reply('reloading...'); let success = engine.reloadScripts(); if (success) { reply(SUCCESS_PREFIX + `Scripts reloaded.\nNew scripts require a complete sinusbot restart.`); @@ -797,14 +829,9 @@ registerPlugin({ if (audio.isPlaying()) { media.stop(); } else { - // is something in queue? try to resume - if (media.getQueue().length !== 0) { - media.resumeQueue(); - return; - } if (!track) return; + const pos = audio.getTrackPosition(); - const pos = audio.getTrackPosition() if (pos && pos < track.duration()) { // continue playing at last pos audio.setMute(true); @@ -813,6 +840,7 @@ registerPlugin({ audio.setMute(false); } else { // or start from beginning if it already ended + audio.seek(0); track.play(); } } From 22359b70afe2359c6d0eed5fe35f8640f5d26542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 16 Oct 2019 15:22:30 +0200 Subject: [PATCH 19/77] strip url bb-code --- default-attached/sinusbot-commands.js | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 2945d1d..42f14a7 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -504,7 +504,7 @@ registerPlugin({ return; } - if (!media.ytStream(args.url)) { + if (!media.ytStream(stripURL(args.url))) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } @@ -556,7 +556,7 @@ registerPlugin({ return; } - audio.setTTSURL(args.url); + audio.setTTSURL(stripURL(args.url)); successReaction(ev); }); @@ -588,7 +588,7 @@ registerPlugin({ return; } - if (!media.yt(args.url)) { + if (!media.yt(stripURL(args.url))) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } @@ -607,7 +607,7 @@ registerPlugin({ return; } - if (!media.ytdl(args.url, true)) { + if (!media.ytdl(stripURL(args.url), true)) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } @@ -626,7 +626,7 @@ registerPlugin({ return; } - if (!media.enqueueYt(args.url)) { + if (!media.enqueueYt(stripURL(args.url))) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } @@ -645,7 +645,7 @@ registerPlugin({ return; } - if (!media.enqueueYtdl(args.url)) { + if (!media.enqueueYtdl(stripURL(args.url))) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } @@ -700,7 +700,7 @@ registerPlugin({ .manual('Changes the prefix for all core commands to , default is "!".') .checkPermission(requirePrivileges(EDITBOT)) .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { - // print syntax if no url given + // print syntax if no prefix given if (!args.prefix) { reply(USAGE_PREFIX + 'prefix '); return; @@ -1011,6 +1011,22 @@ registerPlugin({ return artist ? `${artist} - ${title}` : title; } + /** + * Removes TeamSpeaks URL bb-code from a given string. + * + * @param {string} str + * @returns {string} str without [URL][/URL] + */ + function stripURL(str) { + if (typeof str !== 'string') return str; + + const match = str.match(/\[URL\](.+)\[\/URL\]/); + if (match && match.length >= 2) { + return match[1]; + } + return str; + } + /** * Returns a more human readable timestamp (hours:minutes:secods) * @param {number} milliseconds From a1dd709a7047b529e8700a8cbac0c0e460fcb80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 16 Oct 2019 21:11:28 +0200 Subject: [PATCH 20/77] implement sub commands --- default-attached/sinusbot-commands.js | 83 +++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 42f14a7..65f5c55 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -672,6 +672,89 @@ registerPlugin({ successReaction(ev); }); + if (engine.getBackend() == 'ts3') { + command.createCommand('sub') + .help('Subscribe to bot') + .manual('Subscribes to the bot. (subscription transfer-mode only)') + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.subscribe(true); + successReaction(ev); + }); + + command.createCommand('unsub') + .help('Unsubscribe from bot') + .manual('Unsubscribes from the bot. (subscription transfer-mode only)') + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.subscribe(false); + successReaction(ev); + }); + + command.createCommand('subchan') + .help('Add subscription for channel') + .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.getChannels()[0].subscribe(true); + successReaction(ev); + }); + + command.createCommand('unsubchan') + .help('Remove subscription for channel') + .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.getChannels()[0].subscribe(false); + successReaction(ev); + }); + + command.createCommand('mode') + .addArgument(command.createArgument('string').setName('mode')) + .help('Change Transmit-Mode') + .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + let mode = args.mode; + if (typeof mode === 'string') { + mode = mode.toLowerCase(); + } + + switch (mode) { + case "0": + case "chan": + case "channel": + //FIXME: set transmit mode + reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Channel (default).'); + successReaction(ev); + break; + case "1": + case "sub": + case "subscription": + //FIXME: set transmit mode + reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Subscription.'); + successReaction(ev); + break; + default: + reply(`Transmit-Mode is currently set to ${engine.isSubscriptionMode() ? 'Subscription' : 'Channel (default)'}.\n` + USAGE_PREFIX + 'mode <0|chan(nel)|1|sub(scription)>'); + } + }); + } + command.createCommand('registration') .addArgument(command.createArgument('string').setName('value')) .help('Enable / disable user registration via chat') From 8c45364a236ecff25bdd19c3c4d849f4bd4f5e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 17 Oct 2019 01:06:38 +0200 Subject: [PATCH 21/77] set nicer argument display --- default-attached/sinusbot-commands.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 65f5c55..da58c3e 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -321,7 +321,7 @@ registerPlugin({ command.createCommand('play') .alias('p') - .addArgument(command.createArgument('rest').setName('idORsearchstring')) + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) .help('Play a track by its id or name') .manual('Plays a track by its id or searches for a track and plays the first match.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -378,7 +378,7 @@ registerPlugin({ command.createCommand('queue') .alias('q') - .addArgument(command.createArgument('rest').setName('idORsearchstring').optional(true)) + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid').optional(true)) .help('Enqueue a track or resume queue') .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) @@ -408,7 +408,7 @@ registerPlugin({ command.createCommand('queuenext') .alias('qnext', 'qn') - .addArgument(command.createArgument('rest').setName('idORsearchstring')) + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) .help('Prepends a track to the queue') .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') .checkPermission(requirePrivileges(ENQUEUENEXT)) From 8db49e4848f7fc5f1a19ec42f4c5096b2a3d97f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 18 Oct 2019 02:42:00 +0200 Subject: [PATCH 22/77] fix: set sub-mode --- default-attached/sinusbot-commands.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index da58c3e..22be160 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -738,14 +738,14 @@ registerPlugin({ case "0": case "chan": case "channel": - //FIXME: set transmit mode + engine.setSubscriptionMode(false); reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Channel (default).'); successReaction(ev); break; case "1": case "sub": case "subscription": - //FIXME: set transmit mode + engine.setSubscriptionMode(true); reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Subscription.'); successReaction(ev); break; From 4fed5fec92853a8fb5c98c276e3c0644e3dae3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 18 Oct 2019 02:48:44 +0200 Subject: [PATCH 23/77] fix: playlist --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 22be160..2213b33 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -371,7 +371,7 @@ registerPlugin({ return; } - media.playlistPlayById(match, 0); + media.playlistPlayByID(match, 0); successReaction(ev); }); From e43292f27668483f8ba821ee708e9e82012c2c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 20 Oct 2019 20:39:22 +0200 Subject: [PATCH 24/77] update typings --- jsconfig.json | 10 ++++++++-- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/jsconfig.json b/jsconfig.json index 8fe1aa7..d248292 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,6 +1,12 @@ { "compilerOptions": { + "checkJs": true, "target": "es2018", - "checkJs": true - } + "types" : ["sinusbot-scripting-engine"] + }, + "typeAcquisition": {"enable": false, "include": ["sinusbot-scripting-engine"]}, + "exclude": [ + "node_modules", + "**/node_modules/*" + ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4c82699..12f5207 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.13.tgz", - "integrity": "sha512-0sydynVSmWFGC2aY8Ns07lYBc0VUK643vEY6zdVPHhDGH+d1FdVSNG892NYR8oQUGKkNw7bmyOKaXFSHybyWhA==", + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.14.tgz", + "integrity": "sha512-tlQCIn79bMsDJk2A2Gxtkyopw26uabZw+cc33f4pagYTtxbJa1nQnnwuowiHjwJW57LNYFK3m2KCHASkLnJIjQ==", "dev": true } } diff --git a/package.json b/package.json index 531e1b5..c3b5718 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.13" + "sinusbot-scripting-engine": "^1.0.14" } } From bf8e53433ceb3288483434f1e371a2a8470160d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 20 Oct 2019 21:09:42 +0200 Subject: [PATCH 25/77] remove type clutter --- default-attached/sinusbot-commands.js | 92 +++++++++++++++------------ 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 2213b33..6c14db5 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -138,7 +138,7 @@ registerPlugin({ .addArgument(command.createArgument('string').setName('username')) .help('Register a new user') .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!engine.registrationEnabled()) { reply('Registration is disabled.'); return; @@ -182,7 +182,7 @@ registerPlugin({ .checkPermission(client => { return getUserByUid(client.uid()) != null; }) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no value given if (!args.value) { reply(USAGE_PREFIX + 'password \n'+ WARNING_PREFIX + 'Don\'t use this command in a public channel.'); @@ -210,7 +210,7 @@ registerPlugin({ command.createCommand('playing') .help('Show what\'s currantly playing') .manual('Show what\'s currantly playing') - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { return reply('There is nothing playing at the moment.'); } @@ -265,8 +265,7 @@ registerPlugin({ command.createCommand('playing') .help('Show what\'s currantly playing') .manual('Show what\'s currantly playing') - // eslint-disable-next-line no-unused-vars - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { return reply('There is nothing playing at the moment.'); } @@ -279,7 +278,7 @@ registerPlugin({ .help('Play the next track') .manual('Plays the next track (only when a playlist or queue is active).') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { media.playNext(); successReaction(ev); }); @@ -289,7 +288,7 @@ registerPlugin({ .help('Play the previous track') .manual('Plays the previous track (only when a playlistis active).') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { media.playPrevious(); successReaction(ev); }); @@ -300,7 +299,7 @@ registerPlugin({ .help('Search for tracks') .manual('Searches for tracks, returns 20 results at most.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no searchstring given if (!args.searchstring) { reply(USAGE_PREFIX + 'search '); @@ -325,7 +324,7 @@ registerPlugin({ .help('Play a track by its id or name') .manual('Plays a track by its id or searches for a track and plays the first match.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no idORsearchstring given if (!args.idORsearchstring) { reply(USAGE_PREFIX + 'play '); @@ -353,7 +352,7 @@ registerPlugin({ .help('Start playing back the playlist ') .manual('starts playing back the playlist .') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no playlistname given if (!args.playlistname) { reply(USAGE_PREFIX + 'playlist '); @@ -382,7 +381,7 @@ registerPlugin({ .help('Enqueue a track or resume queue') .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!args.idORsearchstring) { if (!audio.isPlaying()) { media.playQueueNext(); @@ -412,7 +411,7 @@ registerPlugin({ .help('Prepends a track to the queue') .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') .checkPermission(requirePrivileges(ENQUEUENEXT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no idORsearchstring given if (!args.idORsearchstring) { reply(USAGE_PREFIX + 'queuenext '); @@ -439,7 +438,7 @@ registerPlugin({ .help('Stop playback') .manual('Stops playback.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { media.stop(); successReaction(ev); }); @@ -448,7 +447,7 @@ registerPlugin({ .help('Stop playback and remove idle-track') .manual('Stops playback and removes idle-track.') .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { media.stop(); media.clearIdleTrack(); successReaction(ev); @@ -460,7 +459,7 @@ registerPlugin({ .help('Change the volume') .manual('Changes the volume.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { let value = args.value; let volume = audio.getVolume(); @@ -497,7 +496,7 @@ registerPlugin({ .help('Stream a url') .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'stream '); @@ -516,7 +515,7 @@ registerPlugin({ .help('Say a text via TTS') .manual('Uses text-to-speech (if configured) to say the given text.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no text given if (!args.text) { reply(USAGE_PREFIX + 'say '); @@ -533,7 +532,7 @@ registerPlugin({ .help('Say a text via TTS with given locale') .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no locale/text given if (!args.locale || !args.text) { reply(USAGE_PREFIX + 'sayex '); @@ -549,7 +548,7 @@ registerPlugin({ .help('Set the TTS url.') .manual('Sets the TTS url.') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'ttsurl '); @@ -565,7 +564,7 @@ registerPlugin({ .help('Set the TTS locale.') .manual('Sets the TTS locale.') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no locale given if (!args.locale) { reply(USAGE_PREFIX + 'ttslocale '); @@ -581,7 +580,7 @@ registerPlugin({ .help('Play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'yt '); @@ -600,7 +599,7 @@ registerPlugin({ .help('Download and play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'ytdl '); @@ -619,7 +618,7 @@ registerPlugin({ .help('Enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'qyt '); @@ -638,7 +637,7 @@ registerPlugin({ .help('Download and enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { reply(USAGE_PREFIX + 'qytdl '); @@ -656,7 +655,7 @@ registerPlugin({ .help('Toggle shuffle') .manual('Toggles shuffle.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { audio.setShuffle(!audio.isShuffle()); reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); successReaction(ev); @@ -666,7 +665,7 @@ registerPlugin({ .help('Toggle repeat') .manual('Toggles repeat.') .checkPermission(requirePrivileges(PLAYBACK)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { audio.setRepeat(!audio.isRepeat()); reply(SUCCESS_PREFIX + `Repeat is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); successReaction(ev); @@ -676,7 +675,7 @@ registerPlugin({ command.createCommand('sub') .help('Subscribe to bot') .manual('Subscribes to the bot. (subscription transfer-mode only)') - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); return; @@ -688,7 +687,7 @@ registerPlugin({ command.createCommand('unsub') .help('Unsubscribe from bot') .manual('Unsubscribes from the bot. (subscription transfer-mode only)') - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); return; @@ -701,7 +700,7 @@ registerPlugin({ .help('Add subscription for channel') .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); return; @@ -714,7 +713,7 @@ registerPlugin({ .help('Remove subscription for channel') .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); return; @@ -728,7 +727,7 @@ registerPlugin({ .help('Change Transmit-Mode') .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { let mode = args.mode; if (typeof mode === 'string') { mode = mode.toLowerCase(); @@ -760,7 +759,7 @@ registerPlugin({ .help('Enable / disable user registration via chat') .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { switch (args.value) { case "enable": engine.enableRegistration(); @@ -782,7 +781,7 @@ registerPlugin({ .help('Change command prefix') .manual('Changes the prefix for all core commands to , default is "!".') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { // print syntax if no prefix given if (!args.prefix) { reply(USAGE_PREFIX + 'prefix '); @@ -797,7 +796,7 @@ registerPlugin({ command.createCommand('ping') .help('pong') .manual('Responds with "PONG".') - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { reply(`PONG`); successReaction(ev); }); @@ -806,7 +805,7 @@ registerPlugin({ .help('Show version') .manual('Shows the SinusBot version.') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { reply(`SinusBot v${engine.version()}\ncommand.js v${command.getVersion()}`); successReaction(ev); }); @@ -815,7 +814,7 @@ registerPlugin({ .help('Reload scripts') .manual('Reloads scripts.\nPlease Note: New scripts require a complete sinusbot restart.') .checkPermission(requirePrivileges(EDITBOT)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(message: string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { reply('reloading...'); let success = engine.reloadScripts(); if (success) { @@ -831,7 +830,7 @@ registerPlugin({ .help('Move the SinusBot to your channel') .manual('Moves the SinusBot into your channel.') .checkPermission(requirePrivileges(STARTSTOP)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(msg:string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { var channel = client.getChannels()[0] if (!channel) { return reply(ERROR_PREFIX+'I\'m unable to join your channel :(') @@ -849,7 +848,7 @@ registerPlugin({ .help('Disconnect the SinusBot') .manual('Disconnects the SinusBot from the current voice channel.') .checkPermission(requirePrivileges(STARTSTOP)) - .exec((/** @type {Client} */client, /** @type {object} */args, /** @type {(msg:string)=>void} */reply, /** @implements {Message} */ev) => { + .exec((client, args, reply, ev) => { bot = backend.getBotClient() || bot if (!bot) { return reply(ERROR_BOT_NULL) @@ -1143,18 +1142,27 @@ registerPlugin({ return str; } + /** + * @ignore + * @typedef MessageEvent + * @type {object} + * @property {Client} client + * @property {Channel} channel + * @property {string} text + * @property {number} mode + * @property {DiscordMessage} [message] + */ + /** * Gives the user feedback if a command was successfull. * - * @param {Message} ev + * @param {MessageEvent} ev */ function successReaction(ev) { if (!config.createSuccessReaction) { return; } if (engine.getBackend() == 'discord') { - /** @type {DiscordMessage} */ - // @ts-ignore let message = ev.message; if (message) { message.createReaction(REACTION_SUCCESS); @@ -1259,4 +1267,4 @@ registerPlugin({ }); }); } -}) \ No newline at end of file +}) From 0fdb8dc154c8c249717b4f977ee23a6a77327b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 22 Oct 2019 23:19:02 +0200 Subject: [PATCH 26/77] make !leave discord only --- default-attached/sinusbot-commands.js | 29 ++++++++++++++------------- package-lock.json | 6 +++--- package.json | 2 +- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 6c14db5..4a004eb 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -844,20 +844,21 @@ registerPlugin({ successReaction(ev); }); - command.createCommand('leave') - .help('Disconnect the SinusBot') - .manual('Disconnects the SinusBot from the current voice channel.') - .checkPermission(requirePrivileges(STARTSTOP)) - .exec((client, args, reply, ev) => { - bot = backend.getBotClient() || bot - if (!bot) { - return reply(ERROR_BOT_NULL) - } - - // @ts-ignore - bot.moveTo('') - successReaction(ev); - }); + if (engine.getBackend() == 'discord') { + command.createCommand('leave') + .help('Disconnect the SinusBot') + .manual('Disconnects the SinusBot from the current voice channel.') + .checkPermission(requirePrivileges(STARTSTOP)) + .exec((client, args, reply, ev) => { + bot = backend.getBotClient() || bot + if (!bot) { + return reply(ERROR_BOT_NULL) + } + + bot.moveTo('') + successReaction(ev); + }); + } }); /********** !playing stuff for discord **********/ diff --git a/package-lock.json b/package-lock.json index 12f5207..718d578 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.14.tgz", - "integrity": "sha512-tlQCIn79bMsDJk2A2Gxtkyopw26uabZw+cc33f4pagYTtxbJa1nQnnwuowiHjwJW57LNYFK3m2KCHASkLnJIjQ==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.15.tgz", + "integrity": "sha512-/xz7wsZ2j8FetSectse3ga/TMSkRR5PpYDMs8LujhqygY+hxh0Noe0ib6eJZUxX4jUnzBedp8UTVZ1nbG3zSGQ==", "dev": true } } diff --git a/package.json b/package.json index c3b5718..e9a9864 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.14" + "sinusbot-scripting-engine": "^1.0.15" } } From bd97106930eb39136c3df13d1b9428c41499f3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 22 Oct 2019 23:24:51 +0200 Subject: [PATCH 27/77] add eslint cfg --- .eslintrc.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .eslintrc.yml diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..38e3d72 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,10 @@ +env: + browser: true + commonjs: true + es6: true +extends: 'eslint:recommended' +globals: + registerPlugin: readonly +parserOptions: + ecmaVersion: 2018 +rules: {} \ No newline at end of file From 31eee8b3c8f56814c163dcff91234d8aabd9225c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 22 Oct 2019 23:25:04 +0200 Subject: [PATCH 28/77] add successReaction --- default-attached/sinusbot-commands.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 4a004eb..ac3fc20 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -267,10 +267,12 @@ registerPlugin({ .manual('Show what\'s currantly playing') .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { + successReaction(ev); return reply('There is nothing playing at the moment.'); } reply(formatTrack(media.getCurrentTrack())); + successReaction(ev); }); } @@ -1072,15 +1074,15 @@ registerPlugin({ }; } - /** - * Returns a formatted string from a track. - * - * @param {Track} track - * @returns {string} formatted string - */ - function formatTrackWithID(track) { - return `${format.code(track.id())} ${formatTrack(track)}`; - } + // /** + // * Returns a formatted string from a track. + // * + // * @param {Track} track + // * @returns {string} formatted string + // */ + // function formatTrackWithID(track) { + // return `${format.code(track.id())} ${formatTrack(track)}`; + // } /** * Returns a formatted string from a track. From 90dc14b3e8d8b0072496ecc7c4a7923f4a09710f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 28 Oct 2019 22:36:50 +0100 Subject: [PATCH 29/77] fix: stream --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index ac3fc20..5d7c1f2 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -505,7 +505,7 @@ registerPlugin({ return; } - if (!media.ytStream(stripURL(args.url))) { + if (!media.playURL(stripURL(args.url))) { reply(ERROR_PREFIX + 'Invalid URL.'); return; } From 5c723b5b80365a4bf66d7e82469b8ad5e183d39a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 30 Oct 2019 23:54:54 +0100 Subject: [PATCH 30/77] don't require discord-dangerous --- default-attached/sinusbot-commands.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 5d7c1f2..c319a0c 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -32,7 +32,8 @@ registerPlugin({ author: 'Jonas Bögle (@irgendwr)', engine: '>= 1.0.0', backends: ['ts3', 'discord'], - requiredModules: ['discord-dangerous'], + // the next line is not required since beta.7 + //requiredModules: ['discord-dangerous'], autorun: true, vars: [ { From 320732fa70e2582c8ce9974ac67e2f0fbb9f2f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 30 Oct 2019 23:55:14 +0100 Subject: [PATCH 31/77] add: whoami command --- default-attached/sinusbot-commands.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index c319a0c..18a46ed 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -207,6 +207,19 @@ registerPlugin({ successReaction(ev); }); + command.createCommand('whoami') + .help('Show user identities') + .manual('Shows user identities matching your ID/groups.') + .exec((client, args, reply, ev) => { + let users = getUsersByClient(client); + if (users && users.length != 0) { + reply(`You match the following users: ${users.map(user => user.name()).join(", ")}.`); + } else { + reply("You don't match any users."); + } + successReaction(ev); + }); + if (engine.getBackend() == 'discord') { command.createCommand('playing') .help('Show what\'s currantly playing') @@ -827,7 +840,6 @@ registerPlugin({ reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); } }); - command.createCommand('join') .help('Move the SinusBot to your channel') From db6e57ae3e8d42b4322d4ee44f6b6f6625baf0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 31 Oct 2019 00:02:18 +0100 Subject: [PATCH 32/77] show script version in version cmd --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 18a46ed..f3f1c9f 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -822,7 +822,7 @@ registerPlugin({ .manual('Shows the SinusBot version.') .checkPermission(requirePrivileges(EDITBOT)) .exec((client, args, reply, ev) => { - reply(`SinusBot v${engine.version()}\ncommand.js v${command.getVersion()}`); + reply(`SinusBot v${engine.version()}\nsinusbot-commands.js v${meta.version}\ncommand.js v${command.getVersion()}`); successReaction(ev); }); From a39876ae427bcdfa4f44207f3613433219cee8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 1 Nov 2019 22:27:15 +0100 Subject: [PATCH 33/77] fix typo: currently --- default-attached/sinusbot-commands.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index f3f1c9f..f27f2f9 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -222,8 +222,8 @@ registerPlugin({ if (engine.getBackend() == 'discord') { command.createCommand('playing') - .help('Show what\'s currantly playing') - .manual('Show what\'s currantly playing') + .help('Show what\'s currently playing') + .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { return reply('There is nothing playing at the moment.'); @@ -277,8 +277,8 @@ registerPlugin({ }); } else { command.createCommand('playing') - .help('Show what\'s currantly playing') - .manual('Show what\'s currantly playing') + .help('Show what\'s currently playing') + .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { successReaction(ev); From 78e9cf31d5b4f1ca8331923f499fe19be5c8db64 Mon Sep 17 00:00:00 2001 From: multivit4min Date: Sun, 3 Nov 2019 09:22:01 +0100 Subject: [PATCH 34/77] add success reaction for teamspeak --- default-attached/sinusbot-commands.js | 135 ++++++++++++-------------- 1 file changed, 64 insertions(+), 71 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index f27f2f9..aa56c2e 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -36,6 +36,12 @@ registerPlugin({ //requiredModules: ['discord-dangerous'], autorun: true, vars: [ + { + name: 'createSuccessReaction', + title: 'Add a reaction to each command if it was successfull.', + type: 'checkbox', + default: false + }, { name: 'discord', title: 'Show discord settings', @@ -62,14 +68,7 @@ registerPlugin({ type: 'checkbox', default: true, conditions: [{ field: 'discord', value: true }], - }, - { - name: 'createSuccessReaction', - title: 'Add a reaction to each command if it was successfull.', - type: 'checkbox', - default: false, - conditions: [{ field: 'discord', value: true }], - }, + } ] }, (_, config, meta) => { const event = require('event') @@ -169,10 +168,12 @@ registerPlugin({ reply(ERROR_PREFIX + 'Unable to create user, try another username.'); return; } - // set uid - newUser.setTSUid(client.uid()); - successReaction(ev); + if (!newUser.setTSUid(client.uid())) { + newUser.delete() + return reply(ERROR_PREFIX + 'Unable to assign uid to user.'); + } + }); command.createCommand('password') @@ -180,9 +181,7 @@ registerPlugin({ .addArgument(command.createArgument('rest').setName('value')) .help('Change your password') .manual('Changes your password to .') - .checkPermission(client => { - return getUserByUid(client.uid()) != null; - }) + .checkPermission(client => getUserByUid(client.uid())) .exec((client, args, reply, ev) => { // print syntax if no value given if (!args.value) { @@ -204,7 +203,7 @@ registerPlugin({ // set password user.setPassword(args.value); reply(SUCCESS_PREFIX + 'Changed your password.'); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('whoami') @@ -217,7 +216,7 @@ registerPlugin({ } else { reply("You don't match any users."); } - successReaction(ev); + successReaction(ev, reply); }); if (engine.getBackend() == 'discord') { @@ -273,7 +272,7 @@ registerPlugin({ // store lastEmbeds store.set('lastEmbeds', lastEmbeds); }); - successReaction(ev); + successReaction(ev, reply); }); } else { command.createCommand('playing') @@ -281,12 +280,12 @@ registerPlugin({ .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { if (!audio.isPlaying()) { - successReaction(ev); + successReaction(ev, reply); return reply('There is nothing playing at the moment.'); } reply(formatTrack(media.getCurrentTrack())); - successReaction(ev); + successReaction(ev, reply); }); } @@ -296,7 +295,7 @@ registerPlugin({ .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { media.playNext(); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('prev') @@ -306,7 +305,7 @@ registerPlugin({ .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { media.playPrevious(); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('search') @@ -325,13 +324,13 @@ registerPlugin({ const tracks = media.search(args.searchstring); if (tracks.length == 0) { reply('Sorry, nothing found.'); - successReaction(ev); + successReaction(ev, reply); return; } const response = tracks.map(formatTrack).join("\n") reply(response); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('play') @@ -360,7 +359,7 @@ registerPlugin({ track.play(); reply(`Playing ${formatTrack(track)}`); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('playlist') @@ -382,13 +381,13 @@ registerPlugin({ if (!match) { reply('Sorry, no matching playlist found.'); - successReaction(ev); + successReaction(ev, reply); return; } media.playlistPlayByID(match, 0); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('queue') @@ -418,7 +417,7 @@ registerPlugin({ track.enqueue(); reply(`Added ${formatTrack(track)} to the queue`); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('queuenext') @@ -447,7 +446,7 @@ registerPlugin({ track.enqueue(); reply(`Added ${formatTrack(track)} to the queue`); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('stop') @@ -456,7 +455,7 @@ registerPlugin({ .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { media.stop(); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('!stop') @@ -466,7 +465,7 @@ registerPlugin({ .exec((client, args, reply, ev) => { media.stop(); media.clearIdleTrack(); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('volume') @@ -504,7 +503,7 @@ registerPlugin({ } audio.setVolume(volume); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('stream') @@ -523,7 +522,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Invalid URL.'); return; } - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('say') @@ -539,7 +538,7 @@ registerPlugin({ } audio.say(args.text); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('sayex') @@ -556,7 +555,7 @@ registerPlugin({ } audio.say(args.text, args.locale); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('ttsurl') @@ -572,7 +571,7 @@ registerPlugin({ } audio.setTTSURL(stripURL(args.url)); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('ttslocale') @@ -588,7 +587,7 @@ registerPlugin({ } audio.setTTSDefaultLocale(args.locale); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('yt') @@ -607,7 +606,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Invalid URL.'); return; } - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('ytdl') @@ -626,7 +625,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Invalid URL.'); return; } - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('qyt') @@ -645,7 +644,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Invalid URL.'); return; } - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('qytdl') @@ -664,7 +663,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Invalid URL.'); return; } - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('shuffle') @@ -674,7 +673,7 @@ registerPlugin({ .exec((client, args, reply, ev) => { audio.setShuffle(!audio.isShuffle()); reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('repeat') @@ -684,7 +683,7 @@ registerPlugin({ .exec((client, args, reply, ev) => { audio.setRepeat(!audio.isRepeat()); reply(SUCCESS_PREFIX + `Repeat is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); - successReaction(ev); + successReaction(ev, reply); }); if (engine.getBackend() == 'ts3') { @@ -697,7 +696,7 @@ registerPlugin({ return; } client.subscribe(true); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('unsub') @@ -709,7 +708,7 @@ registerPlugin({ return; } client.subscribe(false); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('subchan') @@ -722,7 +721,7 @@ registerPlugin({ return; } client.getChannels()[0].subscribe(true); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('unsubchan') @@ -735,7 +734,7 @@ registerPlugin({ return; } client.getChannels()[0].subscribe(false); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('mode') @@ -755,14 +754,14 @@ registerPlugin({ case "channel": engine.setSubscriptionMode(false); reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Channel (default).'); - successReaction(ev); + successReaction(ev, reply); break; case "1": case "sub": case "subscription": engine.setSubscriptionMode(true); reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Subscription.'); - successReaction(ev); + successReaction(ev, reply); break; default: reply(`Transmit-Mode is currently set to ${engine.isSubscriptionMode() ? 'Subscription' : 'Channel (default)'}.\n` + USAGE_PREFIX + 'mode <0|chan(nel)|1|sub(scription)>'); @@ -780,12 +779,12 @@ registerPlugin({ case "enable": engine.enableRegistration(); reply(SUCCESS_PREFIX + 'Registration is now enabled.'); - successReaction(ev); + successReaction(ev, reply); break; case "disable": engine.disableRegistration(); reply(SUCCESS_PREFIX + 'Registration is now disabled.'); - successReaction(ev); + successReaction(ev, reply); break; default: reply(`Registartion is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); @@ -806,15 +805,13 @@ registerPlugin({ engine.setCommandPrefix(args.prefix); reply(SUCCESS_PREFIX + 'New prefix: ' + args.prefix); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('ping') - .help('pong') - .manual('Responds with "PONG".') + .help('responds with "PONG"') .exec((client, args, reply, ev) => { reply(`PONG`); - successReaction(ev); }); command.createCommand('version') @@ -823,7 +820,7 @@ registerPlugin({ .checkPermission(requirePrivileges(EDITBOT)) .exec((client, args, reply, ev) => { reply(`SinusBot v${engine.version()}\nsinusbot-commands.js v${meta.version}\ncommand.js v${command.getVersion()}`); - successReaction(ev); + successReaction(ev, reply); }); command.createCommand('reload') @@ -835,7 +832,7 @@ registerPlugin({ let success = engine.reloadScripts(); if (success) { reply(SUCCESS_PREFIX + `Scripts reloaded.\nNew scripts require a complete sinusbot restart.`); - successReaction(ev); + successReaction(ev, reply); } else { reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); } @@ -856,7 +853,7 @@ registerPlugin({ return reply(ERROR_BOT_NULL) } bot.moveTo(channel) - successReaction(ev); + successReaction(ev, reply); }); if (engine.getBackend() == 'discord') { @@ -871,7 +868,7 @@ registerPlugin({ } bot.moveTo('') - successReaction(ev); + successReaction(ev, reply); }); } }); @@ -1047,13 +1044,7 @@ registerPlugin({ * @returns {User} first user with given uid */ function getUserByUid(uid) { - for (let user of engine.getUsers()) { - if (user.tsUid() == uid) { - return user; - } - } - - return null; + return engine.getUsers().find(user => user.tsUid() === uid) } /** @@ -1173,16 +1164,18 @@ registerPlugin({ * Gives the user feedback if a command was successfull. * * @param {MessageEvent} ev + * @param {(msg: string) => void} reply */ - function successReaction(ev) { + function successReaction(ev, reply) { if (!config.createSuccessReaction) { return; } - if (engine.getBackend() == 'discord') { - let message = ev.message; - if (message) { - message.createReaction(REACTION_SUCCESS); - } + switch (engine.getBackend()) { + case "discord": + if (ev.message) ev.message.createReaction(REACTION_SUCCESS) + return + case "ts3": + return reply(`${REACTION_SUCCESS} done!`) } } From a68251b39b50d331670da4adf7582f4741c8ad5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 16:00:31 +0100 Subject: [PATCH 35/77] add check on password set --- default-attached/sinusbot-commands.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index aa56c2e..d25c470 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -201,7 +201,10 @@ registerPlugin({ } // set password - user.setPassword(args.value); + if (!user.setPassword(args.value)) { + reply(ERROR_PREFIX + 'Unable to set password.'); + return; + } reply(SUCCESS_PREFIX + 'Changed your password.'); successReaction(ev, reply); }); From dc01a066e89eb80b75d870bda42d851092ef2ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 16:00:54 +0100 Subject: [PATCH 36/77] add missing successReactions --- default-attached/sinusbot-commands.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index d25c470..280f579 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -171,9 +171,10 @@ registerPlugin({ if (!newUser.setTSUid(client.uid())) { newUser.delete() - return reply(ERROR_PREFIX + 'Unable to assign uid to user.'); + reply(ERROR_PREFIX + 'Unable to assign uid to user.'); + return; } - + successReaction(ev, reply); }); command.createCommand('password') @@ -815,6 +816,7 @@ registerPlugin({ .help('responds with "PONG"') .exec((client, args, reply, ev) => { reply(`PONG`); + successReaction(ev, reply); }); command.createCommand('version') From 36057325f5a22807a1f0a9b50490062360e1ad71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 16:06:54 +0100 Subject: [PATCH 37/77] check instancePrivileges --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 280f579..fee499a 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1077,7 +1077,7 @@ registerPlugin({ return getUsersByClient(client).some(user => { // check if at least one privilege is found return privileges.some(priv => { - return (user.privileges() & priv) === priv; + return ((user.privileges()|user.instancePrivileges()) & priv) === priv; }); }); }; From d750cbadd63205ea9d09a9d0a763f6c275aa97be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 16:14:10 +0100 Subject: [PATCH 38/77] use new user funcs --- default-attached/sinusbot-commands.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index fee499a..cdb5f79 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -169,7 +169,7 @@ registerPlugin({ return; } - if (!newUser.setTSUid(client.uid())) { + if (!newUser.setUid(client.uid())) { newUser.delete() reply(ERROR_PREFIX + 'Unable to assign uid to user.'); return; @@ -1061,9 +1061,9 @@ registerPlugin({ function getUsersByClient(client) { return engine.getUsers().filter(user => // does the UID match? - client.uid() == user.tsUid() || + client.uid() == user.uid() || // does a group ID match? - client.getServerGroups().map(group => group.id()).includes(user.tsGroupId()) + client.getServerGroups().map(group => group.id()).includes(user.groupId()) ); } From 4f8f618f6a9a89eba768cdfd98d8384a0aa7f45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 16:16:21 +0100 Subject: [PATCH 39/77] only show sub cmds in sub-mode --- default-attached/sinusbot-commands.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index cdb5f79..88d42a6 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -694,6 +694,7 @@ registerPlugin({ command.createCommand('sub') .help('Subscribe to bot') .manual('Subscribes to the bot. (subscription transfer-mode only)') + .checkPermission(() => engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); @@ -706,6 +707,7 @@ registerPlugin({ command.createCommand('unsub') .help('Unsubscribe from bot') .manual('Unsubscribes from the bot. (subscription transfer-mode only)') + .checkPermission(() => engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); @@ -718,7 +720,7 @@ registerPlugin({ command.createCommand('subchan') .help('Add subscription for channel') .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); @@ -731,7 +733,7 @@ registerPlugin({ command.createCommand('unsubchan') .help('Remove subscription for channel') .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); From 20b3c65af0517033c54902e30cc3b63cdf6a785f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 23:26:36 +0100 Subject: [PATCH 40/77] upgrade typings --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 718d578..5e64d96 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.15.tgz", - "integrity": "sha512-/xz7wsZ2j8FetSectse3ga/TMSkRR5PpYDMs8LujhqygY+hxh0Noe0ib6eJZUxX4jUnzBedp8UTVZ1nbG3zSGQ==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.16.tgz", + "integrity": "sha512-UOEdmnDaL4oiMHf0DfSab3Wfs5EbNiH1ZD6T8tZRwT2yaw7buix+SH1xZ12bu3LAaSfb0Zfu18Cc0vz6Xu5l6w==", "dev": true } } diff --git a/package.json b/package.json index e9a9864..cdc0259 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.15" + "sinusbot-scripting-engine": "^1.0.16" } } From 96d464e3fd9fbbc3597ea71c88cae040d335ac5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 Nov 2019 23:36:12 +0100 Subject: [PATCH 41/77] add register success response --- default-attached/sinusbot-commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 88d42a6..490b65c 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -174,6 +174,7 @@ registerPlugin({ reply(ERROR_PREFIX + 'Unable to assign uid to user.'); return; } + reply(SUCCESS_PREFIX + 'Registered a user with the given name.\nThis account has no privileges by default but can be edited by the bot administrators.'); successReaction(ev, reply); }); From 670b79dd45b49073edd81ac1cbf047f462e117fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 3 Dec 2019 21:44:25 +0100 Subject: [PATCH 42/77] thanks Jay :) --- default-attached/sinusbot-commands.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 490b65c..d89f306 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -4,7 +4,7 @@ * * MIT License * - * Copyright (c) 2019 Michael Friese, Jonas Bögle + * Copyright (c) 2019 Jonas Bögle, Michael Friese * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,11 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. - * @ignore + * + * Thanks to the following GitHub sponsors for supporting my work: + * - Jay Vasallo + * + * github.com/sponsors/irgendwr */ registerPlugin({ name: 'SinusBot Commands', From 5f194437712cd17ad7d02a8ae688912f34b15a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 4 Dec 2019 11:49:31 +0100 Subject: [PATCH 43/77] thanks Michael :) --- default-attached/sinusbot-commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index d89f306..be2ddfc 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -26,6 +26,7 @@ * * Thanks to the following GitHub sponsors for supporting my work: * - Jay Vasallo + * - Michael Friese * * github.com/sponsors/irgendwr */ From b3d2af475ab783c0c63c8c02cd9e76f3fcc4c976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Thu, 5 Dec 2019 10:28:48 +0100 Subject: [PATCH 44/77] add user-group wildcard "-1" --- default-attached/sinusbot-commands.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index be2ddfc..e5799ff 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1071,7 +1071,9 @@ registerPlugin({ // does the UID match? client.uid() == user.uid() || // does a group ID match? - client.getServerGroups().map(group => group.id()).includes(user.groupId()) + client.getServerGroups().map(group => group.id()).includes(user.groupId()) || + // group ID '-1' matches everyone + user.groupId() == '-1' ); } From f7b475ca7dabf411c2b6a17bb9a245e1213091e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 8 Dec 2019 02:32:44 +0100 Subject: [PATCH 45/77] fix typo in repeat, thanks kira --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index be2ddfc..67e8e2e 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -692,7 +692,7 @@ registerPlugin({ .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { audio.setRepeat(!audio.isRepeat()); - reply(SUCCESS_PREFIX + `Repeat is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); + reply(SUCCESS_PREFIX + `Repeat is now ${audio.isRepeat() ? 'en' : 'dis'}abled.`); successReaction(ev, reply); }); From 75400ff736daa4f8f71e329dff13e0655db0a43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 11 Dec 2019 01:12:26 +0100 Subject: [PATCH 46/77] enh: ignore < > around URLs --- default-attached/sinusbot-commands.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 239fd3f..e6cf0eb 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1116,18 +1116,28 @@ registerPlugin({ } /** - * Removes TeamSpeaks URL bb-code from a given string. + * Removes TeamSpeaks URL bb-code or Discords < > from a given string. * * @param {string} str - * @returns {string} str without [URL][/URL] + * @returns {string} str without [URL] [/URL] and < > */ function stripURL(str) { + // don't handle non-strings, return as provided if (typeof str !== 'string') return str; - const match = str.match(/\[URL\](.+)\[\/URL\]/); + // remove surrounding [URL] [/URL] tags + let match = str.match(/\[URL\](.+)\[\/URL\]/i); if (match && match.length >= 2) { return match[1]; } + + // remove surrounding < > + match = str.match(/<(.+)>/); + if (match && match.length >= 2) { + return match[1]; + } + + // if nothing matches just return str return str; } @@ -1136,7 +1146,7 @@ registerPlugin({ * @param {number} milliseconds */ function timestamp(milliseconds) { - const SECOND = 1000; + const SECOND = 1000; //milliseconds const MINUTE = 60 * SECOND; const HOUR = 60 * MINUTE; From 488909062e4939269f9e5b98c86269790e7e7656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 11 Dec 2019 01:43:36 +0100 Subject: [PATCH 47/77] support custom emoji --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index e6cf0eb..9e99983 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -894,7 +894,7 @@ registerPlugin({ }); event.on('discord:MESSAGE_REACTION_ADD', ev => { - const emoji = (ev.emoji.id || '') + ev.emoji.name; + const emoji = ev.emoji.id ? `${ev.emoji.name}:${ev.emoji.id}` : ev.emoji.name; // ignore reactions that are not controls if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; From 28ab6f91c2fd4acfdf72cd103f2c7b5d3ac54cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 11 Dec 2019 01:47:45 +0100 Subject: [PATCH 48/77] fix: don't continue finished track --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 9e99983..19773c8 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -940,7 +940,7 @@ registerPlugin({ if (!track) return; const pos = audio.getTrackPosition(); - if (pos && pos < track.duration()) { + if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { // continue playing at last pos audio.setMute(true); track.play(); From 072efa4ffa9a1f9ddbf984b14ef690cccbb9e3f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Wed, 11 Dec 2019 03:51:24 +0100 Subject: [PATCH 49/77] fix: ignore reactions to other users --- default-attached/sinusbot-commands.js | 154 +++++++++++++++----------- 1 file changed, 87 insertions(+), 67 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 19773c8..ef6441a 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -82,7 +82,6 @@ registerPlugin({ const format = require('format') const audio = require('audio') const media = require('media') - const store = require('store') engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) @@ -122,9 +121,8 @@ registerPlugin({ const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' let bot = backend.getBotClient(); - // restore lastEmbeds /** @type {object[]} */ - let lastEmbeds = store.get('lastEmbeds') || []; + let lastEmbeds = []; if (config.discord && engine.getBackend() != 'discord') { // hide discord-only settings if backend is not discord @@ -278,9 +276,6 @@ registerPlugin({ .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) .then(() => wait(150)) .then(() => createReaction(channel_id, id, REACTION_NEXT)); - - // store lastEmbeds - store.set('lastEmbeds', lastEmbeds); }); successReaction(ev, reply); }); @@ -888,88 +883,101 @@ registerPlugin({ /********** !playing stuff for discord **********/ if (engine.getBackend() == 'discord') { - event.on('unload', () => { - // save lastEmbeds - store.set('lastEmbeds', lastEmbeds); - }); - event.on('discord:MESSAGE_REACTION_ADD', ev => { - const emoji = ev.emoji.id ? `${ev.emoji.name}:${ev.emoji.id}` : ev.emoji.name; + let ename = ev.emoji.name; + // remove 0xefb88f aka. "VARIATION SELECTOR-16" (no idea why discord puts that at the end) + if (ename.endsWith('\ufe0f')) { + ename = ename.slice(0, -1); + } + const emoji = ev.emoji.id ? `${ename}:${ev.emoji.id}` : ename; // ignore reactions that are not controls if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; + // ignore reactions from the bot itself if (backend.getBotClientID().endsWith(ev.user_id)) return; // get user via id - const client = backend.getClientByID((ev.guild_id ? ev.guild_id+'/' : '')+ev.user_id); - // check if user was found - if (client) { - // ignore reactions from the bot itself - if (client.isSelf()) return; + const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); + + // ignore if no matching user found or reaction from the bot itself + if (!client || client.isSelf()) return; + let callback = () => { // delete the rection deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); // check if user has the 'playback' permission - if (requirePrivileges(PLAYBACK)(client)) { - const track = media.getCurrentTrack(); + if (!requirePrivileges(PLAYBACK)(client)) { + engine.log(`${client.nick()} is missing playback permissions for reaction controls`); + client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); + return; + } - switch (emoji) { - case REACTION_PREV: - // ignore if nothing is playing - if (!audio.isPlaying()) return; + const track = media.getCurrentTrack(); - if (media.getQueue().length !== 0) { - // start from beginning if we're playing queue - audio.seek(0); - } else { - // try prev (doesn't work for queue or folder) - media.playPrevious(); - - // fallback: start from beginning if there is no previous track - if (!audio.isPlaying()) { - if (track) track.play(); - } + switch (emoji) { + case REACTION_PREV: + // ignore if nothing is playing + if (!audio.isPlaying()) return; + + if (media.getQueue().length !== 0) { + // start from beginning if we're playing queue + audio.seek(0); + } else { + // try prev (doesn't work for queue or folder) + media.playPrevious(); + + // fallback: start from beginning if there is no previous track + if (!audio.isPlaying()) { + if (track) track.play(); } - break; - case REACTION_PLAYPAUSE: - if (audio.isPlaying()) { - media.stop(); + } + break; + case REACTION_PLAYPAUSE: + if (audio.isPlaying()) { + media.stop(); + } else { + if (!track) return; + const pos = audio.getTrackPosition(); + + if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { + // continue playing at last pos + audio.setMute(true); + track.play(); + audio.seek(pos); + audio.setMute(false); } else { - if (!track) return; - const pos = audio.getTrackPosition(); - - if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { - // continue playing at last pos - audio.setMute(true); - track.play(); - audio.seek(pos); - audio.setMute(false); - } else { - // or start from beginning if it already ended - audio.seek(0); - track.play(); - } + // or start from beginning if it already ended + track.play(); } - break; - case REACTION_NEXT: - if (!audio.isPlaying()) { - // is something in queue? try to resume - if (media.getQueue().length !== 0) { - media.playQueueNext(); - } - // ignore if nothing is playing - return; - } - + } + break; + case REACTION_NEXT: + if (audio.isPlaying()) { media.playNext(); + } else { + // is something in queue? + if (media.getQueue().length !== 0) { + // resume queue + media.playQueueNext(); + } } - } else { - engine.log(`${client.nick()} is missing playback permissions for reaction controls`); - client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); } + }; + + // was reaction added to previous response? + if (lastEmbeds.some(embed => embed.messageId == ev.message_id)) { + callback(); + return; } + + getMessage(ev.channel_id, ev.message_id).then(msg => { + // was reaction added to previous response of the bot? + if (backend.getBotClientID().endsWith(msg.author.id)) { + callback(); + } + }) }); /** @@ -1236,6 +1244,16 @@ registerPlugin({ return discord('DELETE', `/channels/${channelID}/messages/${messageID}/reactions/${emoji}/${userID}`, null, false); } + /** + * Gets a message. + * @param {string} channelID Channel ID + * @param {string} messageID Message ID + * @return {Promise} + */ + function getMessage(channelID, messageID) { + return discord('GET', `/channels/${channelID}/messages/${messageID}`, null, true); + } + /** * Edits a message. * @param {string} channelID Channel ID @@ -1279,7 +1297,7 @@ registerPlugin({ * @param {boolean} [repsonse] `true` if you're expecting a json response, `false` otherwise * @return {Promise} */ - function discord(method, path, data, repsonse=true) { + function discord(method, path, data=null, repsonse=true) { return new Promise((resolve, reject) => { backend.extended().rawCommand(method, path, data, (err, data) => { if (err) return reject(err); @@ -1288,6 +1306,8 @@ registerPlugin({ try { res = JSON.parse(data); } catch (err) { + engine.log(`${method} ${path}`); + engine.log('Invalid JSON: ' + data); return reject(err); } From e2d69a3b1d129d7c9dbb6346ba641f07ded70223 Mon Sep 17 00:00:00 2001 From: rtrind <413433+rtrind@users.noreply.github.com> Date: Fri, 14 Feb 2020 13:54:06 +0000 Subject: [PATCH 50/77] Alone mode when bot leaves channel (#11) In the current version, when the bot leaves the channel, it causes an error: `error on callback func: Uncaught exception: TypeError: Cannot read property 'getClientCount' of undefined at alonemode:31:49 let clients = backend.getCurrentChannel().getClientCount()` With the changes, you do not get the error anymore and if the bot leaves the channel. --- default-attached/alonemode.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index b594228..a68b9fb 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'AloneMode', - version: '3.0', + version: '3.1', backends: ['ts3', 'discord'], description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', author: 'Michael Friese , Max Schmitt ', @@ -29,7 +29,8 @@ registerPlugin({ audio.setMute(false) event.on('clientMove', () => { - let clients = backend.getCurrentChannel().getClientCount() + let currentChannel = backend.getCurrentChannel() + let clients = currentChannel ? currentChannel.getClientCount() : 0 if (clients > 1 && isMuted) { isMuted = false @@ -58,4 +59,4 @@ registerPlugin({ } } }) -}) \ No newline at end of file +}) From a76866d4d5f970f5453e0f07e33b0ec789ff6591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 25 Feb 2020 18:52:43 +0100 Subject: [PATCH 51/77] add option to disable default commands --- default-attached/sinusbot-commands.js | 50 +++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index ef6441a..df471fc 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -4,7 +4,7 @@ * * MIT License * - * Copyright (c) 2019 Jonas Bögle, Michael Friese + * Copyright (c) 2019-2020 Jonas Bögle, Michael Friese * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,10 +25,10 @@ * SOFTWARE. * * Thanks to the following GitHub sponsors for supporting my work: - * - Jay Vasallo * - Michael Friese + * - Jay Vasallo * - * github.com/sponsors/irgendwr + * https://github.com/sponsors/irgendwr */ registerPlugin({ name: 'SinusBot Commands', @@ -41,38 +41,65 @@ registerPlugin({ //requiredModules: ['discord-dangerous'], autorun: true, vars: [ + { + /* + * Note: Normally you should **not** add something like this, + * because you can already disable scripts by unchecking them. + * However in this case it makes sense as `autorun: true` + * no longer allows users to disable it otherwise. + */ + name: 'disable', + title: 'Disable the default SinusBot commands.', + type: 'checkbox', + default: false + }, { name: 'createSuccessReaction', title: 'Add a reaction to each command if it was successfull.', type: 'checkbox', - default: false + default: false, + conditions: [ + { field: 'disable', value: false } + ], }, { name: 'discord', title: 'Show discord settings', type: 'checkbox', default: true, + conditions: [ + { field: 'disable', value: false } + ], }, { name: 'url', title: 'URL to Webinterface (optional, for album covers in discord)', type: 'string', placeholder: 'i.e. https://sinusbot.example.com', - conditions: [{ field: 'discord', value: true }], + conditions: [ + { field: 'discord', value: true }, + { field: 'disable', value: false } + ], }, { name: 'songInStatus', title: 'Show playing song in status.', type: 'checkbox', default: true, - conditions: [{ field: 'discord', value: true }], + conditions: [ + { field: 'discord', value: true }, + { field: 'disable', value: false } + ], }, { name: 'deleteOldMessages', title: 'Delete previous responses if !playing command is used again', type: 'checkbox', default: true, - conditions: [{ field: 'discord', value: true }], + conditions: [ + { field: 'discord', value: true }, + { field: 'disable', value: false } + ], } ] }, (_, config, meta) => { @@ -85,6 +112,11 @@ registerPlugin({ engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) + if (config.disable) { + engine.log('SinusBot commands are DISABLED.') + return; + } + /********* privileges *********/ /* eslint-disable no-unused-vars */ const LOGIN = 1 << 0; @@ -128,6 +160,10 @@ registerPlugin({ // hide discord-only settings if backend is not discord config.discord = false; engine.saveConfig(config); + } else if (!config.discord && engine.getBackend() == 'discord') { + // show discord-only settings if backend is discord + config.discord = true; + engine.saveConfig(config); } event.on('load', () => { From 05881d510e0c894d0d518b65a1e63b4c96c76817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sat, 21 Mar 2020 18:16:17 +0100 Subject: [PATCH 52/77] log sinusbot version --- default-attached/sinusbot-commands.js | 1 + 1 file changed, 1 insertion(+) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index df471fc..e7dae2a 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -111,6 +111,7 @@ registerPlugin({ const media = require('media') engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) + engine.log(`SinusBot v${engine.version()}`) if (config.disable) { engine.log('SinusBot commands are DISABLED.') From d3f3435bc92bbed9aeed6c6dea40e8451b684e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sat, 21 Mar 2020 18:27:57 +0100 Subject: [PATCH 53/77] also log OS --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index e7dae2a..293f5db 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -111,7 +111,7 @@ registerPlugin({ const media = require('media') engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) - engine.log(`SinusBot v${engine.version()}`) + engine.log(`SinusBot v${engine.version()} on ${engine.os()}`) if (config.disable) { engine.log('SinusBot commands are DISABLED.') From 3cd06a62361ce19eed8469458ef831397b537a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sat, 21 Mar 2020 18:28:35 +0100 Subject: [PATCH 54/77] add: log where to download command.js --- default-attached/sinusbot-commands.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 293f5db..20e4da3 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -170,7 +170,8 @@ registerPlugin({ event.on('load', () => { const command = require('command'); if (!command) { - engine.log('command.js library not found! Please download command.js and enable it to be able use this script!'); + engine.log('command.js library not found! Please download command.js to your scripts folder and restart the SinusBot, otherwise this script will not work.'); + engine.log('command.js can be found here: https://github.com/Multivit4min/Sinusbot-Command/blob/master/command.js'); return; } From 6cae2436af796dbf00ee7ff767762b1f6fcd6fe5 Mon Sep 17 00:00:00 2001 From: Fabian <11352551+fabm3n@users.noreply.github.com> Date: Tue, 31 Mar 2020 18:49:13 +0200 Subject: [PATCH 55/77] Fix selected mode and spamming messages (#12) * Fix wrong selected mode * Fix spamming "Starting AloneMode" Messages --- default-attached/alonemode.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index a68b9fb..6ff1322 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -1,6 +1,6 @@ registerPlugin({ name: 'AloneMode', - version: '3.1', + version: '3.2', backends: ['ts3', 'discord'], description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', author: 'Michael Friese , Max Schmitt ', @@ -20,7 +20,7 @@ registerPlugin({ const audio = require('audio') const media = require('media') - const MUTE_ONLY = '1' + const MUTE_ONLY = '0' let isMuted = false let lastPosition = 0 @@ -45,10 +45,10 @@ registerPlugin({ engine.log(`Seeking to ${lastPosition} of track '${lastTrack.title()}'`) } } - } else if (clients <= 1 && audio.isPlaying()) { + } else if (clients <= 1 && audio.isPlaying() && isMuted == false) { isMuted = true engine.log('Starting AloneMode...') - + if (mode == MUTE_ONLY) { audio.setMute(true) } else { From f3829f1157d5b4c749b4ae040a93e45a1687d050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 5 Apr 2020 14:40:31 +0200 Subject: [PATCH 56/77] minor changes (sorry, too lazy) --- default-attached/sinusbot-commands.js | 1546 +++++++++++++------------ 1 file changed, 786 insertions(+), 760 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 20e4da3..3894852 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -29,6 +29,7 @@ * - Jay Vasallo * * https://github.com/sponsors/irgendwr + * */ registerPlugin({ name: 'SinusBot Commands', @@ -87,8 +88,7 @@ registerPlugin({ type: 'checkbox', default: true, conditions: [ - { field: 'discord', value: true }, - { field: 'disable', value: false } + { field: 'discord', value: true } ], }, { @@ -113,11 +113,6 @@ registerPlugin({ engine.log(`Loaded ${meta.name} v${meta.version} by ${meta.author}.`) engine.log(`SinusBot v${engine.version()} on ${engine.os()}`) - if (config.disable) { - engine.log('SinusBot commands are DISABLED.') - return; - } - /********* privileges *********/ /* eslint-disable no-unused-vars */ const LOGIN = 1 << 0; @@ -152,7 +147,6 @@ registerPlugin({ // for join/leave const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' - let bot = backend.getBotClient(); /** @type {object[]} */ let lastEmbeds = []; @@ -167,892 +161,908 @@ registerPlugin({ engine.saveConfig(config); } - event.on('load', () => { - const command = require('command'); - if (!command) { - engine.log('command.js library not found! Please download command.js to your scripts folder and restart the SinusBot, otherwise this script will not work.'); - engine.log('command.js can be found here: https://github.com/Multivit4min/Sinusbot-Command/blob/master/command.js'); - return; - } - - command.createCommand('register') - .addArgument(command.createArgument('string').setName('username')) - .help('Register a new user') - .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') - .exec((client, args, reply, ev) => { - if (!engine.registrationEnabled()) { - reply('Registration is disabled.'); - return; - } - - // print syntax if no username given - if (!args.username) { - reply(USAGE_PREFIX + 'register '); - return; - } - - if (engine.getUserByName(args.username)) { - reply(ERROR_PREFIX + 'This username already exists.'); - return; - } - - // check if client already has a user - let user = getUserByUid(client.uid()); - if (user) { - reply(ERROR_PREFIX + `You already have a user with the name "${user.name()}".`); - return; - } - - // create user - let newUser = engine.addUser(args.username); - if (!newUser) { - reply(ERROR_PREFIX + 'Unable to create user, try another username.'); - return; - } - - if (!newUser.setUid(client.uid())) { - newUser.delete() - reply(ERROR_PREFIX + 'Unable to assign uid to user.'); - return; - } - reply(SUCCESS_PREFIX + 'Registered a user with the given name.\nThis account has no privileges by default but can be edited by the bot administrators.'); - successReaction(ev, reply); - }); - - command.createCommand('password') - .alias('pass') - .addArgument(command.createArgument('rest').setName('value')) - .help('Change your password') - .manual('Changes your password to .') - .checkPermission(client => getUserByUid(client.uid())) - .exec((client, args, reply, ev) => { - // print syntax if no value given - if (!args.value) { - reply(USAGE_PREFIX + 'password \n'+ WARNING_PREFIX + 'Don\'t use this command in a public channel.'); + if (config.disable) { + engine.log('SinusBot commands are DISABLED.'); + } else { // BEGIN COMMANDS-ENABLED + event.on('load', () => { + const command = require('command'); + if (!command) { + engine.log('command.js library not found! Please download command.js to your scripts folder and restart the SinusBot, otherwise this script will not work.'); + engine.log('command.js can be found here: https://github.com/Multivit4min/Sinusbot-Command/blob/master/command.js'); return; } + + command.createCommand('register') + .addArgument(command.createArgument('string').setName('username')) + .help('Register a new user') + .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') + .exec((client, args, reply, ev) => { + if (!engine.registrationEnabled()) { + reply('Registration is disabled.'); + return; + } - if (ev.mode !== 1) { - reply(WARNING_PREFIX + 'Don\'t use this command in a public channel.'); - return; - } + // print syntax if no username given + if (!args.username) { + reply(USAGE_PREFIX + 'register '); + return; + } - let user = getUserByUid(client.uid()); - if (!user) { - reply(ERROR_PREFIX + `You don't have a user-account. Use ${format.bold('!register')} to create one.`); - return; - } + if (engine.getUserByName(args.username)) { + reply(ERROR_PREFIX + 'This username already exists.'); + return; + } - // set password - if (!user.setPassword(args.value)) { - reply(ERROR_PREFIX + 'Unable to set password.'); - return; - } - reply(SUCCESS_PREFIX + 'Changed your password.'); - successReaction(ev, reply); - }); + // check if client already has a user + let user = getUserByUid(client.uid()); + if (user) { + reply(ERROR_PREFIX + `You already have a user with the name "${user.name()}".`); + return; + } - command.createCommand('whoami') - .help('Show user identities') - .manual('Shows user identities matching your ID/groups.') - .exec((client, args, reply, ev) => { - let users = getUsersByClient(client); - if (users && users.length != 0) { - reply(`You match the following users: ${users.map(user => user.name()).join(", ")}.`); - } else { - reply("You don't match any users."); - } - successReaction(ev, reply); - }); + // create user + let newUser = engine.addUser(args.username); + if (!newUser) { + reply(ERROR_PREFIX + 'Unable to create user, try another username.'); + return; + } - if (engine.getBackend() == 'discord') { - command.createCommand('playing') - .help('Show what\'s currently playing') - .manual('Show what\'s currently playing') + if (!newUser.setUid(client.uid())) { + newUser.delete() + reply(ERROR_PREFIX + 'Unable to assign uid to user.'); + return; + } + reply(SUCCESS_PREFIX + 'Registered a user with the given name.\nThis account has no privileges by default but can be edited by the bot administrators.'); + successReaction(ev, reply); + }); + + command.createCommand('password') + .alias('pass') + .addArgument(command.createArgument('rest').setName('value')) + .help('Change your password') + .manual('Changes your password to .') + .checkPermission(client => getUserByUid(client.uid())) .exec((client, args, reply, ev) => { - if (!audio.isPlaying()) { - return reply('There is nothing playing at the moment.'); + // print syntax if no value given + if (!args.value) { + reply(USAGE_PREFIX + 'password \n'+ WARNING_PREFIX + 'Don\'t use this command in a public channel.'); + return; } - backend.extended().createMessage(ev.channel.id(), getPlayingEmbed(), (err, res) => { - if (err) return engine.log(err); - if (!res) return engine.log('Error: empty response'); - - const {id, channel_id} = JSON.parse(res); - - // messages that should be deleted - let deleteMsg = []; - const msgId = ev.message ? ev.message.ID() : null; - const index = lastEmbeds.findIndex(embed => embed.channelId == channel_id); - if (index !== -1) { - if (config.deleteOldMessages) { - // delete previous embed - deleteMsg.push(lastEmbeds[index].messageId); - // delete previous command from user - if (lastEmbeds[index].messageId) { - deleteMsg.push(lastEmbeds[index].invokeMessageId); - } - } - // save new embed - lastEmbeds[index].messageId = id; - lastEmbeds[index].invokeMessageId = msgId; - } else { - // save new embed - lastEmbeds.push({ - channelId: channel_id, - messageId: id, - invokeMessageId: msgId - }); - } + if (ev.mode !== 1) { + reply(WARNING_PREFIX + 'Don\'t use this command in a public channel.'); + return; + } - deleteMessages(channel_id, deleteMsg); - - wait(1000) - // create reaction controls - .then(() => createReaction(channel_id, id, REACTION_PREV)) - .then(() => wait(150)) - .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) - .then(() => wait(150)) - .then(() => createReaction(channel_id, id, REACTION_NEXT)); - }); + let user = getUserByUid(client.uid()); + if (!user) { + reply(ERROR_PREFIX + `You don't have a user-account. Use ${format.bold('!register')} to create one.`); + return; + } + + // set password + if (!user.setPassword(args.value)) { + reply(ERROR_PREFIX + 'Unable to set password.'); + return; + } + reply(SUCCESS_PREFIX + 'Changed your password.'); successReaction(ev, reply); }); - } else { - command.createCommand('playing') - .help('Show what\'s currently playing') - .manual('Show what\'s currently playing') + + command.createCommand('whoami') + .help('Show user identities') + .manual('Shows user identities matching your ID/groups.') .exec((client, args, reply, ev) => { - if (!audio.isPlaying()) { - successReaction(ev, reply); - return reply('There is nothing playing at the moment.'); + let users = getUsersByClient(client); + if (users && users.length != 0) { + reply(`You match the following users: ${users.map(user => user.name()).join(", ")}.`); + } else { + reply("You don't match any users."); } - - reply(formatTrack(media.getCurrentTrack())); successReaction(ev, reply); }); - } - command.createCommand('next') - .help('Play the next track') - .manual('Plays the next track (only when a playlist or queue is active).') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - media.playNext(); - successReaction(ev, reply); - }); + if (engine.getBackend() == 'discord') { + command.createCommand('playing') + .help('Show what\'s currently playing') + .manual('Show what\'s currently playing') + .exec((client, args, reply, ev) => { + if (!audio.isPlaying()) { + return reply('There is nothing playing at the moment.'); + } - command.createCommand('prev') - .alias('previous') - .help('Play the previous track') - .manual('Plays the previous track (only when a playlistis active).') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - media.playPrevious(); - successReaction(ev, reply); - }); + backend.extended().createMessage(ev.channel.id(), getPlayingEmbed(), (err, res) => { + if (err) return engine.log(err); + if (!res) return engine.log('Error: empty response'); + + const {id, channel_id} = JSON.parse(res); + + // messages that should be deleted + let deleteMsg = []; + const msgId = ev.message ? ev.message.ID() : null; + const index = lastEmbeds.findIndex(embed => embed.channelId == channel_id); + if (index !== -1) { + if (config.deleteOldMessages) { + // delete previous embed + deleteMsg.push(lastEmbeds[index].messageId); + // delete previous command from user + if (lastEmbeds[index].messageId) { + deleteMsg.push(lastEmbeds[index].invokeMessageId); + } + } + // save new embed + lastEmbeds[index].messageId = id; + lastEmbeds[index].invokeMessageId = msgId; + } else { + // save new embed + lastEmbeds.push({ + channelId: channel_id, + messageId: id, + invokeMessageId: msgId + }); + } - command.createCommand('search') - .alias('s') - .addArgument(command.createArgument('rest').setName('searchstring')) - .help('Search for tracks') - .manual('Searches for tracks, returns 20 results at most.') - .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((client, args, reply, ev) => { - // print syntax if no searchstring given - if (!args.searchstring) { - reply(USAGE_PREFIX + 'search '); - return; + deleteMessages(channel_id, deleteMsg); + + wait(1000) + // create reaction controls + .then(() => createReaction(channel_id, id, REACTION_PREV)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_NEXT)); + }); + successReaction(ev, reply); + }); + } else { + command.createCommand('playing') + .help('Show what\'s currently playing') + .manual('Show what\'s currently playing') + .exec((client, args, reply, ev) => { + if (!audio.isPlaying()) { + successReaction(ev, reply); + return reply('There is nothing playing at the moment.'); + } + + reply(formatTrack(media.getCurrentTrack())); + successReaction(ev, reply); + }); } - const tracks = media.search(args.searchstring); - if (tracks.length == 0) { - reply('Sorry, nothing found.'); + command.createCommand('next') + .help('Play the next track') + .manual('Plays the next track (only when a playlist or queue is active).') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + media.playNext(); successReaction(ev, reply); - return; - } + }); - const response = tracks.map(formatTrack).join("\n") - reply(response); - successReaction(ev, reply); - }); + command.createCommand('prev') + .alias('previous') + .help('Play the previous track') + .manual('Plays the previous track (only when a playlistis active).') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + media.playPrevious(); + successReaction(ev, reply); + }); - command.createCommand('play') - .alias('p') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) - .help('Play a track by its id or name') - .manual('Plays a track by its id or searches for a track and plays the first match.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no idORsearchstring given - if (!args.idORsearchstring) { - reply(USAGE_PREFIX + 'play '); - return; - } + command.createCommand('search') + .alias('s') + .addArgument(command.createArgument('rest').setName('searchstring')) + .help('Search for tracks') + .manual('Searches for tracks, returns 20 results at most.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) + .exec((client, args, reply, ev) => { + // print syntax if no searchstring given + if (!args.searchstring) { + reply(USAGE_PREFIX + 'search '); + return; + } - let track = media.getTrackByID(args.idORsearchstring); - if (!track) { - let tracks = media.search(args.idORsearchstring); - if (tracks.length > 0) { - track = tracks[0]; - } else { + const tracks = media.search(args.searchstring); + if (tracks.length == 0) { reply('Sorry, nothing found.'); + successReaction(ev, reply); return; } - } - - track.play(); - reply(`Playing ${formatTrack(track)}`); - successReaction(ev, reply); - }); - - command.createCommand('playlist') - .addArgument(command.createArgument('rest').setName('playlistname')) - .help('Start playing back the playlist ') - .manual('starts playing back the playlist .') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no playlistname given - if (!args.playlistname) { - reply(USAGE_PREFIX + 'playlist '); - return; - } - - const match = media.getPlaylists().find(playlist => { - // case insensitive equals - return playlist.name() == args.playlistname || playlist.name().localeCompare(args.playlistname, undefined, { sensitivity: 'accent' }) === 0 - }); - if (!match) { - reply('Sorry, no matching playlist found.'); + const response = tracks.map(formatTrack).join("\n") + reply(response); successReaction(ev, reply); - return; - } - - media.playlistPlayByID(match, 0); - - successReaction(ev, reply); - }); - - command.createCommand('queue') - .alias('q') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid').optional(true)) - .help('Enqueue a track or resume queue') - .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') - .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((client, args, reply, ev) => { - if (!args.idORsearchstring) { - if (!audio.isPlaying()) { - media.playQueueNext(); - } - return; - } + }); - let track = media.getTrackByID(args.idORsearchstring); - if (!track) { - const tracks = media.search(args.idORsearchstring); - if (tracks.length > 0) { - track = tracks[0]; - } else { - reply('Sorry, nothing found.'); + command.createCommand('play') + .alias('p') + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) + .help('Play a track by its id or name') + .manual('Plays a track by its id or searches for a track and plays the first match.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no idORsearchstring given + if (!args.idORsearchstring) { + reply(USAGE_PREFIX + 'play '); return; } - } - track.enqueue(); - reply(`Added ${formatTrack(track)} to the queue`); - successReaction(ev, reply); - }); + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + let tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } - command.createCommand('queuenext') - .alias('qnext', 'qn') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) - .help('Prepends a track to the queue') - .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') - .checkPermission(requirePrivileges(ENQUEUENEXT)) - .exec((client, args, reply, ev) => { - // print syntax if no idORsearchstring given - if (!args.idORsearchstring) { - reply(USAGE_PREFIX + 'queuenext '); - return; - } + track.play(); + reply(`Playing ${formatTrack(track)}`); + successReaction(ev, reply); + }); - let track = media.getTrackByID(args.idORsearchstring); - if (!track) { - const tracks = media.search(args.idORsearchstring); - if (tracks.length > 0) { - track = tracks[0]; - } else { - reply('Sorry, nothing found.'); + command.createCommand('playlist') + .addArgument(command.createArgument('rest').setName('playlistname')) + .help('Start playing back the playlist ') + .manual('starts playing back the playlist .') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no playlistname given + if (!args.playlistname) { + reply(USAGE_PREFIX + 'playlist '); return; } - } - - track.enqueue(); - reply(`Added ${formatTrack(track)} to the queue`); - successReaction(ev, reply); - }); - command.createCommand('stop') - .help('Stop playback') - .manual('Stops playback.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - media.stop(); - successReaction(ev, reply); - }); - - command.createCommand('!stop') - .help('Stop playback and remove idle-track') - .manual('Stops playback and removes idle-track.') - .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) - .exec((client, args, reply, ev) => { - media.stop(); - media.clearIdleTrack(); - successReaction(ev, reply); - }); + const match = media.getPlaylists().find(playlist => { + // case insensitive equals + return playlist.name() == args.playlistname || playlist.name().localeCompare(args.playlistname, undefined, { sensitivity: 'accent' }) === 0 + }); - command.createCommand('volume') - .alias('vol') - .addArgument(command.createArgument('string').setName('value')) - .help('Change the volume') - .manual('Changes the volume.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - let value = args.value; - let volume = audio.getVolume(); - - switch (value) { - case 'up': - volume += 10; - break; - case 'dn': - case 'down': - volume -= 10; - break; - default: - value = parseInt(value, 10); - if (value >= 0 && value <= 100) { - volume = value; - } else { - reply(USAGE_PREFIX + 'volume '); + if (!match) { + reply('Sorry, no matching playlist found.'); + successReaction(ev, reply); return; } - } - - if (volume < 0) { - volume = 0; - } else if (volume > 100) { - volume = 100; - } - - audio.setVolume(volume); - successReaction(ev, reply); - }); + + media.playlistPlayByID(match, 0); - command.createCommand('stream') - .addArgument(command.createArgument('string').setName('url')) - .help('Stream a url') - .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'stream '); - return; - } + successReaction(ev, reply); + }); - if (!media.playURL(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } - successReaction(ev, reply); - }); + command.createCommand('queue') + .alias('q') + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid').optional(true)) + .help('Enqueue a track or resume queue') + .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) + .exec((client, args, reply, ev) => { + if (!args.idORsearchstring) { + if (!audio.isPlaying()) { + media.playQueueNext(); + } + return; + } - command.createCommand('say') - .addArgument(command.createArgument('rest').setName('text')) - .help('Say a text via TTS') - .manual('Uses text-to-speech (if configured) to say the given text.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no text given - if (!args.text) { - reply(USAGE_PREFIX + 'say '); - return; - } + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + const tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } - audio.say(args.text); - successReaction(ev, reply); - }); + track.enqueue(); + reply(`Added ${formatTrack(track)} to the queue`); + successReaction(ev, reply); + }); - command.createCommand('sayex') - .addArgument(command.createArgument('string').setName('locale')) - .addArgument(command.createArgument('rest').setName('text')) - .help('Say a text via TTS with given locale') - .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no locale/text given - if (!args.locale || !args.text) { - reply(USAGE_PREFIX + 'sayex '); - return; - } + command.createCommand('queuenext') + .alias('qnext', 'qn') + .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) + .help('Prepends a track to the queue') + .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') + .checkPermission(requirePrivileges(ENQUEUENEXT)) + .exec((client, args, reply, ev) => { + // print syntax if no idORsearchstring given + if (!args.idORsearchstring) { + reply(USAGE_PREFIX + 'queuenext '); + return; + } - audio.say(args.text, args.locale); - successReaction(ev, reply); - }); + let track = media.getTrackByID(args.idORsearchstring); + if (!track) { + const tracks = media.search(args.idORsearchstring); + if (tracks.length > 0) { + track = tracks[0]; + } else { + reply('Sorry, nothing found.'); + return; + } + } - command.createCommand('ttsurl') - .addArgument(command.createArgument('string').setName('url')) - .help('Set the TTS url.') - .manual('Sets the TTS url.') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'ttsurl '); - return; - } + track.enqueue(); + reply(`Added ${formatTrack(track)} to the queue`); + successReaction(ev, reply); + }); - audio.setTTSURL(stripURL(args.url)); - successReaction(ev, reply); - }); + command.createCommand('stop') + .help('Stop playback') + .manual('Stops playback.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + media.stop(); + successReaction(ev, reply); + }); - command.createCommand('ttslocale') - .addArgument(command.createArgument('string').setName('locale')) - .help('Set the TTS locale.') - .manual('Sets the TTS locale.') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - // print syntax if no locale given - if (!args.locale) { - reply(USAGE_PREFIX + 'ttslocale '); - return; - } + command.createCommand('!stop') + .help('Stop playback and remove idle-track') + .manual('Stops playback and removes idle-track.') + .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) + .exec((client, args, reply, ev) => { + media.stop(); + media.clearIdleTrack(); + successReaction(ev, reply); + }); - audio.setTTSDefaultLocale(args.locale); - successReaction(ev, reply); - }); + command.createCommand('volume') + .alias('vol') + .addArgument(command.createArgument('string').setName('value')) + .help('Change the volume') + .manual('Changes the volume.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + let value = args.value; + let volume = audio.getVolume(); - command.createCommand('yt') - .addArgument(command.createArgument('string').setName('url')) - .help('Play via youtube-dl') - .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'yt '); - return; - } + switch (value) { + case 'up': + volume += 10; + break; + case 'dn': + case 'down': + volume -= 10; + break; + default: + value = parseInt(value, 10); + if (value >= 0 && value <= 100) { + volume = value; + } else { + reply(USAGE_PREFIX + 'volume '); + return; + } + } + + if (volume < 0) { + volume = 0; + } else if (volume > 100) { + volume = 100; + } - if (!media.yt(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } - successReaction(ev, reply); - }); + audio.setVolume(volume); + successReaction(ev, reply); + }); - command.createCommand('ytdl') - .addArgument(command.createArgument('string').setName('url')) - .help('Download and play via youtube-dl') - .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') - .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'ytdl '); - return; - } + command.createCommand('stream') + .addArgument(command.createArgument('string').setName('url')) + .help('Stream a url') + .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'stream '); + return; + } - if (!media.ytdl(stripURL(args.url), true)) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } - successReaction(ev, reply); - }); + if (!media.playURL(stripURL(args.url))) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; + } + successReaction(ev, reply); + }); - command.createCommand('qyt') - .addArgument(command.createArgument('string').setName('url')) - .help('Enqueue via youtube-dl') - .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') - .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'qyt '); - return; - } + command.createCommand('say') + .addArgument(command.createArgument('rest').setName('text')) + .help('Say a text via TTS') + .manual('Uses text-to-speech (if configured) to say the given text.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no text given + if (!args.text) { + reply(USAGE_PREFIX + 'say '); + return; + } - if (!media.enqueueYt(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } - successReaction(ev, reply); - }); + audio.say(args.text); + successReaction(ev, reply); + }); - command.createCommand('qytdl') - .addArgument(command.createArgument('string').setName('url')) - .help('Download and enqueue via youtube-dl') - .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') - .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) - .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'qytdl '); - return; - } + command.createCommand('sayex') + .addArgument(command.createArgument('string').setName('locale')) + .addArgument(command.createArgument('rest').setName('text')) + .help('Say a text via TTS with given locale') + .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no locale/text given + if (!args.locale || !args.text) { + reply(USAGE_PREFIX + 'sayex '); + return; + } - if (!media.enqueueYtdl(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } - successReaction(ev, reply); - }); + audio.say(args.text, args.locale); + successReaction(ev, reply); + }); - command.createCommand('shuffle') - .help('Toggle shuffle') - .manual('Toggles shuffle.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - audio.setShuffle(!audio.isShuffle()); - reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); - successReaction(ev, reply); - }); + command.createCommand('ttsurl') + .addArgument(command.createArgument('string').setName('url')) + .help('Set the TTS url.') + .manual('Sets the TTS url.') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'ttsurl '); + return; + } - command.createCommand('repeat') - .help('Toggle repeat') - .manual('Toggles repeat.') - .checkPermission(requirePrivileges(PLAYBACK)) - .exec((client, args, reply, ev) => { - audio.setRepeat(!audio.isRepeat()); - reply(SUCCESS_PREFIX + `Repeat is now ${audio.isRepeat() ? 'en' : 'dis'}abled.`); - successReaction(ev, reply); - }); + audio.setTTSURL(stripURL(args.url)); + successReaction(ev, reply); + }); - if (engine.getBackend() == 'ts3') { - command.createCommand('sub') - .help('Subscribe to bot') - .manual('Subscribes to the bot. (subscription transfer-mode only)') - .checkPermission(() => engine.isSubscriptionMode()) + command.createCommand('ttslocale') + .addArgument(command.createArgument('string').setName('locale')) + .help('Set the TTS locale.') + .manual('Sets the TTS locale.') + .checkPermission(requirePrivileges(EDITBOT)) .exec((client, args, reply, ev) => { - if (!engine.isSubscriptionMode()) { - reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + // print syntax if no locale given + if (!args.locale) { + reply(USAGE_PREFIX + 'ttslocale '); return; } - client.subscribe(true); + + audio.setTTSDefaultLocale(args.locale); successReaction(ev, reply); }); - command.createCommand('unsub') - .help('Unsubscribe from bot') - .manual('Unsubscribes from the bot. (subscription transfer-mode only)') - .checkPermission(() => engine.isSubscriptionMode()) + command.createCommand('yt') + .addArgument(command.createArgument('string').setName('url')) + .help('Play via youtube-dl') + .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') + .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { - if (!engine.isSubscriptionMode()) { - reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'yt '); + return; + } + + if (!media.yt(stripURL(args.url))) { + reply(ERROR_PREFIX + 'Invalid URL.'); return; } - client.subscribe(false); successReaction(ev, reply); }); - command.createCommand('subchan') - .help('Add subscription for channel') - .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + command.createCommand('ytdl') + .addArgument(command.createArgument('string').setName('url')) + .help('Download and play via youtube-dl') + .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) .exec((client, args, reply, ev) => { - if (!engine.isSubscriptionMode()) { - reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'ytdl '); + return; + } + + if (!media.ytdl(stripURL(args.url), true)) { + reply(ERROR_PREFIX + 'Invalid URL.'); return; } - client.getChannels()[0].subscribe(true); successReaction(ev, reply); }); - command.createCommand('unsubchan') - .help('Remove subscription for channel') - .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + command.createCommand('qyt') + .addArgument(command.createArgument('string').setName('url')) + .help('Enqueue via youtube-dl') + .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') + .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) .exec((client, args, reply, ev) => { - if (!engine.isSubscriptionMode()) { - reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'qyt '); + return; + } + + if (!media.enqueueYt(stripURL(args.url))) { + reply(ERROR_PREFIX + 'Invalid URL.'); return; } - client.getChannels()[0].subscribe(false); successReaction(ev, reply); }); - command.createCommand('mode') - .addArgument(command.createArgument('string').setName('mode')) - .help('Change Transmit-Mode') - .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') - .checkPermission(requirePrivileges(EDITBOT)) + command.createCommand('qytdl') + .addArgument(command.createArgument('string').setName('url')) + .help('Download and enqueue via youtube-dl') + .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) .exec((client, args, reply, ev) => { - let mode = args.mode; - if (typeof mode === 'string') { - mode = mode.toLowerCase(); + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'qytdl '); + return; } - switch (mode) { - case "0": - case "chan": - case "channel": - engine.setSubscriptionMode(false); - reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Channel (default).'); - successReaction(ev, reply); - break; - case "1": - case "sub": - case "subscription": - engine.setSubscriptionMode(true); - reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Subscription.'); - successReaction(ev, reply); - break; - default: - reply(`Transmit-Mode is currently set to ${engine.isSubscriptionMode() ? 'Subscription' : 'Channel (default)'}.\n` + USAGE_PREFIX + 'mode <0|chan(nel)|1|sub(scription)>'); + if (!media.enqueueYtdl(stripURL(args.url))) { + reply(ERROR_PREFIX + 'Invalid URL.'); + return; } + successReaction(ev, reply); }); - } - command.createCommand('registration') - .addArgument(command.createArgument('string').setName('value')) - .help('Enable / disable user registration via chat') - .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - switch (args.value) { - case "enable": - engine.enableRegistration(); - reply(SUCCESS_PREFIX + 'Registration is now enabled.'); + command.createCommand('shuffle') + .help('Toggle shuffle') + .manual('Toggles shuffle.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + audio.setShuffle(!audio.isShuffle()); + reply(SUCCESS_PREFIX + `Shuffle is now ${audio.isShuffle() ? 'en' : 'dis'}abled.`); successReaction(ev, reply); - break; - case "disable": - engine.disableRegistration(); - reply(SUCCESS_PREFIX + 'Registration is now disabled.'); + }); + + command.createCommand('repeat') + .help('Toggle repeat') + .manual('Toggles repeat.') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + audio.setRepeat(!audio.isRepeat()); + reply(SUCCESS_PREFIX + `Repeat is now ${audio.isRepeat() ? 'en' : 'dis'}abled.`); successReaction(ev, reply); - break; - default: - reply(`Registartion is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); - } - }); + }); - command.createCommand('prefix') - .addArgument(command.createArgument('string').setName('prefix')) - .help('Change command prefix') - .manual('Changes the prefix for all core commands to , default is "!".') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - // print syntax if no prefix given - if (!args.prefix) { - reply(USAGE_PREFIX + 'prefix '); - return; + if (engine.getBackend() == 'ts3') { + command.createCommand('sub') + .help('Subscribe to bot') + .manual('Subscribes to the bot. (subscription transfer-mode only)') + .checkPermission(() => engine.isSubscriptionMode()) + .exec((client, args, reply, ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.subscribe(true); + successReaction(ev, reply); + }); + + command.createCommand('unsub') + .help('Unsubscribe from bot') + .manual('Unsubscribes from the bot. (subscription transfer-mode only)') + .checkPermission(() => engine.isSubscriptionMode()) + .exec((client, args, reply, ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.subscribe(false); + successReaction(ev, reply); + }); + + command.createCommand('subchan') + .help('Add subscription for channel') + .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') + .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + .exec((client, args, reply, ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.getChannels()[0].subscribe(true); + successReaction(ev, reply); + }); + + command.createCommand('unsubchan') + .help('Remove subscription for channel') + .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') + .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + .exec((client, args, reply, ev) => { + if (!engine.isSubscriptionMode()) { + reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); + return; + } + client.getChannels()[0].subscribe(false); + successReaction(ev, reply); + }); + + command.createCommand('mode') + .addArgument(command.createArgument('string').setName('mode')) + .help('Change Transmit-Mode') + .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + let mode = args.mode; + if (typeof mode === 'string') { + mode = mode.toLowerCase(); + } + + switch (mode) { + case "0": + case "chan": + case "channel": + engine.setSubscriptionMode(false); + reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Channel (default).'); + successReaction(ev, reply); + break; + case "1": + case "sub": + case "subscription": + engine.setSubscriptionMode(true); + reply(SUCCESS_PREFIX + 'Transmit-Mode is now set to Subscription.'); + successReaction(ev, reply); + break; + default: + reply(`Transmit-Mode is currently set to ${engine.isSubscriptionMode() ? 'Subscription' : 'Channel (default)'}.\n` + USAGE_PREFIX + 'mode <0|chan(nel)|1|sub(scription)>'); + } + }); } - engine.setCommandPrefix(args.prefix); - reply(SUCCESS_PREFIX + 'New prefix: ' + args.prefix); - successReaction(ev, reply); - }); + command.createCommand('registration') + .addArgument(command.createArgument('string').setName('value')) + .help('Enable / disable user registration via chat') + .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + switch (args.value) { + case "enable": + engine.enableRegistration(); + reply(SUCCESS_PREFIX + 'Registration is now enabled.'); + successReaction(ev, reply); + break; + case "disable": + engine.disableRegistration(); + reply(SUCCESS_PREFIX + 'Registration is now disabled.'); + successReaction(ev, reply); + break; + default: + reply(`Registartion is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); + } + }); - command.createCommand('ping') - .help('responds with "PONG"') - .exec((client, args, reply, ev) => { - reply(`PONG`); - successReaction(ev, reply); - }); + command.createCommand('prefix') + .addArgument(command.createArgument('string').setName('prefix')) + .help('Change command prefix') + .manual('Changes the prefix for all core commands to , default is "!".') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + // print syntax if no prefix given + if (!args.prefix) { + reply(USAGE_PREFIX + 'prefix '); + return; + } - command.createCommand('version') - .help('Show version') - .manual('Shows the SinusBot version.') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - reply(`SinusBot v${engine.version()}\nsinusbot-commands.js v${meta.version}\ncommand.js v${command.getVersion()}`); - successReaction(ev, reply); - }); + engine.setCommandPrefix(args.prefix); + reply(SUCCESS_PREFIX + 'New prefix: ' + args.prefix); + successReaction(ev, reply); + }); - command.createCommand('reload') - .help('Reload scripts') - .manual('Reloads scripts.\nPlease Note: New scripts require a complete sinusbot restart.') - .checkPermission(requirePrivileges(EDITBOT)) - .exec((client, args, reply, ev) => { - reply('reloading...'); - let success = engine.reloadScripts(); - if (success) { - reply(SUCCESS_PREFIX + `Scripts reloaded.\nNew scripts require a complete sinusbot restart.`); + command.createCommand('ping') + .help('responds with "PONG"') + .exec((client, args, reply, ev) => { + reply(`PONG`); successReaction(ev, reply); - } else { - reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); - } - }); - - command.createCommand('join') - .help('Move the SinusBot to your channel') - .manual('Moves the SinusBot into your channel.') - .checkPermission(requirePrivileges(STARTSTOP)) - .exec((client, args, reply, ev) => { - var channel = client.getChannels()[0] - if (!channel) { - return reply(ERROR_PREFIX+'I\'m unable to join your channel :(') - } + }); - bot = backend.getBotClient() || bot - if (!bot) { - return reply(ERROR_BOT_NULL) - } - bot.moveTo(channel) - successReaction(ev, reply); - }); + command.createCommand('version') + .help('Show version') + .manual('Shows the SinusBot version.') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + reply(`SinusBot v${engine.version()} on ${engine.os()}\nsinusbot-commands.js v${meta.version}\ncommand.js v${command.getVersion()}`); + successReaction(ev, reply); + }); - if (engine.getBackend() == 'discord') { - command.createCommand('leave') - .help('Disconnect the SinusBot') - .manual('Disconnects the SinusBot from the current voice channel.') + command.createCommand('reload') + .help('Reload scripts') + .manual('Reloads scripts.\nNote: Adding new scripts requires a complete sinusbot restart.') + .checkPermission(requirePrivileges(EDITBOT)) + .exec((client, args, reply, ev) => { + reply('reloading...'); + let success = engine.reloadScripts(); + if (success) { + reply(SUCCESS_PREFIX + `Scripts reloaded.\n*Please note: addning new scripts requires a complete sinusbot restart.*`); + successReaction(ev, reply); + } else { + reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); + } + }); + + command.createCommand('join') + .help('Move the SinusBot to your channel') + .manual('Moves the SinusBot into your channel.') .checkPermission(requirePrivileges(STARTSTOP)) .exec((client, args, reply, ev) => { - bot = backend.getBotClient() || bot - if (!bot) { + var channel = client.getChannels()[0] + if (!channel) { + return reply(ERROR_PREFIX+'I\'m unable to join your channel :(') + } + + if (!getBotClient()) { return reply(ERROR_BOT_NULL) } - - bot.moveTo('') + bot.moveTo(channel) successReaction(ev, reply); }); - } - }); - /********** !playing stuff for discord **********/ - if (engine.getBackend() == 'discord') { - event.on('discord:MESSAGE_REACTION_ADD', ev => { - let ename = ev.emoji.name; - // remove 0xefb88f aka. "VARIATION SELECTOR-16" (no idea why discord puts that at the end) - if (ename.endsWith('\ufe0f')) { - ename = ename.slice(0, -1); + if (engine.getBackend() == 'discord') { + command.createCommand('leave') + .help('Disconnect the SinusBot') + .manual('Disconnects the SinusBot from the current voice channel.') + .checkPermission(requirePrivileges(STARTSTOP)) + .exec((client, args, reply, ev) => { + if (!getBotClient()) { + return reply(ERROR_BOT_NULL) + } + + bot.moveTo('') + successReaction(ev, reply); + }); } - const emoji = ev.emoji.id ? `${ename}:${ev.emoji.id}` : ename; + }); + + /********** !playing stuff for discord **********/ + if (engine.getBackend() == 'discord') { + event.on('discord:MESSAGE_REACTION_ADD', ev => { + let ename = ev.emoji.name; + // remove 0xefb88f aka. "VARIATION SELECTOR-16" (no idea why discord puts that at the end) + if (ename.endsWith('\ufe0f')) { + ename = ename.slice(0, -1); + } + const emoji = ev.emoji.id ? `${ename}:${ev.emoji.id}` : ename; - // ignore reactions that are not controls - if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; + // ignore reactions that are not controls + if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; - // ignore reactions from the bot itself - if (backend.getBotClientID().endsWith(ev.user_id)) return; + // ignore reactions from the bot itself + if (backend.getBotClientID().endsWith(ev.user_id)) return; - // get user via id - const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); + // get user via id + const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); - // ignore if no matching user found or reaction from the bot itself - if (!client || client.isSelf()) return; + // ignore if no matching user found or reaction from the bot itself + if (!client || client.isSelf()) return; - let callback = () => { - // delete the rection - deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); + let callback = () => { + // delete the rection + deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); - // check if user has the 'playback' permission - if (!requirePrivileges(PLAYBACK)(client)) { - engine.log(`${client.nick()} is missing playback permissions for reaction controls`); - client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); - return; - } + // check if user has the 'playback' permission + if (!requirePrivileges(PLAYBACK)(client)) { + engine.log(`${client.nick()} is missing playback permissions for reaction controls`); + client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); + return; + } - const track = media.getCurrentTrack(); + const track = media.getCurrentTrack(); - switch (emoji) { - case REACTION_PREV: - // ignore if nothing is playing - if (!audio.isPlaying()) return; + switch (emoji) { + case REACTION_PREV: + // ignore if nothing is playing + if (!audio.isPlaying()) return; - if (media.getQueue().length !== 0) { - // start from beginning if we're playing queue - audio.seek(0); - } else { - // try prev (doesn't work for queue or folder) - media.playPrevious(); + if (media.getQueue().length !== 0) { + // start from beginning if we're playing queue + audio.seek(0); + } else { + // try prev (doesn't work for queue or folder) + media.playPrevious(); - // fallback: start from beginning if there is no previous track - if (!audio.isPlaying()) { - if (track) track.play(); + // fallback: start from beginning if there is no previous track + if (!audio.isPlaying()) { + if (track) track.play(); + } } - } - break; - case REACTION_PLAYPAUSE: - if (audio.isPlaying()) { - media.stop(); - } else { - if (!track) return; - const pos = audio.getTrackPosition(); - - if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { - // continue playing at last pos - audio.setMute(true); - track.play(); - audio.seek(pos); - audio.setMute(false); + break; + case REACTION_PLAYPAUSE: + if (audio.isPlaying()) { + media.stop(); } else { - // or start from beginning if it already ended - track.play(); + if (!track) return; + const pos = audio.getTrackPosition(); + + if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { + // continue playing at last pos + audio.setMute(true); + track.play(); + audio.seek(pos); + audio.setMute(false); + } else { + // or start from beginning if it already ended + track.play(); + } } - } - break; - case REACTION_NEXT: - if (audio.isPlaying()) { - media.playNext(); - } else { - // is something in queue? - if (media.getQueue().length !== 0) { - // resume queue - media.playQueueNext(); + break; + case REACTION_NEXT: + if (audio.isPlaying()) { + media.playNext(); + } else { + // is something in queue? + if (media.getQueue().length !== 0) { + // resume queue + media.playQueueNext(); + } } } - } - }; - - // was reaction added to previous response? - if (lastEmbeds.some(embed => embed.messageId == ev.message_id)) { - callback(); - return; - } + }; - getMessage(ev.channel_id, ev.message_id).then(msg => { - // was reaction added to previous response of the bot? - if (backend.getBotClientID().endsWith(msg.author.id)) { + // was reaction added to previous response? + if (lastEmbeds.some(embed => embed.messageId == ev.message_id)) { callback(); + return; } - }) - }); - /** - * Called when track or it's info changes - * @param {Track} track - */ - const onChange = track => { - if (config.songInStatus) { - const prefix = '🎵 '; - const suffix = ' 🎵'; - - // set track info as status - backend.extended().setStatus({ - game: { - name: prefix + formatTrack(track) + suffix, - type: 2, // => 0 (game), 1 (streaming), 2 (listening) - }, - status: "online", - afk: false - }); - } + getMessage(ev.channel_id, ev.message_id).then(msg => { + // was reaction added to previous response of the bot? + if (backend.getBotClientID().endsWith(msg.author.id)) { + callback(); + } + }) + }); + } // END COMMANDS-ENABLED + } + + // stores last bot client object for `getBotClient()` + let bot = backend.getBotClient(); - // update embeds - lastEmbeds.forEach(async embed => { - await editMessage(embed.channelId, embed.messageId, getPlayingEmbed()).then(() => wait(100)); + /** + * Wrapper for `backend.getBotClient()` because it sometimes returns `null` -_- + * @returns {Client} Bot client + */ + function getBotClient() { + bot = backend.getBotClient() || bot; + return bot; + } + + /** + * Called when track or it's info changes + * @param {Track} track + */ + const onChange = track => { + if (config.songInStatus) { + const prefix = '🎵 '; + const suffix = ' 🎵'; + + // set track info as status + backend.extended().setStatus({ + game: { + name: prefix + formatTrack(track) + suffix, + type: 2, // => 0 (game), 1 (streaming), 2 (listening) + }, + status: "online", + afk: false }); - }; + } - event.on('track', onChange); - event.on('trackInfo', onChange); - event.on('trackEnd', () => { - if (!config.songInStatus) { - return; - } - backend.getBotClient().setDescription(''); + // update embeds + lastEmbeds.forEach(async embed => { + await editMessage(embed.channelId, embed.messageId, getPlayingEmbed()).then(() => wait(100)); }); - } + }; + + event.on('track', onChange); + event.on('trackInfo', onChange); + event.on('trackEnd', () => { + if (!config.songInStatus) { + return; + } + if (getBotClient()) { + bot.setDescription(''); + } + }); /** * Returns embed for current track @@ -1265,6 +1275,8 @@ registerPlugin({ * @param {string} messageID Message ID * @param {string} emoji Emoji * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function createReaction(channelID, messageID, emoji) { return discord('PUT', `/channels/${channelID}/messages/${messageID}/reactions/${emoji}/@me`, null, false); @@ -1277,6 +1289,8 @@ registerPlugin({ * @param {string} userID User ID * @param {string} emoji Emoji * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function deleteUserReaction(channelID, messageID, userID, emoji) { return discord('DELETE', `/channels/${channelID}/messages/${messageID}/reactions/${emoji}/${userID}`, null, false); @@ -1287,6 +1301,8 @@ registerPlugin({ * @param {string} channelID Channel ID * @param {string} messageID Message ID * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function getMessage(channelID, messageID) { return discord('GET', `/channels/${channelID}/messages/${messageID}`, null, true); @@ -1298,6 +1314,8 @@ registerPlugin({ * @param {string} messageID Message ID * @param {object} message New message * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function editMessage(channelID, messageID, message) { return discord('PATCH', `/channels/${channelID}/messages/${messageID}`, message, true); @@ -1308,6 +1326,8 @@ registerPlugin({ * @param {string} channelID Channel ID * @param {string} messageID Message ID * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function deleteMessage(channelID, messageID) { return discord('DELETE', `/channels/${channelID}/messages/${messageID}`, null, false); @@ -1318,6 +1338,8 @@ registerPlugin({ * @param {string} channelID Channel ID * @param {string[]} messageIDs Message IDs * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function deleteMessages(channelID, messageIDs) { switch (messageIDs.length) { @@ -1334,6 +1356,8 @@ registerPlugin({ * @param {object} [data] json data * @param {boolean} [repsonse] `true` if you're expecting a json response, `false` otherwise * @return {Promise} + * @author Jonas Bögle + * @license MIT */ function discord(method, path, data=null, repsonse=true) { return new Promise((resolve, reject) => { @@ -1344,12 +1368,14 @@ registerPlugin({ try { res = JSON.parse(data); } catch (err) { - engine.log(`${method} ${path}`); - engine.log('Invalid JSON: ' + data); + engine.log(`${method} ${path} failed`) + engine.log(`${data}`) return reject(err); } if (res === undefined) { + engine.log(`${method} ${path} failed`) + engine.log(`${data}`) return reject('Invalid Response'); } From 8450ec859166d5dbae709ba63af73f775dde67c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 5 Apr 2020 15:43:27 +0200 Subject: [PATCH 57/77] fix/feature: (re-)add support for youtube streams --- default-attached/sinusbot-commands.js | 64 ++++++++++++++++++++------- 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 3894852..575c491 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -145,6 +145,8 @@ registerPlugin({ const REACTION_NEXT = '⏭'; const REACTION_SUCCESS = '✅'; + const YT_DOMAIN = /^https?:\/\/(?:www\.)?youtube\.com\//i; + // for join/leave const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' @@ -558,8 +560,19 @@ registerPlugin({ return; } - if (!media.playURL(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); + const url = stripURL(args.url); + + if (url.match(YT_DOMAIN)) { + if (!media.ytStream(url)) { + reply(ERROR_PREFIX + 'Unable to stream this YouTube URL.'); + return; + } + successReaction(ev, reply); + return; + } + + if (!media.playURL(url)) { + reply(ERROR_PREFIX + 'Unable to stream this URL.'); return; } successReaction(ev, reply); @@ -642,8 +655,26 @@ registerPlugin({ return; } - if (!media.yt(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); + media.yt(stripURL(args.url)); + // TODO: add success/error callback + successReaction(ev, reply); + }); + + command.createCommand('ytstream') + .alias('streamyt') + .addArgument(command.createArgument('string').setName('url')) + .help('Stream via youtube-dl') + .manual('Streams via external youtube-dl (if enabled)') + .checkPermission(requirePrivileges(PLAYBACK)) + .exec((client, args, reply, ev) => { + // print syntax if no url given + if (!args.url) { + reply(USAGE_PREFIX + 'ytstream '); + return; + } + + if (!media.ytStream(stripURL(args.url))) { + reply(ERROR_PREFIX + 'Unable to stream this URL.'); return; } successReaction(ev, reply); @@ -661,10 +692,8 @@ registerPlugin({ return; } - if (!media.ytdl(stripURL(args.url), true)) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } + media.ytdl(stripURL(args.url), true); + // TODO: add success/error callback successReaction(ev, reply); }); @@ -680,10 +709,8 @@ registerPlugin({ return; } - if (!media.enqueueYt(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } + media.enqueueYt(stripURL(args.url)); + // TODO: add success/error callback successReaction(ev, reply); }); @@ -699,10 +726,8 @@ registerPlugin({ return; } - if (!media.enqueueYtdl(stripURL(args.url))) { - reply(ERROR_PREFIX + 'Invalid URL.'); - return; - } + media.enqueueYtdl(stripURL(args.url)); + // TODO: add success/error callback successReaction(ev, reply); }); @@ -1015,6 +1040,13 @@ registerPlugin({ } // END COMMANDS-ENABLED } + event.on("ytdl.success", ev => { + engine.log(`Successfully downloaded YouTube Video: ${ev.url}`) + }) + event.on("ytdl.error", (ev, message) => { + engine.log(`Error while downloading YouTube Video: ${ev.url}; ${message}`) + }) + // stores last bot client object for `getBotClient()` let bot = backend.getBotClient(); From c56fd1edbcf398507ed3b0c72e836ee976ed181f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 01:12:13 +0200 Subject: [PATCH 58/77] fix: typo --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 575c491..fc8baf9 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -899,7 +899,7 @@ registerPlugin({ reply('reloading...'); let success = engine.reloadScripts(); if (success) { - reply(SUCCESS_PREFIX + `Scripts reloaded.\n*Please note: addning new scripts requires a complete sinusbot restart.*`); + reply(SUCCESS_PREFIX + `Scripts reloaded.\n*Please note: adding new scripts requires a complete sinusbot restart.*`); successReaction(ev, reply); } else { reply('Unable to reload scripts. Did you allow it in your `config.ini`?'); From defaa607afb8eec60354ee861c3f53eedb204912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 02:24:41 +0200 Subject: [PATCH 59/77] add: youtube callbacks, show errors --- default-attached/sinusbot-commands.js | 79 ++++++++++++++++++++------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index fc8baf9..e0fca67 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -163,6 +163,58 @@ registerPlugin({ engine.saveConfig(config); } + const ytCallbacks = {}; + event.on("ytdl.success", ev => { + engine.log(`Downloaded YouTube Video: ${ev.url}`); + const jobId = ev.jobId; + if (typeof ytCallbacks[jobId] === 'function') { + ytCallbacks[jobId](ev); + delete ytCallbacks[jobId]; + } + }); + + event.on("ytdl.error", (ev, message) => { + engine.log(`Error while downloading YouTube Video: ${ev.url}; ${message}`); + if (message.startsWith("exit status")) { + engine.log('Please see "Upload" page in web-interface for more details and read the documentation for troubleshooting advice: https://sinusbot.github.io/docs/youtube-dl/'); + } + + const jobId = ev.jobId; + if (typeof ytCallbacks[jobId] === 'function') { + ytCallbacks[jobId](ev, message); + delete ytCallbacks[jobId]; + } + }); + + /** + * Registers a callback for success/error events of a given jobId. + * @param {string} jobId Job ID + * @param {(ev: {url: string, jobId: string, trackId?: string}, message: string) => void} callback Callback + */ + function ytCallback(jobId, callback) { + ytCallbacks[jobId] = callback; + } + + /** + * + * @param {string} jobId Job ID + * @param {MessageEvent} ev Event + * @param {(msg: string) => void} reply + */ + function handleYT(jobId, ev, reply) { + ytCallback(jobId, (ytev, err) => { + if (err) { + if (err.startsWith("exit status")) { + reply(ERROR_PREFIX + `Error: ${err}; Please see "Upload" page in web-interface for more details.`); + } else { + reply(ERROR_PREFIX + `Error: ${err}`); + } + return; + } + successReaction(ev, reply); + }); + } + if (config.disable) { engine.log('SinusBot commands are DISABLED.'); } else { // BEGIN COMMANDS-ENABLED @@ -655,9 +707,8 @@ registerPlugin({ return; } - media.yt(stripURL(args.url)); - // TODO: add success/error callback - successReaction(ev, reply); + const jobId = media.yt(stripURL(args.url)); + handleYT(jobId, ev, reply); }); command.createCommand('ytstream') @@ -692,9 +743,8 @@ registerPlugin({ return; } - media.ytdl(stripURL(args.url), true); - // TODO: add success/error callback - successReaction(ev, reply); + const jobId = media.ytdl(stripURL(args.url), true); + handleYT(jobId, ev, reply); }); command.createCommand('qyt') @@ -709,9 +759,8 @@ registerPlugin({ return; } - media.enqueueYt(stripURL(args.url)); - // TODO: add success/error callback - successReaction(ev, reply); + const jobId = media.enqueueYt(stripURL(args.url)); + handleYT(jobId, ev, reply); }); command.createCommand('qytdl') @@ -726,9 +775,8 @@ registerPlugin({ return; } - media.enqueueYtdl(stripURL(args.url)); - // TODO: add success/error callback - successReaction(ev, reply); + const jobId = media.enqueueYtdl(stripURL(args.url)); + handleYT(jobId, ev, reply); }); command.createCommand('shuffle') @@ -1040,13 +1088,6 @@ registerPlugin({ } // END COMMANDS-ENABLED } - event.on("ytdl.success", ev => { - engine.log(`Successfully downloaded YouTube Video: ${ev.url}`) - }) - event.on("ytdl.error", (ev, message) => { - engine.log(`Error while downloading YouTube Video: ${ev.url}; ${message}`) - }) - // stores last bot client object for `getBotClient()` let bot = backend.getBotClient(); From 570d58baee4d64c45e0913b8e5d884585d7a7915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 02:39:25 +0200 Subject: [PATCH 60/77] add(yt): check URL --- default-attached/sinusbot-commands.js | 55 +++++++++++---------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index e0fca67..deaf906 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -145,7 +145,8 @@ registerPlugin({ const REACTION_NEXT = '⏭'; const REACTION_SUCCESS = '✅'; - const YT_DOMAIN = /^https?:\/\/(?:www\.)?youtube\.com\//i; + const PATTERN_URL = /^https?:\/\/\S+/i; + const PATTERN_YT_DOMAIN = /^https?:\/\/(?:www\.)?youtube\.com\//i; // for join/leave const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' @@ -614,7 +615,7 @@ registerPlugin({ const url = stripURL(args.url); - if (url.match(YT_DOMAIN)) { + if (url.match(PATTERN_YT_DOMAIN)) { if (!media.ytStream(url)) { reply(ERROR_PREFIX + 'Unable to stream this YouTube URL.'); return; @@ -701,13 +702,11 @@ registerPlugin({ .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'yt '); - return; - } + const url = stripURL(args.url); + if (!url) return reply(USAGE_PREFIX + 'yt '); + if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); - const jobId = media.yt(stripURL(args.url)); + const jobId = media.yt(url); handleYT(jobId, ev, reply); }); @@ -718,13 +717,11 @@ registerPlugin({ .manual('Streams via external youtube-dl (if enabled)') .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'ytstream '); - return; - } + const url = stripURL(args.url); + if (!url) return reply(USAGE_PREFIX + 'ytstream '); + if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); - if (!media.ytStream(stripURL(args.url))) { + if (!media.ytStream(url)) { reply(ERROR_PREFIX + 'Unable to stream this URL.'); return; } @@ -737,13 +734,11 @@ registerPlugin({ .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'ytdl '); - return; - } + const url = stripURL(args.url); + if (!url) return reply(USAGE_PREFIX + 'ytdl '); + if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); - const jobId = media.ytdl(stripURL(args.url), true); + const jobId = media.ytdl(url, true); handleYT(jobId, ev, reply); }); @@ -753,13 +748,11 @@ registerPlugin({ .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'qyt '); - return; - } + const url = stripURL(args.url); + if (!url) return reply(USAGE_PREFIX + 'qyt '); + if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); - const jobId = media.enqueueYt(stripURL(args.url)); + const jobId = media.enqueueYt(url); handleYT(jobId, ev, reply); }); @@ -769,13 +762,11 @@ registerPlugin({ .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) .exec((client, args, reply, ev) => { - // print syntax if no url given - if (!args.url) { - reply(USAGE_PREFIX + 'qytdl '); - return; - } + const url = stripURL(args.url); + if (!url) return reply(USAGE_PREFIX + 'qytdl '); + if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); - const jobId = media.enqueueYtdl(stripURL(args.url)); + const jobId = media.enqueueYtdl(url); handleYT(jobId, ev, reply); }); From 89e27873a2efe131d432519c6e84785df0ebf779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 02:56:38 +0200 Subject: [PATCH 61/77] simplify command.js calls --- default-attached/sinusbot-commands.js | 123 +++++++++++++------------- 1 file changed, 62 insertions(+), 61 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index deaf906..c3b4e57 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -226,9 +226,10 @@ registerPlugin({ engine.log('command.js can be found here: https://github.com/Multivit4min/Sinusbot-Command/blob/master/command.js'); return; } + const {createCommand} = command; - command.createCommand('register') - .addArgument(command.createArgument('string').setName('username')) + createCommand('register') + .addArgument(args => args.string.setName('username')) .help('Register a new user') .manual('Registers a new user bound to the Account you are using. This account has no privileges by default but can be edited by the bot administrators.') .exec((client, args, reply, ev) => { @@ -271,9 +272,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('password') + createCommand('password') .alias('pass') - .addArgument(command.createArgument('rest').setName('value')) + .addArgument(args => args.rest.setName('value')) .help('Change your password') .manual('Changes your password to .') .checkPermission(client => getUserByUid(client.uid())) @@ -304,7 +305,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('whoami') + createCommand('whoami') .help('Show user identities') .manual('Shows user identities matching your ID/groups.') .exec((client, args, reply, ev) => { @@ -318,7 +319,7 @@ registerPlugin({ }); if (engine.getBackend() == 'discord') { - command.createCommand('playing') + createCommand('playing') .help('Show what\'s currently playing') .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { @@ -370,7 +371,7 @@ registerPlugin({ successReaction(ev, reply); }); } else { - command.createCommand('playing') + createCommand('playing') .help('Show what\'s currently playing') .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { @@ -384,7 +385,7 @@ registerPlugin({ }); } - command.createCommand('next') + createCommand('next') .help('Play the next track') .manual('Plays the next track (only when a playlist or queue is active).') .checkPermission(requirePrivileges(PLAYBACK)) @@ -393,7 +394,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('prev') + createCommand('prev') .alias('previous') .help('Play the previous track') .manual('Plays the previous track (only when a playlistis active).') @@ -403,9 +404,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('search') + createCommand('search') .alias('s') - .addArgument(command.createArgument('rest').setName('searchstring')) + .addArgument(args => args.rest.setName('searchstring')) .help('Search for tracks') .manual('Searches for tracks, returns 20 results at most.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) @@ -428,9 +429,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('play') + createCommand('play') .alias('p') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) + .addArgument(args => args.rest.setName('idORsearchstring', 'searchstring / uuid')) .help('Play a track by its id or name') .manual('Plays a track by its id or searches for a track and plays the first match.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -457,8 +458,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('playlist') - .addArgument(command.createArgument('rest').setName('playlistname')) + createCommand('playlist') + .addArgument(args => args.rest.setName('playlistname')) .help('Start playing back the playlist ') .manual('starts playing back the playlist .') .checkPermission(requirePrivileges(PLAYBACK)) @@ -485,9 +486,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('queue') + createCommand('queue') .alias('q') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid').optional(true)) + .addArgument(args => args.rest.setName('idORsearchstring', 'searchstring / uuid').optional(true)) .help('Enqueue a track or resume queue') .manual('Enqueue a track by its id or search for a track and enqueue the first match. When no track is provided it wil resume the queue.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) @@ -515,9 +516,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('queuenext') + createCommand('queuenext') .alias('qnext', 'qn') - .addArgument(command.createArgument('rest').setName('idORsearchstring', 'searchstring / uuid')) + .addArgument(args => args.rest.setName('idORsearchstring', 'searchstring / uuid')) .help('Prepends a track to the queue') .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') .checkPermission(requirePrivileges(ENQUEUENEXT)) @@ -544,7 +545,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('stop') + createCommand('stop') .help('Stop playback') .manual('Stops playback.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -553,7 +554,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('!stop') + createCommand('!stop') .help('Stop playback and remove idle-track') .manual('Stops playback and removes idle-track.') .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) @@ -563,9 +564,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('volume') + createCommand('volume') .alias('vol') - .addArgument(command.createArgument('string').setName('value')) + .addArgument(args => args.string.setName('value')) .help('Change the volume') .manual('Changes the volume.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -601,8 +602,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('stream') - .addArgument(command.createArgument('string').setName('url')) + createCommand('stream') + .addArgument(args => args.string.setName('url')) .help('Stream a url') .manual('Streams from ; this may be http-streams like shoutcast / icecast or just remote soundfiles.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -631,8 +632,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('say') - .addArgument(command.createArgument('rest').setName('text')) + createCommand('say') + .addArgument(args => args.rest.setName('text')) .help('Say a text via TTS') .manual('Uses text-to-speech (if configured) to say the given text.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -647,9 +648,9 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('sayex') - .addArgument(command.createArgument('string').setName('locale')) - .addArgument(command.createArgument('rest').setName('text')) + createCommand('sayex') + .addArgument(args => args.string.setName('locale')) + .addArgument(args => args.rest.setName('text')) .help('Say a text via TTS with given locale') .manual('Uses text-to-speech (if configured) to say the given text with a given locale.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -664,8 +665,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('ttsurl') - .addArgument(command.createArgument('string').setName('url')) + createCommand('ttsurl') + .addArgument(args => args.string.setName('url')) .help('Set the TTS url.') .manual('Sets the TTS url.') .checkPermission(requirePrivileges(EDITBOT)) @@ -680,8 +681,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('ttslocale') - .addArgument(command.createArgument('string').setName('locale')) + createCommand('ttslocale') + .addArgument(args => args.string.setName('locale')) .help('Set the TTS locale.') .manual('Sets the TTS locale.') .checkPermission(requirePrivileges(EDITBOT)) @@ -696,8 +697,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('yt') - .addArgument(command.createArgument('string').setName('url')) + createCommand('yt') + .addArgument(args => args.string.setName('url')) .help('Play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -710,9 +711,9 @@ registerPlugin({ handleYT(jobId, ev, reply); }); - command.createCommand('ytstream') + createCommand('ytstream') .alias('streamyt') - .addArgument(command.createArgument('string').setName('url')) + .addArgument(args => args.string.setName('url')) .help('Stream via youtube-dl') .manual('Streams via external youtube-dl (if enabled)') .checkPermission(requirePrivileges(PLAYBACK)) @@ -728,8 +729,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('ytdl') - .addArgument(command.createArgument('string').setName('url')) + createCommand('ytdl') + .addArgument(args => args.string.setName('url')) .help('Download and play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) @@ -742,8 +743,8 @@ registerPlugin({ handleYT(jobId, ev, reply); }); - command.createCommand('qyt') - .addArgument(command.createArgument('string').setName('url')) + createCommand('qyt') + .addArgument(args => args.string.setName('url')) .help('Enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts.') .checkPermission(requirePrivileges(PLAYBACK, ENQUEUE)) @@ -756,8 +757,8 @@ registerPlugin({ handleYT(jobId, ev, reply); }); - command.createCommand('qytdl') - .addArgument(command.createArgument('string').setName('url')) + createCommand('qytdl') + .addArgument(args => args.string.setName('url')) .help('Download and enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) @@ -770,7 +771,7 @@ registerPlugin({ handleYT(jobId, ev, reply); }); - command.createCommand('shuffle') + createCommand('shuffle') .help('Toggle shuffle') .manual('Toggles shuffle.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -780,7 +781,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('repeat') + createCommand('repeat') .help('Toggle repeat') .manual('Toggles repeat.') .checkPermission(requirePrivileges(PLAYBACK)) @@ -791,7 +792,7 @@ registerPlugin({ }); if (engine.getBackend() == 'ts3') { - command.createCommand('sub') + createCommand('sub') .help('Subscribe to bot') .manual('Subscribes to the bot. (subscription transfer-mode only)') .checkPermission(() => engine.isSubscriptionMode()) @@ -804,7 +805,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('unsub') + createCommand('unsub') .help('Unsubscribe from bot') .manual('Unsubscribes from the bot. (subscription transfer-mode only)') .checkPermission(() => engine.isSubscriptionMode()) @@ -817,7 +818,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('subchan') + createCommand('subchan') .help('Add subscription for channel') .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) @@ -830,7 +831,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('unsubchan') + createCommand('unsubchan') .help('Remove subscription for channel') .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) @@ -843,8 +844,8 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('mode') - .addArgument(command.createArgument('string').setName('mode')) + createCommand('mode') + .addArgument(args => args.string.setName('mode')) .help('Change Transmit-Mode') .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') .checkPermission(requirePrivileges(EDITBOT)) @@ -875,8 +876,8 @@ registerPlugin({ }); } - command.createCommand('registration') - .addArgument(command.createArgument('string').setName('value')) + createCommand('registration') + .addArgument(args => args.string.setName('value')) .help('Enable / disable user registration via chat') .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') .checkPermission(requirePrivileges(EDITBOT)) @@ -897,8 +898,8 @@ registerPlugin({ } }); - command.createCommand('prefix') - .addArgument(command.createArgument('string').setName('prefix')) + createCommand('prefix') + .addArgument(args => args.string.setName('prefix')) .help('Change command prefix') .manual('Changes the prefix for all core commands to , default is "!".') .checkPermission(requirePrivileges(EDITBOT)) @@ -914,14 +915,14 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('ping') + createCommand('ping') .help('responds with "PONG"') .exec((client, args, reply, ev) => { reply(`PONG`); successReaction(ev, reply); }); - command.createCommand('version') + createCommand('version') .help('Show version') .manual('Shows the SinusBot version.') .checkPermission(requirePrivileges(EDITBOT)) @@ -930,7 +931,7 @@ registerPlugin({ successReaction(ev, reply); }); - command.createCommand('reload') + createCommand('reload') .help('Reload scripts') .manual('Reloads scripts.\nNote: Adding new scripts requires a complete sinusbot restart.') .checkPermission(requirePrivileges(EDITBOT)) @@ -945,7 +946,7 @@ registerPlugin({ } }); - command.createCommand('join') + createCommand('join') .help('Move the SinusBot to your channel') .manual('Moves the SinusBot into your channel.') .checkPermission(requirePrivileges(STARTSTOP)) @@ -963,7 +964,7 @@ registerPlugin({ }); if (engine.getBackend() == 'discord') { - command.createCommand('leave') + createCommand('leave') .help('Disconnect the SinusBot') .manual('Disconnects the SinusBot from the current voice channel.') .checkPermission(requirePrivileges(STARTSTOP)) From 524ef4da11af51861f864ef741ab3924fb0cc4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 03:04:37 +0200 Subject: [PATCH 62/77] set author to SinusBot Team, use semver --- default-attached/advertising.js | 4 ++-- default-attached/alonemode.js | 4 ++-- default-attached/bookmark.js | 4 ++-- default-attached/followme.js | 4 ++-- default-attached/norecording.js | 4 ++-- default-attached/rememberChannel.js | 4 ++-- default-attached/welcome.js | 4 ++-- package-lock.json | 6 +++--- package.json | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/default-attached/advertising.js b/default-attached/advertising.js index 1483729..a77bb00 100644 --- a/default-attached/advertising.js +++ b/default-attached/advertising.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'Advertising (Text)', - version: '3.0', + version: '3.0.0', backends: ['ts3'], description: 'This script will announce one of the configured lines every x seconds.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [{ name: 'ads', title: 'Ads (supports bbcode)', diff --git a/default-attached/alonemode.js b/default-attached/alonemode.js index 6ff1322..f50f39a 100644 --- a/default-attached/alonemode.js +++ b/default-attached/alonemode.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'AloneMode', - version: '3.2', + version: '3.2.0', backends: ['ts3', 'discord'], description: 'This script will save CPU and bandwidth by stopping or muting the bot when nobody is listening anyways.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle, Fabian "fabm3n" vars: [{ name: 'mode', title: 'Mode', diff --git a/default-attached/bookmark.js b/default-attached/bookmark.js index 9cceebd..60e047d 100644 --- a/default-attached/bookmark.js +++ b/default-attached/bookmark.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'Bookmarks!', - version: '3.0', + version: '3.0.0', backends: ['ts3', 'discord'], description: 'Enter .bookmark to save the current position, enter .resume to seek to the bookmarked position.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [] }, () => { const store = require('store') diff --git a/default-attached/followme.js b/default-attached/followme.js index 899d3b8..d238245 100644 --- a/default-attached/followme.js +++ b/default-attached/followme.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'Follow Me', - version: '3.0', + version: '3.0.0', backends: ['ts3', 'discord'], description: 'The bot will follow the movements of any of the clients given', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [{ name: 'clientUids', title: 'Comma-separated list of client-UIDs that the bot should follow', diff --git a/default-attached/norecording.js b/default-attached/norecording.js index c65f654..3c6e587 100644 --- a/default-attached/norecording.js +++ b/default-attached/norecording.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'No Recording!', - version: '3.0', + version: '3.0.0', backends: ['ts3'], description: 'This script will kick anyone who attempts to record.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [{ name: 'kickMessage', title: 'The optional kick message.', diff --git a/default-attached/rememberChannel.js b/default-attached/rememberChannel.js index f4821c0..0060282 100644 --- a/default-attached/rememberChannel.js +++ b/default-attached/rememberChannel.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'Remember Last Channel', - version: '3.0', + version: '3.0.0', backends: ['ts3', 'discord'], description: 'This script will remember, which channel the bot was last moved to and will set it as default channel on join.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [] }, () => { const event = require('event') diff --git a/default-attached/welcome.js b/default-attached/welcome.js index 9e694cf..aa2e874 100644 --- a/default-attached/welcome.js +++ b/default-attached/welcome.js @@ -1,9 +1,9 @@ registerPlugin({ name: 'Welcome!', - version: '3.0', + version: '3.0.0', backends: ['ts3'], description: 'This plugin will let the bot greet everyone.', - author: 'Michael Friese , Max Schmitt ', + author: 'SinusBot Team', // Michael Friese, Max Schmitt, Jonas Bögle vars: [{ name: 'message', title: 'The message that should be displayed. (%n = nickname)', diff --git a/package-lock.json b/package-lock.json index 5e64d96..c7018fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.16.tgz", - "integrity": "sha512-UOEdmnDaL4oiMHf0DfSab3Wfs5EbNiH1ZD6T8tZRwT2yaw7buix+SH1xZ12bu3LAaSfb0Zfu18Cc0vz6Xu5l6w==", + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.17.tgz", + "integrity": "sha512-SOBYEUB44Wzjmz14VpT62cqBX1NxLomIE/14ugl6LJiSWyocbflQ9G/3/5uUgspH+FnmUhlo05cBJdulmJomXA==", "dev": true } } diff --git a/package.json b/package.json index cdc0259..a444c0c 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.16" + "sinusbot-scripting-engine": "^1.0.17" } } From 20d0c5d3c63209a76253a5c12798f3165020d9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 03:15:34 +0200 Subject: [PATCH 63/77] improve whoami --- default-attached/sinusbot-commands.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index c3b4e57..5d332e6 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -311,7 +311,12 @@ registerPlugin({ .exec((client, args, reply, ev) => { let users = getUsersByClient(client); if (users && users.length != 0) { - reply(`You match the following users: ${users.map(user => user.name()).join(", ")}.`); + const usersStr = users.map(user => user.name()).join(", "); + if (users.length == 1) { + reply(`You match the following user: ${usersStr}.`); + } else { + reply(`You match the following ${users.length} users: ${usersStr}.`); + } } else { reply("You don't match any users."); } From ca3fe1cb873c5d18d6445ec74cbd7ece4b24cde9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 03:22:57 +0200 Subject: [PATCH 64/77] also show controls when not playing --- default-attached/sinusbot-commands.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 5d332e6..5c5b3ac 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -328,11 +328,12 @@ registerPlugin({ .help('Show what\'s currently playing') .manual('Show what\'s currently playing') .exec((client, args, reply, ev) => { + let msg = getPlayingEmbed(); if (!audio.isPlaying()) { - return reply('There is nothing playing at the moment.'); + msg.content = 'There is nothing playing at the moment.'; } - backend.extended().createMessage(ev.channel.id(), getPlayingEmbed(), (err, res) => { + backend.extended().createMessage(ev.channel.id(), msg, (err, res) => { if (err) return engine.log(err); if (!res) return engine.log('Error: empty response'); @@ -1139,6 +1140,11 @@ registerPlugin({ */ function getPlayingEmbed() { let track = media.getCurrentTrack(); + + if (!track) { + return {}; + } + let album = track.album(); let duration = track.duration(); @@ -1159,7 +1165,7 @@ registerPlugin({ return { embed: { title: formatTrack(track), - url: sinusbotURL ? sinusbotURL : null, + url: sinusbotURL || null, color: 0xe13438, thumbnail: { url: sinusbotURL && track.thumbnail() ? `${sinusbotURL}/cache/${track.thumbnail()}` : null From 98bed1862a95b997aab54525ab3c8f9f2f714b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 03:27:49 +0200 Subject: [PATCH 65/77] playing: also show title as normal text --- default-attached/sinusbot-commands.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 5c5b3ac..9e750d2 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1142,7 +1142,10 @@ registerPlugin({ let track = media.getCurrentTrack(); if (!track) { - return {}; + return { + content: "", + embed: {}, + }; } let album = track.album(); @@ -1163,6 +1166,7 @@ registerPlugin({ } return { + content: formatTrack(track), embed: { title: formatTrack(track), url: sinusbotURL || null, @@ -1175,7 +1179,7 @@ registerPlugin({ icon_url: "https://sinusbot.github.io/logo.png", text: "SinusBot" } - } + }, }; } From 0b4197fe4ebefedd894ba9383c59f2d4cd257ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 04:44:38 +0200 Subject: [PATCH 66/77] fix/add privileges --- default-attached/sinusbot-commands.js | 101 +++++++++++++++++--------- 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 9e750d2..02c5aaf 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -114,25 +114,20 @@ registerPlugin({ engine.log(`SinusBot v${engine.version()} on ${engine.os()}`) /********* privileges *********/ - /* eslint-disable no-unused-vars */ - const LOGIN = 1 << 0; - const LIST_FILE = 1 << 1; - const UPLOAD_FILE = 1 << 2; - const DELETE_FILE = 1 << 3; - const EDIT_FILE = 1 << 4; - const CREATE_PLAYLIST = 1 << 5; - const DELETE_PLAYLIST = 1 << 6; - const ADDTO_PLAYLIST = 1 << 7; - const STARTSTOP = 1 << 8; - const EDITUSERS = 1 << 9; - const CHANGENICK = 1 << 10; - const BROADCAST = 1 << 11; - const PLAYBACK = 1 << 12; - const ENQUEUE = 1 << 13; - const ENQUEUENEXT = 1 << 14; - const EDITBOT = 1 << 15; - const EDITINSTANCE = 1 << 16; - /* eslint-enable no-unused-vars */ + const ENQUEUE = 1 << 13; + const SKIP_QUEUE = 1 << 14; + const ADMIN_QUEUE = 1 << 15; + const PLAYBACK = 1 << 12; + const START_STOP = 1 << 8; + const EDIT_BOT_SETTINGS = 1 << 16; + const LOGIN = 1 << 0; + const UPLOAD_FILES = 1 << 2; + const DELETE_FILES = 1 << 3; + const EDIT_FILES = 1 << 4; + const CREATE_AND_DELETE_PLAYLISTS = 1 << 5; + const EDIT_PLAYLISTS = 1 << 7; + const EDIT_INSTANCES = 1 << 17; + const EDIT_USERS = 1 << 9; const ERROR_PREFIX = '❌ '; const WARNING_PREFIX = '⚠ '; @@ -323,6 +318,44 @@ registerPlugin({ successReaction(ev, reply); }); + createCommand('privileges') + .alias('priv', 'privs') + .help('Show user privileges') + .manual('Shows user privileges.') + .exec((client, args, reply, ev) => { + let privs = [ + { n: ENQUEUE, s: 'Enqueue' }, + { n: SKIP_QUEUE, s: 'Skip Queue' }, + { n: ADMIN_QUEUE, s: 'Admin Queue' }, + { n: PLAYBACK, s: 'Playback' }, + { n: START_STOP, s: 'Start/Stop' }, + { n: EDIT_BOT_SETTINGS, s: 'Edit Bot Settings' }, + { n: LOGIN, s: 'Login' }, + { n: UPLOAD_FILES, s: 'Upload Files' }, + { n: DELETE_FILES, s: 'Delete Files' }, + { n: EDIT_FILES, s: 'Edit Files' }, + { n: CREATE_AND_DELETE_PLAYLISTS, s: 'Create/Delete Playlists' }, + { n: EDIT_PLAYLISTS, s: 'Edit Playlists' }, + { n: EDIT_INSTANCES, s: 'Edit Instances' }, + { n: EDIT_USERS, s: 'Edit Users' }, + ]; + let uprivs = []; + privs.forEach(p => { + if (requirePrivileges(p.n)(client)) { + uprivs.push(p.s); + } + }) + + if (uprivs.length >= 1) { + reply(`You have the following privileges: ${uprivs.join(", ")}.`); + } else { + reply(`You have no privileges.`); + } + //reply(getUsersByClient(client).map(u => u.privileges().toString(2)).join(", ")); + + successReaction(ev, reply); + }); + if (engine.getBackend() == 'discord') { createCommand('playing') .help('Show what\'s currently playing') @@ -527,7 +560,7 @@ registerPlugin({ .addArgument(args => args.rest.setName('idORsearchstring', 'searchstring / uuid')) .help('Prepends a track to the queue') .manual('Prepends a track by its id or searches for a track and prepends the first match to the queue.') - .checkPermission(requirePrivileges(ENQUEUENEXT)) + .checkPermission(requirePrivileges(SKIP_QUEUE)) .exec((client, args, reply, ev) => { // print syntax if no idORsearchstring given if (!args.idORsearchstring) { @@ -563,7 +596,7 @@ registerPlugin({ createCommand('!stop') .help('Stop playback and remove idle-track') .manual('Stops playback and removes idle-track.') - .checkPermission(requirePrivileges(PLAYBACK|EDITBOT)) + .checkPermission(requirePrivileges(PLAYBACK|EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { media.stop(); media.clearIdleTrack(); @@ -675,7 +708,7 @@ registerPlugin({ .addArgument(args => args.string.setName('url')) .help('Set the TTS url.') .manual('Sets the TTS url.') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { // print syntax if no url given if (!args.url) { @@ -691,7 +724,7 @@ registerPlugin({ .addArgument(args => args.string.setName('locale')) .help('Set the TTS locale.') .manual('Sets the TTS locale.') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { // print syntax if no locale given if (!args.locale) { @@ -739,7 +772,7 @@ registerPlugin({ .addArgument(args => args.string.setName('url')) .help('Download and play via youtube-dl') .manual('Plays via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') - .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE)) + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILES)) .exec((client, args, reply, ev) => { const url = stripURL(args.url); if (!url) return reply(USAGE_PREFIX + 'ytdl '); @@ -767,7 +800,7 @@ registerPlugin({ .addArgument(args => args.string.setName('url')) .help('Download and enqueue via youtube-dl') .manual('Enqueues via external youtube-dl (if enabled); beware: the file will be downloaded first and played back afterwards, so there might be a slight delay before playback starts; additionally, the file will be stored.') - .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILE, ENQUEUE|UPLOAD_FILE)) + .checkPermission(requirePrivileges(PLAYBACK|UPLOAD_FILES, ENQUEUE|UPLOAD_FILES)) .exec((client, args, reply, ev) => { const url = stripURL(args.url); if (!url) return reply(USAGE_PREFIX + 'qytdl '); @@ -827,7 +860,7 @@ registerPlugin({ createCommand('subchan') .help('Add subscription for channel') .manual('Adds subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + .checkPermission(client => requirePrivileges(EDIT_BOT_SETTINGS)(client) && engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); @@ -840,7 +873,7 @@ registerPlugin({ createCommand('unsubchan') .help('Remove subscription for channel') .manual('Removes subscription for the channel the user is currently in. (subscription transfer-mode only)') - .checkPermission(client => requirePrivileges(EDITBOT)(client) && engine.isSubscriptionMode()) + .checkPermission(client => requirePrivileges(EDIT_BOT_SETTINGS)(client) && engine.isSubscriptionMode()) .exec((client, args, reply, ev) => { if (!engine.isSubscriptionMode()) { reply(ERROR_PREFIX + 'This command only works if Transmit-Mode is set to Subscription.'); @@ -854,7 +887,7 @@ registerPlugin({ .addArgument(args => args.string.setName('mode')) .help('Change Transmit-Mode') .manual('Changes Transmit-Mode; 0 = to channel, 1 = subscription mode') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { let mode = args.mode; if (typeof mode === 'string') { @@ -886,7 +919,7 @@ registerPlugin({ .addArgument(args => args.string.setName('value')) .help('Enable / disable user registration via chat') .manual('Enables / disables user registration via chat. Value should be either `enable` or `disable`.') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { switch (args.value) { case "enable": @@ -908,7 +941,7 @@ registerPlugin({ .addArgument(args => args.string.setName('prefix')) .help('Change command prefix') .manual('Changes the prefix for all core commands to , default is "!".') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { // print syntax if no prefix given if (!args.prefix) { @@ -931,7 +964,7 @@ registerPlugin({ createCommand('version') .help('Show version') .manual('Shows the SinusBot version.') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { reply(`SinusBot v${engine.version()} on ${engine.os()}\nsinusbot-commands.js v${meta.version}\ncommand.js v${command.getVersion()}`); successReaction(ev, reply); @@ -940,7 +973,7 @@ registerPlugin({ createCommand('reload') .help('Reload scripts') .manual('Reloads scripts.\nNote: Adding new scripts requires a complete sinusbot restart.') - .checkPermission(requirePrivileges(EDITBOT)) + .checkPermission(requirePrivileges(EDIT_BOT_SETTINGS)) .exec((client, args, reply, ev) => { reply('reloading...'); let success = engine.reloadScripts(); @@ -955,7 +988,7 @@ registerPlugin({ createCommand('join') .help('Move the SinusBot to your channel') .manual('Moves the SinusBot into your channel.') - .checkPermission(requirePrivileges(STARTSTOP)) + .checkPermission(requirePrivileges(START_STOP)) .exec((client, args, reply, ev) => { var channel = client.getChannels()[0] if (!channel) { @@ -973,7 +1006,7 @@ registerPlugin({ createCommand('leave') .help('Disconnect the SinusBot') .manual('Disconnects the SinusBot from the current voice channel.') - .checkPermission(requirePrivileges(STARTSTOP)) + .checkPermission(requirePrivileges(START_STOP)) .exec((client, args, reply, ev) => { if (!getBotClient()) { return reply(ERROR_BOT_NULL) From 025a82421ff9b2e0e53d4fe312cdde42c18329e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 04:58:39 +0200 Subject: [PATCH 67/77] play: allow URLs --- default-attached/sinusbot-commands.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 02c5aaf..06d8807 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -475,20 +475,36 @@ registerPlugin({ .manual('Plays a track by its id or searches for a track and plays the first match.') .checkPermission(requirePrivileges(PLAYBACK)) .exec((client, args, reply, ev) => { + let query = args.idORsearchstring; // print syntax if no idORsearchstring given - if (!args.idORsearchstring) { + if (!query) { reply(USAGE_PREFIX + 'play '); return; } - let track = media.getTrackByID(args.idORsearchstring); + let track = media.getTrackByID(query); if (!track) { - let tracks = media.search(args.idORsearchstring); + let tracks = media.search(query); if (tracks.length > 0) { track = tracks[0]; } else { - reply('Sorry, nothing found.'); - return; + query = stripURL(query); + if (query.match(PATTERN_URL)) { + if (!query.match(PATTERN_YT_DOMAIN)) { + if (media.playURL(query)) { + successReaction(ev, reply); + return; + } + } + if (media.ytStream(query)) { + successReaction(ev, reply); + return; + } + const jobId = media.yt(query); + handleYT(jobId, ev, reply); + return; + } + return reply('Sorry, nothing found.'); } } From 0bdd7cd05933f1fb1409c7abced5426694865786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 05:04:13 +0200 Subject: [PATCH 68/77] SinusBot Commands v1.1.0 --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 06d8807..6013544 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -33,7 +33,7 @@ */ registerPlugin({ name: 'SinusBot Commands', - version: '1.0.0', + version: '1.1.0', description: 'Enables the default commands.', author: 'Jonas Bögle (@irgendwr)', engine: '>= 1.0.0', From 041510c616d743bee7d4c22f9f139036707bc478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 16:44:11 +0200 Subject: [PATCH 69/77] add youtu.be to YT pattern --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 6013544..3384999 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -141,7 +141,7 @@ registerPlugin({ const REACTION_SUCCESS = '✅'; const PATTERN_URL = /^https?:\/\/\S+/i; - const PATTERN_YT_DOMAIN = /^https?:\/\/(?:www\.)?youtube\.com\//i; + const PATTERN_YT_DOMAIN = /^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\//i; // for join/leave const ERROR_BOT_NULL = ERROR_PREFIX+'Unable to change channel.\nTry to set a *Default Channel* in the webinterface and click save.' From 5067eb85715a58dc6f3289a8b2c5444eb4f2c645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Mon, 6 Apr 2020 16:53:43 +0200 Subject: [PATCH 70/77] (re-)add stream support to !yt --- default-attached/sinusbot-commands.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 3384999..75f6b13 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -763,7 +763,18 @@ registerPlugin({ if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); const jobId = media.yt(url); - handleYT(jobId, ev, reply); + ytCallback(jobId, (ytev, err) => { + if (err) { + // try to stream + if (!media.ytStream(url)) { + if (err.startsWith("exit status")) { + return reply(ERROR_PREFIX + `Error: ${err}; Please see "Upload" page in web-interface for more details.`); + } + return reply(ERROR_PREFIX + `Error: ${err}`); + } + } + successReaction(ev, reply); + }); }); createCommand('ytstream') @@ -778,8 +789,7 @@ registerPlugin({ if (!url.match(PATTERN_URL)) return reply(ERROR_PREFIX + 'Invalid URL.'); if (!media.ytStream(url)) { - reply(ERROR_PREFIX + 'Unable to stream this URL.'); - return; + return reply(ERROR_PREFIX + 'Unable to stream this URL.'); } successReaction(ev, reply); }); From 8e4f27f461e3c9122dc27fa851fc8dcf1210010c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 7 Apr 2020 05:21:27 +0200 Subject: [PATCH 71/77] fix: only set status on discord --- default-attached/sinusbot-commands.js | 258 +++++++++++++------------- 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 75f6b13..2ad7ab4 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1043,156 +1043,156 @@ registerPlugin({ }); } }); + } // END COMMANDS-ENABLED - /********** !playing stuff for discord **********/ - if (engine.getBackend() == 'discord') { - event.on('discord:MESSAGE_REACTION_ADD', ev => { - let ename = ev.emoji.name; - // remove 0xefb88f aka. "VARIATION SELECTOR-16" (no idea why discord puts that at the end) - if (ename.endsWith('\ufe0f')) { - ename = ename.slice(0, -1); - } - const emoji = ev.emoji.id ? `${ename}:${ev.emoji.id}` : ename; + // stores last bot client object for `getBotClient()` + let bot = backend.getBotClient(); - // ignore reactions that are not controls - if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; + /** + * Wrapper for `backend.getBotClient()` because it sometimes returns `null` -_- + * @returns {Client} Bot client + */ + function getBotClient() { + bot = backend.getBotClient() || bot; + return bot; + } - // ignore reactions from the bot itself - if (backend.getBotClientID().endsWith(ev.user_id)) return; + /********** !playing stuff for discord **********/ + if (engine.getBackend() == 'discord') { + event.on('discord:MESSAGE_REACTION_ADD', ev => { + let ename = ev.emoji.name; + // remove 0xefb88f aka. "VARIATION SELECTOR-16" (no idea why discord puts that at the end) + if (ename.endsWith('\ufe0f')) { + ename = ename.slice(0, -1); + } + const emoji = ev.emoji.id ? `${ename}:${ev.emoji.id}` : ename; - // get user via id - const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); + // ignore reactions that are not controls + if (![REACTION_PREV, REACTION_PLAYPAUSE, REACTION_NEXT].includes(emoji)) return; - // ignore if no matching user found or reaction from the bot itself - if (!client || client.isSelf()) return; + // ignore reactions from the bot itself + if (backend.getBotClientID().endsWith(ev.user_id)) return; - let callback = () => { - // delete the rection - deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); + // get user via id + const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); - // check if user has the 'playback' permission - if (!requirePrivileges(PLAYBACK)(client)) { - engine.log(`${client.nick()} is missing playback permissions for reaction controls`); - client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); - return; - } + // ignore if no matching user found or reaction from the bot itself + if (!client || client.isSelf()) return; - const track = media.getCurrentTrack(); + let callback = () => { + // delete the rection + deleteUserReaction(ev.channel_id, ev.message_id, ev.user_id, emoji); + + // check if user has the 'playback' permission + if (!requirePrivileges(PLAYBACK)(client)) { + engine.log(`${client.nick()} is missing playback permissions for reaction controls`); + client.chat(ERROR_PREFIX + 'You need the playback permission to use reaction controls'); + return; + } - switch (emoji) { - case REACTION_PREV: - // ignore if nothing is playing - if (!audio.isPlaying()) return; + const track = media.getCurrentTrack(); - if (media.getQueue().length !== 0) { - // start from beginning if we're playing queue - audio.seek(0); - } else { - // try prev (doesn't work for queue or folder) - media.playPrevious(); + switch (emoji) { + case REACTION_PREV: + // ignore if nothing is playing + if (!audio.isPlaying()) return; - // fallback: start from beginning if there is no previous track - if (!audio.isPlaying()) { - if (track) track.play(); - } + if (media.getQueue().length !== 0) { + // start from beginning if we're playing queue + audio.seek(0); + } else { + // try prev (doesn't work for queue or folder) + media.playPrevious(); + + // fallback: start from beginning if there is no previous track + if (!audio.isPlaying()) { + if (track) track.play(); } - break; - case REACTION_PLAYPAUSE: - if (audio.isPlaying()) { - media.stop(); + } + break; + case REACTION_PLAYPAUSE: + if (audio.isPlaying()) { + media.stop(); + } else { + if (!track) return; + const pos = audio.getTrackPosition(); + + if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { + // continue playing at last pos + audio.setMute(true); + track.play(); + audio.seek(pos); + audio.setMute(false); } else { - if (!track) return; - const pos = audio.getTrackPosition(); - - if (pos && pos < (track.duration() - 1000 /* milliseconds */)) { - // continue playing at last pos - audio.setMute(true); - track.play(); - audio.seek(pos); - audio.setMute(false); - } else { - // or start from beginning if it already ended - track.play(); - } + // or start from beginning if it already ended + track.play(); } - break; - case REACTION_NEXT: - if (audio.isPlaying()) { - media.playNext(); - } else { - // is something in queue? - if (media.getQueue().length !== 0) { - // resume queue - media.playQueueNext(); - } + } + break; + case REACTION_NEXT: + if (audio.isPlaying()) { + media.playNext(); + } else { + // is something in queue? + if (media.getQueue().length !== 0) { + // resume queue + media.playQueueNext(); } } - }; - - // was reaction added to previous response? - if (lastEmbeds.some(embed => embed.messageId == ev.message_id)) { - callback(); - return; } + }; - getMessage(ev.channel_id, ev.message_id).then(msg => { - // was reaction added to previous response of the bot? - if (backend.getBotClientID().endsWith(msg.author.id)) { - callback(); - } - }) - }); - } // END COMMANDS-ENABLED - } - - // stores last bot client object for `getBotClient()` - let bot = backend.getBotClient(); - - /** - * Wrapper for `backend.getBotClient()` because it sometimes returns `null` -_- - * @returns {Client} Bot client - */ - function getBotClient() { - bot = backend.getBotClient() || bot; - return bot; - } + // was reaction added to previous response? + if (lastEmbeds.some(embed => embed.messageId == ev.message_id)) { + callback(); + return; + } - /** - * Called when track or it's info changes - * @param {Track} track - */ - const onChange = track => { - if (config.songInStatus) { - const prefix = '🎵 '; - const suffix = ' 🎵'; - - // set track info as status - backend.extended().setStatus({ - game: { - name: prefix + formatTrack(track) + suffix, - type: 2, // => 0 (game), 1 (streaming), 2 (listening) - }, - status: "online", - afk: false + getMessage(ev.channel_id, ev.message_id).then(msg => { + // was reaction added to previous response of the bot? + if (backend.getBotClientID().endsWith(msg.author.id)) { + callback(); + } + }) + }); + + /** + * Called when track or it's info changes + * @param {Track} track + */ + const onChange = track => { + if (config.songInStatus) { + const prefix = '🎵 '; + const suffix = ' 🎵'; + + // set track info as status + backend.extended().setStatus({ + game: { + name: prefix + formatTrack(track) + suffix, + type: 2, // => 0 (game), 1 (streaming), 2 (listening) + }, + status: "online", + afk: false + }); + } + + // update embeds + lastEmbeds.forEach(async embed => { + await editMessage(embed.channelId, embed.messageId, getPlayingEmbed()).then(() => wait(100)); }); - } - - // update embeds - lastEmbeds.forEach(async embed => { - await editMessage(embed.channelId, embed.messageId, getPlayingEmbed()).then(() => wait(100)); + }; + + event.on('track', onChange); + event.on('trackInfo', onChange); + event.on('trackEnd', () => { + if (!config.songInStatus) { + return; + } + if (getBotClient()) { + bot.setDescription(''); + } }); - }; - - event.on('track', onChange); - event.on('trackInfo', onChange); - event.on('trackEnd', () => { - if (!config.songInStatus) { - return; - } - if (getBotClient()) { - bot.setDescription(''); - } - }); + } /** * Returns embed for current track From 315f82452c96d742c9a3e3b9c28e04cd00718ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Tue, 7 Apr 2020 05:21:52 +0200 Subject: [PATCH 72/77] SinusBot Commands v1.1.1 --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index 2ad7ab4..a2f6ffc 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -33,7 +33,7 @@ */ registerPlugin({ name: 'SinusBot Commands', - version: '1.1.0', + version: '1.1.1', description: 'Enables the default commands.', author: 'Jonas Bögle (@irgendwr)', engine: '>= 1.0.0', From 542b09b631389765528eba3220d337c47845af0c Mon Sep 17 00:00:00 2001 From: Jniklas2 <18490197+Jniklas2@users.noreply.github.com> Date: Fri, 17 Apr 2020 22:51:11 +0200 Subject: [PATCH 73/77] fix(spelling): Registartion => Registration (#13) --- default-attached/sinusbot-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index a2f6ffc..79503d6 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -959,7 +959,7 @@ registerPlugin({ successReaction(ev, reply); break; default: - reply(`Registartion is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); + reply(`Registration is currently ${engine.registrationEnabled() ? 'en' : 'dis'}abled.\n` + USAGE_PREFIX + 'registration '); } }); From a16c2f9e388f645b216177c4e5ac668b22415a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 17 Apr 2020 23:54:23 +0200 Subject: [PATCH 74/77] remove conditions with "false" Conditions checking for "false" are currently still buggy. @flyth needs to fix this. --- default-attached/sinusbot-commands.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index a2f6ffc..5408aad 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -59,18 +59,18 @@ registerPlugin({ title: 'Add a reaction to each command if it was successfull.', type: 'checkbox', default: false, - conditions: [ + /* conditions: [ { field: 'disable', value: false } - ], + ], */ // conditions checking for "false" are currently buggy. @flyth needs to fix this. }, { name: 'discord', title: 'Show discord settings', type: 'checkbox', default: true, - conditions: [ + /* conditions: [ { field: 'disable', value: false } - ], + ], */ // conditions checking for "false" are currently buggy. @flyth needs to fix this. }, { name: 'url', @@ -79,8 +79,8 @@ registerPlugin({ placeholder: 'i.e. https://sinusbot.example.com', conditions: [ { field: 'discord', value: true }, - { field: 'disable', value: false } - ], + /*{ field: 'disable', value: false }*/ + ], // conditions checking for "false" are currently buggy. @flyth needs to fix this. }, { name: 'songInStatus', @@ -98,8 +98,8 @@ registerPlugin({ default: true, conditions: [ { field: 'discord', value: true }, - { field: 'disable', value: false } - ], + /*{ field: 'disable', value: false }*/ + ], // conditions checking for "false" are currently buggy. @flyth needs to fix this. } ] }, (_, config, meta) => { From 459b18db4117cb226623ef7f08c5a4bebc1f41a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sat, 18 Apr 2020 04:08:12 +0200 Subject: [PATCH 75/77] fix: !playing in private chat --- default-attached/sinusbot-commands.js | 174 +++++++++++++++++--------- 1 file changed, 112 insertions(+), 62 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index ccdc140..de7d445 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -33,7 +33,7 @@ */ registerPlugin({ name: 'SinusBot Commands', - version: '1.1.1', + version: '1.1.2', description: 'Enables the default commands.', author: 'Jonas Bögle (@irgendwr)', engine: '>= 1.0.0', @@ -139,6 +139,7 @@ registerPlugin({ const REACTION_PLAYPAUSE = '⏯'; const REACTION_NEXT = '⏭'; const REACTION_SUCCESS = '✅'; + const HIDE_REACTIONS_IF_PRIVATE = false; const PATTERN_URL = /^https?:\/\/\S+/i; const PATTERN_YT_DOMAIN = /^https?:\/\/(?:www\.)?(?:youtube\.com|youtu\.be)\//i; @@ -356,64 +357,11 @@ registerPlugin({ successReaction(ev, reply); }); - if (engine.getBackend() == 'discord') { - createCommand('playing') - .help('Show what\'s currently playing') - .manual('Show what\'s currently playing') - .exec((client, args, reply, ev) => { - let msg = getPlayingEmbed(); - if (!audio.isPlaying()) { - msg.content = 'There is nothing playing at the moment.'; - } - - backend.extended().createMessage(ev.channel.id(), msg, (err, res) => { - if (err) return engine.log(err); - if (!res) return engine.log('Error: empty response'); - - const {id, channel_id} = JSON.parse(res); - - // messages that should be deleted - let deleteMsg = []; - const msgId = ev.message ? ev.message.ID() : null; - const index = lastEmbeds.findIndex(embed => embed.channelId == channel_id); - if (index !== -1) { - if (config.deleteOldMessages) { - // delete previous embed - deleteMsg.push(lastEmbeds[index].messageId); - // delete previous command from user - if (lastEmbeds[index].messageId) { - deleteMsg.push(lastEmbeds[index].invokeMessageId); - } - } - // save new embed - lastEmbeds[index].messageId = id; - lastEmbeds[index].invokeMessageId = msgId; - } else { - // save new embed - lastEmbeds.push({ - channelId: channel_id, - messageId: id, - invokeMessageId: msgId - }); - } - - deleteMessages(channel_id, deleteMsg); - - wait(1000) - // create reaction controls - .then(() => createReaction(channel_id, id, REACTION_PREV)) - .then(() => wait(150)) - .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) - .then(() => wait(150)) - .then(() => createReaction(channel_id, id, REACTION_NEXT)); - }); - successReaction(ev, reply); - }); - } else { - createCommand('playing') - .help('Show what\'s currently playing') - .manual('Show what\'s currently playing') - .exec((client, args, reply, ev) => { + createCommand('playing') + .help('Show what\'s currently playing') + .manual('Show what\'s currently playing') + .exec((client, args, reply, ev) => { + if (engine.getBackend() !== 'discord' || !ev.message) { if (!audio.isPlaying()) { successReaction(ev, reply); return reply('There is nothing playing at the moment.'); @@ -421,8 +369,59 @@ registerPlugin({ reply(formatTrack(media.getCurrentTrack())); successReaction(ev, reply); + return; + } + + let msg = getPlayingEmbed(); + if (!audio.isPlaying()) { + msg.content = 'There is nothing playing at the moment.'; + } + + backend.extended().createMessage(ev.message.channelID(), msg, (err, res) => { + if (err) return engine.log(err); + if (!res) return engine.log('Error: empty response'); + + const {id, channel_id} = JSON.parse(res); + + // messages that should be deleted + let deleteMsg = []; + const msgId = ev.message ? ev.message.ID() : null; + const index = lastEmbeds.findIndex(embed => embed.channelId == channel_id); + if (index !== -1) { + if (config.deleteOldMessages) { + // delete previous embed + deleteMsg.push(lastEmbeds[index].messageId); + // delete previous command from user + if (lastEmbeds[index].messageId) { + deleteMsg.push(lastEmbeds[index].invokeMessageId); + } + } + // save new embed + lastEmbeds[index].messageId = id; + lastEmbeds[index].invokeMessageId = msgId; + } else { + // save new embed + lastEmbeds.push({ + channelId: channel_id, + messageId: id, + invokeMessageId: msgId + }); + } + + deleteMessages(channel_id, deleteMsg); + + if (HIDE_REACTIONS_IF_PRIVATE && ev.mode === 1) return; + + wait(1000) + // create reaction controls + .then(() => createReaction(channel_id, id, REACTION_PREV)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_PLAYPAUSE)) + .then(() => wait(150)) + .then(() => createReaction(channel_id, id, REACTION_NEXT)); }); - } + successReaction(ev, reply); + }); createCommand('next') .help('Play the next track') @@ -1074,10 +1073,19 @@ registerPlugin({ if (backend.getBotClientID().endsWith(ev.user_id)) return; // get user via id - const client = backend.getClientByID(ev.guild_id ? `${ev.guild_id}/${ev.user_id}` : ev.user_id); + let client = backend.getClientByID(`${ev.guild_id || backend.getBotClientID().split('/')[0]}/${ev.user_id}`); + + if (!client) { + engine.log(`playing controls: using workaround for client '${ev.user_id}'`); + // @ts-ignore: workaround + client = fakeClient(ev.guild_id || backend.getBotClientID().split('/')[0], ev.user_id, ev.channel_id); + } // ignore if no matching user found or reaction from the bot itself - if (!client || client.isSelf()) return; + if (!client) return engine.log(`playing controls: could not find client '${ev.user_id}'`); + + // ignore if reaction is from the bot itself + if (client.isSelf()) return; let callback = () => { // delete the rection @@ -1242,6 +1250,48 @@ registerPlugin({ }; } + /** + * Returns a fake client object from IDs. (Discord only) + * @param {string} guild Guild ID + * @param {string} id User ID + * @param {string} channelid Channel ID + */ + function fakeClient(guild, id, channelid) { + const clid = `${guild}/${id}` + return { + chat: (/** @type {string} */ str) => { + backend.extended().createMessage(channelid, { + content: str + }); + }, + isSelf: () => false, + id: () => clid, + uid: () => clid, + uniqueId: () => clid, + uniqueID: () => clid, + DBID: () => clid, + databaseID: () => clid, + databaseId: () => clid, + type: () => 1, + getURL: () => `<@${id}>`, + name: () => `unknown (ID: ${id})`, + nick: () => `unknown (ID: ${id})`, + phoneticName: () => '', + description: () => '', + getServerGroups: () => [], + getChannelGroup: () => null, + getChannels: () => [], + getAudioChannel: () => null, + equals: (/** @type {Client} */ client) => { + const uid = client.uid().split("/") + if (uid.length === 2) { + return uid[2] === id + } else { + return client.uid() === clid + } + } + } + } /********** helper functions **********/ From c3e3ff240790532d1456e14962be9daf8c13dc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sat, 18 Apr 2020 04:20:07 +0200 Subject: [PATCH 76/77] chore: update typings --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index c7018fa..3b91017 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "sinusbot-scripting-engine": { - "version": "1.0.17", - "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.17.tgz", - "integrity": "sha512-SOBYEUB44Wzjmz14VpT62cqBX1NxLomIE/14ugl6LJiSWyocbflQ9G/3/5uUgspH+FnmUhlo05cBJdulmJomXA==", + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/sinusbot-scripting-engine/-/sinusbot-scripting-engine-1.0.18.tgz", + "integrity": "sha512-tRJDIAN8carWE4LCOKM15elemn7zLAkg2RB9KjGPTfhwMxePsZJs+Xl1+i2MrF5T0qmUpbMxzEg3941Kud3hKg==", "dev": true } } diff --git a/package.json b/package.json index a444c0c..4aaacdc 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,6 @@ "author": "SinusBot", "license": "MIT", "devDependencies": { - "sinusbot-scripting-engine": "^1.0.17" + "sinusbot-scripting-engine": "^1.0.18" } } From 0e23b2708e71c52bbd84e2b2621726e1a25debfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 3 May 2020 18:35:28 +0200 Subject: [PATCH 77/77] improve: setDefaultChannel on join/leave --- default-attached/sinusbot-commands.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/default-attached/sinusbot-commands.js b/default-attached/sinusbot-commands.js index de7d445..c7fd451 100644 --- a/default-attached/sinusbot-commands.js +++ b/default-attached/sinusbot-commands.js @@ -1017,15 +1017,26 @@ registerPlugin({ .exec((client, args, reply, ev) => { var channel = client.getChannels()[0] if (!channel) { - return reply(ERROR_PREFIX+'I\'m unable to join your channel :(') + return reply(ERROR_PREFIX+'I\'m unable to join your channel :('); } if (!getBotClient()) { - return reply(ERROR_BOT_NULL) + return reply(ERROR_BOT_NULL); } - bot.moveTo(channel) + bot.moveTo(channel); + engine.setDefaultChannelID(channel.id()) successReaction(ev, reply); }); + + /* // currently not working due to a bug. + createCommand('disconnect') + .help('Disconnect the SinusBot') + .manual('Disconnects the SinusBot.') + .checkPermission(requirePrivileges(START_STOP)) + .exec((client, args, reply, ev) => { + backend.disconnect() + }); + // */ if (engine.getBackend() == 'discord') { createCommand('leave') @@ -1034,10 +1045,11 @@ registerPlugin({ .checkPermission(requirePrivileges(START_STOP)) .exec((client, args, reply, ev) => { if (!getBotClient()) { - return reply(ERROR_BOT_NULL) + return reply(ERROR_BOT_NULL); } - bot.moveTo('') + bot.moveTo(''); + engine.setDefaultChannelID(''); successReaction(ev, reply); }); }