Files
ph0sgene f3154396fa Initial bridge: Discord <-> Fluxer channel relay via webhooks
- 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)
2026-08-25 18:41:43 -07:00

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).