- discord.py + fluxer.py bots run side-by-side in one asyncio process - messages relay through per-channel incoming webhooks with the original author's name and avatar (suffixed '(Discord)' / '(Fluxer)') - loop protection: bot-authored and webhook-authored messages are ignored - attachments re-uploaded natively both directions (8 MB cap) - emoji mirroring: on-demand upload into the receiving guild with LRU eviction of bridge-created emojis only; pre-existing emojis untouched; to-Discord direction opt-in (50-slot default guild cap)
155 lines
5.2 KiB
Markdown
155 lines
5.2 KiB
Markdown
# itako — INSTALL
|
|
|
|
Bridge one Discord channel and one Fluxer channel so messages cross between
|
|
them, shown as webhook posts with the original author's name and avatar.
|
|
|
|
## Requirements
|
|
|
|
- **Python 3.11+**
|
|
- **[uv](https://docs.astral.sh/uv/)** (package manager) — `pip install uv` or
|
|
the [standalone installer](https://docs.astral.sh/uv/getting-started/installation/)
|
|
- A machine that can reach `discord.com`, `fluxer.app`, and
|
|
`gateway.fluxer.app` over HTTPS/WSS.
|
|
|
|
## 1. Discord bot
|
|
|
|
1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
|
|
→ **New Application**.
|
|
2. **Bot** tab → *Reset Token* → copy the token (you'll paste it into `.env`).
|
|
3. **Bot** tab → *Privileged Gateway Intents* → enable:
|
|
- **MESSAGE CONTENT INTENT** (required — without it the bot can't read text)
|
|
- **SERVER MEMBERS INTENT** (not required) · **PRESENCE INTENT** (not required)
|
|
4. **OAuth2 → URL Generator**: check `bot`, then permissions:
|
|
- Manage Webhooks
|
|
- Send Messages
|
|
- View Channels / View Server Insights (read access to the relay channel)
|
|
5. Open the generated URL, invite the bot to your server.
|
|
|
|
> The bridge creates one webhook named `itako-bridge` in the relay channel on
|
|
> first run and reuses it afterwards. You can also create it manually with
|
|
> that exact name if you prefer.
|
|
|
|
## 2. Fluxer bot
|
|
|
|
Fluxer's API is Discord-compatible; bots are created similarly:
|
|
|
|
1. In Fluxer: **Settings → Applications** (or the developer portal) → create a
|
|
**bot application**. Copy the **bot token** and note the **client secret**
|
|
(only needed for OAuth flows — this bridge doesn't use it).
|
|
2. Invite the bot to your Fluxer guild with:
|
|
- Manage Webhooks
|
|
- Send Messages
|
|
- Read Messages
|
|
|
|
## 3. Get the channel & guild IDs
|
|
|
|
Enable Developer Mode to right-click → **Copy ID**:
|
|
|
|
| Platform | How |
|
|
|---|---|
|
|
| Discord | User Settings → Advanced → Developer Mode; right-click guild/channel → Copy ID |
|
|
| Fluxer | Same pattern as Discord (it's wire-compatible) |
|
|
|
|
You need: **Discord guild id**, **Discord channel id**, **Fluxer guild id**,
|
|
**Fluxer channel id**.
|
|
|
|
## 4. Configure
|
|
|
|
```bash
|
|
cd Code/itako
|
|
cp .env.example .env
|
|
```
|
|
|
|
Edit `.env`:
|
|
|
|
```ini
|
|
DISCORD_TOKEN = "your-discord-bot-token"
|
|
FLUXER_TOKEN = "your-fluxer-bot-token"
|
|
|
|
DISCORD_CHANNEL_ID = "1234567890123456789"
|
|
FLUXER_CHANNEL_ID = "9876543210987654321"
|
|
|
|
DISCORD_GUILD_ID = "1111111111111111111"
|
|
FLUXER_GUILD_ID = "2222222222222222222"
|
|
```
|
|
|
|
Guild IDs are used for emoji-name lookups (so matching custom emojis render
|
|
natively instead of degrading to `:name:` text). Quotes are optional;
|
|
`python-dotenv` handles both styles.
|
|
|
|
Optional keys:
|
|
|
|
```ini
|
|
BRIDGE_WEBHOOK_NAME = "itako-bridge" # webhook name created/reused per channel
|
|
|
|
# Emoji mirroring: upload unknown emojis into the receiving guild on first
|
|
# use, evicting the least-recently-used *bridge-created* emoji when the cap
|
|
# is hit. Pre-existing emojis are never touched or counted.
|
|
EMOJI_MIRROR_TO_FLUXER = true # mirror Discord emojis into Fluxer (default)
|
|
EMOJI_MIRROR_CAP_FLUXER = 150 # Fluxer's hard cap is 500; stay well under
|
|
EMOJI_MIRROR_TO_DISCORD = false # off by default — normal Discord guilds have
|
|
# only 50 emoji slots; set true + raise cap if
|
|
# your guild has more slots to spare
|
|
EMOJI_MIRROR_CAP_DISCORD = 30
|
|
```
|
|
|
|
## 5. Install dependencies
|
|
|
|
```bash
|
|
uv sync
|
|
```
|
|
|
|
This pulls in `discord.py`, `fluxer-py` (from GitHub), `python-dotenv`,
|
|
and `aiohttp`.
|
|
|
|
## 6. Run
|
|
|
|
```bash
|
|
uv run python -m itako.bridge
|
|
```
|
|
|
|
Expected startup log:
|
|
|
|
```
|
|
itako INFO Fluxer connected as <botname>
|
|
itako INFO Reusing Fluxer webhook ...
|
|
itako INFO Reusing Discord webhook ...
|
|
itako INFO Loaded N Fluxer emojis
|
|
itako INFO Discord connected as <botname>#0000
|
|
itako INFO Loaded N Discord emojis
|
|
```
|
|
|
|
Send a message in either channel — it should appear in the other within a
|
|
second, posted by the `itako-bridge` webhook with the author's username
|
|
(`name (Discord)` / `name (Fluxer)`) and avatar.
|
|
|
|
### Run at startup (optional)
|
|
|
|
For an always-on bridge, wrap the command in a service, e.g. with
|
|
[NSSM](https://nssm.cc/) on Windows:
|
|
|
|
```
|
|
nssm install itako "C:\path\to\uv.exe" run python -m itako.bridge
|
|
nssm set itako AppDirectory C:\Users\<you>\Code\itako
|
|
nssm start itako
|
|
```
|
|
|
|
(Or see TODO.md for planned first-class service support.)
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Fix |
|
|
|---|---|
|
|
| Discord logs `session has been invalidated` repeatedly | Message Content intent not enabled in the Developer Portal |
|
|
| Messages relay but show no avatar | Author has default avatar; bridge substitutes platform default |
|
|
| Emojis show as `:name:` | That emoji doesn't exist on the receiving side; add it there or ignore |
|
|
| `AttributeError: 'NoneType' object has no attribute ... fluxer` | Fluxer bot token wrong, or bot not invited to the guild/channel |
|
|
| Nothing relays at all | Check both channel IDs point at channels the respective bot can read |
|
|
|
|
## Behavior notes
|
|
|
|
- Bot-authored and webhook-authored messages are ignored (loop prevention).
|
|
- Attachments up to **8 MB** are re-uploaded natively so images embed inline.
|
|
- Custom emojis are **never uploaded/mirrored** — only rewritten when the same
|
|
emoji name exists on the receiving platform (no slot usage on either side).
|