{"id":19204610,"url":"https://github.com/openttd/dibridge","last_synced_at":"2025-05-12T16:09:19.579Z","repository":{"id":55062017,"uuid":"522718422","full_name":"OpenTTD/dibridge","owner":"OpenTTD","description":"Discord \u003c-\u003e IRC Bridge","archived":false,"fork":false,"pushed_at":"2025-04-01T06:40:33.000Z","size":167,"stargazers_count":17,"open_issues_count":4,"forks_count":3,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-20T14:42:56.899Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenTTD.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-08T21:54:49.000Z","updated_at":"2025-03-31T08:54:03.000Z","dependencies_parsed_at":"2024-04-09T18:45:45.271Z","dependency_job_id":"0b251c2f-1267-4653-bd0e-71435c79fd17","html_url":"https://github.com/OpenTTD/dibridge","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenTTD%2Fdibridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenTTD%2Fdibridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenTTD%2Fdibridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenTTD%2Fdibridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenTTD","download_url":"https://codeload.github.com/OpenTTD/dibridge/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253773923,"owners_count":21962195,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T13:08:54.914Z","updated_at":"2025-05-12T16:09:19.543Z","avatar_url":"https://github.com/OpenTTD.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dibridge: an Discord \u003c-\u003e IRC Bridge\n\n[![GitHub License](https://img.shields.io/github/license/OpenTTD/dibridge)](https://github.com/OpenTTD/dibridge/blob/main/LICENSE)\n\nSometimes you have parts of your community that don't want to leave IRC.\nBut other parts are active on Discord.\nWhat do you do?\n\nBridge the two!\n\nThis server logs in to both IRC and Discord, and forward messages between the two.\n\nThis server is very limited, as in: it only bridges a single Discord channel with a single IRC channel.\nIf you want to bridge multiple, you will have to run more than one server.\n\n## TODO-list\n\nThis software is currently in pre-alpha.\nHere is a list of things that still needs doing:\n\n- [ ] Set IRC status to away if user goes offline on Discord.\n- [ ] Show IRC joins if the user talked recently, left, but came back.\n- [ ] Investigate IRC private messages, if we can relay them to Discord and back.\n\n## Implementation\n\nThe idea behind this bridge is to be as native on Discord as on IRC.\nThat on both sides, it is hard to notice you are not talking to a native user.\n\nFor Discord, this means we use multi-presence.\nEvery IRC user gets its own Discord user to talk to you, including its own avatar.\nHighlights on IRC, after you talked in the Discord channel, are converted to Discord highlights.\nIn other words, it looks and feels like you are talking to a Disord user.\n\nFor IRC, this also means we use multi-presence.\nOnce you said something in the Discord channel, an IRC puppet is created with your name, that joins the IRC network.\nHighlights on Discord are converted to readable names on IRC, which you can use again to create a highlight on Discord.\nIn other words, it looks and feels like you are talking to an IRC user.\n\nIt is really important to make it feel as native as possible.\nThis with the goal that the IRC population doesn't think strange about this, and that the Discord population can just do their thing.\n\nThere are however some limitations:\n- Edits on Discord are not send to IRC.\n- Reactions on Discord are not send to IRC.\n- This bridges a single Discord channel to a single IRC channel, and no more.\n- On IRC you do not see who is online on Discord unless they said something.\n- On Discord you do not see who is online on IRC unless they said something.\n\n## Usage\n\n```\nUsage: python -m dibridge [OPTIONS]\n\nOptions:\n  --sentry-dsn TEXT             Sentry DSN.\n  --sentry-environment TEXT     Environment we are running in.\n  --discord-token TEXT          Discord bot token to authenticate.  [required]\n  --discord-channel-id INTEGER  Discord channel ID to relay to.  [required]\n  --irc-host TEXT               IRC host to connect to.  [required]\n  --irc-port INTEGER            IRC SSL port to connect to.\n  --irc-nick TEXT               IRC nick to use.  [required]\n  --irc-channel TEXT            IRC channel to relay to, without the first\n                                '#'.  [required]\n  --irc-puppet-ip-range TEXT    An IPv6 CIDR range to use for IRC puppets.\n                                (2001:A:B:C:D::/80)\n  --irc-puppet-postfix TEXT     Postfix to add to IRC puppet nicknames\n                                (default: none).\n  --irc-ignore-list TEXT        IRC nicknames to not relay messages for (comma\n                                separated, case-insensitive).\n  --irc-idle_timeout INTEGER    IRC puppet idle timeout, in seconds (default:\n                                2 days).\n  -h, --help                    Show this message and exit.\n```\n\nYou can also set environment variables instead of using the options.\n`DIBRIDGE_DISCORD_TOKEN` for example sets the `--discord-token`.\nIt is strongly advised to use environment variables for secrets and tokens.\n\n### Discord bot\n\nThis application logs in as a Discord bot to get a presence on Discord.\nYou have to create this bot yourself, by going to https://discord.com/developers/ and registering one.\nThe Discord token can be found under `Bot`.\n\nAdditionally, the bot uses the following intents:\n- `messages`: to read messages.\n- `guilds`: to read channel information.\n- `presences`: to know when a user goes offline.\n- `members`: to read member information.\n- `message_content`: to read message content.\n\nSome of these intents need additional permission on the bot's side, under `Privileged Gateway Intents`.\nWithout those, this application will fail to start.\n\nAfter creating a bot, you need to invite this bot to your Discord channel.\nIf you are not the owner of that channel, you would need to make the bot `Public` before the admin can add it.\nThe bot needs at least `Send Messages`, `Read Messages` and `Manage Webhooks` permissions on the Discord server channel.\nThese permissions need to be assigned on the Discord server itself, by someone with sufficient permissions to do so.\n\n### IRC Puppet IP Range\n\nThe more complicated setting in this row is `--irc-puppet-ip-range`, and needs some explaining.\n\nWithout this setting, the bridge will join the IRC channel with a single user, and relays all messages via that single user.\nThis means it sends things like: `\u003cusername\u003e hi`.\nThe problem with this is, that it isn't really giving this native IRC feel.\nNeither can you do `us\u003ctab\u003e` to quickly send a message to the username.\n\nA much better way is to join the IRC channel with a user for every person talking on Discord.\nBut as most IRC networks do not allow connecting with multiple users from the same IP address (most networks allow 3 before blocking the 4th), we need a bit of a trick.\n\n`--irc-puppet-ip-range` defines a range of IP address to use.\nFor every user talking on Discord, the bridge creates a new connection to the IRC channel with a unique IP address for that user from this range.\n\nIn order for this to work, you do need to setup a few things.\nFirst of all, you need Linux 4.3+ for this to work.\nNext, you need to have an IPv6 prefix, of which you can delegate a part to this bridge.\n\nAll decent ISPs these days can assign you an IPv6 prefix, mostly a `/64` or better.\nWe only need a `/80` for this (or at least a `/96`), so that is fine.\nSimilar, cloud providers also offer assigning IPv6 prefixes to VMs.\nFor example [AWS allows you to assign a `/80` to a single VM](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-prefix-eni.html).\n\nNext, you need to make sure that this prefix is forwarded to the machine you are hosting the bridge on.\nFor example:\n```bash\nip route add local ${prefix} dev eth0\nip addr add local ${prefix} dev eth0\n```\n\nWhere `${prefix}` is something like `2001:db8::/80`.\nPlease use a part of the prefix assigned by your ISP, and not this example.\n\nNext, we need to tell the kernel to allow us to bind to IP addresses that are not local:\n```bash\nsysctl -w net.ipv6.ip_nonlocal_bind=1\n```\n\nAnd that is it.\nNow we can call this bridge with, for example, `--irc-puppet-ip-range 2001:db8::/80`.\nIRC puppets will now use an IP in that range.\n\nAnd don't worry, the same Discord user will always get the same IPv6 (given the range stays the same).\nSo if they get banned on IRC, they are done.\n\n## Development\n\n```bash\npython3 -m venv .env\n.env/bin/pip install -r requirements.txt\n.env/bin/python -m dibridge --help\n```\n\n### IRC server\n\nTo run a local IRC server to test with, one could do that with the following Docker statement:\n\n```bash\ndocker run --rm --name irc --net=host -p 6667:6667 hatamiarash7/irc-server --nofork --debug\n```\n\nThe `--net=host` is useful in case you want to work with IRC Puppets.\nFor example, one could add a local route for some random IPv6 addresses, and tell this bridge to use that to connect to the IRC server.\nA typical way of doing this would be:\n\n```bash\nsysctl -w net.ipv6.ip_nonlocal_bind=1\nip route add local 2001:db8:100::/80 dev lo\n```\n\n(don't forget to use as `--irc-host` something that also resolves to a local IPv6, like `localhost`)\n\nBy default, the `oper` is named `dusty` with as password `IAmDusty`.\n\n### Discord bot\n\nTo connect to Discord, one could register their own Discord bot, invite it to a private server, and create a dedicated channel for testing.\n\n## Why yet-another-bridge\n\nOpenTTD has been using IRC ever since the project started.\nAs such, many old-timers really like being there, everyone mostly knows each other, etc.\n\nOn the other hand, it isn't the most friendly platform to great new players with questions, to share screenshots, etc.\nDiscord does deliver that, but that means the community is split in two.\n\nSo, we needed to bridge that gap.\n\nNow there are several ways to go about this.\n\nFirst, one can just close IRC and say: go to Discord.\nThis is not the most popular choice, as a few people would rather die on the sword than switch.\nAnd as OpenTTD, we like to be inclusive.\nSo not an option.\n\nSecond, we can bridge IRC and Discord, so we can read on Discord what happens on IRC, and participate without actually opening an IRC client.\nThis is a much better option.\n\nNow there are a few projects that already do this.\nFor example:\n- https://github.com/qaisjp/go-discord-irc\n- https://github.com/42wim/matterbridge\n- https://github.com/reactiflux/discord-irc\n\nSadly, most of those only support a single presence on IRC.\nThis is for our use-case rather annoying, as it makes it much more obvious that things are bridged.\nAs people on IRC can be grumpy, they will not take kind of that.\nAdditionally, things like user-highlighting etc won't work.\n\nThe first one on the list does support it, but in such way that is impractical: every user on Discord gets an IRC puppet.\nThat would be thousands of outgoing IRC connections.\n\nFor example Matrix does do this properly: when you join the channel explicitly, it creates an IRC puppet.\n\nSo, we needed something \"in between\".\nAnd that is what this repository delivers.\n\nCodewise, thanks to the awesome [irc](https://github.com/jaraco/irc) and [discord.py](https://github.com/Rapptz/discord.py), it is relative trivial.\nA bit ironic that the oldest of the two (IRC), is the hardest to implement.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenttd%2Fdibridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenttd%2Fdibridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenttd%2Fdibridge/lists"}