fair-twitch
Version:
Fair's Twitch API and Chat bot library
322 lines (321 loc) • 14.5 kB
JavaScript
;
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var ExpandedEventEmitter_1 = __importDefault(require("./ExpandedEventEmitter"));
var v4_1 = __importDefault(require("uuid/v4"));
// Wait to notify gift subs in case they are a part of mass gift subs
var mysteryGiftTimeout = 5000; // If count is reached, it will call it
var giftTimeout = 1000;
var SmartTimeout = /** @class */ (function () {
function SmartTimeout(callback, time) {
this.time = time;
this.callback = callback;
this.timeout = null;
this.start = this.start.bind(this);
this.refresh = this.refresh.bind(this);
this.clear = this.clear.bind(this);
}
SmartTimeout.prototype.start = function () {
this.timeout = setTimeout(this.callback, this.time);
};
SmartTimeout.prototype.clear = function () {
if (this.timeout !== null) {
clearTimeout(this.timeout);
}
};
SmartTimeout.prototype.refresh = function (newTime) {
if (newTime !== undefined)
this.time = newTime;
this.clear();
this.start();
};
SmartTimeout.prototype.call = function () {
this.clear();
this.callback();
};
return SmartTimeout;
}());
var NotificationsEmitter = /** @class */ (function (_super) {
__extends(NotificationsEmitter, _super);
/**
* @param twitchIRC The Twitch IRC client
*/
function NotificationsEmitter(twitchIRC) {
var _this = _super.call(this) || this;
_this.twitchIRC = twitchIRC;
_this.eventID = v4_1.default();
// We want to collect all the recepients of a mass gift sub under 1 notice
// Since all mass gift subs are also displayed as a gift sub and there's no way
// to guarantee that 'submysterygift' event triggers before the giftsub events,
// we have to wait a short while before displaying the notice, in case a
// 'submysterygift' event happens
_this.giftSubs = [];
_this.massGifters = [];
_this.twitchIRC.addListener('usernotice#' + _this.eventID, function (channel, login, message, tags) {
var data = {
login: login,
displayName: tags['display-name'],
id: tags.id,
timestamp: Number(tags['tmi-sent-ts']),
systemMsg: tags['system-msg'].replace(/\\s/g, ' ')
};
switch (tags['msg-id']) {
case 'sub': {
data.tier = tags['msg-param-sub-plan'];
_this._emitNotification('sub', channel, data, tags);
break;
}
case 'resub': {
data.msg = message;
data.months = Number(tags['msg-param-cumulative-months']);
data.tier = tags['msg-param-sub-plan'];
_this._emitNotification('resub', channel, data, tags);
break;
}
case 'subgift': {
data.recepient = {
login: tags['msg-param-recipient-user-name'],
displayName: tags['msg-param-recipient-display-name']
};
data.msg = message;
data.months = Number(tags['msg-param-months']);
data.senderCount = Number(tags['msg-param-sender-count']);
data.tier = tags['msg-param-sub-plan'];
var key = data.login + '#' + channel + '!' + data.tier;
var absorbed = false;
// First check if there's any mass gifts going on
for (var i = 0; i < _this.massGifters.length; i++) {
var massGift = _this.massGifters[i];
if (massGift.key === key) {
if (massGift.data.recepients.length < massGift.data.massCount) {
massGift.data.recepients.push(data.recepient);
if (massGift.data.recepients.length >= massGift.data.massCount) {
massGift.timeout.call();
}
else {
// Refresh timeout
massGift.timeout.refresh(giftTimeout);
}
absorbed = true;
break;
}
}
}
if (!absorbed) {
var obj_1 = {
key: key,
channel: channel,
data: data,
timeout: new SmartTimeout(function () {
_this._emitNotification('giftsub', channel, data, tags);
// Remove from list
for (var i = 0; i < _this.giftSubs.length; i++) {
if (_this.giftSubs[i] === obj_1) {
_this.giftSubs.splice(i, 1);
break;
}
}
}, giftTimeout)
};
obj_1.timeout.start();
_this.giftSubs.push(obj_1);
}
break;
}
case 'submysterygift': {
data.massCount = Number(tags['msg-param-mass-gift-count']);
data.senderCount = Number(tags['msg-param-sender-count']);
data.tier = tags['msg-param-sub-plan'];
data.recepients = [];
var key = data.login + '#' + channel + '!' + data.tier;
// Check all sub gifts going on, and add them to this part
for (var i = 0; i < _this.giftSubs.length; i++) {
var giftSub = _this.giftSubs[i];
if (giftSub.key === key && data.recepient.length < data.massCount) {
data.recepients.push(giftSub.data.recepient);
giftSub.timeout.clear();
_this.giftSubs.splice(i, 1);
i--;
}
}
var obj_2 = {
key: key,
channel: channel,
data: data,
timeout: new SmartTimeout(function () {
_this._emitNotification('massgiftsub', channel, data, tags);
for (var i = 0; i < _this.massGifters.length; i++) {
if (_this.massGifters[i] === obj_2) {
_this.massGifters.splice(i, 1);
break;
}
}
}, mysteryGiftTimeout)
};
if (data.recepients.length >= data.massCount) {
obj_2.timeout.call();
}
else {
obj_2.timeout.start();
_this.massGifters.push(obj_2);
}
break;
}
}
});
_this.twitchIRC.addListener('msg#' + _this.eventID, function (channel, login, message, tags) {
if (tags.bits) {
var data = {
login: login,
displayName: tags['display-name'],
id: tags.id,
timestamp: Number(tags['tmi-sent-ts']),
msg: message,
bits: Number(tags.bits)
};
_this._emitNotification('bits', channel, data, tags);
}
});
return _this;
}
/**
* Removes all event listeners added from this tracker
*/
NotificationsEmitter.prototype.dispose = function () {
this.twitchIRC.removeIDListeners(this.eventID);
};
/**
* Emit an 'any' event but also a normal event
* @param eventName The name of the event
* @param args The args/parameters of the event
*/
NotificationsEmitter.prototype._emitNotification = function (eventName) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
this.emit.apply(this, ['any', eventName].concat(args));
this.emit.apply(this, [eventName].concat(args));
};
/**
* Get a dummy notification object
* @param eventName The event name (sub, resub, giftsub, massgiftsub, bits, any)
* @param channel The optional target channel (default DummyChannel)
* @param overwriteData Will overwrite the final object these keys and values
*/
NotificationsEmitter.prototype.getDummyNotification = function (eventName, channel, overwriteData) {
if (channel === void 0) { channel = 'DummyChannel'; }
if (overwriteData === void 0) { overwriteData = {}; }
// First generate basic object
var nameAffix = getRandomAffix();
var login = 'dummyfan' + nameAffix;
var displayName = 'DummyFan' + nameAffix;
var obj = {
login: login,
displayName: displayName,
id: v4_1.default(),
timestamp: Date.now()
};
switch (eventName) {
case 'sub': {
obj.tier = randomOneOf('Prime', '1000', '2000', '3000');
var tierMsg = obj.tier === 'Prime' ? 'Twitch Prime' : 'Tier ' + obj.tier.charAt(0);
obj.systemMsg = obj.displayName + " subscribed with " + tierMsg + ".";
break;
}
case 'resub': {
obj.tier = randomOneOf('Prime', '1000', '2000', '3000');
obj.months = 1 + Math.floor(Math.random() * 23);
var tierMsg = obj.tier === 'Prime' ? 'Twitch Prime' : 'Tier ' + obj.tier.charAt(0);
obj.systemMsg = obj.displayName + " subscribed with " + tierMsg + ". They've subscribed for " + obj.months + " months!";
if (Math.floor(Math.random() * 3) !== 1) {
obj.msg = "Dummy message " + getRandomAffix();
}
break;
}
case 'giftsub': {
obj.tier = randomOneOf('1000', '2000', '3000');
obj.recepient = getDummyRecepient();
obj.senderCount = Math.max(0, Math.floor(Math.random() * 500) - 200);
var systemMsgAffix = obj.senderCount > 1 ? " They have given " + obj.senderCount + " Gift Subs in the channel!" : '';
obj.systemMsg = obj.displayName + " gifted a Tier " + obj.tier.charAt(0) + " sub to " + obj.recepient.displayName + "!" + systemMsgAffix;
obj.months = Math.floor(Math.random() * 12);
break;
}
case 'massgiftsub': {
obj.tier = randomOneOf('1000', '2000', '3000');
obj.massCount = randomOneOf(5, 5, 5, 10, 10, 100);
obj.senderCount = Math.max(0, Math.floor(Math.random() * 500) - 200) + obj.massCount;
var community = channel ? channel : 'Unknown';
obj.systemMsg = obj.displayName + " is gifting " + obj.massCount + " Tier " + obj.tier.charAt(0) + " to " + community + "'s community! They've gifted a total of " + obj.senderCount + " in the channel!";
obj.recepients = [];
for (var i = 0; i < obj.massCount; i++) {
obj.recepients.push(getDummyRecepient());
}
break;
}
case 'bits': {
obj.bits = randomOneOf(1, 100, 1000, 10000);
obj.msg = "Dummy message " + getRandomAffix() + " cheer" + obj.bits;
break;
}
default: {
return this.getDummyNotification(randomOneOf('sub', 'resub', 'giftsub', 'massgiftsub', 'bits'));
}
}
for (var key in overwriteData) {
obj[key] = overwriteData[key];
}
return obj;
};
/**
* Emit a dummy notification event (tags will not be included)
* @param eventName The event name (sub, resub, giftsub, massgiftsub, bits, any)
* @param channel The channel name (optional)
* @param overwriteData Will overwrite the final object these keys and values (optional)
*/
NotificationsEmitter.prototype.sendDummyNotification = function (eventName, channel, overwriteData) {
if (eventName === 'any')
eventName = randomOneOf('sub', 'resub', 'giftsub', 'massgiftsub', 'bits');
var obj = this.getDummyNotification(eventName, channel, overwriteData);
this._emitNotification(eventName, channel, obj);
};
return NotificationsEmitter;
}(ExpandedEventEmitter_1.default));
function randomOneOf() {
var items = [];
for (var _i = 0; _i < arguments.length; _i++) {
items[_i] = arguments[_i];
}
return items[Math.floor(Math.random() * items.length)];
}
function getDummyRecepient() {
var recipientAffix = getRandomAffix();
return {
login: 'dummytarget' + recipientAffix,
displayName: 'DummyTarget' + recipientAffix
};
}
function getRandomAffix() {
var affix = '';
for (var i = 0; i < 5; i++) {
var num = Math.floor(Math.random() * 10);
affix += num;
}
return affix;
}
module.exports = NotificationsEmitter;