mirror of
https://github.com/qwerinope/qweribot.git
synced 2025-12-19 01:01:39 +01:00
add iteminfo command, change name of project to qweribot, fix ghcr publish url, add proper README.md
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
name: Build and Publish docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Login to container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.qwerinope.com
|
||||
username: qwerinope
|
||||
password: ${{ secrets.PAT }}
|
||||
- name: Get repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Docker Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: Dockerfile.dogbot
|
||||
context: .
|
||||
push: true
|
||||
tags: git.qwerinope.com/qwerinope/dogbot-bot:latest
|
||||
@@ -1,26 +0,0 @@
|
||||
name: Build and Publish docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Login to container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.qwerinope.com
|
||||
username: qwerinope
|
||||
password: ${{ secrets.PAT }}
|
||||
- name: Get repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Docker Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: Dockerfile.pocketbase
|
||||
context: .
|
||||
push: true
|
||||
tags: git.qwerinope.com/qwerinope/dogbot-pocketbase:latest
|
||||
4
.github/workflows/docker-pocketbase.yml
vendored
4
.github/workflows/docker-pocketbase.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Build and Publish pocketbase docker image
|
||||
name: Build and Publish qweribot-pocketbase docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -23,5 +23,5 @@ jobs:
|
||||
file: Dockerfile.pocketbase
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/qweri0p/dogbot-pocketbase:latest
|
||||
tags: ghcr.io/qwerinope/qweribot-pocketbase:latest
|
||||
secrets: "github_token=${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Build and Publish dogbot docker image
|
||||
name: Build and Publish qweribot docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -20,8 +20,8 @@ jobs:
|
||||
- name: Docker Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: Dockerfile.dogbot
|
||||
file: Dockerfile.qweribot
|
||||
context: .
|
||||
push: true
|
||||
tags: ghcr.io/qweri0p/dogbot-bot:latest
|
||||
tags: ghcr.io/qwerinope/qweribot-bot:latest
|
||||
secrets: "github_token=${{ secrets.GITHUB_TOKEN }}"
|
||||
119
README.md
119
README.md
@@ -1,18 +1,109 @@
|
||||
# OpenMandooBot
|
||||
# qweribot
|
||||
|
||||
A copy of twitch bot 'MandooBot' in [eddie's stream](twitch.tv/eddie).
|
||||
|
||||
## Usage
|
||||
|
||||
### Commands
|
||||
|
||||
Here is the list of commands.
|
||||
|
||||
COMMAND|FUNCTION|USER|ALIASES
|
||||
-|-|-|-
|
||||
`!balance [target]`|List write the amount of money the user or the target user has.|anyone|`!bal, !qbucks, !qweribucks`
|
||||
`!inventory [target]`|Show inventory contents of user or the target user.|anyone|`!inv`
|
||||
`!getloot`|Give user a lootbox. This command has a cooldown that can be changed in `lootbox.ts`. You can optionally require the user to subscribe.|anyone|`None`
|
||||
`!stats [target]`|Show the stats of user or target user including users shot, TNT used and grenades lobbed.|anyone|`None`
|
||||
`!timeout {target}`|Give the target user a timeout of 60 seconds. This requires 100 qbucks.|anyone|`None`
|
||||
`!use {item}`|Use a specific item. The user needs the specific item in their inventory. For items please look at the table below|anyone|`None`
|
||||
`!iteminfo {item}`|Gives a description of the requested item. Identical to [the item descriptions in this document](#items)|anyone|`!item`
|
||||
`!modme`|Gives the user moderator status. Only gives users moderator status if their name is in `modme.ts`|anyone|`None`
|
||||
`!give {target} {item} {count}`|Give a specific user a specific amount of an item. Negative amounts can be used to remove items|streamer|`None`
|
||||
`!vulnchatters`|Print how many users are vulnerable to TNT and grenade explosions.|streamer|`None`
|
||||
|
||||
### Items
|
||||
|
||||
Here are the items that can be used.
|
||||
These can be used with the `!use` command or with their aliases.
|
||||
|
||||
ITEM|FUNCTION|ALIASES
|
||||
-|-|-
|
||||
`blaster {target}`|Times the target user out for 60 seconds|`!blast, !blaster`
|
||||
`silverbullet {target}`|Times the target user out for 24 hours|`!execute, !silverbullet`
|
||||
`grenade`|Times a random chatter out for 60 seconds|`!grenade`
|
||||
`tnt`|Times out 1 to 10 chatters for 60 seconds|`!tnt`
|
||||
`lootbox`|Gives the user some qbucks, and possibly some items|`!lootbox`
|
||||
`clipboard {message}`|Starts a two minute long poll with the user specified message|`!clipboard`
|
||||
|
||||
## Setup
|
||||
|
||||
### Docker compose (recommended)
|
||||
|
||||
Docker compose is the only recommended way to use qweribot as it sets up pocketbase and the bot automatically.
|
||||
The `compose.yaml` file in the repository is for development.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
qweribot:
|
||||
container_name: qweribot
|
||||
image: ghcr.io/qwerinope/qweribot:latest
|
||||
environment: # The README.md has more detail on these config options
|
||||
# Use the supplied .example.env for setting environment variables
|
||||
- BOT_NAME=$BOT_NAME
|
||||
- CHANNEL=$CHANNEL
|
||||
# The following environment variables can be removed after first setup
|
||||
- CLIENT_ID=$CLIENT_ID
|
||||
- CLIENT_SECRET=$CLIENT_SECRET
|
||||
- REDIRECT_URI=$REDIRECT_URI
|
||||
- OAUTH_CODE=$OAUTH_CODE # If this variable is left empty on starting, the bot will direct the user to a URL where the OAuth code can be obtained
|
||||
# The following environment variables need to only be set if the bot user and the streamer are not using the same account
|
||||
- DIFFERENT_BROADCASTER=$DIFFERENT_BROADCASTER # Set to either true or false
|
||||
- BROADCASTER_OAUTH_CODE=$BROADCASTER_OAUTH_CODE # As with OAUTH_CODE, leave empty for instructions
|
||||
# Make sure that CLIENT_ID, CLIENT_SECRET and REDIRECT_URI are still set when enabling DIFFERENT_BROADCASTER after first setup
|
||||
restart: no
|
||||
depends_on:
|
||||
pocketbase:
|
||||
condition: service_started
|
||||
|
||||
pocketbase:
|
||||
container_name: pocketbase
|
||||
image: ghcr.io/qwerinope/pocketbase-qweribot:latest
|
||||
# If environment variables are left empty, the default user & password will be: test@example.com and 1234567890
|
||||
# This will only impact the login on http://localhost:8090
|
||||
#environment:
|
||||
# - EMAIL=test@example.com
|
||||
# - PASSWORD=1234567890
|
||||
restart: no
|
||||
ports:
|
||||
- 8090:8090
|
||||
volumes:
|
||||
# Make sure that the data in the container at /pb/pb_data is persistent
|
||||
- ./data:/pb/pb_data
|
||||
```
|
||||
|
||||
### Native (not recommended)
|
||||
|
||||
If you wish to run the bot not using docker, you will need to set up a [pocketbase](pocketbase.io) instance, and point the `PBURL` environment variable to the correct address.
|
||||
Also make sure the migration from `pb/migrations` is passed into the pocketbase instance.
|
||||
|
||||
Install dependencies with `bun install`.
|
||||
Run the bot with `bun run src/bot.ts`
|
||||
|
||||
## Configuration
|
||||
|
||||
VARIABLE|DEFAULT|FUNCTION
|
||||
-|-|-
|
||||
`BOT_NAME`|None|Set the name of the bot user for Authentification
|
||||
`CHANNEL`|None| Set the name of the twitch channel to join
|
||||
`CLIENT_ID`|None|Set the CLIENT_ID to authenticate the bot (ignored after setup)
|
||||
`CLIENT_SECRET`|None|Set the CLIENT_SECRET to authenticate the bot (ignored after setup)
|
||||
`REDIRECT_URI`|`https://qweri0p.github.io/url-params/`|The REDIRECT_URI set in the twitch dev console (optional after setup)
|
||||
`OAUTH_CODE`|None|Authorization code for OAuth (ignored after setup)
|
||||
`DIFFERENT_BROADCASTER`|`false`|Set this to true when `BOT_NAME` and `CHANNEL` are different.
|
||||
`BROADCASER_OAUTH_CODE`|None|OAuth authorization code for the broadcaster (ignored if `DIFFERENT_BROADCASTER` is false) (optional after setup)
|
||||
`PBURL`|`http://pocketbase:8090`|Where the pocketbase database is found
|
||||
`EMAIL`|`test@example.com`|Pocketbase Admin UI email used for login (ignored after setup)
|
||||
`PASSWORD`|`1234567890`|Pocketbase Admin UI password used for login (ignored after setup)
|
||||
These are the environment variables that can be used to set up the bot.
|
||||
Options with :bangbang: in the Required column need to be present for setup, and can be removed afterwards.
|
||||
|
||||
VARIABLE|DEFAULT|FUNCTION|REQUIRED
|
||||
-|-|-|-
|
||||
`BOT_NAME`|None|Set the name of the bot user for Authentification|:white_check_mark:
|
||||
`CHANNEL`|None| Set the name of the twitch channel to join|:white_check_mark:
|
||||
`CLIENT_ID`|None|Set the CLIENT_ID 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:
|
||||
`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:
|
||||
`BROADCASER_OAUTH_CODE`|None|OAuth authorization code for the broadcaster (ignored if `DIFFERENT_BROADCASTER` is false)|:bangbang:
|
||||
`PBURL`|`http://pocketbase:8090`|Where the pocketbase database is found|:x:
|
||||
`EMAIL`|`test@example.com`|Pocketbase Admin UI email used for login|:x:
|
||||
`PASSWORD`|`1234567890`|Pocketbase Admin UI password used for login|:x:
|
||||
|
||||
@@ -18,10 +18,10 @@ services:
|
||||
depends_on:
|
||||
pocketbase:
|
||||
condition: service_started
|
||||
container_name: dogbot
|
||||
container_name: qweribot
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.dogbot
|
||||
dockerfile: Dockerfile.qweribot
|
||||
restart: no
|
||||
develop:
|
||||
watch:
|
||||
|
||||
@@ -4,7 +4,7 @@ import { changeItemCount } from "../lib/items";
|
||||
import { changeBalance } from "../lib/userHelper";
|
||||
import { vulnerableUsers } from "../lib/timeoutHelper";
|
||||
|
||||
const give = createBotCommand('give', async (params, { say, broadcasterId, userId }) => {
|
||||
const give = createBotCommand('give', async (params, { say, broadcasterId, userId, userName }) => {
|
||||
if (userId !== broadcasterId) return
|
||||
|
||||
const target = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
|
||||
@@ -12,7 +12,7 @@ const give = createBotCommand('give', async (params, { say, broadcasterId, userI
|
||||
|
||||
if (isNaN(parseInt(params[2]))) { await say(`Specify the amount`); return }
|
||||
|
||||
const data = params[1].toLowerCase() === 'mbucks' ? await changeBalance(target, parseInt(params[2])) : await changeItemCount(target, params[1].toLowerCase(), parseInt(params[2]))
|
||||
const data = params[1].toLowerCase() === 'qbucks' ? await changeBalance(target, parseInt(params[2])) : await changeItemCount(target, params[1].toLowerCase(), parseInt(params[2]))
|
||||
|
||||
if (data.reason === 'negative') { await say(`${target.name} only has ${data.count}. Cannot yoink ${-parseInt(params[2])} ${params[1]}`); return }
|
||||
else if (data.reason === 'noexist') { await say(`Can't find item ${params[1]}`); return }
|
||||
@@ -20,7 +20,7 @@ const give = createBotCommand('give', async (params, { say, broadcasterId, userI
|
||||
await say(`${target.name} now has ${data.count} ${params[1]}`)
|
||||
})
|
||||
|
||||
const vulnChatters = createBotCommand('vulnchatters', async (_params, { say, userId, broadcasterId }) => {
|
||||
const vulnChatters = createBotCommand('vulnchatters', async (_params, { say, userId, broadcasterId, userName }) => {
|
||||
if (userId !== broadcasterId) return
|
||||
|
||||
await say(`There are ${vulnerableUsers.length} vulnerable chatters`)
|
||||
|
||||
@@ -3,7 +3,7 @@ import { COOLDOWN, lootboxReady, resetLootboxTimer } from "../lib/lootboxes";
|
||||
import { changeItemCount } from "../lib/items"
|
||||
import api from "../lib/api"
|
||||
|
||||
function getTimeDifference(date1: number , date2: number) {
|
||||
function getTimeDifference(date1: number, date2: number) {
|
||||
const diff = Math.abs(date1 - date2);
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
||||
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
@@ -13,9 +13,10 @@ function getTimeDifference(date1: number , date2: number) {
|
||||
return { days, hours, minutes, seconds };
|
||||
}
|
||||
|
||||
export default createBotCommand('getloot', async (_params, { reply, userId/*, broadcasterId*/ }) => {
|
||||
export default createBotCommand('getloot', async (_params, { reply, userId, broadcasterId }) => {
|
||||
const user = await api.users.getUserById(userId)
|
||||
// if (!user?.isSubscribedTo(broadcasterId)) {await reply('Subscribe to get loot mandoooSmile'); return}
|
||||
// Remove the comment on the following line to only give lootboxes to subscribed users
|
||||
//if (!user?.isSubscribedTo(broadcasterId)) { await reply('Subscribe to get loot :)'); return }
|
||||
const data = await lootboxReady(user)
|
||||
if (!data.result) {
|
||||
const { days, hours, minutes, seconds } = getTimeDifference(data.lastlootbox, Date.now() - COOLDOWN)
|
||||
@@ -27,7 +28,7 @@ export default createBotCommand('getloot', async (_params, { reply, userId/*, br
|
||||
`)
|
||||
return
|
||||
}
|
||||
await reply(`You got a lootbox mandoooSmile`)
|
||||
await reply(`You got a lootbox :)`)
|
||||
await changeItemCount(user!, 'lootbox', 1)
|
||||
await resetLootboxTimer(data.DBuser)
|
||||
})
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import timeout from "./timeout";
|
||||
import thank from "./thank"
|
||||
import inventory from "./inventory";
|
||||
import stats from "./stats";
|
||||
import mbucks from "./mbucks";
|
||||
import qbucks from "./qbucks";
|
||||
import getloot from "./getloot";
|
||||
import modme from "./modme";
|
||||
import use from "./use";
|
||||
import iteminfo from "./iteminfo"
|
||||
|
||||
import aliases from './itemAliases'
|
||||
import admin from './admin'
|
||||
|
||||
export default [timeout, thank, inventory, stats, mbucks, getloot, modme, use, ...aliases, ...admin]
|
||||
export default [timeout, inventory, stats, qbucks, getloot, modme, use, iteminfo, ...aliases, ...admin]
|
||||
|
||||
31
src/commands/iteminfo.ts
Normal file
31
src/commands/iteminfo.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { createBotCommand } from "@twurple/easy-bot";
|
||||
|
||||
export default createBotCommand('iteminfo', async (params, { say }) => {
|
||||
if (params[0] === undefined) { await say('No item specified!'); return }
|
||||
let message = ''
|
||||
switch (params[0].toLowerCase()) {
|
||||
case 'blaster':
|
||||
message = "Item: blaster {target}, Function: Times the target user out for 60 seconds. Aliases: !blast, !blaster"
|
||||
break
|
||||
case 'silver':
|
||||
case 'silverbullet':
|
||||
message = "`Item: silverbullet {target}, Function: Times the target user out for 24 hours. Aliases: !execute, !silverbullet"
|
||||
break
|
||||
case 'grenade':
|
||||
message = "Item: grenade, Function: Times a random chatter out for 60 seconds. Aliases: !grenade"
|
||||
break
|
||||
case 'tnt':
|
||||
message = "Item: tnt, Function: Times out 1 to 10 chatters for 60 seconds. Aliases: !tnt"
|
||||
break
|
||||
case 'lootbox':
|
||||
message = "Item: lootbox, Function: Gives the user some qbucks, and possibly some items. Aliases: !lootbox"
|
||||
break
|
||||
case 'clipboard':
|
||||
message = "Item: clipboard {message}, Function: Starts a two minute long poll with the user specified message. Aliases: !clipboard"
|
||||
break
|
||||
default:
|
||||
message = "Item not found"
|
||||
break
|
||||
}
|
||||
await say(message)
|
||||
}, { aliases: ['item'] })
|
||||
@@ -3,10 +3,10 @@ import { HelixUser } from "@twurple/api";
|
||||
import api from "../lib/api";
|
||||
import { getBalance } from "../lib/userHelper";
|
||||
|
||||
export default createBotCommand('mbucks', async (params, { userName, say }) => {
|
||||
export default createBotCommand('balance', async (params, { userName, say }) => {
|
||||
let user: HelixUser | null
|
||||
if (params.length !== 0) {
|
||||
user = await api.users.getUserByName(params[0].replace(/[^a-zA-Z0-9]/g, ''))
|
||||
user = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
|
||||
} else user = await api.users.getUserByName(userName)
|
||||
if (!user) {
|
||||
await say(`User ${params[0]} not found`)
|
||||
@@ -14,6 +14,6 @@ export default createBotCommand('mbucks', async (params, { userName, say }) => {
|
||||
}
|
||||
|
||||
const data = await getBalance(user)
|
||||
await say(`${user.name} has ${data.balance} mbucks ${data.balance === 0 ? 'mandoooYikes' : 'mandoooSmile'}`)
|
||||
await say(`${user.name} has ${data.balance} qbucks ${data.balance === 0 ? 'mandoooYikes' : 'mandoooSmile'}`)
|
||||
|
||||
}, { aliases: ['mbux', 'mandoobucks'] })
|
||||
}, { aliases: ['qbucks', 'qweribucks', 'bal'] })
|
||||
@@ -1,6 +0,0 @@
|
||||
import { createBotCommand } from "@twurple/easy-bot";
|
||||
|
||||
export default createBotCommand("thank", async (params, { say, msg }) => {
|
||||
if (params.length === 0) { await say(`chumpi4Heart ${msg.userInfo.userName}`); return }
|
||||
await say(`chumpi4Heart ${params.join(' ')}`)
|
||||
})
|
||||
@@ -6,12 +6,12 @@ import api from "../lib/api";
|
||||
export default createBotCommand('timeout', async (params, { say, broadcasterId, userName }) => {
|
||||
const attacker = await api.users.getUserByName(userName)
|
||||
const userbal = await getBalance(attacker!)
|
||||
if (userbal.balance < 100) { await say('not enough mandoobucks'); return }
|
||||
if (userbal.balance < 100) { await say('not enough qbucks'); return }
|
||||
if (params.length === 0) { await say("nice miss bro"); return }
|
||||
const target = await api.users.getUserByName(params[0].replace(/[^a-zA-Z0-9]/g, ''))
|
||||
const target = await api.users.getUserByName(params[0].replace(/[@]/g, ''))
|
||||
const status = await timeout(broadcasterId, target!, 60, `You got blasted by ${userName}`)
|
||||
if (status.status) {
|
||||
await say(`${params[0]} got mandoooGun by ${userName}! mandoooGOTTEM ${userName} now has ${userbal.balance - 100} mandoobucks remaining`)
|
||||
await say(`${params[0]} got blasted by ${userName}! mandoooGOTTEM ${userName} now has ${userbal.balance - 100} qbucks remaining`)
|
||||
await changeBalance(attacker!, -100)
|
||||
await addTimeoutToDB(attacker!, target!, 'blaster')
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function useBlaster(broadcasterId: string, attacker: HelixUser, tar
|
||||
|
||||
const result = await timeout(broadcasterId, target!, 60, `You got blasted by ${attacker.name}`)
|
||||
if (result.status) {
|
||||
await say(`${targetname} got mandoooGun by ${attacker.name}! mandoooGOTTEM ${attacker.name} has ${itemResult.count} blaster${itemResult.count === 1 ? '' : 's'} remaining`)
|
||||
await say(`${targetname} got blasted by ${attacker.name}! mandoooGOTTEM ${attacker.name} has ${itemResult.count} blaster${itemResult.count === 1 ? '' : 's'} remaining`)
|
||||
await addTimeoutToDB(attacker, target!, 'blaster')
|
||||
} else {
|
||||
switch (result.reason) {
|
||||
@@ -126,11 +126,11 @@ function getRandom(): number {
|
||||
export async function useLootbox(user: HelixUser, say: (arg0: string) => Promise<void>) {
|
||||
const itemResult = await changeItemCount(user, 'lootbox')
|
||||
if (!itemResult.result && itemResult.reason === 'negative') { await say('You have no lootboxes mandoooYikes'); return }
|
||||
// Lootbox logic will for now just be get 25 mbucks, with 50% chance to get a grenade 25% chance to get a blaster and 10% chance to get TNT
|
||||
// Lootbox logic will for now just be get 25 qbucks, with 50% chance to get a grenade 25% chance to get a blaster and 10% chance to get TNT
|
||||
let inventory = await getInventory(user)
|
||||
let newitems: string[] = []
|
||||
await changeBalance(user, 25)
|
||||
newitems.push('25 mbucks')
|
||||
newitems.push('25 qbucks')
|
||||
if (getRandom() <= 50) { newitems.push('1 grenade'); inventory.grenade += 1 }
|
||||
if (getRandom() <= 25) { newitems.push('1 blaster'); inventory.blaster += 1 }
|
||||
if (getRandom() <= 10) { newitems.push('1 tnt'); inventory.tnt += 1 }
|
||||
|
||||
Reference in New Issue
Block a user