diff --git a/apps/docs/src/content/docs/guides/python-wrapper.mdx b/apps/docs/src/content/docs/guides/python-wrapper.mdx new file mode 100644 index 0000000..73d2cfa --- /dev/null +++ b/apps/docs/src/content/docs/guides/python-wrapper.mdx @@ -0,0 +1,229 @@ +--- +title: How to use HCTV's python wrapper! +description: How to use HCTV's unofficial Python wrapper. +--- + +A Pycord-style Python wrapper for [hackclub.tv](https://hackclub.tv), made by [Christian](https://github.com/christianwell). Build chat bots with decorators and minimal boilerplate. + +Check it out on PyPI: https://pypi.org/project/hctvwrapper/ +You can take a look at the code [here](https://github.com/christianwell/hctvwrapper) + +``` +pip install hctvwrapper +``` + +## Quick Start + +```python +from hctvwrapper import Bot + +bot = Bot(command_prefix="!") + +@bot.event +async def on_ready(session): + print(f"Logged in as {session.viewer}") + +@bot.event +async def on_message(message): + print(f"{message.author.username}: {message.content}") + +@bot.command() +async def ping(ctx): + await ctx.reply("pong!") + +bot.run("hctvb_your_token_here", channel="bot-playground") +``` + +## Getting a Bot Token + +1. Go to [hackclub.tv](https://hackclub.tv) +2. Create a bot account and get your API key (starts with `hctvb_`) +3. Set it as an environment variable: `export BOT_TOKEN=hctvb_xxx` + +## Guide + +### Events + +Register event handlers with `@bot.event`. The function name determines which event it handles. + +```python +@bot.event +async def on_ready(session): + """Fired when the bot connects and receives session info.""" + print(f"Logged in as {session.viewer.username}") + print(f"Can moderate: {session.permissions.can_moderate}") + print(f"Max message length: {session.moderation.max_message_length}") + +@bot.event +async def on_message(message): + """Fired on every chat message.""" + print(f"[{message.channel}] {message.author.username}: {message.content}") + # message.author.id, .pfp_url, .display_name, .is_bot, + # .is_platform_admin, .channel_role + # message.msg_id, .timestamp, .type + +@bot.event +async def on_history(messages): + """Fired once on connect with up to 100 recent messages.""" + print(f"Got {len(messages)} historical messages") + +@bot.event +async def on_system_message(message): + """Fired on system notifications (bans, unbans, etc.).""" + print(f"System: {message.content}") + +@bot.event +async def on_message_deleted(event): + """Fired when a message is deleted by a moderator.""" + print(f"Message {event.msg_id} deleted in {event.channel}") + +@bot.event +async def on_chat_access(access, channel): + """Fired when chat permissions change (timeouts, bans).""" + print(f"Can send in {channel}: {access.can_send}") + if access.restriction: + print(f" Restriction: {access.restriction.type}") + +@bot.event +async def on_moderation_error(error, channel): + """Fired when a moderation action or message is rejected.""" + print(f"Error in {channel}: {error.code} — {error.message}") + # error.code is one of: FORBIDDEN, RATE_LIMIT, SLOW_MODE, + # TIMED_OUT, BANNED, MESSAGE_TOO_LONG, BLOCKED_TERM, + # INVALID_TARGET, INVALID_REQUEST, NOT_FOUND +``` + +### Commands + +Register commands with `@bot.command()`. The bot automatically parses messages starting with the prefix. + +```python +bot = Bot(command_prefix="!") + +# Simple command — no arguments +@bot.command() +async def ping(ctx): + await ctx.reply("pong!") + +# Named command with aliases +@bot.command(name="say", aliases=["echo", "repeat"]) +async def say_cmd(ctx, *, text): + await ctx.send(text) + +# Positional arguments (split by whitespace) +@bot.command() +async def greet(ctx, name, greeting="hello"): + await ctx.reply(f"{greeting}, {name}!") +``` + +### Context + +The `ctx` object passed to commands gives you everything you need: + +```python +@bot.command() +async def info(ctx): + ctx.message # the full Message object + ctx.author # shortcut to ctx.message.author (Author) + ctx.channel # channel name (str) + ctx.bot # reference to the Bot + + await ctx.reply("text") # sends "@username text" + await ctx.send("text") # sends "text" without mention + await ctx.delete() # deletes the triggering message (needs mod perms) +``` + +### Sending Messages + +```python +# Inside a command +await ctx.reply("mentioned reply") +await ctx.send("plain message") + +# Anywhere (if you have a reference to the bot) +await bot.send("hello!", channel="bot-playground") +``` + +### Multi-Channel + +Connect to multiple channels at once: + +```python +bot.run("hctvb_xxx", channels=["channel1", "channel2", "bot-playground"]) +``` + +Messages and commands work across all channels. Use `ctx.channel` or `message.channel` to know which channel a message came from. + +```python +@bot.event +async def on_message(message): + print(f"[{message.channel}] {message.author.username}: {message.content}") + +@bot.command() +async def where(ctx): + await ctx.reply(f"you're in {ctx.channel}") +``` + +### Moderation + +Bots with moderation permissions can manage users: + +```python +# Timeout a user for 5 minutes (default) +await bot.timeout_user("channel", user_id="user123", duration=300, reason="spam") + +# Ban a user +await bot.ban_user("channel", user_id="user123", reason="repeated violations") + +# Remove a timeout +await bot.lift_timeout("channel", user_id="user123") + +# Unban a user +await bot.unban_user("channel", user_id="user123") + +# Delete a specific message +await bot.delete_message("channel", msg_id="msg-uuid") +``` + +### Async Entry Point + +If you manage your own event loop: + +```python +import asyncio + +async def main(): + bot = Bot(command_prefix="!") + + @bot.event + async def on_ready(session): + print("Connected!") + + await bot.start("hctvb_xxx", channel="bot-playground") + +asyncio.run(main()) +``` + +## Models Reference + +| Model | Fields | +|---|---| +| `Message` | `content`, `author`, `channel`, `msg_id`, `timestamp`, `type`, `is_bot` | +| `Author` | `id`, `username`, `pfp_url`, `display_name`, `is_bot`, `is_platform_admin`, `channel_role` | +| `Session` | `viewer` (Author), `permissions`, `moderation` | +| `Permissions` | `can_moderate` | +| `ModerationSettings` | `has_blocked_terms`, `slow_mode_seconds`, `max_message_length` | +| `SystemMessage` | `type`, `channel`, `content`, `timestamp` | +| `ChatAccess` | `can_send`, `restriction` | +| `Restriction` | `type` (timeout/ban), `reason`, `expires_at` | +| `ModerationError` | `code`, `message`, `restriction` | +| `ModerationEvent` | `type`, `msg_id`, `channel` | + +## Requirements + +- Python 3.10+ +- `websockets` (only dependency) + +## License + +Copyright (c) 2026 Christian Well - [MIT License](https://github.com/christianwell/hctvwrapper/blob/main/LICENSE) \ No newline at end of file diff --git a/apps/docs/src/content/docs/guides/start-stream.mdx b/apps/docs/src/content/docs/guides/start-stream.mdx index 0b9c0b3..71c5fd3 100644 --- a/apps/docs/src/content/docs/guides/start-stream.mdx +++ b/apps/docs/src/content/docs/guides/start-stream.mdx @@ -3,40 +3,40 @@ title: How to stream description: Get started with OBS and streaming on hackclub.tv --- -_This guide demonstrates how to stream with hackclub.tv via OBS Studio, for other streaming softwares you will need to edit these steps for your chosen softwear._ +_This guide demonstrates how to stream with hackclub.tv via OBS Studio. For other streaming software, you will need to adapt these steps for your chosen software._ -- Open OBS Studio +- Open OBS Studio. -(_if it is not installed head to [this webpage](https://obsproject.com/) to download the installer_) +(_If it is not installed, head to [this webpage](https://obsproject.com/) to download the installer._) -![OBS in Windows start menue](../../../assets/obs.png) +![OBS in Windows start menu](../../../assets/obs.png) -- In OBS, in the navbar click `File > Settings` +- In OBS, click `File > Settings` in the top navigation bar. ![Animated GIF of opening the settings page](../../../assets/obs-open-settings.gif) -- In the popup Setting box, from the sidebar open `Stream` +- In the Settings popup, open `Stream` from the sidebar. -- Set `Service` box to `Custom...` +- Set `Service` to `Custom...`. ![Animated GIF of opening 'Stream' settings and changing to 'Custom'](../../../assets/obs-changing-settings.gif) -- Go to https://hackclub.tv/settings/channel/ on your chosen web browser +- Go to https://hackclub.tv/settings/channel/ in your web browser. -(_if you are not logged in you may have to log back in and then try again_) +(_If you are not logged in, you may have to log in again and then try again._) -- Under `Stream Settings` you will find your `Stream Key` and `Stream URL` - copy the `Stream URL` and paste it into OBS +- Under `Stream Settings`, you will find your `Stream Key` and `Stream URL`. Copy the `Stream URL` and paste it into OBS. ![Hack Club TV Stream Settings](../../../assets/hctv-settings.png) -- Go back on to the website and click this Lock Icon icon to regenerate your stream key - copy the new key and past it into the `Stream Key` box in OBS +- Go back to the website and click this Lock Icon icon to regenerate your stream key. Copy the new key and paste it into the `Stream Key` box in OBS. ![OBS Stream Settings with data filled in](../../../assets/obs-custom.png) (_Your OBS settings should now look like this_) -- You can now safely `Apply` changes in OBS and start streaming! +- You can now safely apply the changes in OBS and start streaming. Thanks for using this guide and happy streaming! -_A video tutorial is currently in the making, check back another time if you would like to see it!_ +_A video tutorial is currently being made, so check back later if you would like to see it!_