diff --git a/.dockerignore b/.dockerignore index d751884cf..7d9bab09c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,16 +1,17 @@ -.vscode -.github -node_modules -npm-debug.log +.dockerignore .env .git +.github .gitignore .node-version .prettierrc .replit -config.json +.vscode CODE_OF_CONDUCT.md +config.json CONTRIBUTING.md -Procfile Dockerfile -.dockerignore +docs +node_modules +npm-debug.log +Procfile diff --git a/.github/configs/cr.yaml b/.github/configs/cr.yaml new file mode 100644 index 000000000..2243d327a --- /dev/null +++ b/.github/configs/cr.yaml @@ -0,0 +1,5 @@ +## Reference: https://github.com/helm/chart-releaser + +# Enable automatic generation of release notes using GitHubs release notes generator. +# see: https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes +generate-release-notes: true diff --git a/.github/configs/ct-install.yml b/.github/configs/ct-install.yml new file mode 100644 index 000000000..605945d65 --- /dev/null +++ b/.github/configs/ct-install.yml @@ -0,0 +1,13 @@ +## Reference: https://github.com/helm/chart-testing/blob/master/doc/ct_lint-and-install.md +# Don't add the 'debug' attribute, otherwise the workflow won't work anymore +# Only Used for the CT Install Stage +remote: origin +target-branch: main +chart-dirs: + - charts +helm-extra-args: "--timeout 600s" +validate-chart-schema: false +validate-maintainers: true +validate-yaml: true +exclude-deprecated: true +excluded-charts: [] diff --git a/.github/configs/ct-lint.yaml b/.github/configs/ct-lint.yaml new file mode 100644 index 000000000..ed7bfe188 --- /dev/null +++ b/.github/configs/ct-lint.yaml @@ -0,0 +1,13 @@ +## Reference: https://github.com/helm/chart-testing/blob/master/doc/ct_lint-and-install.md +# Don't add the 'debug' attribute, otherwise the workflow won't work anymore +# Only Used for the CT Lint Stage +remote: origin +target-branch: main +chart-dirs: + - charts +helm-extra-args: "--timeout 600s" +validate-chart-schema: false +validate-maintainers: true +validate-yaml: true +exclude-deprecated: true +excluded-charts: [] diff --git a/.github/configs/lintconf.yaml b/.github/configs/lintconf.yaml new file mode 100644 index 000000000..dbefbcc68 --- /dev/null +++ b/.github/configs/lintconf.yaml @@ -0,0 +1,42 @@ +--- +rules: + braces: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + brackets: + min-spaces-inside: 0 + max-spaces-inside: 0 + min-spaces-inside-empty: -1 + max-spaces-inside-empty: -1 + colons: + max-spaces-before: 0 + max-spaces-after: 1 + commas: + max-spaces-before: 0 + min-spaces-after: 1 + max-spaces-after: 1 + comments: + require-starting-space: true + min-spaces-from-content: 1 + document-end: disable + document-start: disable # No --- to start a file + empty-lines: + max: 2 + max-start: 0 + max-end: 0 + hyphens: + max-spaces-after: 1 + indentation: + spaces: consistent + indent-sequences: whatever # - list indentation will handle both indentation and without + check-multi-line-strings: false + key-duplicates: enable + line-length: disable # Lines can be any length + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + level: warning diff --git a/.github/workflows/docker.yml b/.github/workflows/docker-build-and-publish.yml similarity index 60% rename from .github/workflows/docker.yml rename to .github/workflows/docker-build-and-publish.yml index 893746ee1..93306b317 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker-build-and-publish.yml @@ -1,60 +1,65 @@ -name: Docker Hub - -on: - release: - types: [published] - -env: - # Use docker.io for Docker Hub if empty - REGISTRY: docker.io - # github.repository as / - IMAGE_NAME: ${{ github.repository }} - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - # QEMU for emulation - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - # Docker Buildx for creating multi arch docker images - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - # Login against a Docker registry when not a PR - # https://github.com/docker/login-action - - name: Log into registry ${{ env.REGISTRY }} - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - # Extract metadata (tags, labels) for Docker - # https://github.com/docker/metadata-action - - name: Extract Docker metadata - id: meta - uses: docker/metadata-action@v3 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - # Build and push Docker image with Buildx (don't push on PR) - # https://github.com/docker/build-push-action - - name: Build and push Docker image - uses: docker/build-push-action@v2 - with: - context: . - platforms: linux/amd64,linux/arm64,linux/arm/v7 - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} +name: Docker Build/Publish +on: + push: + tags: ["*.*.*"] # Publish semver tags as Docker releases. + paths: + - "**/*.ts" + - "**/*.js" + - "**/*.json" + - ".dockerignore" + - "Dockerfile" + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +permissions: + contents: read + +jobs: + build: + permissions: + packages: write # to push image to GitHub registry + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # QEMU for emulation + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + # Docker Buildx for creating multi arch docker images + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Login against a Docker registry except on PR + # https://github.com/docker/login-action + - name: Log into registry ${{ env.REGISTRY }} + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 #,linux/arm64,linux/arm/v7 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 000000000..c92d782d0 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,55 @@ +name: Docker Build +on: + push: + tags: ["!*.*.*"] + paths: + - "**/*.ts" + - "**/*.js" + - "**/*.json" + - ".dockerignore" + - "Dockerfile" + pull_request: + branches: + - main + - master + +env: + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # QEMU for emulation + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + # Docker Buildx for creating multi arch docker images + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Extract metadata (tags, labels) for Docker + # https://github.com/docker/metadata-action + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + # Build and push Docker image with Buildx (don't push on PR) + # https://github.com/docker/build-push-action + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64 #,linux/arm64,linux/arm/v7 + tags: build + labels: ${{ steps.meta.outputs.labels }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/helm-lint-and-test.yml b/.github/workflows/helm-lint-and-test.yml new file mode 100644 index 000000000..f48704081 --- /dev/null +++ b/.github/workflows/helm-lint-and-test.yml @@ -0,0 +1,72 @@ +## Reference: https://github.com/helm/chart-testing-action +name: Helm Lint and Test +on: + push: + paths: + - "charts/**" + pull_request: + branches: + - main + - master + +permissions: + contents: read + +jobs: + linter-artifacthub: + runs-on: ubuntu-latest + container: + image: public.ecr.aws/artifacthub/ah:v1.14.0 + options: --user 1001 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run ah lint + working-directory: ./charts + run: ah lint + + chart-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.13.0 # Also update in helm-publish.yaml + + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: 3.9 + + - name: Setup Chart Linting + id: lint + uses: helm/chart-testing-action@v2 + with: + # Note: Also update in scripts/lint.sh + version: v3.7.1 + + # - name: List changed charts + # id: list-changed + # run: | + # ## If executed with debug this won't work anymore. + # changed=$(ct --config ./.github/configs/ct-lint.yaml list-changed) + # charts=$(echo "$changed" | tr '\n' ' ' | xargs) + # if [[ -n "$changed" ]]; then + # echo "changed=true" >> $GITHUB_OUTPUT + # echo "changed_charts=$charts" >> $GITHUB_OUTPUT + # fi + + # - name: Create kind cluster + # uses: helm/kind-action@dda0770415bac9fc20092cacbc54aa298604d140 # v1.8.0 + # if: steps.list-changed.outputs.changed == 'true' + # with: + # config: .github/configs/kind-config.yaml + + # - name: Run chart-testing (install) + # run: ct install --config ./.github/configs/ct-install.yaml + # if: steps.list-changed.outputs.changed == 'true' diff --git a/.github/workflows/helm-publish.yml b/.github/workflows/helm-publish.yml new file mode 100644 index 000000000..8521fe726 --- /dev/null +++ b/.github/workflows/helm-publish.yml @@ -0,0 +1,58 @@ +## Reference: https://github.com/helm/chart-releaser-action +name: Helm Publish +on: + push: + branches: + - main + - master + paths: + - "charts/**" + +permissions: + contents: read + +jobs: + publish: + permissions: + contents: write # for helm/chart-releaser-action to push chart release and create a release + packages: write # to push OCI chart package to GitHub Registry + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Helm + uses: azure/setup-helm@v3 + with: + version: v3.13.0 # Also update in lint-and-test.yaml + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + with: + config: "./.github/configs/cr.yaml" + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push chart to GHCR + run: | + shopt -s nullglob + for pkg in .cr-release-packages/*.tgz; do + if [ -z "${pkg:-}" ]; then + break + fi + helm push "${pkg}" oci://ghcr.io/${{ github.repository }} + done diff --git a/.github/workflows/node-build.yml b/.github/workflows/node-build.yml new file mode 100644 index 000000000..b7f1acb56 --- /dev/null +++ b/.github/workflows/node-build.yml @@ -0,0 +1,26 @@ +name: Node.js Build +on: + push: + paths-ignore: + - "**/*.md" + pull_request: + branches: + - main + - master + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Use Node.js 18.19.0 + uses: actions/setup-node@v3 + with: + node-version: "18.19.0" + cache: "npm" + - run: npm ci --loglevel info + - run: npm run build --if-present --loglevel info diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml deleted file mode 100644 index 94ed309b2..000000000 --- a/.github/workflows/node.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Node.js CI - -on: - push: - branches: [master] - paths-ignore: - - README.md - - .github/** - - locales/** - - sounds/** - - package.json - pull_request: - branches: [master] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Use Node.js 16.11.0 - uses: actions/setup-node@v3 - with: - node-version: "16.11.0" - cache: "npm" - - run: npm ci - - run: npm run build --if-present diff --git a/Dockerfile b/Dockerfile index 852834ce9..601b471c7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,29 @@ -ARG NODE_VERSION=18.18.2-slim -FROM node:${NODE_VERSION} as base - -ENV USER=evobot +ARG NODE_VERSION=18.19.0-slim +FROM node:${NODE_VERSION} as build RUN apt-get update && \ apt-get install -y --no-install-recommends python3 build-essential && \ apt-get purge -y --auto-remove && \ rm -rf /var/lib/apt/lists/* -RUN groupadd -r ${USER} && \ - useradd --create-home --home /home/evobot -r -g ${USER} ${USER} - -USER ${USER} -WORKDIR /home/evobot +WORKDIR /home/node -FROM base as build +COPY package*.json ./ +RUN npm ci --loglevel info -COPY --chown=${USER}:${USER} . . -RUN npm ci +COPY . . RUN npm run build -RUN rm -rf node_modules && \ - npm ci --omit=dev +RUN mv node_modules _modules && \ + npm ci --omit=dev --loglevel info FROM node:${NODE_VERSION} as prod +ENV USER="node" +ENV APP_DIR="/home/node" +WORKDIR ${APP_DIR} COPY --chown=${USER}:${USER} package*.json ./ -COPY --from=build --chown=${USER}:${USER} /home/evobot/node_modules ./node_modules -COPY --from=build --chown=${USER}:${USER} /home/evobot/dist ./dist +COPY --from=build --chown=${USER}:${USER} ${APP_DIR}/node_modules ./node_modules +COPY --from=build --chown=${USER}:${USER} ${APP_DIR}/dist ./dist -CMD [ "node", "./dist/index.js" ] \ No newline at end of file +CMD [ "node", "./dist/index.js" ] diff --git a/README.md b/README.md index 288211e6f..b6b706b1f 100644 --- a/README.md +++ b/README.md @@ -1,137 +1,104 @@ -![Node build](https://github.com/eritislami/evobot/actions/workflows/node.yml/badge.svg) -![Docker build](https://github.com/eritislami/evobot/actions/workflows/docker.yml/badge.svg) -[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) - -![logo](https://repository-images.githubusercontent.com/186841818/8aa95700-7730-11e9-84be-e80f28520325) - # 🤖 EvoBot (Discord Music Bot) -> EvoBot is a Discord Music Bot built with TypeScript, discord.js & uses Command Handler from [discordjs.guide](https://discordjs.guide) - -## Requirements +![Node build](https://github.com/drewburr-labs/evobot/actions/workflows/node-build.yml/badge.svg) ![Docker build](https://github.com/drewburr-labs/evobot/actions/workflows/docker-build-and-publish.yml/badge.svg) ![Helm build](https://github.com/drewburr-labs/evobot/actions/workflows/helm-publish.yml/badge.svg) [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/evobot)](https://artifacthub.io/packages/search?repo=evobot) + [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) -1. Discord Bot Token **[Guide](https://discordjs.guide/preparations/setting-up-a-bot-application.html#creating-your-bot)** - 1.1. Enable 'Message Content Intent' in Discord Developer Portal -2. Node.js 16.11.0 or newer +![logo](https://repository-images.githubusercontent.com/186841818/8aa95700-7730-11e9-84be-e80f28520325) -## 🚀 Getting Started +> EvoBot is a Discord Music Bot built with TypeScript, discord.js & uses Command Handler from [discordjs.guide](https://discordjs.guide) -```sh -git clone https://github.com/eritislami/evobot.git -cd evobot -npm install -``` +## 📝 Features & Commands -After installation finishes follow configuration instructions then run `npm run start` to start the bot. +- 🎶 Play music from YouTube via url or search query -## ⚙️ Configuration +`/play https://www.youtube.com/watch?v=GLvohMXgcBo` +`/play under the bridge red hot chili peppers` -Copy or Rename `config.json.example` to `config.json` and fill out the values: +- 🔎 Search and select music to play -⚠️ **Note: Never commit or share your token or api keys publicly** ⚠️ +`/search Pearl Jam` -```json -{ - "TOKEN": "", - "MAX_PLAYLIST_SIZE": 10, - "PRUNING": false, - "LOCALE": "en", - "DEFAULT_VOLUME": 100, - "STAY_TIME": 30 -} -``` +- 📃 Play youtube playlists via url or search query -## 🐬 Docker Configuration +`/playlist https://www.youtube.com/watch?v=YlUKcNNmywk&list=PL5RNCwK3GIO13SR_o57bGJCEmqFAwq82c` +`/playlist linkin park meteora` -For those who would prefer to use our [Docker container](https://hub.docker.com/repository/docker/eritislami/evobot), you may provide values from `config.json` as environment variables. +- Multi-lingual, with [27 languages supported](./docs/locales.md) + +## 🎧 Commands + +- Display all commands and descriptions (/help) + +- Music controls: + - Plays audio from YouTube (/play) + - Show now playing song (/nowplaying) + - Pause the currently playing music (/pause) + - Skip the currently playing song (/skip) + - Toggle music loop (/loop) + - Change volume of currently playing music (/volume) + - Get lyrics for the currently playing song (/lyrics) + - Stops the music (/stop) + - Resume currently playing music (/resume) +- Queue controls: + - Add song to queue (/play) + - Play a playlist from youtube (/playlist) + - Search and select videos to play (/search) + - Remove song from the queue (/remove) + - Show the music queue and now playing (/queue) + - Move songs around in the queue (/move) + - Shuffle queue (/shuffle) + - Skip to the selected queue number (/skipto) +- Clips: + - Plays a clip sound (/clip) + - List all clips (/clips) +- Bot settings: + - Toggle pruning of bot messages (/pruning) + - Show the bot's average ping (/ping) + - Check the uptime (/uptime) + - Send bot invite link (/invite) + +Media Controls available via Reactions -```shell -docker run -e "TOKEN=" eritislami/evobot -``` +![reactions](https://i.imgur.com/0hdUX1C.png) -## 📝 Features & Commands +## 🚀 Getting Started -- 🎶 Play music from YouTube via url +1. Generate a Discord Bot Token **[Guide](https://discordjs.guide/preparations/setting-up-a-bot-application.html#creating-your-bot)** -`/play https://www.youtube.com/watch?v=GLvohMXgcBo` +2. Enable `Message Content Intent` in Discord Developer Portal -- 🔎 Play music from YouTube via search query +3. Use both the `bot` and `applications.commands` scopes, and enable the following permissions: -`/play under the bridge red hot chili peppers` + - View Channels + - Send Messages + - Manage Messages + - Connect (Voice) + - Speak (Voice) -- 🔎 Search and select music to play +4. Copy or rename `config.json.example` to `config.json` and enter the Discord Bot Token for `TOKEN` -`/search Pearl Jam` +⚠️ **Note: Never commit or share your token or api keys publicly** ⚠️ -- 📃 Play youtube playlists via url +## 👾 CLI configuration -`/playlist https://www.youtube.com/watch?v=YlUKcNNmywk&list=PL5RNCwK3GIO13SR_o57bGJCEmqFAwq82c` +Install Node.js 18.19.0 or newer then run the following commands: -- 🔎 Play youtube playlists via search query +```sh +git clone https://github.com/eritislami/evobot.git +cd evobot +npm install +``` -`/playlist linkin park meteora` +After the installation finishes run `npm run start` to start the bot. -- Now Playing (/np) -- Queue system (/queue) -- Loop / Repeat (/loop) -- Shuffle (/shuffle) -- Volume control (/volume) -- Lyrics (/lyrics) -- Pause (/pause) -- Resume (/resume) -- Skip (/skip) -- Skip to song # in queue (/skipto) -- Move a song in the queue (/move) -- Remove song # from queue (/remove) -- Show ping to Discord API (/ping) -- Show bot uptime (/uptime) -- Toggle pruning of bot messages (/pruning) -- Help (/help) -- Command Handler from [discordjs.guide](https://discordjs.guide/) -- Media Controls via Reactions +## 🐬 Docker Configuration -![reactions](https://i.imgur.com/0hdUX1C.png) +For those who would prefer to use our [Docker container](https://hub.docker.com/repository/docker/eritislami/evobot), you may provide values from `config.json` as environment variables. -## 🌎 Locales - -Currently available locales are: - -- English (en) -- Arabic (ar) -- Brazilian Portuguese (pt_br) -- Bulgarian (bg) -- Romanian (ro) -- Czech (cs) -- Dutch (nl) -- French (fr) -- German (de) -- Greek (el) -- Indonesian (id) -- Italian (it) -- Japanese (ja) -- Korean (ko) -- Minionese (mi) -- Persian (fa) -- Polish (pl) -- Russian (ru) -- Simplified Chinese (zh_cn) -- Singaporean Mandarin (zh_sg) -- Spanish (es) -- Swedish (sv) -- Traditional Chinese (zh_tw) -- Thai (th) -- Turkish (tr) -- Ukrainian (uk) -- Vietnamese (vi) -- Check [Contributing](#-contributing) if you wish to help add more languages! -- For languages please use [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two letter format +```shell +docker run -e "TOKEN=" eritislami/evobot +``` ## 🤝 Contributing -1. [Fork the repository](https://github.com/eritislami/evobot/fork) -2. Clone your fork: `git clone https://github.com/your-username/evobot.git` -3. Create your feature branch: `git checkout -b my-new-feature` -4. Stage changes `git add .` -5. Commit your changes: `cz` OR `npm run commit` do not use `git commit` -6. Push to the branch: `git push origin my-new-feature` -7. Submit a pull request +Please see the [Contributing](./CONTRIBUTING.md) documentation for contribution steps. diff --git a/charts/evobot/.helmignore b/charts/evobot/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/evobot/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/evobot/Chart.yaml b/charts/evobot/Chart.yaml new file mode 100644 index 000000000..fea0b4bf5 --- /dev/null +++ b/charts/evobot/Chart.yaml @@ -0,0 +1,10 @@ +apiVersion: v2 +name: evobot +description: A Helm chart for Kubernetes +type: application +version: 0.1.1 +appVersion: "3.0.0" +maintainers: + - name: drewburr + email: drew@drewburr.com + url: https://github.com/drewburr diff --git a/charts/evobot/README.md b/charts/evobot/README.md new file mode 100644 index 000000000..adba33797 --- /dev/null +++ b/charts/evobot/README.md @@ -0,0 +1,59 @@ +# EvoBot + +Installs EvoBot, a Discord Music Bot built with TypeScript and discord.js. + +See [drewburr-labs/evobot](https://github.com/drewburr-labs/evobot/blob/main/README.md) README for details about usage and setup requirements. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3+ + +## Get Helm Repository Info + +```console +helm repo add drewburr-labs-evobot https://drewburr-labs.github.io/evobot +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Helm Chart + +```console +helm install [RELEASE_NAME] drewburr-labs-evobot/evobot +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Dependencies + +There are no dependencies at this time. + +## Uninstall Helm Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] evobot/evobot +``` + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments: + +```console +helm show values drewburr-labs-evobot/evobot +``` diff --git a/charts/evobot/templates/_helpers.tpl b/charts/evobot/templates/_helpers.tpl new file mode 100644 index 000000000..e37870d4b --- /dev/null +++ b/charts/evobot/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "evobot.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "evobot.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "evobot.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "evobot.labels" -}} +helm.sh/chart: {{ include "evobot.chart" . }} +{{ include "evobot.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "evobot.selectorLabels" -}} +app.kubernetes.io/name: {{ include "evobot.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/charts/evobot/templates/deployment.yaml b/charts/evobot/templates/deployment.yaml new file mode 100644 index 000000000..44a87ca76 --- /dev/null +++ b/charts/evobot/templates/deployment.yaml @@ -0,0 +1,69 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "evobot.fullname" . }} + labels: + {{- include "evobot.labels" . | nindent 4 }} +spec: + replicas: 1 # Does not support sharding + selector: + matchLabels: + {{- include "evobot.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "evobot.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + # livenessProbe: + # httpGet: + # path: / + # port: http + # readinessProbe: + # httpGet: + # path: / + # port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + env: + {{- toYaml .Values.env | nindent 12 }} + envFrom: + {{- toYaml .Values.envFrom | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/evobot/values.yaml b/charts/evobot/values.yaml new file mode 100644 index 000000000..f00c1cf0e --- /dev/null +++ b/charts/evobot/values.yaml @@ -0,0 +1,39 @@ +# Default values for evobot. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +image: + repository: ghcr.io/drewburr-labs/evobot + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} +securityContext: {} + +resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# Additional volumes and volumeMounts on the output Deployment definition. +volumes: [] +volumeMounts: [] + +# Environment variables to set in the container. +env: [] +envFrom: [] + +nodeSelector: {} +tolerations: [] +affinity: {} diff --git a/config.json.example b/config.json.example index 5f7f39c46..af2c0ffe1 100644 --- a/config.json.example +++ b/config.json.example @@ -1,8 +1,9 @@ { "TOKEN": "", + "DEFAULT_VOLUME": 100, + "LISTENING_ACTIVITY": "", + "LOCALE": "en", "MAX_PLAYLIST_SIZE": 10, "PRUNING": false, - "LOCALE": "en", - "STAY_TIME": 30, - "DEFAULT_VOLUME": 100 -} \ No newline at end of file + "STAY_TIME": 30 +} diff --git a/docker-build.sh b/docker-build.sh new file mode 100644 index 000000000..040e986f2 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ -z $IMAGE_NAME ]; then + export IMAGE_NAME="evobot-local" +fi + +echo "Building $IMAGE_NAME..." +docker build -t $IMAGE_NAME . diff --git a/docker-test.sh b/docker-test.sh new file mode 100644 index 000000000..0ada7ed80 --- /dev/null +++ b/docker-test.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +if [ -z $IMAGE_NAME ]; then + export IMAGE_NAME="evobot-local" +fi + +echo "Starting $IMAGE_NAME..." +docker run -it --rm --name "$IMAGE_NAME" --env-file .env "$IMAGE_NAME" diff --git a/docs/locales.md b/docs/locales.md new file mode 100644 index 000000000..f2ac570aa --- /dev/null +++ b/docs/locales.md @@ -0,0 +1,33 @@ +# 🌎 Locales + +Currently available locales are: + +- English (en) +- Arabic (ar) +- Brazilian Portuguese (pt_br) +- Bulgarian (bg) +- Romanian (ro) +- Czech (cs) +- Dutch (nl) +- French (fr) +- German (de) +- Greek (el) +- Indonesian (id) +- Italian (it) +- Japanese (ja) +- Korean (ko) +- Minionese (mi) +- Persian (fa) +- Polish (pl) +- Russian (ru) +- Simplified Chinese (zh_cn) +- Singaporean Mandarin (zh_sg) +- Spanish (es) +- Swedish (sv) +- Traditional Chinese (zh_tw) +- Thai (th) +- Turkish (tr) +- Ukrainian (uk) +- Vietnamese (vi) +- Check [Contributing](../CONTRIBUTING.md) if you wish to help add more languages! +- For languages please use [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) two letter format diff --git a/interfaces/Config.ts b/interfaces/Config.ts index 7d5ad2e8f..abdb34eff 100644 --- a/interfaces/Config.ts +++ b/interfaces/Config.ts @@ -1,8 +1,9 @@ export interface Config { TOKEN: string; + DEFAULT_VOLUME: number; + LISTENING_ACTIVITY: string; + LOCALE: string; MAX_PLAYLIST_SIZE: number; PRUNING: boolean; STAY_TIME: number; - DEFAULT_VOLUME: number; - LOCALE: string; } diff --git a/package-lock.json b/package-lock.json index 9b3b7a753..8159f4b9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,12 +24,12 @@ "@types/i18n": "^0.13.10", "@types/node": "^20.10.0", "cz-conventional-changelog": "^3.0.1", - "nodemon": "^2.0.22", + "nodemon": "^3.0.2", "prettier": "^3.1.0", "ts-node": "^10.9.1" }, "engines": { - "node": ">=16.11.0" + "node": ">=18.19.0" }, "optionalDependencies": { "@discordjs/opus": "^0.9.0", @@ -2354,7 +2354,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, + "devOptional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -2598,18 +2598,18 @@ } }, "node_modules/nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.2.tgz", + "integrity": "sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==", "dev": true, "dependencies": { "chokidar": "^3.5.2", - "debug": "^3.2.7", + "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -2618,31 +2618,13 @@ "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", @@ -3112,7 +3094,7 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, + "devOptional": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -3136,24 +3118,15 @@ "devOptional": true }, "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "dependencies": { - "semver": "~7.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10" } }, "node_modules/sodium-native": { @@ -3616,7 +3589,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true + "devOptional": true }, "node_modules/yn": { "version": "3.1.1", diff --git a/package.json b/package.json index 8a553dfc4..f02453eda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "evobot", - "version": "2.8.1", + "version": "3.0.0", "description": "Discord music bot built with discord.js", "main": "index.ts", "author": "Erit Islami ", @@ -9,7 +9,7 @@ "repository": "github:eritislami/evobot", "bugs": "https://github.com/eritislami/evobot/issues", "engines": { - "node": ">=16.11.0" + "node": "18.19.0" }, "scripts": { "dev": "nodemon index.ts", @@ -36,7 +36,7 @@ "@types/i18n": "^0.13.10", "@types/node": "^20.10.0", "cz-conventional-changelog": "^3.0.1", - "nodemon": "^2.0.22", + "nodemon": "^3.0.2", "prettier": "^3.1.0", "ts-node": "^10.9.1" }, diff --git a/scripts/helm-lint.sh b/scripts/helm-lint.sh new file mode 100644 index 000000000..702dac4af --- /dev/null +++ b/scripts/helm-lint.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# This script runs the chart-testing tool locally. It simulates the linting that is also done by the github action. Run this without any errors before pushing. +# Reference: https://github.com/helm/chart-testing +set -eux + +SRCROOT="$(cd "$(dirname "$0")/.." && pwd)" + + +echo -e "\n-- Linting all Helm Charts --\n" +docker run \ + -v "$SRCROOT:/workdir" \ + --entrypoint /bin/sh \ + quay.io/helmpack/chart-testing:v3.7.1 \ + -c "cd /workdir && ct lint \ + --config ./.github/configs/ct-lint.yaml \ + --lint-conf ./.github/configs/lintconf.yaml \ + --debug" diff --git a/structs/Bot.ts b/structs/Bot.ts index f533f6a09..375536178 100644 --- a/structs/Bot.ts +++ b/structs/Bot.ts @@ -1,4 +1,5 @@ import { + ActivityType, ApplicationCommandDataResolvable, ChatInputCommandInteraction, Client, @@ -29,10 +30,14 @@ export class Bot { public constructor(public readonly client: Client) { this.client.login(config.TOKEN); - this.client.on("ready", () => { - console.log(`${this.client.user!.username} ready!`); - + this.client.once(Events.ClientReady, readyClient => { + console.log(`${readyClient.user!.username} connected!`); + let activity = undefined + if (config.LISTENING_ACTIVITY) + activity = {name: config.LISTENING_ACTIVITY, type: ActivityType.Listening} + readyClient.user.setActivity(activity) this.registerSlashCommands(); + console.log(`${readyClient.user!.username} ready!`); }); this.client.on("warn", (info) => console.log(info)); diff --git a/utils/config.ts b/utils/config.ts index cc22ecfe4..43e90ce45 100644 --- a/utils/config.ts +++ b/utils/config.ts @@ -1,19 +1,28 @@ import "dotenv/config"; import { Config } from "../interfaces/Config"; +let jsonConfig: Config | object +let envConfig: Config let config: Config; try { - config = require("../config.json"); + jsonConfig = require("../config.json"); } catch (error) { - config = { - TOKEN: process.env.TOKEN || "", - MAX_PLAYLIST_SIZE: parseInt(process.env.MAX_PLAYLIST_SIZE!) || 10, - PRUNING: process.env.PRUNING === "true" ? true : false, - STAY_TIME: parseInt(process.env.STAY_TIME!) || 30, - DEFAULT_VOLUME: parseInt(process.env.DEFAULT_VOLUME!) || 100, - LOCALE: process.env.LOCALE || "en" - }; + console.log("No config.json was found.") + jsonConfig = {} } +envConfig = { + TOKEN: process.env.TOKEN || "", + DEFAULT_VOLUME: parseInt(process.env.DEFAULT_VOLUME!) || 100, + LISTENING_ACTIVITY: process.env.ACTIVITY || "", + LOCALE: process.env.LOCALE || "en", + MAX_PLAYLIST_SIZE: parseInt(process.env.MAX_PLAYLIST_SIZE!) || 10, + PRUNING: process.env.PRUNING === "true" ? true : false, + STAY_TIME: parseInt(process.env.STAY_TIME!) || 30, +}; + +// Priority: jsonConfig, envConfig, defaults +config = Object.assign({}, envConfig, jsonConfig) + export { config };