Compare commits

..

5 Commits

17 changed files with 58 additions and 43 deletions

2
.gitignore vendored
View File

@@ -139,4 +139,4 @@ dist
pb/data pb/data
# config files # config files
auth.json .env.*

View File

@@ -107,7 +107,7 @@ VARIABLE|DEFAULT|FUNCTION|REQUIRED
`COOLDOWN`|24 Hours|Cooldown between letting users get a lootbox with `!getloot` in seconds|:x: `COOLDOWN`|24 Hours|Cooldown between letting users get a lootbox with `!getloot` in seconds|:x:
`CLIENT_ID`|None|Set the CLIENT_ID to authenticate the bot|:bangbang: `CLIENT_ID`|None|Set the CLIENT_ID to authenticate the bot|:bangbang:
`CLIENT_SECRET`|None|Set the CLIENT_SECRET to authenticate the bot|:bangbang: `CLIENT_SECRET`|None|Set the CLIENT_SECRET to authenticate the bot|:bangbang:
`REDIRECT_URI`|`https://qweri0p.github.io/url-params/`|The REDIRECT_URI set in the twitch dev console|:bangbang: `REDIRECT_URI`|`https://qwerinope.github.io/url-params/`|The REDIRECT_URI set in the twitch dev console|:bangbang:
`OAUTH_CODE`|None|Authorization code for OAuth|:bangbang: `OAUTH_CODE`|None|Authorization code for OAuth|:bangbang:
`DIFFERENT_BROADCASTER`|`false`|Set this to true when `BOT_NAME` and `CHANNEL` are different.|:white_check_mark: `DIFFERENT_BROADCASTER`|`false`|Set this to true when `BOT_NAME` and `CHANNEL` are different.|:white_check_mark:
`BROADCASER_OAUTH_CODE`|None|OAuth authorization code for the broadcaster (ignored if `DIFFERENT_BROADCASTER` is false)|:bangbang: `BROADCASER_OAUTH_CODE`|None|OAuth authorization code for the broadcaster (ignored if `DIFFERENT_BROADCASTER` is false)|:bangbang:

View File

@@ -5,7 +5,7 @@ import { changeItemCount } from "../lib/items";
import { changeBalance } from "../lib/userHelper"; import { changeBalance } from "../lib/userHelper";
import { vulnerableUsers } from "../lib/timeoutHelper"; import { vulnerableUsers } from "../lib/timeoutHelper";
const give = createBotCommand('give', async (params, { say, broadcasterId, userId, userName }) => { const give = createBotCommand('give', async (params, { say, broadcasterId, userId }) => {
if (userId !== broadcasterId) return if (userId !== broadcasterId) return
const target = await api.users.getUserByName(params[0].replace(/[@]/g, '')) const target = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
@@ -19,10 +19,10 @@ const give = createBotCommand('give', async (params, { say, broadcasterId, userI
else if (data.reason === 'noexist') { await say(`Can't find item ${params[1]}`); return } else if (data.reason === 'noexist') { await say(`Can't find item ${params[1]}`); return }
const selection = items.find(item => item.name === params[1].toLowerCase()) const selection = items.find(item => item.name === params[1].toLowerCase())
await say(`${target.name} now has ${data.count} ${params[1]}${data.count === 1 ? '' : selection?.plural}`) await say(`${target.displayName} now has ${data.count} ${params[1]}${data.count === 1 ? '' : selection?.plural}`)
}) })
const vulnChatters = createBotCommand('vulnchatters', async (_params, { say, userId, broadcasterId, userName }) => { const vulnChatters = createBotCommand('vulnchatters', async (_params, { say, userId, broadcasterId }) => {
if (userId !== broadcasterId) return if (userId !== broadcasterId) return
await say(`There are ${vulnerableUsers.length} vulnerable chatters`) await say(`There are ${vulnerableUsers.length} vulnerable chatters`)

View File

@@ -15,7 +15,7 @@ function getTimeDifference(date1: number, date2: number) {
export default createBotCommand('getloot', async (_params, { reply, userId }) => { export default createBotCommand('getloot', async (_params, { reply, userId }) => {
const user = await api.users.getUserById(userId) const user = await api.users.getUserById(userId)
const data = await lootboxReady(user) const data = await lootboxReady(user!)
if (!data.result) { if (!data.result) {
const { days, hours, minutes, seconds } = getTimeDifference(data.lastlootbox, Date.now() - COOLDOWN) const { days, hours, minutes, seconds } = getTimeDifference(data.lastlootbox, Date.now() - COOLDOWN)
await reply(`lootbox ready in: await reply(`lootbox ready in:

View File

@@ -4,7 +4,7 @@ import api from "../lib/api";
import items from "../items"; import items from "../items";
import { HelixUser } from "@twurple/api"; import { HelixUser } from "@twurple/api";
export default createBotCommand('inv', async (params, { userName, say }) => { export default createBotCommand('inv', async (params, { userName, say, userDisplayName }) => {
let user: HelixUser | null let user: HelixUser | null
if (params.length !== 0) { if (params.length !== 0) {
user = await api.users.getUserByName(params[0].replace(/[@]/g, '')) user = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
@@ -24,10 +24,10 @@ export default createBotCommand('inv', async (params, { userName, say }) => {
messagedata.push(`${itemselection?.prettyname}${amount === 1 ? '' : itemselection?.plural}: ${amount}`) messagedata.push(`${itemselection?.prettyname}${amount === 1 ? '' : itemselection?.plural}: ${amount}`)
} }
if (messagedata.length === 0) { await say(`${data.me ? userName : params[0]} has no items!`); return } if (messagedata.length === 0) { await say(`${data.me ? userDisplayName : params[0]} has no items!`); return }
await say(` await say(`
inventory of ${data.me ? userName : params[0]}: inventory of ${data.me ? userDisplayName : user.displayName}:
${messagedata.join(', ')} ${messagedata.join(', ')}
`) `)
}, { aliases: ['inventory'] }) }, { aliases: ['inventory'] })

View File

@@ -2,18 +2,21 @@ import { BotCommand, createBotCommand } from "@twurple/easy-bot";
import api from "../lib/api"; import api from "../lib/api";
import items from "../items"; import items from "../items";
import { ITEMBUSY, toggleBusy } from "../lib/items";
const aliascommands: BotCommand[] = [] const aliascommands: BotCommand[] = []
for (const item of items) { for (const item of items) {
aliascommands.push(createBotCommand(item.name, async (params, { say, broadcasterId, userId }) => { aliascommands.push(createBotCommand(item.name, async (params, { say, reply, broadcasterId, userId }) => {
if (ITEMBUSY) { await reply(`There is currently an item in use. Try again.`); return }
const user = await api.users.getUserById(userId) const user = await api.users.getUserById(userId)
toggleBusy()
switch (item.name) { switch (item.name) {
case 'blaster': case 'blaster':
case 'silverbullet': case 'silverbullet':
case 'revive': case 'revive':
case 'superrevive': case 'superrevive':
if (params[0] === undefined) { await say('nice miss bro'); return } if (params[0] === undefined) { await reply('Please specify a target'); return }
await item.execute(user!, say, broadcasterId, params[0].replace(/[@]/g, '')) await item.execute(user!, say, broadcasterId, params[0].replace(/[@]/g, ''))
break break
case 'grenade': case 'grenade':
@@ -24,10 +27,11 @@ for (const item of items) {
await item.execute(user!, say) await item.execute(user!, say)
break break
case 'clipboard': case 'clipboard':
if (params[0] === undefined) { await say("Please specify what the clipboard asks") } if (params[0] === undefined) { await reply("Please specify what the clipboard asks") }
await item.execute(user!, say, broadcasterId, params.join(' ')) await item.execute(user!, say, broadcasterId, params.join(' '))
break break
} }
toggleBusy()
}, { aliases: item.aliases })) }, { aliases: item.aliases }))
} }

View File

@@ -14,6 +14,6 @@ export default createBotCommand('balance', async (params, { userName, say }) =>
} }
const data = await getBalance(user) const data = await getBalance(user)
await say(`${user.name} has ${data.balance} qbucks`) await say(`${user.displayName} has ${data.balance} qbucks`)
}, { aliases: ['qbucks', 'qweribucks', 'bal'] }) }, { aliases: ['qbucks', 'qweribucks', 'bal'] })

View File

@@ -3,7 +3,7 @@ import api from "../lib/api";
import { getStats } from "../lib/userHelper"; import { getStats } from "../lib/userHelper";
import { HelixUser } from "@twurple/api"; import { HelixUser } from "@twurple/api";
const stats = createBotCommand('stats', async (params, { say, userName }) => { const stats = createBotCommand('stats', async (params, { say, userName, userDisplayName }) => {
let user: HelixUser | null let user: HelixUser | null
if (params.length !== 0) { if (params.length !== 0) {
user = await api.users.getUserByName(params[0].replace(/[@]/g, '')) user = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
@@ -21,7 +21,7 @@ const stats = createBotCommand('stats', async (params, { say, userName }) => {
await say( await say(
` `
THIS MONTH: Stats of ${data.me ? userName : params[0]}: THIS MONTH: Stats of ${data.me ? userDisplayName : user.displayName}:
Users blasted: ${data.stats.shot.blaster}, Users blasted: ${data.stats.shot.blaster},
Blasted by others: ${data.stats.hit.blaster} (${isNaN(KD) ? 0 : KD.toFixed(2)} K/D). Blasted by others: ${data.stats.hit.blaster} (${isNaN(KD) ? 0 : KD.toFixed(2)} K/D).
Grenades lobbed: ${data.stats.used.grenade} Grenades lobbed: ${data.stats.used.grenade}
@@ -32,7 +32,7 @@ const stats = createBotCommand('stats', async (params, { say, userName }) => {
) )
}) })
const alltime = createBotCommand('alltime', async (params, { say, userName }) => { const alltime = createBotCommand('alltime', async (params, { say, userName, userDisplayName }) => {
let user: HelixUser | null let user: HelixUser | null
if (params.length !== 0) { if (params.length !== 0) {
user = await api.users.getUserByName(params[0].replace(/[@]/g, '')) user = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
@@ -48,7 +48,7 @@ const alltime = createBotCommand('alltime', async (params, { say, userName }) =>
await say( await say(
` `
ALLTIME: Stats of ${data.me ? userName : params[0]}: ALLTIME: Stats of ${data.me ? userDisplayName : user.displayName}:
Users blasted: ${data.stats.shot.blaster}, Users blasted: ${data.stats.shot.blaster},
Blasted by others: ${data.stats.hit.blaster} (${isNaN(KD) ? 0 : KD.toFixed(2)} K/D). Blasted by others: ${data.stats.hit.blaster} (${isNaN(KD) ? 0 : KD.toFixed(2)} K/D).
Grenades lobbed: ${data.stats.used.grenade} Grenades lobbed: ${data.stats.used.grenade}

View File

@@ -3,7 +3,7 @@ import { addTimeoutToDB, timeout } from "../lib/timeoutHelper";
import { changeBalance, getBalance } from "../lib/userHelper"; import { changeBalance, getBalance } from "../lib/userHelper";
import api from "../lib/api"; import api from "../lib/api";
export default createBotCommand('timeout', async (params, { say, broadcasterId, userName }) => { export default createBotCommand('timeout', async (params, { say, broadcasterId, userName, userDisplayName }) => {
const attacker = await api.users.getUserByName(userName) const attacker = await api.users.getUserByName(userName)
const userbal = await getBalance(attacker!) const userbal = await getBalance(attacker!)
if (userbal.balance < 100) { await say('not enough qbucks'); return } if (userbal.balance < 100) { await say('not enough qbucks'); return }
@@ -11,7 +11,7 @@ export default createBotCommand('timeout', async (params, { say, broadcasterId,
const target = await api.users.getUserByName(params[0].replace(/[@]/g, '')) const target = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
const status = await timeout(broadcasterId, target!, 60, `You got blasted by ${userName}`) const status = await timeout(broadcasterId, target!, 60, `You got blasted by ${userName}`)
if (status.status) { if (status.status) {
await say(`${params[0]} got blasted by ${userName}! ${userName} now has ${userbal.balance - 100} qbucks remaining`) await say(`${target?.displayName} got blasted by ${userDisplayName}! ${userDisplayName} now has ${userbal.balance - 100} qbucks remaining`)
await changeBalance(attacker!, -100) await changeBalance(attacker!, -100)
await addTimeoutToDB(attacker!, target!, 'blaster') await addTimeoutToDB(attacker!, target!, 'blaster')
} }
@@ -21,7 +21,7 @@ export default createBotCommand('timeout', async (params, { say, broadcasterId,
await say(`${params[0]} doesn't exist!`) await say(`${params[0]} doesn't exist!`)
break break
case 'banned': case 'banned':
await say(`${params[0]} is already dead!`) await say(`${target?.displayName} is already dead!`)
break break
case 'unknown': case 'unknown':
await say(`NO!`) await say(`NO!`)

View File

@@ -1,21 +1,25 @@
import { createBotCommand } from "@twurple/easy-bot"; import { createBotCommand } from "@twurple/easy-bot";
import api from "../lib/api"; import api from "../lib/api";
import items from "../items"; import items from "../items";
import { ITEMBUSY, toggleBusy } from "../lib/items";
export default createBotCommand('use', async (params, { say, broadcasterId, userId }) => { export default createBotCommand('use', async (params, { say, reply, broadcasterId, userId }) => {
const user = await api.users.getUserById(userId) const user = await api.users.getUserById(userId)
if (params[0] === undefined) return if (params[0] === undefined) return
const selection = items.find(item => item.aliases.includes(params[0].toLowerCase())) const selection = items.find(item => item.aliases.includes(params[0].toLowerCase()))
if (!selection) { say(`${params[0]} does not exist!`); return } if (!selection) { reply(`${params[0]} does not exist!`); return }
if (ITEMBUSY) { await reply(`There is currently an item in use. Try again.`); return }
toggleBusy()
switch (selection.name) { switch (selection.name) {
case 'blaster': case 'blaster':
case 'silverbullet': case 'silverbullet':
case 'revive': case 'revive':
case 'superrevive': case 'superrevive':
if (params[1] === undefined) { await say('nice miss bro'); return } if (params[1] === undefined) { await reply('Please specify a target'); return }
await selection.execute(user!, say, broadcasterId, params[1].replace(/[@]/g, '')) await selection.execute(user!, say, broadcasterId, params[1].replace(/[@]/g, ''))
break break
case 'grenade': case 'grenade':
@@ -26,8 +30,9 @@ export default createBotCommand('use', async (params, { say, broadcasterId, user
await selection.execute(user!, say) await selection.execute(user!, say)
break break
case 'clipboard': case 'clipboard':
if (params[1] === undefined) { await say("Please specify what the clipboard asks")} if (params[1] === undefined) { await reply("Please specify what the clipboard asks") }
await selection.execute(user!, say, broadcasterId, params.slice(1).join(' ')) await selection.execute(user!, say, broadcasterId, params.slice(1).join(' '))
break break
} }
toggleBusy()
}) })

View File

@@ -17,9 +17,9 @@ export const blaster = {
if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no blasters!'); return } if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no blasters!'); return }
const result = await timeout(broadcasterId, target, 60, `You got blasted by ${user.name}`) const result = await timeout(broadcasterId, target, 60, `You got blasted by ${user.displayName}`)
if (result.status) { if (result.status) {
await say(`${targetname} got blasted by ${user.name}! ${user.name} has ${itemResult.count} blaster${itemResult.count === 1 ? '' : 's'} remaining`) await say(`${target?.displayName} got blasted by ${user.displayName}! ${user.displayName} has ${itemResult.count} blaster${itemResult.count === 1 ? '' : 's'} remaining`)
await addTimeoutToDB(user, target!, 'blaster') await addTimeoutToDB(user, target!, 'blaster')
await addUsedItem(user, 'blaster') await addUsedItem(user, 'blaster')
await updateInventory(user, itemResult.inv!) await updateInventory(user, itemResult.inv!)
@@ -29,7 +29,7 @@ export const blaster = {
await say(`${targetname} doesn't exist!`) await say(`${targetname} doesn't exist!`)
break break
case 'banned': case 'banned':
await say(`${targetname} is already dead!`) await say(`${target?.displayName} is already dead!`)
break break
case 'unknown': case 'unknown':
await say(`NO!`) await say(`NO!`)
@@ -52,7 +52,7 @@ export const silverbullet = {
const itemResult = await changeItemCount(user, 'silverbullet') const itemResult = await changeItemCount(user, 'silverbullet')
if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no silver bullets!'); return } if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no silver bullets!'); return }
const result = await timeout(broadcasterId, target, 60 * 60 * 24, `You got hit by a silver bullet fired by ${user.name}`) const result = await timeout(broadcasterId, target, 60 * 60 * 24, `You got hit by a silver bullet fired by ${user.displayName}`)
if (result.status) { if (result.status) {
await say(`${target?.name} got deleted.`) await say(`${target?.name} got deleted.`)
await addTimeoutToDB(user, target!, 'silverbullet') await addTimeoutToDB(user, target!, 'silverbullet')
@@ -64,7 +64,7 @@ export const silverbullet = {
await say(`${targetname} doesn't exist!`) await say(`${targetname} doesn't exist!`)
break break
case 'banned': case 'banned':
await say(`${targetname} is already dead!`) await say(`${target?.displayName} is already dead!`)
break break
case 'unknown': case 'unknown':
await say(`NO!`) await say(`NO!`)

View File

@@ -23,6 +23,6 @@ export const clipboard = {
if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no clipboards!'); return } if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no clipboards!'); return }
await tempapi.polls.createPoll(broadcasterId, { choices: ['Yes', 'No'], duration: 120, title: question }) await tempapi.polls.createPoll(broadcasterId, { choices: ['Yes', 'No'], duration: 120, title: question })
await say(`${user.name} used a clipboard! They have ${itemResult.count} clipboard${itemResult.count === 1 ? '' : 's'} remaining`) await say(`${user.displayName} used a clipboard! They have ${itemResult.count} clipboard${itemResult.count === 1 ? '' : 's'} remaining`)
} }
} }

View File

@@ -28,9 +28,9 @@ export const grenade = {
if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no grenades!'); return } if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no grenades!'); return }
const target = await api.users.getUserById(vulnerableUsers[Math.floor(Math.random() * vulnerableUsers.length)]) const target = await api.users.getUserById(vulnerableUsers[Math.floor(Math.random() * vulnerableUsers.length)])
const result = await timeout(broadcasterId, target!, 60, `You got hit by ${user.name}'s grenade`) const result = await timeout(broadcasterId, target!, 60, `You got hit by ${user.displayName}'s grenade`)
if (result.status) { if (result.status) {
await say(`${target?.name} got blown up by ${user.name}'s grenade!`) await say(`${target?.displayName} got blown up by ${user.displayName}'s grenade!`)
await addTimeoutToDB(user, target!, 'grenade') await addTimeoutToDB(user, target!, 'grenade')
await addUsedItem(user, 'grenade') await addUsedItem(user, 'grenade')
await updateInventory(user, itemResult.inv!) await updateInventory(user, itemResult.inv!)
@@ -59,9 +59,9 @@ export const tnt = {
const soontobedeadusers = shuffle(vulnerableUsers).slice(vulnerableUsers.length - blastedusers) const soontobedeadusers = shuffle(vulnerableUsers).slice(vulnerableUsers.length - blastedusers)
const targets = await api.users.getUsersByIds(soontobedeadusers) const targets = await api.users.getUsersByIds(soontobedeadusers)
for (const target of targets) { for (const target of targets) {
const result = await timeout(broadcasterId, target!, 60, `You got hit by ${user.name}'s TNT`) const result = await timeout(broadcasterId, target!, 60, `You got hit by ${user.displayName}'s TNT`)
if (result.status) { if (result.status) {
await say(`${target?.name} got blown up by TNT!`) await say(`${target?.displayName} got blown up by TNT!`)
await addTimeoutToDB(user, target!, 'tnt') await addTimeoutToDB(user, target!, 'tnt')
await updateInventory(user, itemResult.inv!) await updateInventory(user, itemResult.inv!)
} else { } else {
@@ -71,6 +71,6 @@ export const tnt = {
} }
await addUsedItem(user, 'tnt') await addUsedItem(user, 'tnt')
await say(`${user.name} blew up ${blastedusers} chatters with their TNT! ${user.name} has ${itemResult.count} tnt${itemResult.count === 1 ? '' : 's'} remaining`) await say(`${user.displayName} blew up ${blastedusers} chatters with their TNT! ${user.displayName} has ${itemResult.count} tnt${itemResult.count === 1 ? '' : 's'} remaining`)
} }
} }

View File

@@ -27,6 +27,6 @@ export const lootbox = {
await updateInventory(user, inventory) await updateInventory(user, inventory)
await addUsedItem(user, 'lootbox') await addUsedItem(user, 'lootbox')
await say(`${user.name} got: ${newitems.join(' and ')}`) await say(`${user.displayName} got: ${newitems.join(' and ')}`)
} }
} }

View File

@@ -23,16 +23,16 @@ export const revive = {
await say(`${targetname} does not exist`) await say(`${targetname} does not exist`)
break break
case 'notbanned': case 'notbanned':
await say(`${targetname} doesn't need revives`) await say(`${target?.displayName} doesn't need revives`)
break break
case 'unknown': case 'unknown':
await say("Something went wrong!") await say("Something went wrong!")
break break
case 'healed': case 'healed':
await say(`${targetname} got healed for 30 seconds by ${user.name}`) await say(`${target?.displayName} got healed for 30 seconds by ${user.displayName}`)
break break
case 'revived': case 'revived':
await say(`${targetname} got revived by ${user.name}`) await say(`${target?.displayName} got revived by ${user.displayName}`)
break break
} }
} }
@@ -57,16 +57,16 @@ export const superrevive = {
await say(`${targetname} does not exist`) await say(`${targetname} does not exist`)
break break
case 'notbanned': case 'notbanned':
await say(`${targetname} doesn't need revives`) await say(`${target?.displayName} doesn't need revives`)
break break
case 'unknown': case 'unknown':
await say("Something went wrong!") await say("Something went wrong!")
break break
case 'healed': case 'healed':
await say(`${targetname} got healed for 12 hours by ${user.name}`) await say(`${target?.displayName} got healed for 12 hours by ${user.displayName}`)
break break
case 'revived': case 'revived':
await say(`${targetname} got revived by ${user.name}`) await say(`${target?.displayName} got revived by ${user.displayName}`)
break break
} }
} }

View File

@@ -30,7 +30,7 @@ async function firstAccess(main = true) {
const CLIENT_SECRET = process.env.CLIENT_SECRET const CLIENT_SECRET = process.env.CLIENT_SECRET
const OAUTH_CODE = process.env.OAUTH_CODE const OAUTH_CODE = process.env.OAUTH_CODE
const BROADCASTER_OAUTH_CODE = process.env.BROADCASTER_OAUTH_CODE const BROADCASTER_OAUTH_CODE = process.env.BROADCASTER_OAUTH_CODE
const REDIRECT_URI = process.env.REDIRECT_URI ?? 'https://qweri0p.github.io/url-params/' const REDIRECT_URI = process.env.REDIRECT_URI ?? 'https://qwerinope.github.io/url-params/'
if (!CLIENT_ID) { console.error("No 'CLIENT_ID' for OAuth defined in environment variables."); process.exit(1) } if (!CLIENT_ID) { console.error("No 'CLIENT_ID' for OAuth defined in environment variables."); process.exit(1) }
if (!CLIENT_SECRET) { console.error("No 'CLIENT_SECRET' for OAuth defined in environment variables."); process.exit(1) } if (!CLIENT_SECRET) { console.error("No 'CLIENT_SECRET' for OAuth defined in environment variables."); process.exit(1) }

View File

@@ -26,3 +26,9 @@ export async function changeItemCount(user: HelixUser, item: string, amount = -1
return { result: true, reason: '', count: inv[item], inv } return { result: true, reason: '', count: inv[item], inv }
} }
export let ITEMBUSY = false
export function toggleBusy() {
ITEMBUSY = !ITEMBUSY
}