{"id":19703630,"url":"https://github.com/phantominsights/actions-bot","last_synced_at":"2025-04-29T14:30:56.789Z","repository":{"id":101906966,"uuid":"284580417","full_name":"PhantomInsights/actions-bot","owner":"PhantomInsights","description":"A tutorial explaining how to host and schedule a Discord webhook bot on GitHub Actions.","archived":false,"fork":false,"pushed_at":"2020-09-03T09:45:58.000Z","size":316,"stargazers_count":41,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T17:51:09.454Z","etag":null,"topics":["discord","github-actions","python","python-bot","webhook"],"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/PhantomInsights.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":"agentphantom","patreon":"agentphantom"}},"created_at":"2020-08-03T02:04:00.000Z","updated_at":"2024-11-15T03:41:05.000Z","dependencies_parsed_at":"2023-03-13T00:00:30.123Z","dependency_job_id":null,"html_url":"https://github.com/PhantomInsights/actions-bot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomInsights%2Factions-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomInsights%2Factions-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomInsights%2Factions-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhantomInsights%2Factions-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhantomInsights","download_url":"https://codeload.github.com/PhantomInsights/actions-bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251518890,"owners_count":21602230,"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":["discord","github-actions","python","python-bot","webhook"],"created_at":"2024-11-11T21:18:30.679Z","updated_at":"2025-04-29T14:30:56.762Z","avatar_url":"https://github.com/PhantomInsights.png","language":"Python","readme":"# Simple Bot on GitHub Actions\n\nIn this tutorial we will build a simple Discord webhook bot that posts the top rising submission of any given subreddit every 10 minutes.\n\nThis bot will be hosted on GitHub Actions which allows us to run arbitrary Python code for free. This approach is very similar to using a Linux VPS with crontab.\n\nWe will need very few things:\n\n* A Discord server.\n* One public GitHub repository.\n* Python 3.6 or greater and `pip` on your local machine.\n\n## Discord Webhook\n\nBefore anything else, we will require a Discord webbook, which is an url where we will send a `POST` HTTP request.\n\nTo do so we will require to own a Discord server, which is free.\n\nI will assume you already have a Discord account and your server created.\n\nPlease follow these instructions to generate your webhook:\n\n1. Open Discord on your web browser or desktop client.\n2. Create a new channel or select an already existing one.\n3. Click on the cog icon (settings).\n4. On the left-side menu click on `Integrations`.\n5. Then click on the `Webhooks` button.\n6. Click on the `New Webhook` button.\n\nYou will see something very similar to the next image.\n\n![Webhook created](./images/1.png)\n\n7. Click on the `Copy Webhook URL` button.\n8. Paste the URL somewhere safe, we will use that in the next steps.\n\n## Python Bot\n\nThis step is optional but recommended. We will test the webhook connection on our local machine before uploading it to GitHub.\n\nThis bot does 2 things, it first queries the Reddit API for the top rising submission on the subreddit you want, it then creates a Markdown message and sends it to the webhook using a `POST` request.\n\nThis bot requires Python 3.6 or greater and only has one external dependency which can be installed using the following command on your CMD or Terminal:\n\n```\n# Windows\npip install requests\n\n# macOS / Linux\npip3 install requests\n```\n\nLet's take a look at `script_local.py`.\n\nThe first thing you will notice is the declaration of the webhook url variable.\n\n```python\nWEBHOOK_URL = \"https://discord.com/api/webhooks/...\"\n```\n\nYou must replace this url with the one you copied earlier from the Discord webhook settings panel.\n\nAfter that, we have 2 important functions.\n\n```python\ndef get_rising_submissions(subreddit):\n\n    url = f\"https://www.reddit.com/r/{subreddit}/rising.json?limit=1\"\n    headers = {\"User-Agent\": \"Reddit Rising Checker v1.0\"}\n\n    with requests.get(url, headers=headers) as response:\n\n        data = response.json()[\"data\"][\"children\"]\n\n        # Iterate over all the children.\n        for item in data:\n\n            item_data = item[\"data\"]\n\n            # We will collect only the fields we are interested in.\n            title = item_data[\"title\"]\n            permalink = \"https://reddit.com\" + item_data[\"permalink\"]\n            author = item_data[\"author\"]\n            score = item_data[\"score\"]\n            image_url = item_data[\"url\"]\n\n            # Compose a Markdown message using string formatting.\n            message = f\"[{title}]({permalink})\\nby **{author}**\\n**{score:,}** points\"\n\n            return (message, image_url)\n```\n\nThis function requests the top rising submission from the specified subreddit. I have set r/pics as an example.\n\nThis function composes and returns a Markdown message that will then be used by the `post_message` function.\n\n```python\ndef post_message(message, image_url):\n\n    payload = {\n        \"username\": \"Rising Posts\",\n        \"embeds\": [\n            {\n                \"title\": \"Top Rising Post\",\n                \"color\": 102204,\n                \"description\": message,\n                \"thumbnail\": {\"url\": image_url},\n                \"footer\": {\"text\": \"Powered by Elf Magic™\"}\n            }\n        ]\n    }\n\n    with requests.post(WEBHOOK_URL, json=payload) as response:\n        print(response.status_code)\n```\n\nThis function creates a payload dictionary, adds customizations to our message and finally sends it to the webhook url.\n\nIf you run this script as-is you should receive a message on your server similar to the one on the next image.\n\n![Result](./images/2.png)\n\nAt this point we have learned how to create a Discord webhook bot, but a bot must be automated and this is where GitHub Actions will be used.\n\n## GitHub Actions\n\nGitHub Actions is mostly used for CI tasks but fortunately enough it allows us to run any code we want and this bot is no exception.\n\nBefore continuing I will explain a few key points.\n\n* GitHub Actions allows us to run 2,000 minutes of code for free each month.\n* The repository behaves as a folder, for example this same README.md file is located at `./README.md`. Keep this in mind when you want to reference files in the same folder.\n* We will be using Ubuntu, so any Linux commands work the same.\n* The crontab on GitHub Actions is not precise, so don't rely on it for scripts that demand scheduled precision.\n\nIt's time to configure our repository.\n\n### Secrets\n\nExposing your Discord webhook url is a terrible idea, anyone can use it to flood your server with spam or worse.\n\nThankfully there's a way to store it securely and this is using the repository secrets.\n\nWe are going to add our webhook url to the secrets section.\n\n1. Create or navigate to your repository in a web browser.\n2. Click the `Settings` tab.\n3. On the left-side menu click the `Secrets` option.\n4. Click the `New secret` button.\n4. Name the secret `WEBHOOK` and paste your webhook url on the value field\n\nIt should look similar as in the next image.\n\n![Secret](./images/3.png)\n\nWe are almost done, only 2 things left to do.\n\n### GitHub Actions Workflow\n\nWe now need to upload 3 files to the repository. The first one is the `script_remote.py` file that is included in this same repository.\n\nThis script is almost the same as the local one, the only difference is that it reads the webhook url from an environment variable (the secret we just created) instead of it being hard-coded in the script.\n\nThis file must be uploaded in the top-level of the repository (`./script_remote.py`).\n\nWe also need to add a file named `requirements.txt` to the top-level of the repository. The contents of this file must be the word `requests`. This file is also included in this repository.\n\nAfterwards we need to create a folder named `.github` and INSIDE that folder create another folder named `workflows`.\n\nInside that `workflows` folder we must add a `.yml` file. You can name it as you like but it must have that file extension. I also included a sample one in this repository.\n\nThe following code is the contents of the  `.yml` file we will be using.\n\n```yml\nname: Discord Webhook\n\n# 'on' is the trigger, in this case this Action will\n# be triggered using cron set at a 10 minutes interval.\non:\n  schedule:\n    - cron: \"*/10 * * * *\"\n\n# 'jobs' are the routines, we only have\n# one when the instance is built.\njobs:\n  build:\n    # Our instance will use the latest available version of Ubuntu.\n    runs-on: ubuntu-latest\n\n    # These steps are run in the same order as are defined.\n    steps:\n      # actions checkout and python are pre-built actions\n      # that abstract commonly used tasks.\n      - uses: actions/checkout@v2\n\n      # The python action will set us a Python 3.8 (64-bit) instance.\n      - name: Setting up Python\n        uses: actions/setup-python@v2\n        with:\n          python-version: \"3.8\"\n          architecture: \"x64\"\n\n      # Use PIP to install the dependencies and then run the script.\n      - name: Running Script\n        # But first we read the WEBHOOK secret and create an\n        # environment variable with the same name.\n        env:\n          WEBHOOK: ${{ secrets.WEBHOOK }}\n        run: |\n          pip install -r requirements.txt\n          python script_remote.py\n\n```\n\nI added comments explaining what each line does. Most of the code can be reused for similar projects.\n\nIt is important to note how we read the `WEBHOOK` secret and set it as an environment variable so we can use it in our script without exposing it to the public.\n\nSave this file to the `.github/workflows` folder as `bot.yml` and let's wait a bit until it automatically runs.\n\nIf everything went right you must receive a message in your Discord server as we did with the local file.\n\nDebugging Actions is really easy.\n\n1. On your repository click on the `Actions` tab.\n2. You will see a list of workflow runs.\n3. If the Discord Webhook workflow was successful you will see a small checkmark, otherwise you will see a cross.\n4. Click on the latest workflow run.\n5. On the left-side menu click on the `build` menu item.\n6. On the right-side, a panel will show what happened on each step, we can see the output of each time we used the `print` function.\n\n*Note: If your Action was never triggered, make sure you have the correct folder structure. I encourage you to clone this same repository and use it as a template.*\n\n*The only change you need to make is to remove the underscore from the _workflows folder so they are enabled.*\n\n## Conclusion\n\nI hope you liked this tutorial and I hope it gives you ideas on how to expand on this idea.\n\nFor example, if you want to make a Reddit bot you would only require to set 4 secrets (username, password, app id and app secret), add `praw` to the requirements.txt file and you are ready to go.\n\nWhile writing this tutorial I also tried another script that generated .csv files and stored them into the same repository.\n\nYou can also use this workflow to generate daily reports from different sources.\n\n[![Become a Patron!](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/bePatron?u=20521425)\n","funding_links":["https://github.com/sponsors/agentphantom","https://patreon.com/agentphantom","https://www.patreon.com/bePatron?u=20521425"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphantominsights%2Factions-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphantominsights%2Factions-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphantominsights%2Factions-bot/lists"}