Init commit

This commit is contained in:
Asraelite 2023-10-30 16:41:48 +01:00
commit c45ad79440
48 changed files with 6786 additions and 0 deletions

191
chatbot/bot.js Normal file
View file

@ -0,0 +1,191 @@
import tmi from 'tmi.js';
import { WebSocketServer } from 'ws';
import * as secrets from './secret.js';
const CHECKSUM_SEND_INTERVAL = 8;
// Define configuration options
const opts = {
options: { debug: false },
identity: {
username: secrets.USERNAME,
password: secrets.ACCESS_TOKEN,
},
channels: [secrets.CHANNEL_NAME]
};
// Create a client with our options
const client = new tmi.Client(opts);
client.connect().catch(console.error);
client.on('connected', onConnectedHandler);
function onConnectedHandler(addr, port) {
console.log(`* Connected to ${addr}:${port}`);
listen();
}
function listen() {
const wss = new WebSocketServer({ port: 8090 });
wss.on('connection', (ws) => {
let cancelRequested = false;
ws.on('message', (message) => {
const payload = JSON.parse(message);
if (payload.type === 'data') {
const data = JSON.parse(payload.data);
console.log(`sending ${data.length} values with inveral ${payload.speed}ms...`);
write(data, (update) => {
ws.send(update);
}, () => cancelRequested, payload.speed);
} else if (payload.type === 'cancel') {
cancelRequested = true;
console.log('cancel requested');
}
});
});
}
// Commands:
// 0: reset checksum
// 1: address low
// 2: address high
// 3: value low; write; increment address
// 4: value high
// 5: checksum low; compare
// 6: checksum high
// 7: unlock address
async function write(data, progressCallback, isCancelRequested, waitIntervalMs) {
let previousAddress = null;
let previousVhValue = null;
let checksum = 0;
// Reset checksum
send(0, 0);
await wait(waitIntervalMs);
for (const i in data) {
const remaining = (data.length - i) + (data.length / CHECKSUM_SEND_INTERVAL);
const eta = remaining * (waitIntervalMs * 2) / 1000;
progressCallback(JSON.stringify({
status: 'sending',
message: `${i}/${data.length} (${(i / data.length * 100).toFixed(1)}%) ETA: ${formatDuration(eta)}`,
checksum,
}));
if (i % CHECKSUM_SEND_INTERVAL === 0 && i != 0) {
await sendChecksum(checksum, waitIntervalMs);
}
const [address, value] = data[i];
checksum += address + value;
checksum &= 0xffffff;
const [al, ah] = [address & 0xfff, address >> 12];
const [vl, vh] = [value & 0xfff, value >> 12];
if (address !== previousAddress + 1) {
send(0, 7); // unlock address
await wait(waitIntervalMs);
send(al, 1);
await wait(waitIntervalMs);
send(ah, 2);
await wait(waitIntervalMs);
}
previousAddress = address;
if (vh !== previousVhValue) {
send(vh, 4);
await wait(waitIntervalMs);
}
previousVhValue = vh;
send(vl, 3);
await wait(waitIntervalMs);
if (isCancelRequested()) {
console.log('cancelled');
progressCallback(JSON.stringify({
status: 'cancelled',
message: `Cancelled`,
checksum,
}));
return;
}
}
await sendChecksum(checksum, waitIntervalMs);
progressCallback(JSON.stringify({
status: 'complete',
message: `Sent ${data.length} values`,
checksum,
}));
}
async function wait(timeMs = 1500) {
await new Promise(resolve => setTimeout(resolve, timeMs));
}
function send(value, command) {
// console.log(`sending ${command}: ${value} `);
say(encode(value, command));
}
async function sendChecksum(checksum, waitIntervalMs) {
const [cl, ch] = [checksum & 0xfff, checksum >> 12];
send(ch, 6);
await wait(waitIntervalMs);
send(cl, 5);
await wait(waitIntervalMs);
}
function say(message) {
client.say(secrets.CHANNEL_NAME, message);
}
function formatDuration(seconds) {
seconds = Math.ceil(seconds);
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
if (minutes === 0) {
return `${remainingSeconds}s`;
} else {
return `${minutes}m${remainingSeconds}s`;
}
}
// 1000: al
// 1001: ah
// 1010: vl
// 1011: vh
function encode(value, command) {
const aBitCount = 4;
const bBitCount = 4;
const cBitCount = 4;
const dBitCount = 4;
const valueBitString = value.toString(2).padStart(12, '0');
const commandBitString = command.toString(2).padStart(4, '0');
const bitString = commandBitString + valueBitString;
let index = 0;
const a = parseInt(bitString.slice(0, aBitCount), 2);
index += aBitCount;
const b = parseInt(bitString.slice(index, index + bBitCount), 2);
index += bBitCount;
const c = parseInt(bitString.slice(index, index + cBitCount), 2);
index += cBitCount;
const d = parseInt(bitString.slice(index, index + dBitCount), 2);
index += dBitCount;
const maxTotal = 2 ** aBitCount + 2 ** bBitCount + 2 ** cBitCount + 2 ** dBitCount;
const e = maxTotal - (a + b + c + d);
const values = [...Array(a).fill('a'), ...Array(b).fill('b'), ...Array(c).fill('c'), ...Array(d).fill('d'), ...Array(e).fill('e')];
return values.join(' ');
}

18
chatbot/data.js Normal file
View file

@ -0,0 +1,18 @@
export default [
// [0x000, 0x000, 0x003, 0x046],
[0x001, 0x000, 0x005, 0x047],
// [0x002, 0x000, 0x000, 0x044],
// [0x003, 0x000, 0x001, 0x73d],
// [0x004, 0x000, 0x002, 0xc45],
// [0x005, 0x000, 0xc00, 0x0a4],
// [0x006, 0x000, 0x001, 0x236],
// [0x007, 0x000, 0x001, 0x33f],
// [0x008, 0x000, 0xffb, 0xcc7],
// [0x009, 0x000, 0x000, 0x026],
// [0x00a, 0x000, 0x000, 0xfc4],
];

51
chatbot/notes.txt Normal file
View file

@ -0,0 +1,51 @@
Entering chat into Twitch
In the PS5, when livestream messages are configured to display:
>=101 characters => does not show anything
99 or 100 characters => the final 3 turn into an ellipsis
<=98 characters => all show
a b c d e, result
100 characters is some kind of limit
150 is the limit?
140?
other chars affect the result (limit is based on all message chars, not just matching ones?)
a*100 + b + e = 98 1 1
ab*100 + e = 50 50 0
ab*50 + e = 49 50 1
a*50 + b*50 = 50 50
a*51 + b*51 = 49 51
x*50 + a*50 + b*50 = 55.56 44.44
a*200 + b*200 = 100 0
a*120 + b*120 = 80 20
a*150 + b = 100 0
a*149 + b = 100 0
a*140 + b*10 = 100 0
a*130 + b*20 = 90 10
a*130 + b*10 = 90 10
a*130 + b = 99 1
a*130 + b*2 = 98 2
a*130 + b*5 = 95 5
'aaaaaaaaaa '*13 + b*5 = 100 0
it's only counting at most 10 b's?
'a '*60 + 'b '*40 = 85.71 14.29 (6x more a, 60 a, 10 b)
'a '*100 + 'b '*100 = 100 0
'a '*50 + 'b '*50 = 71.43 28.57 (2.5x more a, 50 a, 20 b)
'd ' + 'a '*50 + 'b '*50 = 71.43 27.14 1.43
a + b*100 = 0 100
a + 'b '*100 = 1.41 98.59 (70x more b)
ac + 'b '*100 = 1.41 97.13 1.41
ac + 'b '*150 = 1.41 97.13 1.41
if a term appears at least once, 10 slots are allocated to it, 150 slots in total?
acd + 'b '*150 = 1.39 95.83 1.39 1.39
'acd ' + 'b '*150 = 1.41 95.77 + 1.41 + 1.41 (67.92x more b)
a*70 + b*10 + c*10 + d*10 = 70 10 10 10
a*80 + b*10 + c*10 + d*10 = 70 10 10 10

15
chatbot/package.json Normal file
View file

@ -0,0 +1,15 @@
{
"name": "lbpcomputerbot",
"version": "1.0.0",
"description": "",
"main": "bot.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"tmi.js": "^1.8.5"
}
}

32
chatbot/tools.js Normal file
View file

@ -0,0 +1,32 @@
function encode(value, upper = false, address = false) {
// const aBitCount = 7;
// const bBitCount = 7;
// const cBitCount = 7;
// const dBitCount = 6;
const aBitCount = 4;
const bBitCount = 4;
const cBitCount = 4;
const dBitCount = 4;
const valueBitString = value.toString(2).padStart(12, '0');
const bitString = '10' + (address ? '0' : '1') + (upper ? '1' : '0') + valueBitString;
let index = 0;
const a = parseInt(bitString.slice(0, aBitCount), 2);
index += aBitCount;
const b = parseInt(bitString.slice(index, index + bBitCount), 2);
index += bBitCount;
const c = parseInt(bitString.slice(index, index + cBitCount), 2);
index += cBitCount;
const d = parseInt(bitString.slice(index, index + dBitCount), 2);
index += dBitCount;
const maxTotal = 2 ** aBitCount + 2 ** bBitCount + 2 ** cBitCount + 2 ** dBitCount;
const e = maxTotal - (a + b + c + d);
console.log(bitString);
console.log(a, b, c, d, e);
const values = [...Array(a).fill('a'), ...Array(b).fill('b'), ...Array(c).fill('c'), ...Array(d).fill('d'), ...Array(e).fill('e')];
return values.join(' ');
}