Skip to content

Commit 94fcf0e

Browse files
committed
Add basic Bot example
1 parent 99084a1 commit 94fcf0e

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

examples/basic_bot/main.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import asyncio
2+
import json
3+
import logging
4+
import random
5+
from typing import Any
6+
7+
import twitchio
8+
from twitchio import authentication, eventsub
9+
from twitchio.ext import commands
10+
11+
12+
# NOTE: Consider reading through the Conduit examples
13+
# Store and retrieve these from a .env or similar, but for example showcase you can just full out the below:
14+
CLIENT_ID = ""
15+
CLIENT_SECRET = ""
16+
BOT_ID = ""
17+
OWNER_ID = ""
18+
19+
LOGGER: logging.Logger = logging.getLogger(__name__)
20+
21+
22+
class Bot(commands.Bot):
23+
def __init__(self, **kwargs: Any) -> None:
24+
super().__init__(**kwargs)
25+
26+
async def setup_hook(self) -> None:
27+
# Add our General Commands Component...
28+
await self.add_component(GeneralCommands())
29+
30+
with open(".tio.tokens.json", "rb") as fp:
31+
tokens = json.load(fp)
32+
33+
for user_id in tokens:
34+
if user_id == BOT_ID:
35+
continue
36+
37+
# Subscribe to chat for everyone we have a token...
38+
chat = eventsub.ChatMessageSubscription(broadcaster_user_id=user_id, user_id=BOT_ID)
39+
await self.subscribe_websocket(chat)
40+
41+
async def event_ready(self) -> None:
42+
LOGGER.info("Logged in as: %s", self.user)
43+
44+
async def event_oauth_authorized(self, payload: authentication.UserTokenPayload) -> None:
45+
# Stores tokens in .tio.tokens.json by default; can be overriden to use a DB for example
46+
# Adds the token to our Client to make requests and subscribe to EventSub...
47+
await self.add_token(payload.access_token, payload.refresh_token)
48+
49+
if payload.user_id == BOT_ID:
50+
return
51+
52+
# Subscribe to chat for new authorizations...
53+
chat = eventsub.ChatMessageSubscription(broadcaster_user_id=payload.user_id, user_id=BOT_ID)
54+
await self.subscribe_websocket(chat)
55+
56+
57+
class GeneralCommands(commands.Component):
58+
@commands.command()
59+
async def hi(self, ctx: commands.Context) -> None:
60+
"""Command that replys to the invoker with Hi <name>!
61+
62+
!hi
63+
"""
64+
await ctx.reply(f"Hi {ctx.chatter}!")
65+
66+
@commands.command()
67+
async def say(self, ctx: commands.Context, *, message: str) -> None:
68+
"""Command which repeats what the invoker sends.
69+
70+
!say <message>
71+
"""
72+
await ctx.send(message)
73+
74+
@commands.command()
75+
async def add(self, ctx: commands.Context, left: int, right: int) -> None:
76+
"""Command which adds to integers together.
77+
78+
!add <number> <number>
79+
"""
80+
await ctx.reply(f"{left} + {right} = {left + right}")
81+
82+
@commands.command()
83+
async def choice(self, ctx: commands.Context, *choices: str) -> None:
84+
"""Command which takes in an arbitrary amount of choices and randomly chooses one.
85+
86+
!choice <choice_1> <choice_2> <choice_3> ...
87+
"""
88+
await ctx.reply(f"You provided {len(choices)}: I chose {random.choice(choices)}")
89+
90+
@commands.command(aliases=["thanks", "thank"])
91+
async def give(self, ctx: commands.Context, user: twitchio.User, amount: int, *, message: str | None = None) -> None:
92+
"""A more advanced example of a command which has makes use of the powerful argument parsing, argument converters and
93+
aliases.
94+
95+
The first argument will be attempted to be converted to a User.
96+
The second argument will be converted to an integer if possible.
97+
The third argument is optional and will consume the reast of the message.
98+
99+
!give <@user|user_name> <number> [message]
100+
!thank <@user|user_name> <number> [message]
101+
!thanks <@user|user_name> <number> [message]
102+
"""
103+
msg = f"with message: {message}" if message else ""
104+
await ctx.send(f"{ctx.chatter.mention} gave {amount} thanks to {user.mention} {msg}")
105+
106+
107+
def main() -> None:
108+
twitchio.utils.setup_logging(level=logging.INFO)
109+
110+
async def runner() -> None:
111+
async with Bot(
112+
client_id=CLIENT_ID,
113+
client_secret=CLIENT_SECRET,
114+
bot_id=BOT_ID,
115+
owner_id=OWNER_ID,
116+
prefix="!",
117+
) as bot:
118+
await bot.start()
119+
120+
try:
121+
asyncio.run(runner())
122+
except KeyboardInterrupt:
123+
LOGGER.warning("Shutting down due to KeyboardInterrupt")
124+
125+
126+
if __name__ == "__main__":
127+
main()

0 commit comments

Comments
 (0)