# Discord Music Bot (TypeScript)

Discord music bot template written in TypeScript using `discord.js` and `shoukaku`, with Lavalink support.

## Features

- Slash commands (e.g., `/ping`, `/join`, `/play`, `/leave`)
- `shoukaku` integration for robust Lavalink audio playback
- Modular command and event handlers written in TypeScript
- Basic Docker support (`Dockerfile`, `docker-compose.yml`)
- Comprehensive test suite with Jest

## Prerequisites

- Node.js (>=16 recommended, check `package.json` for specific engine requirements)
- pnpm (recommended) or npm
- TypeScript (`typescript` package, usually installed as a dev dependency)
- A Discord application with bot token and client ID
- A running Lavalink server

## Setup

1.  **Clone the repository:**
    ```sh
    git clone <repository_url>
    cd discord-music-bot
    ```
2.  **Install dependencies:**
    ```sh
    pnpm install
    ```
3.  **Configure Environment:**
    Copy `.env.example` to `.env` and fill in your credentials:
    ```dotenv
    # Discord Bot Token (Required)
    DISCORD_TOKEN=your_discord_bot_token

    # Discord Application Client ID (Required for command deployment)
    CLIENT_ID=your_discord_application_id

    # Discord Guild ID (Optional, for deploying commands to a specific test server)
    # GUILD_ID=your_guild_id_here

    # Lavalink Configuration (Required)
    LAVALINK_HOST=lavalink # Or 127.0.0.1 if running locally without Docker Compose
    LAVALINK_PORT=2333
    LAVALINK_PASSWORD=your_lavalink_password
    # LAVALINK_SECURE=false # Set to true if Lavalink uses SSL/WSS

    # Logging Level (Optional, defaults typically to 'info')
    # LOG_LEVEL=info

    # YouTube OAuth Token (Optional, needed for YouTube Music via specific plugins)
    # See note below on how to obtain this.
    YOUTUBE_OAUTH_TOKEN=your_youtube_oauth_token_here
    ```

    **Note on YouTube OAuth Token:**
    The `YOUTUBE_OAUTH_TOKEN` is required by some Lavalink plugins (like the `youtube-plugin` potentially used here) to access YouTube Music tracks directly. Obtaining this involves:
    1.  Go to the [Google Cloud Console](https://console.cloud.google.com/).
    2.  Create a new project or select an existing one.
    3.  Navigate to "APIs & Services" -> "Credentials".
    4.  Click "Create Credentials" -> "OAuth client ID".
    5.  Select Application type: **"TVs and Limited Input devices"**.
    6.  Give it a name (e.g., "Lavalink YouTube Music Access").
    7.  Click "Create". You'll get a Client ID and Client Secret (you likely won't need the secret directly for the token flow).
    8.  Follow the on-screen instructions or Google's documentation for the "OAuth 2.0 for TV and Limited Input devices" flow. This usually involves visiting a specific URL with your client ID, getting a user code, authorizing the application on a separate device/browser logged into your Google account, and then exchanging the device code for a **refresh token**.
    9.  Paste the obtained **refresh token** as the value for `YOUTUBE_OAUTH_TOKEN` in your `.env` file.

4.  **Build TypeScript (if needed):**
    Many setups use `ts-node` for development, but for production, you might need to compile:
    ```sh
    pnpm build # Check package.json for the exact build script
    ```

5.  **Register Slash Commands:**
    Run the deployment script (ensure `CLIENT_ID` and `DISCORD_TOKEN` are set in `.env`).
    ```sh
    pnpm deploy # Check package.json for the exact deploy script (might be node/ts-node deploy-commands.ts)
    ```

6.  **Start the Bot:**
    ```sh
    pnpm start # Check package.json for the exact start script (might run compiled JS or use ts-node)
    ```

## Testing

The project includes a comprehensive test suite using Jest. The tests cover commands, events, and utilities.

### Running Tests

```bash
# Run all tests with coverage report
pnpm test

# Run tests in watch mode during development
pnpm test:watch

# Run tests in CI environment
pnpm test:ci
```

### Test Structure

```
tests/
├── commands/           # Tests for bot commands
│   ├── join.test.ts
│   ├── leave.test.ts
│   ├── ping.test.ts
│   └── play.test.ts
├── events/            # Tests for event handlers
│   ├── interactionCreate.test.ts
│   ├── ready.test.ts
│   └── voiceStateUpdate.test.ts
└── utils/            # Test utilities and mocks
    ├── setup.ts     # Jest setup and global mocks
    ├── testUtils.ts # Common test utilities
    └── types.ts     # TypeScript types for tests
```

### Coverage Requirements

The project maintains high test coverage requirements:

- Branches: 80%
- Functions: 80%
- Lines: 80%
- Statements: 80%

## Docker

A `Dockerfile` and `docker-compose.yml` are provided for containerized deployment.

-   Ensure your `.env` file is configured correctly.
-   Build and run with Docker Compose:
    ```sh
    docker-compose up --build -d # Use -d to run in detached mode
    ```
-   The `docker-compose.yml` includes both the bot service and a Lavalink service.

## Project Structure

```
.
├── src/                      # Source code directory
│   ├── commands/             # Slash command modules (.ts)
│   ├── events/              # Discord.js and Shoukaku event handlers (.ts)
│   ├── structures/          # Custom structures or base classes (e.g., Shoukaku event handlers)
│   └── utils/               # Utility functions (e.g., logger.ts)
├── tests/                   # Test files (see Testing section)
├── plugins/                 # Lavalink plugins (e.g., youtube-plugin-*.jar)
├── .env.example            # Example environment variables
├── application.yml         # Lavalink server configuration
├── deploy-commands.ts      # Script to register slash commands
├── docker-compose.yml      # Docker Compose configuration
├── Dockerfile             # Dockerfile for building the bot image
├── jest.config.ts        # Jest test configuration
├── package.json          # Node.js project manifest
├── tsconfig.json        # TypeScript compiler options
└── update-plugin.sh    # Script to update Lavalink plugins
```

## License

This project is licensed under the **GNU General Public License v3.0**. See the [LICENSE](LICENSE) file for details.
