diff --git a/libs/overlays/alerts.js b/libs/overlays/alerts.js index 7d5bfc11f4b..85349b1bc13 100644 --- a/libs/overlays/alerts.js +++ b/libs/overlays/alerts.js @@ -4,7 +4,9 @@ const _ = require('lodash') const constants = require('../constants.js') const cluster = require('cluster') +const snekfetch = require('snekfetch') const Message = require('../message') +const config = require('../../config.json') function Alerts () { global.configuration.register('replayPosition', 'core.no-response', 'string', 'right') @@ -65,12 +67,43 @@ Alerts.prototype.overlay = async function (self, sender, text) { if (data.key === 'text') { data.value = data.value.replace(/\$sender/g, sender.username) } - object[data.key] = data.value }) send.push(object) }) + + // remove clips without url or id + send = _.filter(send, (o) => (o.type === 'clip' && (!_.isNil(o.id) || !_.isNil(o.url))) || o.type !== 'clip') + + for (let object of send) { + if (object.type === 'clip') { + // load clip from api + let clip = null + if (!_.isNil(object.id)) clip = await self.getClipById(object.id) + else if (!_.isNil(object.url)) clip = await self.getClipById(object.url.split('/').pop()) + clip.cDuration = clip.duration; delete clip.duration + if (!_.isNil(clip)) _.merge(object, clip) + } + } global.panel.io.emit('overlay.show', send) } +Alerts.prototype.getClipById = async function (id) { + const url = `https://api.twitch.tv/kraken/clips/${id}` + + var request + try { + request = await snekfetch.get(url) + .set('Accept', 'application/vnd.twitchtv.v5+json') + .set('Client-ID', config.settings.client_id) + .set('Authorization', 'OAuth ' + config.settings.bot_oauth.split(':')[1]) + global.panel.io.emit('api.stats', { data: request.body, timestamp: _.now(), call: 'getClipById', api: 'kraken', endpoint: url, code: request.status, remaining: this.remainingAPICalls }) + return request.body + } catch (e) { + global.log.error(`${url} - ${e.message}`) + global.panel.io.emit('api.stats', { timestamp: _.now(), call: 'getClipById', api: 'kraken', endpoint: url, code: `${e.status} ${_.get(e, 'body.message', e.message)}`, remaining: this.remainingAPICalls }) + return null + } +} + module.exports = new Alerts() diff --git a/public/overlays/alerts.html b/public/overlays/alerts.html index 79a3b642b02..fd37572677e 100644 --- a/public/overlays/alerts.html +++ b/public/overlays/alerts.html @@ -24,7 +24,7 @@ margin: 0; padding: 0; } - #images, #video-pos, #alerts, #html { + #images, #video-pos, #clip-pos, #alerts, #html { display: table; position: absolute; height: 100%; @@ -43,9 +43,9 @@ background-color: rgba(255, 0, 0, 0.5); font-size: 24px; } - #video-rel-pos { display: table-cell; position: relative; height: 100%; width: 100%; } - #video-rel-pos > div { display: inline-block !important; } - #video { + #video-rel-pos, #clip-rel-pos { display: table-cell; position: relative; height: 100%; width: 100%; } + #video-rel-pos > div, #clip-rel-pos > div { display: inline-block !important; } + #video, #clip { display: inline-block !important; opacity: 0; } #video_html5_api { width: 100% } @@ -97,6 +97,15 @@ +
+
+
+
+ CLIP +
+
+
+ @@ -123,6 +132,7 @@ if (d.type === 'audio') playAudio(alert_not_running.id, d) if (d.type === 'text') showText(alert_not_running.id, d) if (d.type === 'video') showVideo(alert_not_running.id, d) + if (d.type === 'clip') showClip(alert_not_running.id, d) if (d.type === 'html') showHtml(alert_not_running.id, d) }) } @@ -291,6 +301,103 @@ }) } + function showClip(id, clip, delay) { + if (!delay) { + if (clip.delay === 0) { + return showClip(id, clip, true) + } else { + setTimeout(function () { + showClip(id, clip, true) + }, clip.delay) + } + } + + if (!_.isNil(clip.url)) clip.id = clip.url.split('/').pop() + if (_.isNil(clip.size)) clip.size = 450 + if (_.isNil(clip.duration)) clip.duration = 1000 + + clip.delay = _.isNil(clip.delay) ? 0 : parseInt(clip.delay, 10) + clip.class = _.isNil(clip.class) ? 'video' : clip.class + + $('#clip').empty().append( + `` + ) + + let style = '' + switch (clip.position) { + case 'top-left': + break + case 'top-center': + case 'top': + style = 'display: table-cell; text-align: center' + break + case 'top-right': + style = 'display: table-cell; text-align: right' + break + case 'left': + style = 'display: table-cell; vertical-align: middle' + break + case 'right': + style = 'display: table-cell; vertical-align: middle; text-align: right' + break + case 'bottom-left': + style = 'display: table-cell; vertical-align: bottom; position: relative; top:10px' + break + case 'bottom-center': + case 'bottom': + style = 'display: table-cell; vertical-align: bottom; position: relative; top:10px; text-align: center' + break + case 'bottom-right': + style = 'display: table-cell; vertical-align: bottom; position: relative; top:10px; text-align: right' + break + default: + style = 'display: table-cell; vertical-align: middle; text-align: center' + break + } + + if (!_.isNil(clip['x-offset'])) { + style += ';left:' + clip['x-offset'] + 'px' + } + + if (!_.isNil(clip['y-offset'])) { + style += ';top:' + clip['y-offset'] + 'px' + } + + if (!_.isNil(clip.filter)) { + $('#clip').addClass(clip.filter) + } + + $('#clip').addClass(clip.class) + + $('#clip-replay-label').css('opacity', 0) + if (clip.label === 'true') { + setTimeout(() => { $('#clip-replay-label').velocity("fadeIn", { loop: true, duration: 1500 }) }, 1000) + } + + $('#clip-rel-pos').attr('style', style) + + $('#clip').css('opacity', 1) + setTimeout(() => { + $("#clip-replay-label").velocity("stop"); + $('#clip-replay-label').velocity("fadeOut", { duration: clip.duration }); + $('#clip').velocity("fadeOut", { duration: clip.duration, complete: function(e) { + if (!_.isNil(alertsQueue[id])) alertsQueue[id].finished++ + $('#clip').removeClass(clip.class) + if (!_.isNil(clip.filter)) { + $('#clip').removeClass(clip.filter) + } + $("#clip-replay-label").velocity("stop"); + }}) + }, clip.cDuration * 1000) + } + function showVideo(id, video) { if (!_.endsWith(video.url, '.mp4') && !_.endsWith(video.url , '.flv') ) { console.error('ERROR: Only mp4 and flv files can be played')