Skip to content

Instantly share code, notes, and snippets.

@nicholastay
Last active February 2, 2022 08:23
Show Gist options
  • Save nicholastay/097ea9d54425dba474bf78747d976d56 to your computer and use it in GitHub Desktop.
Save nicholastay/097ea9d54425dba474bf78747d976d56 to your computer and use it in GitHub Desktop.
Twitch Chat History FFZ addon utilising robotty's service (known issue(s): 'chat history ends here' doesnt show properly always, slow loading where new chat messages are above old ones loaded in)
// ==UserScript==
// @name ChatHistory4FFZ
// @namespace nexerqdev
// @homepage https://gist.github.com/nicholastay/097ea9d54425dba474bf78747d976d56
// @version 0.1.2
// @description Chat history for FFZ with robotty's service
// @author Nexerq <[email protected]>
// @license Zlib/libpng
// @match *://twitch.tv/*
// @match *://www.twitch.tv/*
// @grant none
// @updateURL https://gist.github.com/nicholastay/097ea9d54425dba474bf78747d976d56/raw/nexerq-message-history-ffz.user.js
// ==/UserScript==
function waitForFFZ() {
console.log("[ChatHistory4FFZ] Looking for FFZ.");
let attempts = 0;
let interv = setInterval(findFFZ, 750);
findFFZ();
function findFFZ() {
if (unsafeWindow.FrankerFaceZ) {
clearInterval(interv);
console.log("[ChatHistory4FFZ] Found FFZ, injecting.");
inject();
return;
}
if (attempts > 10) {
clearInterval(interv);
console.log("[ChatHistory4FFZ] Could not find FFZ.");
return;
}
++attempts;
}
}
const defaultColours = ["#FF0000", "#0000FF", "#008000", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E", "#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"];
function getDefaultUserColour(name) {
// users who never set a colour
let tname = name.charCodeAt(0) + name.charCodeAt(name.length-1);
return defaultColours[tname % defaultColours.length];
}
function inject() {
let addon = class MsgHistory extends unsafeWindow.FrankerFaceZ.utilities.addon.Addon {
constructor(...args) {
super(...args);
this.inject('chat');
this.settings.add('nexerq.message-history.load_limit', {
default: 15,
ui: {
path: 'Add-Ons > Message History >> Behaviour',
title: 'Message Load Limit',
description: 'Limit of messages to load from the history API.',
component: 'setting-text-box'
}
});
}
onEnable() {
this.log.info('Loaded message history FFZ addon.');
this.on('chat:room-add', this.roomAdd);
for (const room of this.chat.iterateRooms()) {
if (room)
this.roomAdd(room);
}
}
roomAdd(room) {
this.log.info('Joined room id ' + room.id);
this.loadHistory(room);
}
async loadHistory(room) {
this.log.info('Getting chat history: ' + room.login);
const sitechat = this.resolve('site.chat');
const chatsvc = sitechat.ChatService.first;
const response = await fetch(`https://recent-messages.robotty.de/api/v2/recent-messages/${room.login}?hide_moderation_messages=true&hide_moderated_messages=true&limit=${this.settings.get('nexerq.message-history.load_limit')}`);
if (response.ok) {
const data = await response.json();
if (data.error !== null) {
this.log.info("robotty history error: " + data.error);
return;
}
// parse irc style messages
let count = 0;
for (const msgdata of data.messages) {
const splitmsg = msgdata.split(' ');
if (splitmsg[2] !== 'PRIVMSG')
continue;
let metadata = {};
splitmsg[0].split(';').forEach(data => {
const d = data.split('=');
metadata[d[0]] = d[1];
});
let msg = {
type: sitechat.chat_types.Message,
user: {
login: splitmsg[1].split('!')[0].substr(1)
},
timestamp: Number(metadata['tmi-sent-ts'])
};
// add message
let messagetext = splitmsg.slice(4).join(' ');
if (messagetext[0] === ':')
messagetext = messagetext.substr(1);
msg.message = messagetext;
// add in all the other data
msg.user.color = metadata['color'] || getDefaultUserColour(msg.user.login);
let dn = metadata['display-name'];
if (dn)
msg.user.displayName = dn;
let badges = metadata['badges'];
if (badges) {
msg.badges = {}
for (let b of badges.split(',')) {
let bd = b.split('/');
msg.badges[bd[0]] = bd[1]
}
}
let emotes = metadata['emotes'];
if (emotes) {
msg.emotes = {}
for (let e of emotes.split('/')) {
// id:start-end,start-end,.../id:start-end,.../...
let eSplit = e.split(':');
for (let idx of eSplit[1].split(',')) {
let startIdx = Number(idx.split('-')[0]);
msg.emotes[startIdx] = {
startIndex: startIdx,
id: eSplit[0] // emote id as string is fine
};
}
}
}
// parse the emoted msg with ffz
sitechat.chat.standardizeEmotes(msg); // inplace standardize
msg.messageParts = sitechat.chat.tokenizeMessage(msg); // generate messageparts
chatsvc.addMessage(msg);
++count;
}
if (count > 0) {
chatsvc.addMessage({
type: sitechat.chat_types.Notice,
message: 'Chat history ends here.'
});
this.log.info('Loaded ' + count + ' chat history messages.');
} else {
this.log.info('No chat history messages to load.')
}
} else {
this.log.info('robotty chat history get failed: ' + response);
}
}
};
let ffz = unsafeWindow.FrankerFaceZ.get();
addon.register('nexerq-message-history', {
author: 'Nexerq',
description: 'Loads message history using robotty\'s service.',
icon: 'https://cdn.frankerfacez.com/badge/2/4/solid',
short_name: 'Message History',
name: 'Load Message History',
website: 'https://recent-messages.robotty.de/',
version: '0.1.0'
});
ffz.addons._enableAddon('nexerq-message-history');
}
waitForFFZ();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment