Metadata-Version: 2.4
Name: riscord-bot
Version: 0.2.2
Summary: Official async Riscord bot client
License: All rights reserved.
Project-URL: Documentation, https://riscord.ir/developers/docs
Project-URL: Changelog, https://riscord.ir/downloads/riscord-bot-changelog.md
Project-URL: Homepage, https://riscord.ir
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Framework :: AsyncIO
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-socketio[asyncio_client]<6,>=5.11
Requires-Dist: aiohttp<4,>=3.10
Dynamic: license-file

# Riscord bot SDK — Python

Requires Python 3.11 or newer. Install with `python -m pip install riscord-bot`. Versioned source archives remain available from [Developer Docs](https://riscord.ir/developers/docs); install a downloaded archive with `python -m pip install ./riscord-bot-python-0.2.2.tar.gz`.

[SDK release notes](https://riscord.ir/downloads/riscord-bot-changelog.md)

Create and install a bot through `https://riscord.ir/developers`, request View Channel and Send Messages, generate its token and set the `RISCORD_BOT_TOKEN` environment variable. Never commit the token.

```python
import asyncio, os
from riscord import Client

bot = Client(os.environ['RISCORD_BOT_TOKEN'])

@bot.command('hello')
async def hello(interaction):
    await interaction.reply('Hello!', private=True)

async def main():
    await bot.register_commands([{'name':'hello','description':'Say hello','contexts':['server','dm']}])
    try:
        await bot.run()
    finally:
        await bot.close()

asyncio.run(main())
```

Defer slow work with `await interaction.defer(private=True)` before replying; later replies retain that audience. `show_modal({customId,title,fields})` opens a form. Use `@bot.on('interaction')` for buttons, selects and submitted forms and inspect `interaction.kind` and `interaction.data`.

`send(channel_id,content,components=...)`, `open_dm(user_id)`, `send_dm(conversation_id,content)`, `moderate(server_id,user_id,action,...)`, `history`, `edit` and `delete` expose the corresponding API operations. For message options, `client_id` is a Python keyword argument; component/command JSON follows the documented camelCase wire schema. IDs remain strings.

Only registered text commands, mentions and the bot's DMs are delivered without broader Message Content permission. SDKs ignore automated messages, reconnect with bounded replay and honor retry delays. Deduplication is bounded and memory-only; persist operation IDs for external effects that must survive restarts.

For voice playback, request View Channel, Connect and Speak when installing the bot, and allow them in the target server voice channel. Install a separate FFmpeg executable with the `libopus` encoder and SRTP support and add it to `PATH`; the SDK does not download an encoder. Chat and interactions do not need FFmpeg.

```python
await bot.connect()
voice = await bot.join_voice('VOICE_CHANNEL_ID')
try:
    await voice.play('./music.ogg')
    await voice.play('https://example.com/direct-audio.ogg')
finally:
    await voice.leave()
```

`join_voice(channel_id)` requires a connected bot gateway and returns a `VoiceConnection`. `play(source, ffmpeg='ffmpeg')` accepts a trusted local audio file or direct HTTP(S) audio URL and waits until playback finishes. A new `play` replaces the previous track; call it in an `asyncio` task if your handler must keep accepting other work. `stop()` ends playback while keeping the bot in the channel; `leave()` releases the connection. Cancelling the playback task also stops its encoder. `playing`, `closed`, `channel_id` and `server_id` expose connection state.

Voice is send-only and self-deafened; the SDK never receives or records channel audio. Each playback gets fresh Opus/SRTP media parameters and stays within the server's audio bitrate limit. The SDK renews the lease every ten seconds and stops playback on a lost lease, gateway disconnect or `bot.close()`. Reconnecting the gateway does not rejoin voice automatically. One client owns one voice channel at a time, and stale playback cleanup cannot stop its replacement.

Use sources you control. FFmpeg fetches URLs from the bot's machine, so do not pass arbitrary member-provided paths or URLs to `play`. Website pages that require a media extractor are not direct audio URLs. Encoder errors omit raw process output because it can contain private source URLs or transport keys. Set `RISCORD_VOICE_CHANNEL_ID` and `RISCORD_AUDIO_SOURCE` alongside the bot token, then run `examples/music.py` to play a configured source and leave when it finishes.

The public [Developer Docs](https://riscord.ir/developers/docs) cover the API contract, limits and migration guidance.
