diff --git a/bot.js b/bot.js index 7fb8a79..b08b9b6 100644 --- a/bot.js +++ b/bot.js @@ -1,7 +1,10 @@ -var config = require('./lib/load_config.js'); +var moment = require('moment'); var storyboard = require('storyboard'); +var fs = require('fs'); + +var config = require('./lib/load_config.js'); var langfile = require('./langfile.js'); -var moment = require('moment'); +var story = storyboard.mainStory; storyboard.config({filter: '*:' + config.options.loglevel}); storyboard.mainStory.info('Starting plugbot version ' + require('./package.json').version); @@ -18,39 +21,26 @@ redis.exists('meta:data:staff:active').then(function (ex) { if (ex === 0) redis.set('meta:data:staff:active', 1); }); -plugged.on(plugged.LOGIN_SUCCESS, require('./lib/eventhandlers/login_success')); -plugged.on(plugged.LOGIN_ERROR, require('./lib/eventhandlers/login_error')); - -plugged.on(plugged.CONN_SUCCESS, require('./lib/eventhandlers/conn_success')); -plugged.on(plugged.CONN_PART, require('./lib/eventhandlers/conn_part')); -plugged.on(plugged.CONN_ERROR, require('./lib/eventhandlers/conn_error')); -plugged.on(plugged.CONN_WARNING, require('./lib/eventhandlers/conn_warning')); - -plugged.on(plugged.PLUG_MESSAGE, require('./lib/eventhandlers/plug_message')); -plugged.on(plugged.PLUG_ERROR, require('./lib/eventhandlers/plug_error')); -plugged.on(plugged.KILL_SESSION, require('./lib/eventhandlers/kill_session')); -plugged.on(plugged.PLUG_UPDATE, require('./lib/eventhandlers/plug_update')); -plugged.on(plugged.MAINTENANCE_MODE, require('./lib/eventhandlers/maintenance_mode')); - -plugged.on(plugged.JOINED_ROOM, require('./lib/eventhandlers/joined_room')); - -plugged.on(plugged.ADVANCE, require('./lib/eventhandlers/advance')); -plugged.on(plugged.WAITLIST_UPDATE, require('./lib/eventhandlers/waitlist_update')); - -plugged.on(plugged.FRIEND_JOIN, require('./lib/eventhandlers/user_join')); -plugged.on(plugged.USER_JOIN, require('./lib/eventhandlers/user_join')); - -plugged.on(plugged.USER_LEAVE, require('./lib/eventhandlers/user_leave')); - -plugged.on(plugged.CHAT, require('./lib/eventhandlers/chat')); -plugged.on(plugged.CHAT_MENTION, require('./lib/eventhandlers/chat')); -plugged.on(plugged.CHAT_COMMAND, require('./lib/eventhandlers/chat_command')); - -plugged.on(plugged.VOTE, require('./lib/eventhandlers/vote')); - -plugged.on(plugged.MOD_STAFF, require('./lib/eventhandlers/mod_staff')); -plugged.on(plugged.MOD_BAN, require('./lib/eventhandlers/mod_ban')); -plugged.on(plugged.MOD_SKIP, require('./lib/eventhandlers/mod_skip')); -plugged.on(plugged.MOD_ADD_DJ, require('./lib/eventhandlers/mod_add_dj')); +fs.readdir('./lib/eventhandlers', function (err, files) { + if (err) { + story.fatal('Cannot load eventhandlers.', {attach: err}); + process.exit(1); + } else { + files.forEach(function (file) { + try { + var h = require('./lib/eventhandlers/' + file); + if (Array.isArray(h.event)) { + h.event.forEach(function (event) { + plugged.on(event, h.handler); + }); + } else plugged.on(h.event, h.handler); + story.debug('EventHandlers', 'Loaded Handler for Event ' + (Array.isArray(h.event) ? h.event.join() : h.event)); + } catch (e) { + story.error('Failed to load eventhandler ' + file, {attach: e}); + process.exit(1); + } + }); + } +}); module.exports = {plugged: plugged, app: (config.web.enabled ? require('./web/index').app : null)}; diff --git a/config.example.js b/config.example.js index 05f4f95..b727cfc 100644 --- a/config.example.js +++ b/config.example.js @@ -7,6 +7,7 @@ module.exports = { room: '', bouncer_plus: true, loglevel: 'INFO', + sql_debug: true, dcmoveback: true, command_prefix: '!', disable_emote: true, @@ -21,6 +22,7 @@ module.exports = { }, redis: { host: '', + password: undefined, db: 2 }, sequelize: { @@ -68,7 +70,8 @@ module.exports = { lockskip: false }, blacklist: { - lockskip: true + lockskip: true, + channelblacklist: true }, chatfilter: { enabled: true, @@ -79,7 +82,15 @@ module.exports = { mute_duration: 4000 }, links: { - plugdj: true + enabled: true, + regex: /(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?/g, + mode: 'blacklist', + filter: [], + plugdj: { + enabled: true, + hosts: ['plug.dj', 'support.plug.dj', 'cdn.plug.dj', 'stg.plug.dj', 'blog.plug.dj'], + allowed_paths: ['/subscribe', '/', '/support', '/about', '/ba', '/press', '/terms', '/privacy'] + } }, words: { blacklist: [] @@ -91,13 +102,15 @@ module.exports = { }, youtubeGuard: { enabled: true, + block: false, countryblocks: { - countries: ['DE'] + countries: [] }, lockskip: true }, soundcloudGuard: { enabled: true, + block: false, lockskip: true }, titleguard: { @@ -132,7 +145,7 @@ module.exports = { enabled: false, port: 3000, cors: '*', - websocket: false, + websocket: false, useUWS: true, path: '' }, @@ -149,14 +162,18 @@ module.exports = { msg: 'My software is licensed under the MIT License: https://git.io/vawDl', sender: true }, - tskip:{ + tskip: { msg: 'TSKIP automatically skips songs after a certain amount of time to avoid playing outros, etc.', - sender:true + sender: true } }, dcmoveback: { enabled: true, auto: true, timeout: 3600 + }, + userfilter: { + enabled: false, + username_disallowed: [] } }; \ No newline at end of file diff --git a/docs/commands.md b/docs/commands.md index 37a92a9..bb901cc 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -87,6 +87,7 @@ These commands are only available for bouncers when bouncer+ is enabled. |!roulette| |(moves)[time]|Starts a roulette| |!everyone| |[msg]|Mentions everyone| |!toggleafk| | |Toggles AFKRemoval| +|!channelblacklist|!cbl|add (cid)/rem (cid)/toggle|Adds/Removes a whole youtube channel from the blacklist/toggles the channelblacklist| ## Manager Commands Manager commands include bouncer and bouncer+ commands diff --git a/docs/config.md b/docs/config.md index 0706fba..d26b65a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -43,7 +43,11 @@ |chatfilter.ignorerole|number|Minimum role to ignore chatfilters. Defaults to 1 (resident-dj)| |chatfilter.spam|object|Settings for the aggresivity of the chatfilter, ONLY EDIT IF YOU KNOW WHAT YOU ARE DOING| |chatfilter.links|object|Settings for blocking links| -|chatfilter.links.plugdj|boolean|Sets the blocker for plugdj-links| +|chatfilter.links.enabled|boolean|Default value for the link filter| +|chatfilter.links.mode|ENUM('blacklist','whitelist')|Sets the mode for the linkfilter| +|chatfilter.links.filter|array[string]|Sets the filter for links. Put whitelisted/blacklisted hosts here (without http:///https://)| +|chatfilter.links.plugdj|object|Config for the plug.dj-link blocker| +|chatfilter.links.plugdj.enabled|string|Sets the plug.dj-link blocker| |chatfilter.words.blacklist|array[string]|Sets blacklisted words| |youtubeGuard|object|Settings for youtubeGuard| |youtubeGuard.enabled|boolean|The default value for youtubeGuard| diff --git a/docs/peoples.md b/docs/peoples.md new file mode 100644 index 0000000..1ef6598 --- /dev/null +++ b/docs/peoples.md @@ -0,0 +1,7 @@ +# Peoples + +This program doesn't solely use code of mine, some passages were taken from other programs + +#### URL Regex + +The URL Regex in the default config was taken from [Diego Perini](https://github.com/dperini), licensed under MIT, published on [Github Gist](https://gist.github.com/dperini/729294) \ No newline at end of file diff --git a/langfile.js b/langfile.js index 8c84bc5..b703f01 100644 --- a/langfile.js +++ b/langfile.js @@ -18,6 +18,14 @@ module.exports = { }, idbl: { default: '/me [&{username}: Blacklist] Added "&{song}" to the blacklist.' + }, + channelblacklist: { + enabled: '[&{username}: ChannelBlacklist enabled]', + disabled: '[&{username}: ChannelBlacklist disabled]', + skip: '@&{username}, your song "&{song}" was skipped because the uploaders channel is blacklisted in this room.', + skip_reason: '@&{username}, your song "&{song}" was skipped because the uploaders channel is blacklisted in this room: &{reason}', + add: '[&{username}: ChannelBlacklist] Added "&{cid}" to the channelblacklist.', + remove: '[&{username}: ChannelBlacklist] Removed "&{cid}" from the channelblacklist.' } }, skip: { @@ -127,6 +135,10 @@ module.exports = { }, language: { warn: '@&{username}, please have look at our rules. You are speaking the wrong language!' + }, + link:{ + warn: '@&{username}, please stop sending these links.', + mute: '@&{username} didn\'t stop to send links, now he can\'t...' } }, unmute: { @@ -178,6 +190,9 @@ module.exports = { youtubeGuard: { skip: '/me [YouTubeGuard]', api_unreachable: '@staff, I couldn\'t reach YouTube to check the avability of the current song. Please check.', + block:'@&{username}, YouTube is currently blocked in this room.', + block_enabled:'[&{username}: YouTubeBlock enabled]', + block_disabled:'[&{username}: YouTubeBlock disabled]', blocked: { default: '@&{username}, your song "&{song}" was automatically added to the blacklist because it\'s blocked in the following countries: "&{countries}"', bl_reason: 'Blocked in the following countries: &{countries}' @@ -209,12 +224,18 @@ module.exports = { default: '@&{username}, your song "&{song}" was automatically added to the blacklist because it\'s set as not embeddable on plug.dj.', bl_reason: 'Video not embeddable' }, + ytUnavalable:{ + default:'@&{username}, YouTube seems to be unavailable. Your song "&{song}" has therefore be skipped.' + }, enabled: '[&{username}: YouTubeGuard enabled]', disabled: '[&{username}: YouTubeGuard disabled]' }, soundcloudGuard: { skip: '/me [SoundCloudGuard]', api_unreachable: '@staff, I couldn\'t reach SoundCloud to check the avability of the current song. Please check.', + block:'@&{username}, SoundCloud is currently blocked in this room.', + block_enabled:'[&{username}: SoundCloudBlock enabled]', + block_disabled:'[&{username}: SoundCloudBlock disabled]', deleted: { default: '@&{username}, your song "&{song}" was automatically added to the blacklist because it has been deleted.', bl_reason: 'Song was deleted.' @@ -252,7 +273,7 @@ module.exports = { warn_2: '&{usernames} You are still inactive. This is your last warning. Chat or you will be removed from the waitlist.', remove: '&{usernames} You will now be removed from the waitlist for being afk.', kick: '[Kicking @&{username} for autojoining the waitlist]', - usernames: '@&{username}', + usernames: '@&{username} ', afk_msg: { default: '@&{username}, &{user} is AFK [&{msg}]', no_msg: '@&{username}, &{user} is AFK.' @@ -363,10 +384,10 @@ module.exports = { commands: { reload_commands: '[&{username}: Reloaded Commands]' }, - joinmode:{ + joinmode: { addqueue: '[&{username}: Play] You are now in the queue and will be added when a spot is free.', wlban: '[&{username}: Play] You are not allowed to join the waitlist.', - enabled:'[&{username}: Joinmode enabled]', + enabled: '[&{username}: Joinmode enabled]', disabled: '[&{username}: Joinmode disabled]' }, tskip: { @@ -380,5 +401,13 @@ module.exports = { }, clearghosts: { default: '[&{username}: ClearGhosts] We will now be kicking all possible ghost-users out of the room to increase performance for the others. Be sure to have at least used the chat within the 50 hours @everyone' + }, + userfilter:{ + enabled: '[&{username}: UserFilter enabled]', + disabled: '[&{username}: UserFilter disabled]', + username: { + warn: '@&{username}, you name doesn\'t fit the room rules. Please change it or you will be banned within 60 seconds.', + ban: '@&{username} was banned for using a name against the room rules.' + } } }; \ No newline at end of file diff --git a/lib/afk.js b/lib/afk.js index 60b77ba..560e0b5 100644 --- a/lib/afk.js +++ b/lib/afk.js @@ -5,18 +5,110 @@ var moment = require('moment'); var db = require('./db/sql_db'); var langfile = require('../langfile'); var config = require('./load_config'); +var utils = require('./utils'); module.exports = { - cron: new CronJob('0 */10 * * * *', function () { - //todo - }, null, true), + crons: { + afk: new CronJob('0 */10 * * * *', function () { + var promise; + if (config.afk.enabled) { + promise = db.models.User.findAll({where: {afk_level: 'warned2', status: true}}).then(function (users) { + users = users.filter(function (user) { + return utils.wlPosition(user.id) !== -1; + }); + var kicks = []; + var removes = []; + users.forEach(function (user) { + if (user.wl_removes >= config.afk.kick)kicks.push(user); + else removes.push(user); + }); + kicks.forEach(function (user) { + if (user.s_role > 1) { + plugged.sendChat(utils.replace(langfile.afk.kick, {username: user.username})); + plugged.banUser(user.id, plugged.BANDURATION.HOUR, plugged.BANREASON.VIOLATING_COMMUNITY_RULES, function () { + setTimeout(function () { + plugged.unbanUser(user.id); + }, 10000); + }); + } else removes.push(user); + }); + plugged.sendChat(utils.replace(langfile.afk.remove, { + usernames: removes.map(function (user) { + return utils.replace(langfile.afk.usernames, {username: user.username}); + }).join('').trim() + })); + removes.forEach(function (user) { + plugged.removeDJ(user.id); + }); + return db.models.User.findAll({where: {afk_level: 'warned', status: true}}); + }).then(function (users) { + users = users.filter(function (user) { + return utils.wlPosition(user.id) !== -1; + }); + plugged.sendChat(utils.replace(langfile.afk.warn_2, { + username: users.map(function (user) { + return utils.replace(langfile.afk.usernames, {username: user.username}); + }).join('').trim() + })); + return Promise.all(users.map(function (user) { + user.update({afk_level: 'warned2'}); + })).then(function () { + return db.models.User.findAll({where: {afk_level: 'afk', status: true}}); + }); + }).then(function (users) { + users = users.filter(function (user) { + return utils.wlPosition(user.id) !== -1; + }); + plugged.sendChat(utils.replace(langfile.afk.warn_1, { + username: users.map(function (user) { + return utils.replace(langfile.afk.usernames, {username: user.username}); + }).join('').trim() + })); + return Promise.all(users.map(function (user) { + user.update({afk_level: 'warned'}); + })); + }); + } else promise = Promise.resolve(); + promise.then(function () { + return db.models.User.update({afk_level: 'afk'}, { + where: { + status: true, + last_active: {$lt: moment().subtract(config.afk.time, 'seconds').toDate()} + } + }); + }).catch(function (err) { + story.error('AFK-Removal', {attach: err}); + }); + }, null, true), + activestaff: new CronJob('0 */20 * * * *', function () { + var active = 0; + var stafflist = plugged.getStaffOnline(); + + function checkstaff(index) { + if (stafflist[index].role > 1) { + redis.get('user:afk:' + stafflist[index].id).then(function (ex) { + if (ex === 1) { + active = active + 1 + } + if (stafflist[index + 1] !== undefined) checkstaff(index + 1); + else setvar(); + }); + } else if (stafflist[index + 1] !== undefined) checkstaff(index + 1); + else setvar(); + } + + function setvar() { + redis.set('meta:data:staff:active', active); + } + }, null, true) + }, isAfk: function (user) { if (typeof user === 'object') user = user.id; return new Promise(function (resolve, reject) { db.models.User.find({ where: { id: user, - last_active: {$lt: moment().subtract(config.afk.time).toDate()} + last_active: {$lt: moment().subtract(config.afk.time, 'seconds').toDate()} } }).then(function (user) { resolve((user !== null && user !== undefined)); diff --git a/lib/apiConnectors/youTube.js b/lib/apiConnectors/youTube.js index efe3e6b..19e7264 100644 --- a/lib/apiConnectors/youTube.js +++ b/lib/apiConnectors/youTube.js @@ -29,56 +29,76 @@ function checkRegionRestriction(body) { } module.exports = { + getSong: function (media) { + return new Promise(function (resolve, reject) { + request.get('https://www.googleapis.com/youtube/v3/videos?part=contentDetails,status,snippet&id=' + media.cid + '&key=' + config.apiKeys.youtube, function (err, resp, body) { + if (!err) { + if (resp.statusCode === 200) { + body = JSON.parse(body); + if (body.items.length > 0) resolve(body.items[0]); + else reject(new Error('not found')); + } else reject(new Error('Invalid status code')) + } else reject(err) + }); + }); + }, check: function (media) { return new Promise(function (resolve, reject) { request.get('https://www.googleapis.com/youtube/v3/videos?part=contentDetails,status&id=' + media.cid + '&key=' + config.apiKeys.youtube, function (error, resp, body) { - if (!error && resp.statusCode === 200) { - body = JSON.parse(body); - if (body.items.length > 0) { - if (body.items[0] !== undefined) { - if (checkRegionRestriction(body.items[0]) !== false) { - var intersection = checkRegionRestriction(body.items[0]); - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.blocked.default, { - song: utils.mediatitle(media), - countries: intersection.join(' ') - }), - blacklist: utils.replace(langfile.youtubeGuard.blocked.bl_reason, {countries: intersection.join(' ')}) - }]); - } else if (body.items[0].status.uploadStatus === 'deleted') { - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.deleted.default, { - song: utils.mediatitle(media) - }), blacklist: langfile.youtubeGuard.deleted.bl_reason - }]); - } else if (body.items[0].status.uploadStatus === 'rejected') { - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.rejected.default, { - song: utils.mediatitle(media), - reason: langfile.youtubeGuard.rejected.reasons[body.items[0].status.rejectionReason] - }), - blacklist: utils.replace(langfile.youtubeGuard.rejected.bl_reason, {reason: langfile.youtubeGuard.rejected.reasons[body.items[0].status.rejectionReason]}) - }]); - } else if (body.items[0].status.privacyStatus === 'private') { - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.private.default, { - song: utils.mediatitle(media) - }), blacklist: langfile.youtubeGuard.private.bl_reason - }]); - } else if (body.items[0].status.embeddable === false) { - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.embeddable.default, { - song: utils.mediatitle(media) - }), blacklist: langfile.youtubeGuard.embeddable.bl_reason - }]); - } else resolve([false]); + if (!error ) { + if(resp.statusCode ===200){ + body = JSON.parse(body); + if (body.items.length > 0) { + if (body.items[0] !== undefined) { + if (checkRegionRestriction(body.items[0]) !== false) { + var intersection = checkRegionRestriction(body.items[0]); + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.blocked.default, { + song: utils.mediatitle(media), + countries: intersection.join(' ') + }), + blacklist: utils.replace(langfile.youtubeGuard.blocked.bl_reason, {countries: intersection.join(' ')}) + }]); + } else if (body.items[0].status.uploadStatus === 'deleted') { + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.deleted.default, { + song: utils.mediatitle(media) + }), blacklist: langfile.youtubeGuard.deleted.bl_reason + }]); + } else if (body.items[0].status.uploadStatus === 'rejected') { + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.rejected.default, { + song: utils.mediatitle(media), + reason: langfile.youtubeGuard.rejected.reasons[body.items[0].status.rejectionReason] + }), + blacklist: utils.replace(langfile.youtubeGuard.rejected.bl_reason, {reason: langfile.youtubeGuard.rejected.reasons[body.items[0].status.rejectionReason]}) + }]); + } else if (body.items[0].status.privacyStatus === 'private') { + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.private.default, { + song: utils.mediatitle(media) + }), blacklist: langfile.youtubeGuard.private.bl_reason + }]); + } else if (body.items[0].status.embeddable === false) { + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.embeddable.default, { + song: utils.mediatitle(media) + }), blacklist: langfile.youtubeGuard.embeddable.bl_reason + }]); + } else resolve([false]); + } + } else { + resolve([true, { + skip: utils.replace(langfile.youtubeGuard.deleted.default, { + song: utils.mediatitle(media) + }), blacklist: langfile.youtubeGuard.deleted.bl_reason + }]); } - } else { - resolve([true, { - skip: utils.replace(langfile.youtubeGuard.deleted.default, { + } else if(resp.statusCode ===503 ){ + resolve([true,{ + skip: utils.replace(langfile.youtubeGuard.ytUnavailable.default, { song: utils.mediatitle(media) - }), blacklist: langfile.youtubeGuard.deleted.bl_reason - }]); + })}, false]) } } else { reject(new Error('api unreachable')); diff --git a/lib/chatfilters.js b/lib/chatfilters.js index 456c285..4c623c1 100644 --- a/lib/chatfilters.js +++ b/lib/chatfilters.js @@ -48,7 +48,6 @@ module.exports = { strings: strings }, cron: new CronJob('0 1 * * * *', function () { - console.log('exec'); redis.hkeys('spam:user:spampoints').then(function (keys) { return Promise.all(keys.map(function (key) { return redis.hincrby('spam:user:spampoints', key, (0 - config.chatfilter.spam.points)).then(function (point) { diff --git a/lib/chatfilters/links.js b/lib/chatfilters/links.js new file mode 100644 index 0000000..3b976c1 --- /dev/null +++ b/lib/chatfilters/links.js @@ -0,0 +1,47 @@ +var Promise = require('bluebird'); +var URL = require('url'); +var S = require('string'); + +var langfile = require('../../langfile'); +var config = require('../load_config'); + +module.exports = { + name: 'Link', + type: 'link', + enabled: true, + strings: { + warn: langfile.chatfilter.link.warn, + mute: langfile.chatfilter.link.mute + }, + check: function (data) { + return new Promise(function (resolve, reject) { + if (config.chatfilter.enabled) { + var matches = data.message.match(config.chatfilter.links.regex); + if (matches.length === 0) resolve(); + else { + matches = matches.map(function (match) { + return URL.parse(match); + }); + Promise.all(matches.map(function (match) { + return new Promise(function (resolve, reject) { + if (config.chatfilter.links.plugdj.hosts.indexOf(match.hostname) !== -1 && config.chatfilter.links.plugdj.enabled) { + match.pathname = S(match.pathname).chompRight('/').s; + if (config.chatfilter.links.plugdj.allowed_paths.indexOf(match.pathname) === -1) reject({ + type: 'link', + points: 10 + }); + } else if (config.chatfilter.links.mode === 'blacklist' && config.chatfilter.links.filter.indexOf(match.hostname) !== -1) reject({ + type: 'link', + points: 10 + }); + else if (config.chatfilter.links.mode === 'whitelist' && config.chatfilter.links.filter.indexOf(match.hostname) === -1) reject({ + type: 'link', + points: 10 + }); + }); + })).then(resolve).catch(reject); + } + } else resolve(); + }); + } +}; \ No newline at end of file diff --git a/lib/chatfilters/spam.js b/lib/chatfilters/spam.js index fe4a39e..530083d 100644 --- a/lib/chatfilters/spam.js +++ b/lib/chatfilters/spam.js @@ -25,7 +25,7 @@ module.exports = { redis.hkeys('user:spampoints').then(function (keys) { Promise.all(keys.map(function (key) { return redis.hincrby('user:spampoints', key, -60).then(function (p) { - if (p < 0) return redis.hset(key, 0); + if (p < 0) return redis.hset('user:spampoints',key, 0); else return Promise.resolve(); }); })); diff --git a/lib/client.js b/lib/client.js index 24e1e8d..afcf35b 100644 --- a/lib/client.js +++ b/lib/client.js @@ -1,3 +1,4 @@ +var Promise = require('bluebird'); var Plugged = require('plugged'); var story = require('storyboard').mainStory; @@ -25,6 +26,8 @@ var plugged = new Plugged({ } }); +Promise.promisifyAll(plugged,{suffix:'Promise'}); + plugged.login(config.login); module.exports = plugged; \ No newline at end of file diff --git a/lib/commands/add.js b/lib/commands/add.js index 19346cd..fdb0641 100644 --- a/lib/commands/add.js +++ b/lib/commands/add.js @@ -7,6 +7,7 @@ var redis = require('../db/redis_db'); var config = require('../../config'); var utils = require('../utils'); var langfile = require('../../langfile'); +var addqueue = require('../addqueue'); module.exports = { names: ['add', 'addwl'], @@ -32,14 +33,12 @@ module.exports = { plugged.addToWaitlist(user.id, function (err) { if (err)story.error('add', 'Error adding user to the waitlist.', {attach: err}); }); - } else { - redis.zadd('meta:addqueue', 100, user.id).then(function () { - plugged.sendChat(utils.replace(langfile.bp_actions.add_queue, { - username: user.username, - mod: data.username - })); - }); - } + } else addqueue.add(user.id, 100).then(function () { + plugged.sendChat(utils.replace(langfile.bp_actions.add_queue, { + username: user.username, + mod: data.username + })); + }); } } else plugged.sendChat(utils.replace(langfile.error.wl_banned, { username: data.username, diff --git a/lib/commands/channelblacklist.js b/lib/commands/channelblacklist.js new file mode 100644 index 0000000..b54ca3b --- /dev/null +++ b/lib/commands/channelblacklist.js @@ -0,0 +1,68 @@ +var story = require('storyboard').mainStory; +var _ = require('underscore'); + +var db = require('../db/sql_db'); +var redis = require('../db/redis_db'); +var plugged = require('../client'); +var utils = require('../utils'); +var config = require('../load_config'); +var langfile = require('../../langfile'); + +module.exports = { + names: ['channelblacklist', 'cbl'], + enabled: true, + handler: function (data) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (config.options.bouncer_plus ? (perm > 1) : (perm > 2)) { + var split = data.message.split(' '); + if (split.length > 1) { + var cmd = split[1]; + switch (cmd) { + default: + plugged.sendChat(utils.replace(langfile.error.argument, { + username: data.username, + cmd: 'ChannelBlacklist' + }), 20); + break; + case 'toggle': + if (!config.state.eventmode) { + config.blacklist.channelblacklist = !config.blacklist.channelblacklist; + if (config.blacklist.channelblacklist) plugged.sendChat(utils.replace(langfile.blacklist.channelblacklist.enabled, {username: data.username}), 30); + else plugged.sendChat(utils.replace(langfile.blacklist.channelblacklist.disabled, {username: data.username}), 30); + redis.hset('meta:config', 'channelblacklist:enabled', (config.blacklist.channelblacklist ? 1 : 0)); + story.info('ChannelBlacklist', utils.userLogString(data.username, data.id) + ': --> ' + config.blacklist.channelblacklist.toString()); + } else plugged.sendChat(utils.replace(langfile.error.eventmode, { + username: data.username, + cmd: 'ChannelBlacklist' + })); + break; + case 'add': + var r = _.rest(split, 3).join(' ').trim(); + var cid = split[2]; + db.channelblacklist.add(cid, (r.length > 0 ? r : null)).then(function () { + plugged.sendChat(utils.replace(langfile.blacklist.channelblacklist.add, { + username: data.username, + cid: cid + })); + }); + break; + case 'rem': + var cid = split[2]; + db.channelblacklist.remove(cid).then(function () { + plugged.sendChat(utils.replace(langfile.blacklist.channelblacklist.remove, { + username: data.username, + cid: cid + })); + }); + break; + } + } else plugged.sendChat(utils.replace(langfile.error.argument, { + username: data.username, + cmd: 'ChannelBlacklist' + }), 20); + } + }); + plugged.removeChatMessage(data.cid); + } +}; \ No newline at end of file diff --git a/lib/commands/disable.js b/lib/commands/disable.js new file mode 100644 index 0000000..33fe4c3 --- /dev/null +++ b/lib/commands/disable.js @@ -0,0 +1,23 @@ +var plugged = require('../client'); +var redis = require('../db/redis_db'); + +module.exports = { + names: ['disable'], + enabled: true, + handler: function (data) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (perm > 1) { + var split = data.message.split(' '); + if (split.length === 2) { + if (split[1] === 'afk')plugged.sendChat('!afkdisable', 5 * 1000); + else if (split[1] === 'join')plugged.sendChat('!joindisable', 5 * 1000); + } else { + plugged.sendChat('!joindisable', 5 * 1000); + plugged.sendChat('!afkdisable', 5 * 1000); + } + } + }); + plugged.removeChatMessage(data.cid); + } +}; \ No newline at end of file diff --git a/lib/commands/lockskip.js b/lib/commands/lockskip.js index 3c9fe43..148d2b5 100644 --- a/lib/commands/lockskip.js +++ b/lib/commands/lockskip.js @@ -1,4 +1,5 @@ var story = require('storyboard').mainStory; +var Promise = require('bluebird'); var plugged = require('../client'); var redis = require('../db/redis_db'); @@ -10,23 +11,27 @@ module.exports = { names: ['lockskip', 'ls'], enabled: true, handler: function (data) { - redis.hget('user:roles',data.id).then(function (perm) { + redis.hget('user:roles', data.id).then(function (perm) { redis.exists('meta:state:skipable').then(function (ex) { perm = parseInt(perm, 10); if (perm > 1 && ex === 0) { plugged.sendChat(utils.replace(langfile.skip.lockskip, {username: data.username}), 70); var booth = utils.clone(plugged.getBooth()); var media = utils.clone(plugged.getMedia()); - plugged.setLock(true, false); - plugged.setCycle(true); - plugged.skipDJ(booth.dj); - redis.set('meta:state:skipable', 1).then(function () { - redis.expire('meta:state:skipable', 2); - }); - if (booth.shouldCycle !== plugged.doesWaitlistCycle()) plugged.setCycle(booth.shouldCycle); - if (booth.isLocked !== plugged.isWaitlistLocked()) plugged.setLock(booth.isLocked, false); - if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos); - setTimeout(function () { + plugged.setLockPromise(true, false).then(function () { + return plugged.setCyclePromise(true); + }).then(function () { + return plugged.skipDJPromise(booth.dj); + }).then(function () { + if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos); + return Promise.resolve(); + }).then(function () { + if (booth.shouldCycle !== plugged.doesWaitlistCycle()) return plugged.setCyclePromise(booth.shouldCycle); + else Promise.resolve(); + }).then(function () { + if (booth.isLocked !== plugged.isWaitlistLocked()) plugged.setLockPromise(booth.isLocked, false); + else return Promise.resolve(); + }).then(function () { var split = data.message.trim().split(' '); if (langfile.skip.reasons[split[1]] !== undefined) { plugged.sendChat(utils.replace(langfile.skip.reasons[split[1]], { @@ -34,7 +39,9 @@ module.exports = { song: utils.songtitle(media.author, media.title) }), 60); } - }, 4 * 1000); + }).catch(function (err) { + story.error('Error while lockskipping.', {attach: err}); + }); story.info('lockskip', utils.userLogString(data.username, data.id) + ': ' + utils.mediatitlelog(media) + ' played by ' + utils.userLogString(plugged.getUserByID(booth.dj))); } }); diff --git a/lib/commands/reloadroles.js b/lib/commands/reloadroles.js index 33c777c..06a1585 100644 --- a/lib/commands/reloadroles.js +++ b/lib/commands/reloadroles.js @@ -5,26 +5,22 @@ var utils = require('../utils'); var langfile = require('../../langfile'); var db = require("../db/sql_db.js"); -//todo use hash module.exports = { - names:['reloadroles'], - enabled: false, + names: ['reloadroles'], + enabled: true, handler: function (data) { - redis.hget('user:roles',data.id).then(function (perm) { + redis.hget('user:roles', data.id).then(function (perm) { perm = parseInt(perm, 10); if (config.options.bouncer_plus ? (perm > 1) : (perm > 2)) { - plugged.getUsers().forEach(function (user) { - redis.del('user:role:save:' + user.id).then(function () { - db.models.User.find({where: {id: user.id}}).then(function (usr) { - redis.set('user:role:save:' + user.id, usr.s_role); - if (plugged.getUserRole(user.id) > usr.s_role) { - if (usr.s_role === 0) plugged.removeStaff(user.id); - else plugged.addStaff(user.id, usr.s_role); - } - }); - }); + Promise.all(plugged.getChatByUser().map(function (user) { + return db.models.find({where: {id: user.id}}); + })).then(function (users) { + return Promise.all(users.map(function (user) { + return redis.hset('user:roles', user.id, user.s_role); + })); + }).then(function () { + plugged.sendChat(utils.replace(langfile.reloadroles.default, {username: data.username}), 30); }); - plugged.sendChat(utils.replace(langfile.reloadroles.default, {username: data.username}), 30); } }); plugged.removeChatMessage(data.cid); diff --git a/lib/commands/soundcloudblock.js b/lib/commands/soundcloudblock.js new file mode 100644 index 0000000..3c050da --- /dev/null +++ b/lib/commands/soundcloudblock.js @@ -0,0 +1,25 @@ +var story = require('storyboard').mainStory; + +var config = require('../load_config'); +var redis = require('../db/redis_db'); +var utils = require('../utils'); +var plugged = require('../client'); +var langfile = require('../../langfile'); + +module.exports = { + names: ['soundcloudblock', 'scblock'], + enabled: true, + handler: function (data) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (config.options.bouncer_plus ? (perm > 1) : (perm > 2)) { + config.soundcloudGuard.block = !config.soundcloudGuard.block; + if (config.soundcloudGuard.block) plugged.sendChat(utils.replace(langfile.soundcloudGuard.block_enabled, {username: data.username}), 60); + else plugged.sendChat(utils.replace(langfile.soundcloudGuard.block_disabled, {username: data.username}), 60); + redis.hset('meta:config', 'soundcloudguard:block:enabled', (config.soundcloudGuard.block ? 1 : 0)); + story.info('soundcloudblock', utils.userLogString(data.username, data.id) + ': --> ' + config.soundcloudGuard.block.toString()); + } + }); + plugged.removeChatMessage(data.cid); + } +}; \ No newline at end of file diff --git a/lib/commands/youtubeblock.js b/lib/commands/youtubeblock.js new file mode 100644 index 0000000..1ce122c --- /dev/null +++ b/lib/commands/youtubeblock.js @@ -0,0 +1,25 @@ +var story = require('storyboard').mainStory; + +var config = require('../load_config'); +var redis = require('../db/redis_db'); +var utils = require('../utils'); +var plugged = require('../client'); +var langfile = require('../../langfile'); + +module.exports = { + names: ['youtubeblock', 'ytblock'], + enabled: true, + handler: function (data) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (config.options.bouncer_plus ? (perm > 1) : (perm > 2)) { + config.youtubeGuard.block = !config.youtubeGuard.block; + if (config.youtubeGuard.block) plugged.sendChat(utils.replace(langfile.youtubeGuard.block_enabled, {username: data.username}), 60); + else plugged.sendChat(utils.replace(langfile.youtubeGuard.block_disabled, {username: data.username}), 60); + redis.hset('meta:config', 'youtubeguard:block:enabled', (config.youtubeGuard.block ? 1 : 0)); + story.info('youtubeblock', utils.userLogString(data.username, data.id) + ': --> ' + config.youtubeGuard.block.toString()); + } + }); + plugged.removeChatMessage(data.cid); + } +}; \ No newline at end of file diff --git a/lib/db/models/Channel.js b/lib/db/models/Channel.js new file mode 100644 index 0000000..604e17e --- /dev/null +++ b/lib/db/models/Channel.js @@ -0,0 +1,12 @@ +module.exports = function (sequelize, Sequelize) { + return sequelize.define('Song', { + id: {type: Sequelize.INTEGER.UNSIGNED, autoIncrement: true, unique: true}, + name: {type: Sequelize.STRING, allowNull: true}, + cid: {type: Sequelize.STRING(161), allowNull: true, primaryKey: true, unique: true}, + is_banned: {type: Sequelize.BOOLEAN, defaultValue: false}, + ban_reason: {type: Sequelize.TEXT} + }, { + underscored: true, + tableName: 'channels' + }); +}; \ No newline at end of file diff --git a/lib/db/models/User.js b/lib/db/models/User.js index 1b83cf1..03ddc6b 100644 --- a/lib/db/models/User.js +++ b/lib/db/models/User.js @@ -1,4 +1,4 @@ -module.exports = function(sequelize, Sequelize) { +module.exports = function (sequelize, Sequelize) { return sequelize.define("User", { id: {type: Sequelize.INTEGER.UNSIGNED, primaryKey: true, unique: true}, username: {type: Sequelize.STRING, allowNull: false}, @@ -19,6 +19,7 @@ module.exports = function(sequelize, Sequelize) { afk_msg: {type: Sequelize.TEXT, allowNull: true}, last_seen: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, last_active: {type: Sequelize.DATE, defaultValue: Sequelize.NOW}, + afk_level: {type: Sequelize.ENUM('active', 'afk', 'warned', 'warned2'), defaultValue: 'active'}, wl_removes: {type: Sequelize.INTEGER.UNSIGNED, defaultValue: 0} }, { underscored: true, diff --git a/lib/db/sql_db.js b/lib/db/sql_db.js index ef054a7..b6cee29 100644 --- a/lib/db/sql_db.js +++ b/lib/db/sql_db.js @@ -7,7 +7,7 @@ var config = require('../load_config'); var redis = require('./redis_db'); config.sequelize.options.logging = function (toLog) { - story.debug('sql', toLog); + if (config.options.sql_debug)story.debug('sql', toLog); }; var sequelize = new Sequelize(config.sequelize.database, config.sequelize.username, config.sequelize.password, config.sequelize.options); @@ -15,7 +15,8 @@ var models = { User: sequelize.import(path.join(__dirname, 'models', 'User')), Play: sequelize.import(path.join(__dirname, 'models', 'Play')), Song: sequelize.import(path.join(__dirname, 'models', 'Song')), - CustomCommand: sequelize.import(path.join(__dirname, 'models', 'CustomCommand')) + CustomCommand: sequelize.import(path.join(__dirname, 'models', 'CustomCommand')), + Channel: sequelize.import(path.join(__dirname, 'models', 'Channel')) }; models.Play.belongsTo(models.Song); @@ -28,6 +29,25 @@ sequelize.sync(); module.exports = { models: models, sequelize: sequelize, + channelblacklist: { + add: function (cid, reason) { + return models.Channel.upsert({ + cid: cid, + is_banned: true, + ban_reason: (reason !== null && reason !== undefined ? reason : null) + }).then(function () { + return redis.hset('media:blacklist', cid, (reason !== null && reason !== undefined ? reason : '1')) + }) + }, + remove: function (cid) { + return models.Channel.update({ + is_banned: false, + ban_reason: null + }, {where: {cid: cid}}).then(function () { + return redis.hdel('media:channelblacklist', cid); + }); + } + }, blacklist: { add: function (format, cid, reason) { if (typeof format === 'object') { diff --git a/lib/eventhandlers/advance.js b/lib/eventhandlers/advance.js index 15e187d..c5183d9 100644 --- a/lib/eventhandlers/advance.js +++ b/lib/eventhandlers/advance.js @@ -18,109 +18,129 @@ var timeouts = { tskip: null }; -module.exports = function (booth, now, prev) { - booth = utils.clone(booth); - now = utils.clone(now); - prev = utils.clone(prev); - if (booth.dj !== undefined) { - Promise.all(songfilters.map(function (e) { - return e(booth, now); - })).catch(function (error) { - story.debug('SongFilters', '', {attach: error}); - if (plugged.getMedia().id === now.media.id) { - plugged.sendChat(error.preskip); - if (error.do_lockskip) { - //todo fix lockskip - //plugged.setLock(true, false); - //plugged.setCycle(true); - plugged.skipDJ(booth.dj); - //if (booth.shouldCycle !== plugged.doesWaitlistCycle()) plugged.setCycle(false); - //if (booth.isLocked !== plugged.isWaitlistLocked()) plugged.setLock(false, false); - //if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos); - } else plugged.skipDJ(booth.dj); - setTimeout(function () { - plugged.sendChat(error.afterskip); - if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined); - }, 4 * 1000); - } - }); - db.models.Song.findOrCreate({ - where: {cid: now.media.cid, format: now.media.format}, defaults: { - title: now.media.title, - author: now.media.author, - image: now.media.image, - duration: now.media.duration, - format: now.media.format, - plug_id: now.media.id, - cid: now.media.cid - } - }).spread(function (song) { - song.updateAttributes({ - image: now.media.image, - title: now.media.title, - author: now.media.author, - duration: now.media.duration - }); - if (song.autovote !== 'n') { - if (song.autovote === 'w') plugged.woot(); - else if (song.autovote === 'm')plugged.meh(); - } - if (song.tskip !== null && song.tskip !== undefined && !config.state.eventmode) { - plugged.sendChat(utils.replace(langfile.tskip.default, {time: song.tskip}), song.tskip * 1000); - setTimeout(function () { - if (plugged.getMedia().id === now.media.id) { - plugged.sendChat(langfile.tskip.skip, 60 * 1000); +module.exports = { + event: plugged.ADVANCE, + handler: function (booth, now, prev) { + booth = utils.clone(booth); + now = utils.clone(now); + prev = utils.clone(prev); + if (booth.dj !== undefined) { + Promise.all(songfilters.map(function (e) { + return e(booth, now); + })).catch(function (error) { + story.debug('SongFilters', '', {attach: error}); + if (plugged.getMedia().id === now.media.id) { + plugged.sendChat(error.preskip); + if (error.do_lockskip) { + plugged.setLockPromise(true, false).then(function () { + return plugged.setCyclePromise(true); + }).then(function () { + return plugged.skipDJPromise(booth.dj); + }).then(function () { + if (config.lockskip.move_pos !== undefined) plugged.moveDJ(booth.dj, config.lockskip.move_pos); + return Promise.resolve(); + }).then(function () { + if (booth.shouldCycle !== plugged.doesWaitlistCycle()) return plugged.setCyclePromise(booth.shouldCycle); + else Promise.resolve(); + }).then(function () { + if (booth.isLocked !== plugged.isWaitlistLocked()) plugged.setLockPromise(booth.isLocked, false); + else return Promise.resolve(); + }).then(function () { + plugged.sendChat(error.afterskip); + if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined); + }).catch(function (err) { + story.error('Error while lockskipping.', {attach: err}); + }); + } else { plugged.skipDJ(booth.dj); + setTimeout(function () { + plugged.sendChat(error.afterskip); + if (error.blacklist) db.blacklist.add(now.media.format, now.media.cid, error.bl_reason || undefined); + }, 4 * 1000); } - }, song.tskip * 1000); - } - }); - story.info('advance', utils.userLogString(plugged.getUserByID(booth.dj)) + ': ' + utils.mediatitlelog(now.media)); - } else story.info('advance', 'Nobody is playing!'); - clearTimeout(timeouts.stuck); - clearTimeout(timeouts.tskip); - if (booth.dj !== undefined) { - timeouts.stuck = setTimeout(function () { - if (plugged.getMedia().id === now.media.id) { - plugged.sendChat(langfile.skip.stuck.default, 30); - plugged.skipDJ(booth.dj, now.historyID); - } - }, (now.media.duration + 5) * 1000); - } - if (prev.dj !== undefined) { - redis.set('media:history:' + prev.media.format + ':' + prev.media.cid, 1).then(function () { - redis.expire('media:history:' + prev.media.format + ':' + prev.media.cid, config.history.time * 60); - }); - db.models.Play.create({ - time: new Date, - woots: prev.score.positive, - mehs: prev.score.negative, - grabs: prev.score.grabs - }).then(function (play) { - //noinspection JSUnresolvedFunction - play.setSong(prev.media.id); - //noinspection JSUnresolvedFunction - play.setUser(prev.dj.id); + } + }); + db.models.Song.findOrCreate({ + where: {cid: now.media.cid, format: now.media.format}, defaults: { + title: now.media.title, + author: now.media.author, + image: now.media.image, + duration: now.media.duration, + format: now.media.format, + plug_id: now.media.id, + cid: now.media.cid + } + }).spread(function (song) { + song.updateAttributes({ + image: now.media.image, + title: now.media.title, + author: now.media.author, + duration: now.media.duration + }); + if (song.autovote !== 'n') { + if (song.autovote === 'w') plugged.woot(); + else if (song.autovote === 'm')plugged.meh(); + } + if (song.tskip !== null && song.tskip !== undefined && !config.state.eventmode) { + plugged.sendChat(utils.replace(langfile.tskip.default, {time: song.tskip}), song.tskip * 1000); + setTimeout(function () { + if (plugged.getMedia().id === now.media.id) { + plugged.sendChat(langfile.tskip.skip, 60 * 1000); + plugged.skipDJ(booth.dj); + } + }, song.tskip * 1000); + } + }); + story.info('advance', utils.userLogString(plugged.getUserByID(booth.dj)) + ': ' + utils.mediatitlelog(now.media)); + } else story.info('advance', 'Nobody is playing!'); + clearTimeout(timeouts.stuck); + clearTimeout(timeouts.tskip); + if (booth.dj !== undefined) { + timeouts.stuck = setTimeout(function () { + if (plugged.getMedia().id === now.media.id) { + plugged.sendChat(langfile.skip.stuck.default, 30); + plugged.skipDJ(booth.dj, now.historyID); + } + }, (now.media.duration + 5) * 1000); + } + if (prev.dj !== undefined) { + redis.set('media:history:' + prev.media.format + ':' + prev.media.cid, 1).then(function () { + redis.expire('media:history:' + prev.media.format + ':' + prev.media.cid, config.history.time * 60); + }); + db.sequelize.transaction(function (t) { + return db.models.Play.create({ + time: new Date, + woots: prev.score.positive, + mehs: prev.score.negative, + grabs: prev.score.grabs + }, {transaction: t}).then(function (play) { + //noinspection JSUnresolvedFunction + return play.setSong(prev.media.id, {transaction: t}).then(function () { + //noinspection JSUnresolvedFunction + return play.setUser(prev.dj.id, {transaction: t}); + }); + }); + }); + story.info('score', utils.mediatitlelog(prev.media) + ' woots: ' + prev.score.positive + ' | grabs: ' + prev.score.grabs + ' | mehs: ' + prev.score.negative); + } + redis.del('meta:data:rdjskip:votes'); + websocketUpdate({ + m: function () { + if (now.media.id !== -1) { + return { + cid: now.media.format + ':' + now.media.cid, + t: now.media.title, + a: now.media.author + }; + } else return null; + }(), + dj: function () { + if (booth.dj !== -1 && booth.dj !== undefined) { + var u = plugged.getUserByID(booth.dj); + return {id: u.id, n: u.username}; + } else return null; + + }() }); - story.info('score', utils.mediatitlelog(prev.media) + ' woots: ' + prev.score.positive + ' | grabs: ' + prev.score.grabs + ' | mehs: ' + prev.score.negative); } - redis.del('meta:data:rdjskip:votes'); - websocketUpdate({ - m: function () { - if (now.media.id !== -1) { - return { - cid: now.media.format + ':' + now.media.cid, - t: now.media.title, - a: now.media.author - }; - } else return null; - }(), - dj: function () { - if (booth.dj !== -1 && booth.dj !== undefined) { - var u = plugged.getUserByID(booth.dj); - return {id: u.id, n: u.username}; - } else return null; - - }() - }); }; \ No newline at end of file diff --git a/lib/eventhandlers/chat.js b/lib/eventhandlers/chat.js index 98321f7..b3f8573 100644 --- a/lib/eventhandlers/chat.js +++ b/lib/eventhandlers/chat.js @@ -11,99 +11,108 @@ var plugged = require('../client'); var config = require('../load_config'); var cleverbot = require('../cleverbot'); var langfile = require('../../langfile'); +var webSockUpdate = require('../../web/index').wsGet('chat'); var commands = require('../commands'); var customcommands = require('../customcommands'); var chatfilter = require('../chatfilters'); -module.exports = function (data) { - if (data.id !== plugged.getSelf().id) { - if (config.state.lockdown) { - redis.hget('user:roles', data.id).then(function (perm) { - perm = parseInt(perm, 10); - if (perm < 1) plugged.removeChatMessage(data.cid); - else handleAsCommand(); - }); - } else { - //noinspection JSUnresolvedFunction - redis.exists('user:mute:' + data.id).then(function (exm) { - if (exm === 1) { - plugged.removeChatMessage(data.cid); - //noinspection JSUnresolvedFunction - if (!S(data.message).startsWith(config.options.command_prefix)) { - redis.incr('user:mute:' + data.id + ':violation').then(function () { - redis.get('user:mute:' + data.id + ':violation').then(function (val) { - if (parseInt(val, 10) > config.chatfilter.spam.mute_violation) { - plugged.muteUser(data.id, plugged.MUTEDURATION.LONG, plugged.BANREASON.SPAMMING, function (err) { - if (!err)plugged.sendChat(utils.replace(langfile.chatfilter.spam.hard_mute, {username: data.username}), 60); - }); - } - }); - }); - } - } else if (config.chatfilter.enabled) { - redis.hget('user:roles', data.id).then(function (role) { - role = parseInt(role); - if (role < config.chatfilter.ignorerole) { - return Promise.all(chatfilter.filters.map(function (e) { - return e(data); - })); - } else return Promise.resolve(); - }).then(function () { - handleAsCommand(); - }).catch(function (filter) { - story.debug('Chatfilters', '', {attach: filter}); - plugged.deleteMessage(data.cid); - if (filter.points > 0) { - redis.hincrby('spam:user:spampoints', data.id, filter.points).then(function (points) { - if (points > config.chatfilter.spam.points) { - redis.set('user:mute:' + data.id, 1).then(function () { - redis.set('user:mute:' + data.id + ':violation', 0); - redis.expire('user:mute:' + data.id, config.chatfilter.spam.mute_duration); - }); - plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).mute, {username: data.username})); - } else plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).warn, {username: data.username})); +module.exports = { + event: [plugged.CHAT, plugged.CHAT_MENTION], + handler: function (data) { + if (data.id !== plugged.getSelf().id) { + if (config.state.lockdown) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (perm < 1) plugged.removeChatMessage(data.cid); + else handleAsCommand(); + }); + } else { + //noinspection JSUnresolvedFunction + redis.exists('user:mute:' + data.id).then(function (exm) { + if (exm === 1) { + plugged.removeChatMessage(data.cid); + //noinspection JSUnresolvedFunction + if (!S(data.message).startsWith(config.options.command_prefix)) { + redis.incr('user:mute:' + data.id + ':violation').then(function () { + redis.get('user:mute:' + data.id + ':violation').then(function (val) { + if (parseInt(val, 10) > config.chatfilter.spam.mute_violation) { + plugged.muteUser(data.id, plugged.MUTEDURATION.LONG, plugged.BANREASON.SPAMMING, function (err) { + if (!err)plugged.sendChat(utils.replace(langfile.chatfilter.spam.hard_mute, {username: data.username}), 60); + }); + } + }); }); } - }); - } else handleAsCommand(); - }); - } - //noinspection JSUnresolvedFunction - if (!S(data.message).contains('[AFK]')) { - db.models.User.update({last_active: new Date(), wl_removes: 0}, {where: {id: data.id}}); - } - } - story.info('chat', data.username + '[' + data.id + ']: ' + data.message); - - function handleAsCommand() { - //noinspection JSUnresolvedFunction - if (S(data.message).startsWith(config.options.command_prefix)) { + } else if (config.chatfilter.enabled) { + redis.hget('user:roles', data.id).then(function (role) { + role = parseInt(role); + if (role < config.chatfilter.ignorerole) { + return Promise.all(chatfilter.filters.map(function (e) { + return e(data); + })); + } else return Promise.resolve(); + }).then(function () { + handleAsCommand(); + }).catch(function (filter) { + story.debug('Chatfilters', '', {attach: filter}); + plugged.deleteMessage(data.cid); + if (filter.points > 0) { + redis.hincrby('spam:user:spampoints', data.id, filter.points).then(function (points) { + if (points > config.chatfilter.spam.points) { + redis.set('user:mute:' + data.id, 1).then(function () { + redis.set('user:mute:' + data.id + ':violation', 0); + redis.expire('user:mute:' + data.id, config.chatfilter.spam.mute_duration); + }); + plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).mute, {username: data.username})); + } else plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).warn, {username: data.username})); + }); + } + }); + } else handleAsCommand(); + }); + } //noinspection JSUnresolvedFunction - var split = S(data.message).chompLeft(config.options.command_prefix).s.split(' '); - if (commands[split[0].toLowerCase()] !== undefined) { - commands[split[0].toLowerCase()].handler(data); - story.info('command', utils.userLogString(data.username, data.id) + ': ' + split[0] + ' [' + data.message + ']'); + if (!S(data.message).contains('[AFK]')) { + db.models.User.update({ + last_active: new Date(), + wl_removes: 0, + afk_level: 'active' + }, {where: {id: data.id}}); } - } else { + } + story.info('chat', data.username + '[' + data.id + ']: ' + data.message); + webSockUpdate({m: data.message, u: {id: data.id, n: plugged.getUserByID(data.id).username}, cid: data.cid}); + + function handleAsCommand() { //noinspection JSUnresolvedFunction - if (S(data.message).startsWith(config.customcommands.trigger) && config.customcommands.enabled) { + if (S(data.message).startsWith(config.options.command_prefix)) { + //noinspection JSUnresolvedFunction + var split = S(data.message).chompLeft(config.options.command_prefix).s.split(' '); + if (commands[split[0].toLowerCase()] !== undefined) { + commands[split[0].toLowerCase()].handler(data); + story.info('command', utils.userLogString(data.username, data.id) + ': ' + split[0] + ' [' + data.message + ']'); + } + } else { //noinspection JSUnresolvedFunction - var splt = S(data.message).chompLeft(config.customcommands.trigger).s.split(' '); - if (customcommands[splt[0].toLowerCase()] !== undefined) { - customcommands[splt[0].toLowerCase()].handler(data); - story.info('customcommand', utils.userLogString(data.username, data.id) + ': ' + splt[0] + ' [' + data.message + ']'); + if (S(data.message).startsWith(config.customcommands.trigger) && config.customcommands.enabled) { + //noinspection JSUnresolvedFunction + var splt = S(data.message).chompLeft(config.customcommands.trigger).s.split(' '); + if (customcommands[splt[0].toLowerCase()] !== undefined) { + customcommands[splt[0].toLowerCase()].handler(data); + story.info('customcommand', utils.userLogString(data.username, data.id) + ': ' + splt[0] + ' [' + data.message + ']'); + } + sendToCleverbot(); } sendToCleverbot(); } - sendToCleverbot(); } - } - function sendToCleverbot() { - //noinspection JSUnresolvedFunction - if (config.cleverbot.enabled && S(data.message).contains('@' + plugged.getSelf().username)) { - cleverbot(data); + function sendToCleverbot() { + //noinspection JSUnresolvedFunction + if (config.cleverbot.enabled && S(data.message).contains('@' + plugged.getSelf().username)) { + cleverbot(data); + } } } }; diff --git a/lib/eventhandlers/chat_command.js b/lib/eventhandlers/chat_command.js index 7904b66..2544422 100644 --- a/lib/eventhandlers/chat_command.js +++ b/lib/eventhandlers/chat_command.js @@ -9,68 +9,77 @@ var plugged = require('../client'); var config = require('../load_config'); var langfile = require('../../langfile'); var chatfilter = require('../chatfilters'); +var webSockUpdate = require('../../web/index').wsGet('chat'); -module.exports = function (data) { - if (data.id !== plugged.getSelf().id) { - if (config.state.lockdown) { - redis.hget('user:roles',data.id).then(function (perm) { - perm = parseInt(perm, 10); - if (perm < 2) plugged.removeChatMessage(data.cid); - }); - } else if (config.options.disable_emote) { - redis.hget('user:roles',data.id).then(function (perm) { - perm = parseInt(perm, 10); - if (perm < 1) { - plugged.deleteMessage(data.cid); - } - }); - } else { - redis.exists('user:mute:' + data.id).then(function (exm) { - if (exm === 1) { - plugged.removeChatMessage(data.cid); - //noinspection JSUnresolvedFunction - if (!S(data.message).startsWith(config.options.command_prefix)) { - redis.incr('user:mute:' + data.id + ':violation').then(function () { - redis.get('user:mute:' + data.id + ':violation').then(function (val) { - if (parseInt(val, 10) > config.chatfilter.spam.mute_violation) { - plugged.sendChat(utils.replace(langfile.chatfilter.spam.hard_mute, {username: data.username}), 60); - plugged.muteUser(data.id, plugged.MUTEDURATION.LONG, plugged.BANREASON.SPAMMING); - } - }); - }); - } - } - else if (config.chatfilter.enabled) { - redis.hget('user:roles', data.id).then(function (role) { - role = parseInt(role); - if (role < config.chatfilter.ignorerole) { - return Promise.all(chatfilter.filters.map(function (e) { - return e(data); - })); - } else return Promise.resolve(); - }).then(function () { - - }).catch(function (filter) { - story.debug('Chatfilters', '', {attach: filter}); +module.exports = { + event: plugged.CHAT_COMMAND, + handler: function (data) { + if (data.id !== plugged.getSelf().id) { + if (config.state.lockdown) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (perm < 2) plugged.removeChatMessage(data.cid); + }); + } else if (config.options.disable_emote) { + redis.hget('user:roles', data.id).then(function (perm) { + perm = parseInt(perm, 10); + if (perm < 1) { plugged.deleteMessage(data.cid); - if (filter.points > 0) { - redis.hincrby('spam:user:spampoints', data.id, filter.points).then(function (points) { - if (points > config.chatfilter.spam.points) { - redis.set('user:mute:' + data.id, 1).then(function () { - redis.set('user:mute:' + data.id + ':violation', 0); - redis.expire('user:mute:' + data.id, config.chatfilter.spam.mute_duration); - }); - plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).mute, {username: data.username})); - } else plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).warn, {username: data.username})); + } + }); + } else { + redis.exists('user:mute:' + data.id).then(function (exm) { + if (exm === 1) { + plugged.removeChatMessage(data.cid); + //noinspection JSUnresolvedFunction + if (!S(data.message).startsWith(config.options.command_prefix)) { + redis.incr('user:mute:' + data.id + ':violation').then(function () { + redis.get('user:mute:' + data.id + ':violation').then(function (val) { + if (parseInt(val, 10) > config.chatfilter.spam.mute_violation) { + plugged.sendChat(utils.replace(langfile.chatfilter.spam.hard_mute, {username: data.username}), 60); + plugged.muteUser(data.id, plugged.MUTEDURATION.LONG, plugged.BANREASON.SPAMMING); + } + }); }); } - }); - } - }); - } - if (!S(data.message).contains('[AFK]')) { - db.models.User.update({last_active: new Date(), wl_removes: 0},{where: {id: data.id}}); + } + else if (config.chatfilter.enabled) { + redis.hget('user:roles', data.id).then(function (role) { + role = parseInt(role); + if (role < config.chatfilter.ignorerole) { + return Promise.all(chatfilter.filters.map(function (e) { + return e(data); + })); + } else return Promise.resolve(); + }).then(function () { + + }).catch(function (filter) { + story.debug('Chatfilters', '', {attach: filter}); + plugged.deleteMessage(data.cid); + if (filter.points > 0) { + redis.hincrby('spam:user:spampoints', data.id, filter.points).then(function (points) { + if (points > config.chatfilter.spam.points) { + redis.set('user:mute:' + data.id, 1).then(function () { + redis.set('user:mute:' + data.id + ':violation', 0); + redis.expire('user:mute:' + data.id, config.chatfilter.spam.mute_duration); + }); + plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).mute, {username: data.username})); + } else plugged.sendChat(utils.replace(chatfilter.resolveMsg(filter.type).warn, {username: data.username})); + }); + } + }); + } + }); + } + if (!S(data.message).contains('[AFK]')) { + db.models.User.update({ + last_active: new Date(), + wl_removes: 0, + afk_level: 'active' + }, {where: {id: data.id}}); + } } + story.info('chat', data.username + '[' + data.id + ']: ' + data.message); + webSockUpdate({m: data.message, u: {id: data.id, n: plugged.getUserByID(data.id).username}, cid: data.cid}); } - story.info('chat', data.username + '[' + data.id + ']: ' + data.message); }; \ No newline at end of file diff --git a/lib/eventhandlers/chat_delete.js b/lib/eventhandlers/chat_delete.js new file mode 100644 index 0000000..622c0ef --- /dev/null +++ b/lib/eventhandlers/chat_delete.js @@ -0,0 +1,9 @@ +var plugged = require('../client'); +var wsUpdate = require('../../web/index').wsGet('chatDelete'); + +module.exports = { + event: plugged.CHAT_DELETE, + handler: function (del) { + wsUpdate({mod: {id: del.moderatorID, n: plugged.getUserByID(del.moderatorID).username}, cid: del.cid}); + } +}; \ No newline at end of file diff --git a/lib/eventhandlers/conn_error.js b/lib/eventhandlers/conn_error.js index e6dc059..488a094 100644 --- a/lib/eventhandlers/conn_error.js +++ b/lib/eventhandlers/conn_error.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function (err) { - story.error('Error', 'Error while connecting to plug.dj.', {attach: err}); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.CONN_ERROR, + handler: function (err) { + story.error('Error', 'Error while connecting to plug.dj.', {attach: err}); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/conn_part.js b/lib/eventhandlers/conn_part.js index fe336f2..908b5e4 100644 --- a/lib/eventhandlers/conn_part.js +++ b/lib/eventhandlers/conn_part.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function (err) { - story.error('Error', 'The connection dropped unexpectedly', {attach: err}); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.CONN_ERROR, + handler: function (err) { + story.error('Error', 'The connection dropped unexpectedly', {attach: err}); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/conn_success.js b/lib/eventhandlers/conn_success.js index 2008f32..cd6b055 100644 --- a/lib/eventhandlers/conn_success.js +++ b/lib/eventhandlers/conn_success.js @@ -1,5 +1,10 @@ var story = require('storyboard').mainStory; -module.exports = function () { - story.debug('Connection', 'Connection established'); +var plugged = require('../client'); + +module.exports = { + event: plugged.CONN_SUCCESS, + handler: function () { + story.debug('Connection', 'Connection established'); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/conn_warning.js b/lib/eventhandlers/conn_warning.js index 78d476d..ca2978c 100644 --- a/lib/eventhandlers/conn_warning.js +++ b/lib/eventhandlers/conn_warning.js @@ -1,5 +1,10 @@ var story = require('storyboard').mainStory; -module.exports = function (c) { - story.warn('Connection', 'Connection is about to drop. Count: ' + c); +var plugged = require('../client'); + +module.exports = { + event: plugged.CONN_WARNING, + handler: function (c) { + story.warn('Connection', 'Connection is about to drop. Count: ' + c); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/joined_room.js b/lib/eventhandlers/joined_room.js index 9acae13..ea491a1 100644 --- a/lib/eventhandlers/joined_room.js +++ b/lib/eventhandlers/joined_room.js @@ -6,18 +6,28 @@ var plugged = require('../client'); var config = require('../load_config'); var langfile = require('../../langfile'); -module.exports = function () { - story.info('Joined room ' + config.options.room); - redis.hget('meta:options', 'isRestart').then(function (is) { - if (is !== null && is === '1') { - plugged.sendChat(langfile.restart.back_up, 45); - redis.hdel('meta:options', 'isRestart'); - } - }); - plugged.getUsers().forEach(function (user) { - db.models.User.find({where: {id: user.id}}).then(function (usr) { - if (usr !== null && usr !== undefined) { - if (usr.s_role > 0) redis.hset('user:roles', user.id, usr.s_role); +module.exports = { + event: plugged.JOINED_ROOM, + handler: function () { + story.info('Joined room ' + config.options.room); + redis.hget('meta:options', 'isRestart').then(function (is) { + if (is !== null && is === '1') { + plugged.sendChat(langfile.restart.back_up, 45); + redis.hdel('meta:options', 'isRestart'); + } + }); + plugged.getUsers().forEach(function (user) { + db.models.User.findOrCreate({ + where: {id: user.id}, + defaults: { + id: user.id, + username: user.username, + role: user.role, + avatar_id: user.avatarID, + badge: user.badge + } + }).spread(function (usr) { + redis.hset('user:roles', user.id, usr.s_role); if (!usr.super_user && user.role !== usr.s_role) { if (usr.s_role > 0) plugged.addStaff(user.id, usr.s_role); else plugged.removeStaff(user.id); @@ -27,42 +37,27 @@ module.exports = function () { username: user.username, role: user.role }); + }); + }); + + db.models.User.find({where: {id: plugged.getSelf().id}}).then(function (usr) { + if (usr !== null && usr !== undefined) { + if (usr.s_role > 0) redis.hset('user:roles', plugged.getSelf().id, usr.s_role); + usr.updateAttributes({status: true}); } else { db.models.User.create({ - id: user.id, - username: user.username, - slug: user.slug, - role: user.role, - global_role: user.gRole, - badge: user.badge, - language: user.language, - avatar_id: user.avatarID, - blurb: user.blurb + id: plugged.getSelf().id, + username: plugged.getSelf().username, + slug: plugged.getSelf().slug, + role: plugged.getSelf().role, + s_role: plugged.getSelf().role, + global_role: plugged.getSelf().gRole, + badge: plugged.getSelf().badge, + language: plugged.getSelf().language, + avatar_id: plugged.getSelf().avatarID, + blurb: plugged.getSelf().blurb }); } }); - }); - - db.models.User.find({where: {id: plugged.getSelf().id}}).then(function (usr) { - if (usr !== null && usr !== undefined) { - if (usr.s_role > 0) redis.hset('user:roles', plugged.getSelf().id, usr.s_role); - usr.updateAttributes({status: true}); - } else { - db.models.User.create({ - id: plugged.getSelf().id, - username: plugged.getSelf().username, - slug: plugged.getSelf().slug, - role: plugged.getSelf().role, - s_role: plugged.getSelf().role, - global_role: plugged.getSelf().gRole, - badge: plugged.getSelf().badge, - language: plugged.getSelf().language, - avatar_id: plugged.getSelf().avatarID, - blurb: plugged.getSelf().blurb - }); - } - }); - - //todo rework with cron jobs - var workers = require('../workers.js'); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/kill_session.js b/lib/eventhandlers/kill_session.js index 5eaa781..0fb2ab6 100644 --- a/lib/eventhandlers/kill_session.js +++ b/lib/eventhandlers/kill_session.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function (err) { - story.error('Error', 'Session was killed. Restarting...', {attach: err}); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.KILL_SESSION, + handler: function (err) { + story.error('Error', 'Session was killed. Restarting...', {attach: err}); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/login_error.js b/lib/eventhandlers/login_error.js index f29c14f..c4955ae 100644 --- a/lib/eventhandlers/login_error.js +++ b/lib/eventhandlers/login_error.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function (err) { - story.error('Error', 'Error while logging in.', {attach: err}); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.LOGIN_ERROR, + handler: function (err) { + story.error('Error', 'Error while logging in.', {attach: err}); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/login_success.js b/lib/eventhandlers/login_success.js index 6de986a..75ec979 100644 --- a/lib/eventhandlers/login_success.js +++ b/lib/eventhandlers/login_success.js @@ -1,36 +1,44 @@ -var plugged = require('../client'); var story = require('storyboard').mainStory; var Promise = require('bluebird'); +var plugged = require('../client'); var db = require('../db/sql_db'); var redis = require('../db/redis_db'); var config = require('../load_config'); -module.exports = function () { - plugged.cacheChat(true); - plugged.connect(config.options.room); - plugged.getAuthToken(function (err, token) { - if (!err) { - redis.set('meta:auth:save:jar', JSON.stringify(plugged.getJar())).then(function () { - redis.set('meta:auth:save:token', token).then(function () { - redis.expire('meta:auth:save:token', 604800); +module.exports = { + event: plugged.LOGIN_SUCCESS, + handler: function () { + plugged.cacheChat(true); + plugged.connect(config.options.room); + plugged.getAuthToken(function (err, token) { + if (!err) { + redis.set('meta:auth:save:jar', JSON.stringify(plugged.getJar())).then(function () { + redis.set('meta:auth:save:token', token).then(function () { + redis.expire('meta:auth:save:token', 604800); + }); + redis.expire('meta:auth:save:jar', 604800); }); - redis.expire('meta:auth:save:jar', 604800); - }); - } - }); - redis.del('media:blacklist').then(function () { - //noinspection JSUnresolvedFunction - return db.models.Song.findAll({where: {is_banned: true}}); - }).then(function (songs) { - return Promise.all(songs.map(function (song) { - return redis.hset('media:blacklist', song.format + ':' + song.cid, ((song.ban_reason !== undefined && song.ban_reason !== null) ? song.ban_reason : 1)); - })); - }).then(function (songs) { - story.info('Loaded blacklist with ' + songs.length + ' entries.'); - }).catch(function (err) { - story.error('Failed to load blacklist: ', {attach: err}); - }); + } + }); + redis.del('media:blacklist').then(function () { + //noinspection JSUnresolvedFunction + return db.models.Song.findAll({where: {is_banned: true}}); + }).then(function (songs) { + return Promise.all(songs.map(function (song) { + return redis.hset('media:blacklist', song.format + ':' + song.cid, ((song.ban_reason !== undefined && song.ban_reason !== null) ? song.ban_reason : 1)); + })); + }).then(function (songs) { + story.info('Loaded blacklist with ' + songs.length + ' entries.'); + return db.models.Channel.findAll({where: {is_banned: true}}); + }).then(function (channels) { + return Promise.all(channels.map(function (channel) { + redis.hset('media:channelblacklist', channel.cid, (channel.reason !== null ? channel.reason : 1)); + })); + }).catch(function (err) { + story.error('Failed to load blacklist: ', {attach: err}); + }); - story.info('Successfully authed to plug.dj'); + story.info('Successfully authed to plug.dj'); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/maintenance_mode.js b/lib/eventhandlers/maintenance_mode.js index a6669ab..104beb7 100644 --- a/lib/eventhandlers/maintenance_mode.js +++ b/lib/eventhandlers/maintenance_mode.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function () { - story.info('maintenance', 'Plug.dj went into maintenance mode, you may have to restart the bot.'); - throw new Error('Maintenance Mode!'); +var plugged = require('../client'); + +module.exports = { + event: plugged.MAINTENANCE_MODE, + handler: function () { + story.info('maintenance', 'Plug.dj went into maintenance mode, you may have to restart the bot.'); + throw new Error('Maintenance Mode!'); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/mod_add_dj.js b/lib/eventhandlers/mod_add_dj.js index 30f9c6b..47c9472 100644 --- a/lib/eventhandlers/mod_add_dj.js +++ b/lib/eventhandlers/mod_add_dj.js @@ -1,12 +1,14 @@ var story = require('storyboard').mainStory; -var db = require('../db/sql_db'); var utils = require('../utils'); var plugged = require('../client'); var langfile = require('../../langfile'); -module.exports = function (data) { - if (data.mi !== plugged.getSelf.id) { - story.info('add', utils.userLogString(data.m, data.mi) + ' added ' + utils.userLogString(data.username, data.id)); +module.exports = { + event: plugged.MOD_ADD_DJ, + handler: function (data) { + if (data.mi !== plugged.getSelf.id) { + story.info('add', utils.userLogString(data.m, data.mi) + ' added ' + utils.userLogString(data.username, data.id)); + } } }; \ No newline at end of file diff --git a/lib/eventhandlers/mod_ban.js b/lib/eventhandlers/mod_ban.js index 00aecc2..f9f75e8 100644 --- a/lib/eventhandlers/mod_ban.js +++ b/lib/eventhandlers/mod_ban.js @@ -7,34 +7,37 @@ var plugged = require('../client'); var langfile = require('../../langfile'); var wsBan = require('../../web/index').wsGet('userbane'); -module.exports = function (data) { - if (data.moderatorID !== plugged.getSelf().id) { - redis.get('user:role:save:' + data.moderatorID).then(function (perm) { - perm = parseInt(perm, 10); - if (perm < 2 && data.duration === plugged.BANDURATION.PERMA) { - plugged.sendChat(utils.replace(langfile.ban.no_staff_ban, {username: data.moderator}), 60); - plugged.unbanUser(data.id); - plugged.banUser(data.id, plugged.BANDURATION.DAY, plugged.BANREASON.VIOLATING_COMMUNITY_RULES); - plugged.removeStaff(data.moderatorID); - } else { - redis.hget('user:roles', data.id).then(function (plvl) { - plvl = parseInt(plvl, 10); - if (plvl > 1) { - plugged.sendChat(utils.replace(langfile.ban.staff_ban, {username: data.moderator}), 60); - plugged.unbanUser(data.id); - plugged.removeStaff(data.moderatorID); - } - }); - } - }); - story.info('ban', utils.userLogString(data.moderator, data.moderatorID) + ': ' + data.username + ' --> ' + data.duration); - wsBan({ - m: {id: moderatorID, n: data.moderator}, - u: function () { - var u = plugged.getUserByName(data.username, true); - return (u !== undefined ? {id: u.id, n: u.username} : {n: username}); - }(), - d: data.duration - }); +module.exports = { + event: plugged.MOD_BAN, + handler: function (data) { + if (data.moderatorID !== plugged.getSelf().id) { + redis.get('user:role:save:' + data.moderatorID).then(function (perm) { + perm = parseInt(perm, 10); + if (perm < 2 && data.duration === plugged.BANDURATION.PERMA) { + plugged.sendChat(utils.replace(langfile.ban.no_staff_ban, {username: data.moderator}), 60); + plugged.unbanUser(data.id); + plugged.banUser(data.id, plugged.BANDURATION.DAY, plugged.BANREASON.VIOLATING_COMMUNITY_RULES); + plugged.removeStaff(data.moderatorID); + } else { + redis.hget('user:roles', data.id).then(function (plvl) { + plvl = parseInt(plvl, 10); + if (plvl > 1) { + plugged.sendChat(utils.replace(langfile.ban.staff_ban, {username: data.moderator}), 60); + plugged.unbanUser(data.id); + plugged.removeStaff(data.moderatorID); + } + }); + } + }); + story.info('ban', utils.userLogString(data.moderator, data.moderatorID) + ': ' + data.username + ' --> ' + data.duration); + wsBan({ + m: {id: moderatorID, n: data.moderator}, + u: function () { + var u = plugged.getUserByName(data.username, true); + return (u !== undefined ? {id: u.id, n: u.username} : {n: username}); + }(), + d: data.duration + }); + } } }; \ No newline at end of file diff --git a/lib/eventhandlers/mod_skip.js b/lib/eventhandlers/mod_skip.js index 2da1e88..e39ba50 100644 --- a/lib/eventhandlers/mod_skip.js +++ b/lib/eventhandlers/mod_skip.js @@ -7,17 +7,20 @@ var plugged = require('../client'); var langfile = require('../../langfile'); var wsSkip = require('../../web/index').wsGet('skip'); -module.exports = function (data) { - if (data.moderatorID !== plugged.getSelf().id) { - story.info('skip', utils.userLogString(data.moderator, data.moderatorID)); - //noinspection JSUnresolvedVariable - redis.get('user:role:save:' + data.mi).then(function (perm) { - perm = parseInt(perm, 10); - if (perm < 2) { - plugged.sendChat(utils.replace(langfile.skip.no_mod_skip, {username: data.moderator})); - plugged.removeStaff(data.moderatorID); - } - }); +module.exports = { + event: plugged.MOD_SKIP, + handler: function (data) { + if (data.moderatorID !== plugged.getSelf().id) { + story.info('skip', utils.userLogString(data.moderator, data.moderatorID)); + //noinspection JSUnresolvedVariable + redis.get('user:role:save:' + data.mi).then(function (perm) { + perm = parseInt(perm, 10); + if (perm < 2) { + plugged.sendChat(utils.replace(langfile.skip.no_mod_skip, {username: data.moderator})); + plugged.removeStaff(data.moderatorID); + } + }); + } + wsSkip({m: {id: data.moderatorID, n: data.moderator}}); } - wsSkip({m: {id: data.moderatorID, n: data.moderator}}); }; \ No newline at end of file diff --git a/lib/eventhandlers/mod_staff.js b/lib/eventhandlers/mod_staff.js index 5daa697..37e9f5e 100644 --- a/lib/eventhandlers/mod_staff.js +++ b/lib/eventhandlers/mod_staff.js @@ -6,24 +6,27 @@ var utils = require('../utils'); var plugged = require('../client'); var langfile = require('../../langfile'); -module.exports = function (data) { - data = data[0]; - if (data.moderatorID !== plugged.getSelf().id) { - redis.get('user:role:save:' + data.moderatorID).then(function (perm) { - perm = parseInt(perm, 10); - if (perm > 2) { - redis.set('user:role:save:' + data.id, data.role); - db.models.User.update({s_role: data.role}, {where: {id: data.id}}); - } else { - redis.hget('user:roles', data.id).then(function (permlvl) { - permlvl = parseInt(permlvl, 10); - var role = utils.role(permlvl); - if (role === plugged.USERROLE.NONE) plugged.removeStaff(data.id); - else plugged.addStaff(data.id, role); - plugged.sendChat(utils.replace(langfile.setstaff.no_power, {username: data.moderator}), 60); - }); - } - }); - story.info('promote', utils.userLogString(data.moderator, data.moderatorID) + ': ' + utils.userLogString(data.username, data.id) + ' --> ' + utils.rolename(data.role)); +module.exports = { + event: plugged.MOD_STAFF, + handler: function (data) { + data = data[0]; + if (data.moderatorID !== plugged.getSelf().id) { + redis.get('user:role:save:' + data.moderatorID).then(function (perm) { + perm = parseInt(perm, 10); + if (perm > 2) { + redis.set('user:role:save:' + data.id, data.role); + db.models.User.update({s_role: data.role}, {where: {id: data.id}}); + } else { + redis.hget('user:roles', data.id).then(function (permlvl) { + permlvl = parseInt(permlvl, 10); + var role = utils.role(permlvl); + if (role === plugged.USERROLE.NONE) plugged.removeStaff(data.id); + else plugged.addStaff(data.id, role); + plugged.sendChat(utils.replace(langfile.setstaff.no_power, {username: data.moderator}), 60); + }); + } + }); + story.info('promote', utils.userLogString(data.moderator, data.moderatorID) + ': ' + utils.userLogString(data.username, data.id) + ' --> ' + utils.rolename(data.role)); + } } }; \ No newline at end of file diff --git a/lib/eventhandlers/plug_error.js b/lib/eventhandlers/plug_error.js index 542771a..386a06b 100644 --- a/lib/eventhandlers/plug_error.js +++ b/lib/eventhandlers/plug_error.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function (err) { - story.error('Error', 'plug.dj encountered an error.', {attach: err}); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.PLUG_ERROR, + handler: function (err) { + story.error('Error', 'plug.dj encountered an error.', {attach: err}); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/plug_message.js b/lib/eventhandlers/plug_message.js index 85d5b06..e05f1d0 100644 --- a/lib/eventhandlers/plug_message.js +++ b/lib/eventhandlers/plug_message.js @@ -1,5 +1,10 @@ var story = require('storyboard').mainStory; -module.exports = function (msg) { - story.info('plug', msg); +var plugged = require('../client'); + +module.exports = { + event: plugged.PLUG_MESSAGE, + handler: function (msg) { + story.info('plug', msg); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/plug_update.js b/lib/eventhandlers/plug_update.js index d8126e6..0547cec 100644 --- a/lib/eventhandlers/plug_update.js +++ b/lib/eventhandlers/plug_update.js @@ -1,6 +1,11 @@ var story = require('storyboard').mainStory; -module.exports = function () { - story.error('Update', 'plug.dj gets an update was therefore closed.'); - process.exit(1); +var plugged = require('../client'); + +module.exports = { + event: plugged.PLUG_UPDATE, + handler: function () { + story.error('Update', 'plug.dj gets an update was therefore closed.'); + process.exit(1); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/sock_closed.js b/lib/eventhandlers/sock_closed.js new file mode 100644 index 0000000..644753c --- /dev/null +++ b/lib/eventhandlers/sock_closed.js @@ -0,0 +1,11 @@ +var story = require('storyboard').mainStory; + +var plugged = require('../client'); + +module.exports = { + event: plugged.SOCK_CLOSED, + handler: function () { + story.info('Socket', 'Socket was closed. Restarting...'); + process.exit(1); + } +}; \ No newline at end of file diff --git a/lib/eventhandlers/sock_error.js b/lib/eventhandlers/sock_error.js new file mode 100644 index 0000000..fd7ad6b --- /dev/null +++ b/lib/eventhandlers/sock_error.js @@ -0,0 +1,11 @@ +var story = require('storyboard').mainStory; + +var plugged = require('../client'); + +module.exports = { + event: plugged.SOCK_ERROR, + handler: function () { + story.error('Socket', 'Socket errored. Restarting...'); + process.exit(1); + } +}; \ No newline at end of file diff --git a/lib/eventhandlers/user_join.js b/lib/eventhandlers/user_join.js index 2766d39..6c02d93 100644 --- a/lib/eventhandlers/user_join.js +++ b/lib/eventhandlers/user_join.js @@ -8,88 +8,110 @@ var plugged = require('../client'); var config = require('../load_config'); var langfile = require('../../langfile'); var addqueue = require('../addqueue'); +var userfilters = require('../userfilters').filters; +var wsUpdate = require('../../web/index').wsGet('join'); -module.exports = function (user) { - var greetStr = '&{welcome} &{dcmoveback}'; - var moveAction = function () { +module.exports = { + event: [plugged.USER_JOIN, plugged.FRIEND_JOIN], + handler: function (user) { + if (user.id !== plugged.getSelf().id) { + var greetStr = '&{welcome} &{dcmoveback}'; + var greet = false; + var sendit = false; + var moveAction = function () { - }; - redis.set('user:afk:' + user.id, 1).then(function () { - redis.expire('user:afk:' + user.id, config.afk.time); - }); - Promise.resolve().then(function () { - if (config.dcmoveback.enabled && config.dcmoveback.auto && !config.state.eventmode) { - return redis.get('user:disconnect:' + user.id).then(function (pos) { - if (pos !== null) { - pos = parseInt(pos); - if (pos !== -1 && pos > utils.wlPosition(user)) { - if ((plugged.getWaitlist() === undefined || plugged.getWaitlist().length < 50)) { - moveAction = function () { - if (utils.wlPosition(user) === -1) plugged.addToWaitlist(user.id); - plugged.moveDJ(user.id, pos); - redis.del('user:disconnect:' + user.id); - }; - greetStr = utils.replace(greetStr, {dcmoveback: utils.replace(langfile.dcmoveback.move, {pos: (pos + 1).toString()})}); - return Promise.resolve(); - } else { - return addqueue.add(user.id, pos).then(function () { - greetStr = utils.replace(greetStr, {dcmoveback: utils.replace(langfile.dcmoveback.addqueue, {pos: (pos + 1).toString()})}); + }; + redis.set('user:afk:' + user.id, 1).then(function () { + redis.expire('user:afk:' + user.id, config.afk.time); + }); + Promise.resolve().then(function () { + if (config.dcmoveback.enabled && config.dcmoveback.auto && !config.state.eventmode) { + return redis.get('user:disconnect:' + user.id).then(function (pos) { + if (pos !== null) { + pos = parseInt(pos); + if (pos !== -1 && pos > utils.wlPosition(user)) { + if ((plugged.getWaitlist() === undefined || plugged.getWaitlist().length < 50)) { + moveAction = function () { + if (utils.wlPosition(user) === -1) plugged.addToWaitlist(user.id); + plugged.moveDJ(user.id, pos); + redis.del('user:disconnect:' + user.id); + }; + greetStr = utils.replace(greetStr, {dcmoveback: utils.replace(langfile.dcmoveback.move, {pos: (pos + 1).toString()})}); + sendit = true; + return Promise.resolve(); + } else { + return addqueue.add(user.id, pos).then(function () { + greetStr = utils.replace(greetStr, {dcmoveback: utils.replace(langfile.dcmoveback.addqueue, {pos: (pos + 1).toString()})}); + sendit = true; + return redis.del('user:disconnect:' + user.id); + }); + } + } else { + greetStr = utils.replace(greetStr, {dcmoveback: ''}).trim(); return redis.del('user:disconnect:' + user.id); - }); + } + } else { + greetStr = utils.replace(greetStr, {dcmoveback: ''}).trim(); + return redis.del('user:disconnect:' + user.id); } - } else { - greetStr = utils.replace(greetStr, {dcmoveback: ''}).trim(); - return redis.del('user:disconnect:' + user.id); - } + }); } else { greetStr = utils.replace(greetStr, {dcmoveback: ''}).trim(); - return redis.del('user:disconnect:' + user.id); + return Promise.resolve(); } + }).then(function () { + return db.models.User.find({where: {id: user.id}}).then(function (usr) { + if (usr !== null && usr !== undefined) { + if (usr.s_role > 0) redis.hset('user:roles', user.id, usr.s_role); + if (!usr.super_user && user.role !== usr.s_role) { + if (usr.s_role > 0) plugged.addStaff(user.id, usr.s_role); + else plugged.removeStaff(user.id); + } + if (config.options.welcome.old) { + greet = true; + greetStr = utils.replace(greetStr, {welcome: utils.replace(langfile.welcome.old, {username: user.username})}); + sendit = true; + } else { + greetStr = utils.replace(greetStr, {welcome: ''}).trim(); + } + return usr.updateAttributes({status: true, slug: user.slug, username: user.username}); + } else { + if (config.options.welcome.old) { + greet = true; + greetStr = utils.replace(greetStr, {welcome: utils.replace(langfile.welcome.new, {username: user.username})}); + sendit = true; + } else { + greetStr = utils.replace(greetStr, {welcome: ''}).trim(); + } + return db.models.User.create({ + id: user.id, + username: user.username, + slug: user.slug, + role: user.role, + global_role: user.gRole, + badge: user.badge, + language: user.language, + avatar_id: user.avatarID, + blurb: user.blurb + }); + } + }); + }).then(function () { + Promise.all(userfilters.map(function (f) { + return f(user); + })).then(function () { + setTimeout(function () { + if(sendit){ + plugged.sendChat((greet ? '' : '@' + user.username + ' ') + greetStr.trim()); + } + moveAction(); + }, 4 * 1000); + }).catch(function (filter) { + + }); }); - } else { - greetStr = utils.replace(greetStr, {dcmoveback: ''}).trim(); - return Promise.resolve(); + story.info('join', utils.userLogString(user)); + wsUpdate({id:user.id,n:user.username}); } - }).then(function () { - return db.models.User.find({where: {id: user.id}}).then(function (usr) { - if (usr !== null && usr !== undefined) { - if (usr.s_role > 0) redis.hset('user:roles', user.id, usr.s_role); - if (!usr.super_user && user.role !== usr.s_role) { - if (usr.s_role > 0) plugged.addStaff(user.id, usr.s_role); - else plugged.removeStaff(user.id); - } - usr.updateAttributes({status: true, slug: user.slug, username: user.username}); - if (config.options.welcome.old) { - greetStr = utils.replace(greetStr, {welcome: utils.replace(langfile.welcome.old, {username: user.username})}); - } else { - greetStr = utils.replace(greetStr, {welcome: ''}).trim(); - } - return Promise.resolve(); - } else { - if (config.options.welcome.old) { - greetStr = utils.replace(greetStr, {welcome: utils.replace(langfile.welcome.new, {username: user.username})}); - } else { - greetStr = utils.replace(greetStr, {welcome: ''}).trim(); - } - db.models.User.create({ - id: user.id, - username: user.username, - slug: user.slug, - role: user.role, - global_role: user.gRole, - badge: user.badge, - language: user.language, - avatar_id: user.avatarID, - blurb: user.blurb - }); - return Promise.resolve(); - } - }); - }).then(function () { - setTimeout(function () { - plugged.sendChat(greetStr.trim()); - moveAction(); - }, 4 * 1000); - }); - story.info('join', utils.userLogString(user)); + } }; \ No newline at end of file diff --git a/lib/eventhandlers/user_leave.js b/lib/eventhandlers/user_leave.js index 82a73a7..503d4fe 100644 --- a/lib/eventhandlers/user_leave.js +++ b/lib/eventhandlers/user_leave.js @@ -6,19 +6,25 @@ var utils = require('../utils'); var langfile = require('../../langfile'); var redis = require('../db/redis_db'); var config = require('../load_config'); +var plugged = require('../client'); +var wsUpdate = require('../../web/index').wsGet('leave'); -module.exports = function (user) { - if (user !== null && user !== undefined) { - redis.hget('user:waitlist:lastposition', user.id).then(function (pos) { - pos = parseInt(pos); - if(pos !== -1){ - return redis.set('user:disconnect:' + user.id, pos).then(function () { - return redis.expire ('user:disconnect:' + user.id, config.dcmoveback.timeout); - }); - } else return Promise.resolve(); - }).then(function () { - return db.models.User.update({status: false}, {where: {id: user.id}}); - }); - story.info('leave', utils.userLogString(user)); +module.exports = { + event: plugged.USER_LEAVE, + handler: function (user) { + if (user !== null && user !== undefined) { + redis.hget('user:waitlist:lastposition', user.id).then(function (pos) { + pos = parseInt(pos); + if (pos !== -1) { + return redis.set('user:disconnect:' + user.id, pos).then(function () { + return redis.expire('user:disconnect:' + user.id, config.dcmoveback.timeout); + }); + } else return Promise.resolve(); + }).then(function () { + return db.models.User.update({status: false}, {where: {id: user.id}}); + }); + story.info('leave', utils.userLogString(user)); + wsUpdate({id: user.id, n: user.username}); + } } }; \ No newline at end of file diff --git a/lib/eventhandlers/userupdate.js b/lib/eventhandlers/userupdate.js new file mode 100644 index 0000000..e86eba3 --- /dev/null +++ b/lib/eventhandlers/userupdate.js @@ -0,0 +1,25 @@ +var Promise = require('bluebird'); + +var plugged = require('../client'); +var db = require('../db/redis_db'); +var userfilters = require('../userfilters'); + +module.exports = { + event: plugged.USER_UPDATE, + handler: function (data) { + if (data.level !== undefined) db.models.User.update({level: data.level}, {where: {id: data.id}}); + else if (data.avatarID !== undefined) db.models.User.update({avatar_id: data.avatarID}, {where: {id: data.id}}); + else if (data.username !== undefined) { + var user = plugged.getUserByID(data.id); + user.username = data.username; + Promise.all(userfilters.map(function (e) { + return e(user); + })).then(function () { + if (userfilters.timeouts[data.id] !== undefined)clearTimeout(userfilters.timeouts[data.id]); + }).catch(function (filter) { + plugged.sendChat(filter.chat); + if (userfilters.timeouts[data.id] === undefined) filter.action(); + }); + } + } +}; \ No newline at end of file diff --git a/lib/eventhandlers/vote.js b/lib/eventhandlers/vote.js index 79f68ee..00d3ff8 100644 --- a/lib/eventhandlers/vote.js +++ b/lib/eventhandlers/vote.js @@ -2,38 +2,43 @@ var utils = require('../utils'); var plugged = require('../client'); var config = require('../load_config'); var langfile = require('../../langfile'); +var wsUpdate = require('../../web/index').wsGet('vote'); -module.exports = function () { - var score = {woots: 0, mehs: 0, userCount: plugged.getUsers().length}; - plugged.getVotes(false).forEach(function (vote) { - if (vote.direction === 1) score.woots = score.woots + 1; - else if (vote.direction === -1) score.mehs = score.mehs - 1; - }); - if (function () { - switch (typeof config.voteskip.condition) { - default: - return false; - break; - case 'number': - if (score.mehs >= config.voteskip.condition) return true; - break; - case 'function': - if (config.voteskip.condition(score)) return true; - break; - case 'object': - if (config.voteskip.condition.max <= score.mehs) return true; - else if (config.voteskip.condition.min <= score.mehs)return ((score.mehs / score.userCount) >= config.voteskip.condition.ratio); - else return false; - break; - } - }() && config.voteskip.enabled && !config.state.eventmode) { - plugged.sendChat(langfile.skip.vote.skip); - plugged.skipDJ(plugged.getCurrentDJ().id); - setTimeout(function () { - plugged.sendChat(utils.replace(langfile.skip.vote.default, { - username: plugged.getCurrentDJ(), - song: utils.mediatitle(plugged.getMedia()) - }), 60); - }, 4 * 1000); +module.exports = { + event: plugged.VOTE, + handler: function (vote) { + var score = {woots: 0, mehs: 0, userCount: plugged.getUsers().length}; + plugged.getVotes(false).forEach(function (vote) { + if (vote.direction === 1) score.woots = score.woots + 1; + else if (vote.direction === -1) score.mehs = score.mehs - 1; + }); + if (function () { + switch (typeof config.voteskip.condition) { + default: + return false; + break; + case 'number': + if (score.mehs >= config.voteskip.condition) return true; + break; + case 'function': + if (config.voteskip.condition(score)) return true; + break; + case 'object': + if (config.voteskip.condition.max <= score.mehs) return true; + else if (config.voteskip.condition.min <= score.mehs)return ((score.mehs / score.userCount) >= config.voteskip.condition.ratio); + else return false; + break; + } + }() && config.voteskip.enabled && !config.state.eventmode) { + plugged.sendChat(langfile.skip.vote.skip); + plugged.skipDJ(plugged.getCurrentDJ().id); + setTimeout(function () { + plugged.sendChat(utils.replace(langfile.skip.vote.default, { + username: plugged.getCurrentDJ(), + song: utils.mediatitle(plugged.getMedia()) + }), 60); + }, 4 * 1000); + } + wsUpdate({s: score, v: {dir: vote.direction, u: {id: vote.id, n: plugged.getUserByID(vote.id).username}}}); } }; \ No newline at end of file diff --git a/lib/eventhandlers/waitlist_update.js b/lib/eventhandlers/waitlist_update.js index 3e6ec18..64f5154 100644 --- a/lib/eventhandlers/waitlist_update.js +++ b/lib/eventhandlers/waitlist_update.js @@ -7,26 +7,33 @@ var utils = require('../utils'); var plugged = require('../client'); var langfile = require('../../langfile'); var addQueue = require('../addqueue'); +var wsUpdate = require('../../web/index').wsGet('waitlist'); -module.exports = function (oldWaitlist, newWaitlist) { - oldWaitlist = utils.clone(oldWaitlist); - newWaitlist = utils.clone(newWaitlist); - setTimeout(function () { - Promise.all(plugged.getUsers().map(function (user) { - return redis.hset('user:waitlist:lastposition', user.id, utils.wlPosition(user, newWaitlist)); - })).then(function () { - return Promise.all(newWaitlist.map(function (id) { - return redis.exists('user:waitlist:ban:' + id).then(function (ex) { - if (ex === 1) { - plugged.sendChat(utils.replace(langfile.wlban.remove, {username: plugged.getUserByID(id).username})); - plugged.removeDJ(id); - story.info('waitlist', utils.userLogString(plugged.getUserByID(id)) + ' joined the waitlist but is banned from the waitlist.'); - return redis.hdel('user:waitlist:lastposition', id); - } else return Promise.resolve(); - }); - })); - }).then(function () { - addQueue.wlUpdate(plugged.getWaitlist()); - }); - }, 1000); +module.exports = { + event: plugged.WAITLIST_UPDATE, + handler: function (oldWaitlist, newWaitlist) { + oldWaitlist = utils.clone(oldWaitlist); + newWaitlist = utils.clone(newWaitlist); + setTimeout(function () { + Promise.all(plugged.getUsers().map(function (user) { + return redis.hset('user:waitlist:lastposition', user.id, utils.wlPosition(user, newWaitlist)); + })).then(function () { + return Promise.all(newWaitlist.map(function (id) { + return redis.exists('user:waitlist:ban:' + id).then(function (ex) { + if (ex === 1) { + plugged.sendChat(utils.replace(langfile.wlban.remove, {username: plugged.getUserByID(id).username})); + plugged.removeDJ(id); + story.info('waitlist', utils.userLogString(plugged.getUserByID(id)) + ' joined the waitlist but is banned from the waitlist.'); + return redis.hdel('user:waitlist:lastposition', id); + } else return Promise.resolve(); + }); + })); + }).then(function () { + addQueue.wlUpdate(plugged.getWaitlist()); + }); + }, 1000); + wsUpdate(newWaitlist.map(function (id) { + return {id: id, n: plugged.getUserByID(id).username} + })); + } }; \ No newline at end of file diff --git a/lib/load_config.js b/lib/load_config.js index 1bae5e9..20f4b31 100644 --- a/lib/load_config.js +++ b/lib/load_config.js @@ -146,7 +146,31 @@ if (conf.apiKeys.youtube === '' || conf.apiKeys.soundcloud === '') { conf.options.joinmode = val === '1'; load('joinmode', conf.options.joinmode); }); - } else load('joimode', 'not stored'); + } else load('joinmode', 'not stored'); + }), + redis.hexists('meta:config', 'channelblacklist:enabled').then(function (ex) { + if (ex === 1) { + redis.hget('meta:config', 'channelblacklist:enabled').then(function (val) { + conf.blacklist.channelblacklist = val === '1'; + load('ChannelBlacklist', conf.blacklist.channelblacklist); + }); + } else load('ChannelBlacklist', 'not stored'); + }), + redis.hexists('meta:config', 'youtube:block:enabled').then(function (ex) { + if (ex === 1) { + redis.hget('meta:config', 'youtubeguard:block:enabled').then(function (val) { + conf.youtubeGuard.block = val === '1'; + load('YouTubeBlock', conf.youtubeGuard.block); + }); + } else load('YouTubeBlock', 'not stored'); + }), + redis.hexists('meta:config', 'soundcloud:block:enabled').then(function (ex) { + if (ex === 1) { + redis.hget('meta:config', 'soundcloudguard:block:enabled').then(function (val) { + conf.soundcloudGuard.block = val === '1'; + load('SoundCloudBlock', conf.soundcloudGuard.block); + }); + } else load('SoundCloudBlock', 'not stored'); }), redis.hexists('meta:config', 'titleguard:enabled').then(function (ex) { if (ex === 1) { diff --git a/lib/songfilters.js b/lib/songfilters.js index 862da87..50cf3da 100644 --- a/lib/songfilters.js +++ b/lib/songfilters.js @@ -21,10 +21,10 @@ function loadsongfilters() { var filter = require(path.resolve(__dirname, 'songfilters', file)); if (filter.enabled) { songfilters.push(filter.check); - story.debug('SongFilters', 'Loaded chatfilter ' + filter.name); + story.debug('SongFilters', 'Loaded singfilter ' + filter.name); } else story.debug('SongFilters', 'Skipping ' + filter.name + ' since it\'s disabled.'); } catch (e) { - story.warn('SongFilters', 'Failed to load chatfilter.', {attach: e}); + story.warn('SongFilters', 'Failed to load songfilter.', {attach: e}); } }); } diff --git a/lib/songfilters/channelblacklist.js b/lib/songfilters/channelblacklist.js new file mode 100644 index 0000000..50c3a1b --- /dev/null +++ b/lib/songfilters/channelblacklist.js @@ -0,0 +1,54 @@ +var Promise = require('bluebird'); +var story = require('storyboard').mainStory; + +var redis = require('../db/redis_db'); +var ytApi = require('../apiConnectors/youTube'); +var langfile = require('../../langfile'); +var config = require('../load_config'); +var utils = require('../utils'); +var plugged = require('../client'); +var db = require('../db/sql_db'); + +module.exports = { + name: 'ChannelBlacklist', + enabled: true, + check: function (booth, now) { + return new Promise(function (resolve, reject) { + if (config.blacklist.channelblacklist && !config.state.eventmode && now.media.format === 1) { + ytApi.getSong(now.media).then(function (media) { + redis.hget('media:channelblacklist', media.snippet.channelId).then(function (bl) { + if (bl === null) { + resolve(); + } else { + if (bl === '1') reject({ + type: 'channelblacklist', + preskip: langfile.blacklist.skip_first, + afterskip: utils.replace(langfile.blacklist.channelblacklist.skip, { + username: plugged.getUserByID(booth.dj).username, + song: utils.songtitle(now.media.author, now.media.title) + }), + do_lockskip: config.blacklist.lockskip, + blacklist: false + }); + else reject({ + type: 'channelblacklist', + preskip: langfile.blacklist.skip_first, + afterskip: utils.replace(langfile.blacklist.channelblacklist.skip_reason, { + username: plugged.getUserByID(booth.dj).username, + song: utils.songtitle(now.media.author, now.media.title), + reason: bl + }), + do_lockskip: config.blacklist.lockskip, + blacklist: false + }); + } + db.models.Channel.upsert({cid: media.snippet.channelId, name: media.snippet.channelTitle}); + }); + }).catch(function (err) { + story.debug('ChannelBlacklist', '', {attach: err}); + resolve(); + }); + } else resolve(); + }); + } +}; \ No newline at end of file diff --git a/lib/songfilters/soundcloudguard.js b/lib/songfilters/soundcloudguard.js index e676478..9e72a88 100644 --- a/lib/songfilters/soundcloudguard.js +++ b/lib/songfilters/soundcloudguard.js @@ -11,18 +11,27 @@ module.exports = { enabled: true, check: function (booth, now) { return new Promise(function (resolve, reject) { - if (config.soundcloudGuard.enabled && now.media.format === 2) { - soundCloudApi.check(now.media).spread(function (skip, reasons) { - if (skip) reject({ - type: 'soundcloudguard', - preskip: langfile.soundcloudGuard.skip, - afterskip: utils.replace(reasons.skip, {username: plugged.getUserByID(booth.dj).username}), - do_lockskip: config.soundcloudGuard.lockskip, - blacklist: true, - bl_reason: reasons.blacklist - }); - else resolve(); - }).catch(resolve); + if(now.media.format === 2){ + if (config.soundcloudGuard.block) reject({ + type: 'soundcloudguard', + preskip: langfile.soundcloudGuard.skip, + afterskip: utils.replace(langfile.soundcloudGuard.block, {username: plugged.getUserByID(booth.dj).username}), + do_lockskip: config.soundcloudGuard.lockskip, + blacklist: false + }); + else if (config.soundcloudGuard.enabled) { + soundCloudApi.check(now.media).spread(function (skip, reasons) { + if (skip) reject({ + type: 'soundcloudguard', + preskip: langfile.soundcloudGuard.skip, + afterskip: utils.replace(reasons.skip, {username: plugged.getUserByID(booth.dj).username}), + do_lockskip: config.soundcloudGuard.lockskip, + blacklist: true, + bl_reason: reasons.blacklist + }); + else resolve(); + }).catch(resolve); + } else resolve(); } else resolve(); }); } diff --git a/lib/songfilters/youtubeguard.js b/lib/songfilters/youtubeguard.js index afb1474..34881ff 100644 --- a/lib/songfilters/youtubeguard.js +++ b/lib/songfilters/youtubeguard.js @@ -11,18 +11,27 @@ module.exports = { enabled: true, check: function (booth, now) { return new Promise(function (resolve, reject) { - if (config.youtubeGuard.enabled && now.media.format === 1) { - youTubeApi.check(now.media).spread(function (skip, reasons) { - if (skip) reject({ - type: 'youtubeguard', - preskip: langfile.youtubeGuard.skip, - afterskip: utils.replace(reasons.skip, {username: plugged.getUserByID(booth.dj).username}), - do_lockskip: config.youtubeGuard.lockskip, - blacklist: true, - bl_reason: reasons.blacklist - }); - else resolve(); - }).catch(resolve); + if (now.media.format === 1) { + if (config.youtubeGuard.block) reject({ + type: 'youtubeguard', + preskip: langfile.youtubeGuard.skip, + afterskip: utils.replace(langfile.youtubeGuard.block, {username: plugged.getUserByID(booth.dj).username}), + do_lockskip: config.youtubeGuard.lockskip, + blacklist: false + }); + else if (config.youtubeGuard.enabled && now.media.format === 1) { + youTubeApi.check(now.media).spread(function (skip, reasons, blacklist) { + if (skip) reject({ + type: 'youtubeguard', + preskip: langfile.youtubeGuard.skip, + afterskip: utils.replace(reasons.skip, {username: plugged.getUserByID(booth.dj).username}), + do_lockskip: config.youtubeGuard.lockskip, + blacklist: (blacklist ? true : false), + bl_reason: (reasons.blacklist ? reasons.blacklist : undefined) + }); + else resolve(); + }).catch(resolve); + } else resolve(); } else resolve(); }); } diff --git a/lib/userfilters.js b/lib/userfilters.js new file mode 100644 index 0000000..d1eb426 --- /dev/null +++ b/lib/userfilters.js @@ -0,0 +1,35 @@ +var Promise = require('bluebird'); +var fs = require('fs'); +var story = require('storyboard').mainStory; +var path = require('path'); + +var userfilters = []; + +loadfilters(); + +function loadfilters () { + fs.readdir(path.resolve(__dirname, 'userfilters'), function (err, files) { + if (err) { + story.fatal('UserFilters', 'Cannot load userfilters', {attach: err}); + userfilters.push(Promise.resolve); + } else { + if (files.length === 0) userfilters.push(Promise.resolve); + else { + files.forEach(function (file) { + try { + var filter = require(path.resolve(__dirname, 'userfilters', file)); + if (filter.enabled) { + userfilters.push(filter.check); + story.debug('UserFilters', 'Loaded userfilter ' + filter.name); + } else story.debug('UserFilters', 'Skipping ' + filter.name + ' since it\'s disabled.'); + } catch (e) { + story.warn('UserFilters', 'Failed to load userfilter.', {attach: e}); + } + }); + } + story.info('UserFilters', 'Loaded ' + (userfilters.length) + ' userfilters.'); + } + }); +} + +module.exports = {filters: userfilters, timeouts: {}}; diff --git a/lib/userfilters/username.js b/lib/userfilters/username.js new file mode 100644 index 0000000..26f3f2a --- /dev/null +++ b/lib/userfilters/username.js @@ -0,0 +1,39 @@ +var Promise = require('bluebird'); + +var config = require('../load_config'); +var plugged = require('../client'); +var utils = require('../utils'); +var langfile = require('../../langfile'); +var timeouts = require('../chatfilters').timeouts; + +config.userfilter.username_disallowed = config.userfilter.username_disallowed.map(function (e) { + return new RegExp(e); +}); + +module.exports = { + name: 'Username', + enabled: true, + check: function (user) { + return new Promise(function (resolve, reject) { + if (config.userfilter.enabled) { + for (var i in config.userfilter.username_disallowed) { + if (user.username.match(config.userfilter.username_disallowed[i])) { + reject({ + type: 'username', + chat: utils.replace(langfile.userfilter.username.warn, {username: user.username}), + action: function () { + timeouts[user.id] = setTimeout(function () { + plugged.sendChat(utils.replace(langfile.userfilter.username.ban, {username: user.username})); + plugged.banUser(user.id, plugged.BANDURATION.PERMA, plugged.BANREASON.VIOLATING_COMMUNITY_RULES); + timeouts[user.id] = undefined; + }, 60 * 1000); + } + }); + return; + } + } + resolve(); + } else resolve(); + }); + } +}; \ No newline at end of file diff --git a/lib/workers.js b/lib/workers.js deleted file mode 100644 index 5869f31..0000000 --- a/lib/workers.js +++ /dev/null @@ -1,29 +0,0 @@ -var _ = require('underscore'); - -var redis = require('./db/redis_db'); -var config = require('./load_config'); -var plugged = require('./client'); -var utils = require('./utils'); - -module.exports = { - staffactive: setInterval(function(){ - var active = 0; - var stafflist = plugged.getStaffOnline(); - function checkstaff(index){ - if(stafflist[index].role > 1){ - redis.get('user:afk:' + stafflist[index].id).then(function(ex){ - if(ex === 1){ - active = active + 1 - } - if(stafflist[index + 1] !== undefined) checkstaff(index + 1); - else setvar(); - }); - } else if(stafflist[index + 1] !== undefined) checkstaff(index + 1); - else setvar(); - } - - function setvar(){ - redis.set('meta:data:staff:active', active); - } - }, 180 * 1000) -}; \ No newline at end of file diff --git a/package.json b/package.json index 7f99648..3526d27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plugbot", - "version": "1.2.0", + "version": "1.3.0", "main": "bot.js", "description": "A simple bot for plug.dj", "author": "Fuechschen ", @@ -9,40 +9,39 @@ "start": "node bot.js" }, "repository": { - "type": "git", + "type": "git+https", "url": "git+https://github.com/Fuechschen/plugbot.git" }, "bugs": { "url": "https://github.com/Fuechschen/plugbot/issues" }, "dependencies": { - "bluebird": "^3.4.0", + "bluebird": "^3.4.1", "cron": "^1.1.0", "fs": "0.0.2", - "ioredis": "^1.15.1", - "moment": "^2.12.0", - "mysql": "^2.10.2", + "ioredis": "^2.2.0", + "moment": "^2.14.1", + "mysql": "^2.11.1", "path": "^0.12.7", - "plugged": "^2.5.3", - "request": "^2.69.0", - "sequelize": "^3.19.3", - "storyboard": "0.0.3", + "plugged": "^2.6.1", + "request": "^2.73.0", + "sequelize": "^3.23.4", + "storyboard": "^1.4.0", "string": "^3.3.1", "underscore": "^1.8.3", - "validator": "^5.1.0" + "validator": "^5.4.0" }, "optionalDependencies": { - "body-parser": "^1.15.1", "cld": "^2.4.6", "cleverbot-node": "git://github.com/avatarkava/cleverbot-node.git", - "express": "^4.13.4", + "express": "^4.14.0", "morgan": "^1.7.0", - "pg": "^4.5.1", + "pg": "^6.0.1", "pg-hstore": "^2.3.2", - "pm2": "^1.0.2", - "sqlite3": "^3.1.1", - "tedious": "^1.13.2", - "uws": "^0.4.1", - "ws": "^1.1.0" + "pm2": "^1.1.3", + "sqlite3": "^3.1.4", + "tedious": "^1.14.0", + "uws": "^0.7.0", + "ws": "^1.1.1" } } diff --git a/web/index.js b/web/index.js index be820ce..61398e2 100644 --- a/web/index.js +++ b/web/index.js @@ -5,70 +5,74 @@ var S = require('string'); var config = require('../lib/load_config'); -var Ws = require((config.web.useUWS ? 'u' : '') + 'ws').Server; +var ws = null; +var app = null; +if (config.web.enabled) { + var Ws = require((config.web.useUWS ? 'u' : '') + 'ws').Server; -var app = express(); + app = express(); -var http = require('http').createServer(app); + var http = require('http').createServer(app); -var ws = null; -app.set('trust proxy', 'loopback'); -app.set('json spaces', 4); + app.set('trust proxy', 'loopback'); + app.set('json spaces', 4); -app.use(logger('short', { - stream: { - write: function (toLog) { - //noinspection JSUnresolvedFunction - story.info('web', S(toLog).chompRight('\n').s); + app.use(logger('short', { + stream: { + write: function (toLog) { + //noinspection JSUnresolvedFunction + story.info('web', S(toLog).chompRight('\n').s); + } } - } -})); + })); -app.use(function (req, res, next) { - res.set('Access-Control-Allow-Origin', config.web.cors); - next(); -}); + app.use(function (req, res, next) { + res.set('Access-Control-Allow-Origin', config.web.cors); + next(); + }); -app.use('/v1', require('./v1')); + app.use('/v1', require('./v1')); -app.get('/', function (req, res) { - res.json({ - versions: { - "1": config.web.path + '/v1' - } + app.get('/', function (req, res) { + res.json({ + versions: { + "1": config.web.path + '/v1' + } + }); }); -}); - -app.use(function (req, res) { - res.status(404).json({error: 'Not Found'}); -}); - -if (config.web.websocket) { - if (config.web.port !== null) { - ws = new Ws({server: http, path: config.web.path + '/v1/socket'}); - if (!config.web.useUWS) { - ws.broadcast = function (data) { - ws.clients.forEach(function (client) { - client.send(data); - }); + + app.use(function (req, res) { + res.status(404).json({error: 'Not Found'}); + }); + + if (config.web.websocket) { + if (config.web.port !== null) { + ws = new Ws({server: http, path: config.web.path + '/v1/socket'}); + if (!config.web.useUWS) { + ws.broadcast = function (data) { + ws.clients.forEach(function (client) { + client.send(data); + }); + } } - } - ws.on('connection', function (socket) { - var h = setInterval(function () { - socket.send(JSON.stringify({t: 'hb', d: {}})); - }, 30 * 1000); - socket.on('close', function () { - clearInterval(h); + ws.on('connection', function (socket) { + var h = setInterval(function () { + socket.send(JSON.stringify({t: 'hb', d: {}})); + }, 30 * 1000); + socket.on('close', function () { + clearInterval(h); + }); }); - }); - } else story.warn('web', 'If you want to use the websocket, please provide a port to listen on.'); -} + } else story.warn('web', 'If you want to use the websocket, please provide a port to listen on.'); + } -if (config.web.port !== null) http.listen(config.web.port || 3000, function () { - story.info('web', 'Listening on port ' + (config.web.port || 3000)); -}); -else story.info('web', 'Not Listening on a port because port is set to null'); + if (config.web.port !== null) http.listen(config.web.port || 3000, function () { + story.info('web', 'Listening on port ' + (config.web.port || 3000)); + }); + else story.info('web', 'Not Listening on a port because port is set to null'); + +} module.exports = { app: app, @@ -94,9 +98,34 @@ module.exports = { if (ws !== null)ws.broadcast(JSON.stringify({t: 'ban', d: ban})); }; break; + case 'join': + return function (user) { + if (ws !== null)ws.broadcast(JSON.stringify({t: 'join', d: user})); + }; + break; + case 'leave': + return function (user) { + if (ws !== null)ws.broadcast(JSON.stringify({t: 'leave', d: user})); + }; + break; + case 'waitlist': + return function (wl) { + if (ws !== null)ws.broadcast(JSON.stringify({t: 'wl', d: wl})); + }; + break; + case 'vote': + return function (votes) { + if (ws !== null)ws.broadcast(JSON.stringify({t: 'v', d: votes})); + }; + break; + case 'chatDelete': + return function (data) { + if (ws !== null)ws.broadcast(JSON.stringify({t: 'chatDelete', d: data})); + }; + break; default: return function () { - + }; break; } diff --git a/web/v1.js b/web/v1.js index 3335390..498bf22 100644 --- a/web/v1.js +++ b/web/v1.js @@ -14,13 +14,16 @@ app.get('/', function (req, res) { users: config.web.path + '/v1/users', media: config.web.path + '/v1/media', history: config.web.path + '/v1/history', - room: config.web.path + '/v1/room' + room: config.web.path + '/v1/room', + waitlist: config.web.path + '/v1/waitlist' }, bot_data: { customCommands: config.web.path + '/v1/customcommands', bestVotedSongs: config.web.path + '/v1/highscore', blacklist: config.web.path + '/v1/blacklist', - check: config.web.path + '/v1/check?s={string}' + channelblacklist: config.web.path + '/v1/channelblacklist', + check: config.web.path + '/v1/check?s={string}', + user: config.web.path + '/v1/user?id={userid}&name={username}' }, socket: config.web.path + '/v1/socket' }) @@ -56,6 +59,14 @@ app.get('/room', function (req, res) { }()); }); +app.get('/waitlist', function (req, res) { + res.json({ + data: plugged.getWaitlist().map(function (id) { + return plugged.getUserByID(id); + }) + }); +}); + app.get('/all', function (req, res) { plugged.getRoomHistory(function (err, history) { res.json({ @@ -69,6 +80,9 @@ app.get('/all', function (req, res) { users: plugged.getUsers().map(function (e) { return {id: e.id, username: e.username, slug: e.slug, gRole: e.gRole, role: e.role, level: e.level}; }), + waitlist: plugged.getWaitlist().map(function (id) { + return plugged.getUserByID(id); + }), history: (err ? null : history.map(function (e) { e.room = undefined; return e; @@ -129,7 +143,7 @@ app.get('/blacklist', function (req, res) { //noinspection JSUnresolvedFunction db.models.Song.findAll({where: {is_banned: true}}).then(function (songs) { res.json({ - blacklist: songs.map(function (song) { + data: songs.map(function (song) { return { id: song.id, author: song.author, @@ -147,6 +161,23 @@ app.get('/blacklist', function (req, res) { }); }); +app.get('/channelblacklist', function (req, res) { + db.models.Channel.findAll({where: {is_banned: true}}).then(function (channels) { + res.json({ + data: channels.map(function (c) { + return { + name: c.name, + channel_id: c.cid, + is_banned: c.is_banned, + ban_reason: c.ban_reason + }; + }) + }); + }).catch(function () { + res.status(500).json({error: 'SQL Error'}); + }); +}); + app.get('/check', function (req, res) { if (req.query.s !== undefined) { utils.resolveCID(req.query.s).then(function (cid) { @@ -175,4 +206,32 @@ app.get('/check', function (req, res) { } else res.status(400).json({error: 'invalid query'}); }); +app.get('/user', function (req, res) { + var search = {}; + if (req.query.id !== undefined) search.id = req.query.id; + if (req.query.name !== undefined && req.query.id === undefined) search.username = req.query.name; + + if (req.query.id === undefined && req.query.name === undefined) res.status(400).json({error: 'invalid query'}); + else { + db.models.User.find({where: search}).then(function (user) { + if (user !== undefined && user !== null) { + res.json({ + data: { + id: user.id, + username: user.username, + avatar: user.avatar_id, + badge: user.badge, + grole: user.global_role, + role: user.s_role, + level: user.level, + status: user.status + } + }); + } else res.statusCode(404).json({error: 'User not found'}); + }).catch(function () { + res.status(500).json({error: 'SQL Error'}); + }) + } +}); + module.exports = app; \ No newline at end of file