{"id":22293029,"url":"https://github.com/phanabani/sandpiper","last_synced_at":"2025-03-25T21:47:52.306Z","repository":{"id":44859227,"uuid":"234637406","full_name":"Phanabani/sandpiper","owner":"Phanabani","description":"A Discord bot that makes it easier to communicate with friends around the world.","archived":false,"fork":false,"pushed_at":"2023-05-06T18:24:40.000Z","size":1248,"stargazers_count":2,"open_issues_count":37,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-30T19:18:07.505Z","etag":null,"topics":["conversion","discord-bot","imperial","metric","time","timezone","timezone-conversion","unit","unit-conversion"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Phanabani.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2020-01-17T21:10:40.000Z","updated_at":"2022-01-21T22:55:17.000Z","dependencies_parsed_at":"2024-12-03T17:27:15.629Z","dependency_job_id":"7fff6172-8dbb-40f4-a774-dadf6251ad75","html_url":"https://github.com/Phanabani/sandpiper","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Phanabani%2Fsandpiper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Phanabani%2Fsandpiper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Phanabani%2Fsandpiper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Phanabani%2Fsandpiper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Phanabani","download_url":"https://codeload.github.com/Phanabani/sandpiper/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245550539,"owners_count":20633872,"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":["conversion","discord-bot","imperial","metric","time","timezone","timezone-conversion","unit","unit-conversion"],"created_at":"2024-12-03T17:27:05.022Z","updated_at":"2025-03-25T21:47:52.285Z","avatar_url":"https://github.com/Phanabani.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sandpiper\n\n[![release](https://img.shields.io/github/v/release/phanabani/sandpiper)](https://github.com/phanabani/sandpiper/releases)\n[![license](https://img.shields.io/github/license/phanabani/sandpiper)](LICENSE)\n[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\n\nSandpiper is a Discord bot that makes it easier to communicate with friends\naround the world.\n\nHer current features include:\n- Unit conversion between imperial and metric quantities\n- Time conversion between the timezones of users in your server\n- Miniature user bios\n    - Set your preferred name, pronouns, birthday, and timezone\n    - Manage the privacy of each of these fields (private by default, but they \n    may be set to public visibility)\n- Search for users by their preferred name, Discord username, or server nicknames\n\n## Table of Contents\n\n- [Install](#install)\n- [Usage](#usage)\n- [Config](#config)\n- [Commands and features](#commands-and-features)\n    - [Unit conversion](#unit-conversion)\n    - [Time conversion](#time-conversion)\n    - [Bios](#bios)\n    - [Birthday notifications](#birthday-notifications)\n- [Developers](#developers)\n- [Changelog](#changelog)\n- [Planned features](#planned-features)\n- [Inspiration](#inspiration)\n- [License](#license)\n\n## Install\n\n### Prerequisites\n\n- [Poetry](https://python-poetry.org/docs/#installation) – dependency manager\n- (Optional) pyenv – Python version manager\n    - [pyenv](https://github.com/pyenv/pyenv) (Linux, Mac)\n    - [pyenv-win](https://github.com/pyenv-win/pyenv-win) (Windows)\n- (Optional) [PM2](https://pm2.keymetrics.io/docs/usage/quick-start) – process manager\n\n### Install Sandpiper\n\nTo get started, clone the repo.\n\n```shell\ngit clone https://github.com/phanabani/sandpiper.git\ncd sandpiper\n```\n\nInstall the dependencies with Poetry. Sandpiper requires Python 3.10.\n\n```shell\n# If you're using pyenv, run the following to init a Poetry environment using\n# the correct Python version\npoetry env use $(pyenv which python)\n\n# Install dependencies\npoetry install --no-root --no-dev\n```\n\n## Usage\n\n### Set up configuration\n\nCreate a json file `sandpiper/config.json` (or copy [sandpiper/config_example.json](sandpiper/config_example.json)).\nThe only value you need to set is the `bot_token`.\n\n```json\n{\n    \"bot_token\": \"\u003cYOUR_BOT_TOKEN\u003e\"\n}\n```\n\nSee [config](#config) for more info.\n\n### Running Sandpiper\n\n#### Basic\n\nIn the top level directory, simply run Sandpiper as a Python module with Poetry.\n\n```shell script\npoetry run python -m sandpiper\n```\n\n#### With PM2\n\n[PM2](https://pm2.keymetrics.io/docs/usage/quick-start/) is a daemon process\nmanager. Ensure you've followed the virtual environment setup described above,\nthen simply run the following command in Sandpiper's root directory:\n\n```shell script\npm2 start\n```\n\nThis starts the process as a daemon using info from [ecosystem.config.js](ecosystem.config.js).\n\n### Inviting Sandpiper to your Discord server\n\nSandpiper requires the following permissions to run normally:\n\n- View Channels\n- Send Messages\n- Embed links\n\nThese correspond to the permission integer `19456`.\n\nSandpiper also requires the following [privileged intents](https://discord.com/developers/docs/topics/gateway#privileged-intents):\n\n- Server members\n  - For Discord username/server nickname lookup in the `whois` command\n- Message content\n  - For running commands (will be replaced by slash commands) \n  - For searching messages for unit/time conversion strings\n\nYou can enable these on the bot page of your application (`https://discord.com/developers/applications/CLIENT_ID/bot`).\n\n## Config\n\nSandpiper can be configured with a JSON file at `sandpiper/config.json`.\n[sandpiper/config_example.json](sandpiper/config_example.json) contains\ndefault values and can be used as a template. `bot_token` is the only required\nfield.\n\nSee [Config](docs/config.md) for detailed information about setting up the\nconfig file.\n\n## Commands and features\n\nIn servers, commands must be prefixed with the configured command prefix\n(default=`\"!piper \"`). When DMing Sandpiper, you do not need to prefix commands.\n\n### Unit conversion\n\nConvert measurements written in regular messages! Just surround a measurement\nin curly brackets -- like this: `{5 ft}` -- and Sandpiper will convert it for\nyou. You can put multiple measurements in a message as long as each is put in\nits own brackets.\n\nMany measurements are converted by default without needing to specify an output\nunit. Read [Default unit mappings](docs/default_unit_mappings.md) to see all\ncurrently supported default conversions.\n\nYou can explicitly specify an output unit like this: `{2 tonnes \u003e lbs}`.\nThis opens up to you nearly any unit conversion you may need.\n\nLastly, you can do math in conversions, too! `{2.3 ft + 5 in}`\n\n#### Examples\n\n\u003e guys it's **{30f}** outside today, I'm so cold...\n\n\u003e I've been working out a lot lately and I've already lost **{2 kg}**!!\n\n\u003e I think Jason is like **{6' 2\"}** tall\n\n\u003e Lou lives about **{15km}** from me and TJ's staying at a hotel **{1.5km}**\n\u003e away, so he and I are gonna meet up and drive over to Lou.\n\n\u003e I weigh about 9.3 stone. For you americans, that's **{9.3 stone \u003e lbs}**\n\n\u003e my two favorite songs are **{5min+27s}** and **{4min+34s}**. that's a total\n\u003e time of **{5min+27s + 4min+34s \u003e s}** seconds\n\n\u003e hey sandpiper what's **{30 * 7}**?\n\n### Time conversion\n\nJust like [unit conversion](#unit-conversion), you can also convert times\nbetween timezones! Surround a time in curly brackets `{5:30pm}` and Sandpiper\nwill convert it to the different timezones of users in your server.\n\nTimes can be formatted in 12- or 24-hour time and use colon separators (HH:MM).\n12-hour times can optionally include AM or PM to specify what half of the day\nyou mean. If you don't specify, AM will be assumed.\n\nYou can use the keywords `now`, `midnight`, and `noon` instead of a numeric time.\n \nYou can put multiple times in a message as long as each is put in its own brackets.\n\nYou can explicitly specify input and output timezones very similarly to\nhow units are specified in unit conversion:\n\n| Timezone specification  | How to write                     | What it does                                                             |\n|-------------------------|----------------------------------|--------------------------------------------------------------------------|\n| Input timezone          | `{5:45 PM London}`               | Converts 5:45 PM in London time to all timezones of users in your server |\n| Output timezone         | `{5:45 PM \u003e Los Angeles}`        | Converts 5:45 PM from your timezone to Los Angeles time                  |\n| Input \u0026 output timezone | `{5:45 PM Amsterdam \u003e Helsinki}` | Converts 5:45 PM in Amsterdam time to Helsinki time                      |\n\nTo use this feature without having to specify input/output timezones every time,\nyou and your friends need to set your timezones with the `timezone set` command\n(see the [bio commands section](#setting-your-info) for more info).\n\n#### Examples\n\n\u003e do you guys wanna play at **{9pm}**?\n\n\u003e I wish I could, but I'm busy from **{14}** to **{17:45}**\n\n\u003e yeah I've gotta wake up at **{5}** for work tomorrow, so it's an early bedtime\n\u003e for me\n\n\u003e ugh I have a 2 hr meeting at **{noon}** tomorrow\n\n\u003e my flight took off at **{7pm new york}** and landed at **{8 AM london}**\n\n\u003e what time is it in dubai right now? **{now \u003e dubai}**\n\n\u003e the game's releasing at **{1 PM \u003e new york}** for americans and\n\u003e **{1500 \u003e london}** for europeans\n\n\u003e hey alex, jaakko's getting on at **{8 pm helsinki \u003e amsterdam}**\n\n### Bios\n\nStore some info about yourself to help your friends get to know you more easily!\nUnless [specified otherwise in the config file](docs/config.md#botmodulesbios),\nmost of these commands can only be used in DMs with Sandpiper for your privacy.\n\n#### General commands\n\n| Command      | Description                                              |\n|--------------|----------------------------------------------------------|\n| `bio show`   | Display all your stored info and their privacy settings. |\n| `bio delete` | Delete all your stored info.                             |\n\n#### Setting your info\n\nSetting a field doesn't automatically make it public. See the [privacy section](#manage-the-privacy-of-your-info)\nfor more info about managing your privacy.\n\n| Command                       | Description                                                                                                                                                                                                                                                                                       | Example                   |\n|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------|\n| `name set \u003cnew_name\u003e`         | Set your preferred name (max 64 characters).                                                                                                                                                                                                                                                      | `name set Phana`          |\n| `pronouns set \u003cnew_pronouns\u003e` | Set your pronouns (max 64 characters).                                                                                                                                                                                                                                                            | `pronouns set She/Her`    |\n| `birthday set \u003cnew_birthday\u003e` | Set your birthday in one of the following formats: `1997-08-27`, `8 August 1997`, `Aug 8 1997`, `August 8`, `8 Aug`. You may omit your birth year with the month-name format (age will not be calculated).                                                                                        | `birthday set 1997-08-27` |\n| `timezone set \u003cnew_timezone\u003e` | Set your timezone. Don't worry about formatting. Typing the name of the nearest major city should be good enough, but you can also try your state/country if that doesn't work. If you're confused, use this website to find your full timezone name: http://kevalbhatt.github.io/timezone-picker | `timezone set new york`   |\n\n#### Displaying your info\n\n| Command         | Description                                                     | Example         |\n|-----------------|-----------------------------------------------------------------|-----------------|\n| `name show`     | Display your preferred name.                                    | `name show`     |\n| `pronouns show` | Display your pronouns.                                          | `pronouns show` |\n| `birthday show` | Display your birthday.                                          | `birthday show` |\n| `age show`      | Display your age (calculated automatically from your birthday). | `age show`      |\n| `timezone show` | Display your timezone.                                          | `timezone show` |\n\n#### Deleting your info\n\n| Command           | Description                 | Example           |\n|-------------------|-----------------------------|-------------------|\n| `name delete`     | Delete your preferred name. | `name delete`     |\n| `pronouns delete` | Delete your pronouns.       | `pronouns delete` |\n| `birthday delete` | Delete your birthday.       | `birthday delete` |\n| `timezone delete` | Delete your timezone.       | `timezone delete` |\n\n#### Manage the privacy of your info\n\nYou can set the privacy for each field in your bio to either `public` or\n`private`. Everything is private by default. If you set a field as public,\nanyone may be able to see it as long as they are in the same server as you and\nSandpiper.\n\n| Command                          | Description                               | Example                    |\n|----------------------------------|-------------------------------------------|----------------------------|\n| `privacy all \u003cnew_privacy\u003e`      | Set the privacy of all your info at once. | `privacy all public`       |\n| `privacy name \u003cnew_privacy\u003e`     | Set the privacy of your preferred name.   | `privacy name public`      |\n| `privacy pronouns \u003cnew_privacy\u003e` | Set the privacy of your pronouns.         | `privacy pronouns public`  |\n| `privacy birthday \u003cnew_privacy\u003e` | Set the privacy of your birthday.         | `privacy birthday private` |\n| `privacy age \u003cnew_privacy\u003e`      | Set the privacy of your age.              | `privacy age private`      |\n| `privacy timezone \u003cnew_privacy\u003e` | Set the privacy of your timezone.         | `privacy timezone public`  |\n\n#### Search for users by one of their names\n\nIf you're new to a server, you might hear someone's name floating around but not\nknow who they are. Sandpiper lets you search for users by either their\npreferred name (configured with the `name set` command), their Discord username,\nor their nickname in a server you are both in.\n\nYou can run this command in a server or in Sandpiper DMs.\n\n| Command        | Description                                         | Example       |\n|----------------|-----------------------------------------------------|---------------|\n| `whois \u003cname\u003e` | Search for a user by one of their names on Discord. | `whois jason` |\n\n### Birthday notifications\n\nSandpiper can announce your birthday to your friends!\n\nTo enable this feature, set some of your info with the [bios](#bios) commands:\n\n- Birthday\n- \\[Optional] Timezone\n- \\[Optional] Name\n- \\[Optional] Pronouns\n\nYou also need to set these fields to public with the [privacy commands](#manage-the-privacy-of-your-info)\nfor them to be used (otherwise, they are private by default, and Sandpiper will\nnot use them to keep your personal info private).\n\nHere is how your personal info will be used to create your birthday announcement\nmessage:\n\n- Birthday\n  - (Public) Your birthday will be announced on every server you and Sandpiper are in together\n  - (Private) Your birthday will not be announced\n- Timezone\n  - (Public) Your birthday will be announced at midnight in your timezone\n  - (Private) Your birthday will be announced at midnight UTC (coordinated universal time)\n- Name\n  - (Public) Your preferred name will be used in the message\n  - (Private) Your Discord username will be used in the message\n- Pronouns\n  - (Public) Your pronouns will be used in the message\n  - (Private) They/them will be used in the message\n- Age\n  - (Public and birth year set) Your new age will be displayed in the message\n  - (Private or birth year not set) Your new age will not be displayed in the message\n\n#### Commands\n\n| Command              | Description                       | Example              |\n|----------------------|-----------------------------------|----------------------|\n| `birthdays upcoming` | Show upcoming and past birthdays. | `birthdays upcoming` |\n\n\n## Developers\n\n### Installation\n\nFollow the installation steps in [install](#install) and use Poetry to \ninstall the development dependencies:\n\n```bash\npoetry install --no-root\n```\n\n### Testing\n\n#### Run unit tests\n\n```bash\npoetry run python -m pytest --pyargs sandpiper\n# or run tests with profiling (--profile-svg to generate svg image):\npoetry run python -m pytest --pyargs --profile sandpiper\n```\n\n#### Run tests with code coverage\n\n```bash\npoetry run coverage run -m pytest --pyargs sandpiper\npoetry run coverage html\n```\n\nOpen `htmlcov/index.html` to view the coverage report.\n\n## Changelog\n\nCheck out Sandpiper's version history in [CHANGELOG.md](CHANGELOG.md)!\n\n## Planned features\n\n- [X] Unit conversion\n- [X] User bios\n  - [X] Preferred name\n  - [X] Pronouns\n  - [X] Birthday\n  - [X] Timezone\n- [X] Time conversion\n- [X] Birthday notifications\n- [X] Thread support\n- [ ] Slash commands\n- [ ] Conversion editing/deletion\n- [ ] Time conversion images\n- [ ] Currency conversions\n\n## Inspiration\n\nThese Discord bots inspired the development of Sandpiper:\n\n- [Friend-Time by Kevin Novak](https://github.com/KevinNovak/Friend-Time) - inspiration for time and unit conversion features\n- [Birthday Bot by NoiTheCat](https://github.com/NoiTheCat/BirthdayBot) - inspiration for upcoming birthday feature\n\n## License\n\n[MIT © Phanabani.](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphanabani%2Fsandpiper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphanabani%2Fsandpiper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphanabani%2Fsandpiper/lists"}