Pull Request を通じた貢献に興味をお持ちいただき、誠にありがとうございます。
少しでも興味を持っていただけた方に、このプロジェクトに対する貢献をしていただくうえで役に立つ情報を掲載します。
参考にしていただき、貢献頂ければ大変助かります。よろしくお願いいたします。
- 機能追加やバグ修正など、コード変更を行う際は、できる限り Discord サーバーでその旨のメッセージを送信いただくか、GitHubで Issue を開いてください。
- 誰が何の作業をしているのか明確にすることで、重複した作業をしてしまうおそれを回避することができます。
- ただ、絶対的なルールではないので、ご報告がなかったとしても大丈夫です。
- コミットメッセージは、あまり気にしなくて構いません。
- こちらで適宜変更したうえでマージしますので、適当で構いません。
- Pull Request のタイトルは、日本語でも構いませんので内容が分かるように書いてください。
- Pull request を開く際は必ず
masterブランチ、またはv1、v2、v3などのブランチを対象に行ってください。- このルールに従っていただいたとしても、サポート対象外のブランチにPull requestを送信いただいた場合には、マージされない場合がございます。
- Pull requestを送信いただく前に
npm run lint -- --fixを行っていただき、エラーがない状態にしていただくことをお勧めします。- よくわからなければ、そのまま Pull Request を送っていただいても構いませんが、マージが遅れる可能性があります。
/localesに保管されているファイルは、Crowdin にて一括管理されているため、Pull Request ではなく Crowdin で編集してください。- ただし、
/locales/jaにある、日本語のファイルに関しては、Pull Request 経由で大丈夫です。 - よくわからなければ、
/localesを編集して Pull Request を送っていただいても構いませんが、反映が遅れる可能性があります。
- ただし、
- ドキュメントサイトのプロジェクトは
/docsに保管されています。- 主に
/docs/docsにマークダウン形式で各記事が保管されています。 - 過去のバージョンのドキュメントは、
/docs/versioned_docsにマークダウン形式で各記事が保管されています。
- 主に
- こちらも Pull Request 経由でコードの変更をしていただいて大丈夫です。
- ただし、
/docs/docs/guide/commandsにある、各コマンドのドキュメントに関しては、自動で管理されているため、Pull Request で編集せず、コード内の該当箇所を編集してください。- よくわからなければ、
/docs/docs/guide/commandsを編集して Pull Request を送っていただいても構いませんが、反映が遅れる可能性があります。
- よくわからなければ、
Tip
/docsフォルダ内のどのファイルを編集すればいいかわからない場合には、
ドキュメントサイトの、閲覧しているバージョンをご確認の上、ページ下部の[このページを編集]ボタンをご使用ください。
このプロジェクトは、一見すると複雑に見えるかもしれませんが、一貫した設計思想に基づいて構築したつもりです。このガイドでは、全体の構造を簡単に解説します。どこから手をつければよいか、理解に役立ててください。
このプロジェクトの構築の核心は、「疎結合で拡張性の高いアーキテクチャ」 です。各機能は独立したコンポーネントとして作られており、互いに影響を与えずに修正・拡張できるようになっています。
- サーバーごとの状態管理 (
GuildDataContainer): Discordの各サーバー(ギルド)の状態は、GuildDataContainerというクラスにすべて集約されます。再生中の曲、キュー、音量設定など、すべての情報はここにあります。これにより、サーバー間のデータが完全に分離され、管理が容易になります。 - コマンドシステム (
Commands&Component/commandManager): ユーザーからの命令(コマンド)は、CommandManagerによって解釈され、対応するコマンドクラスが実行されます。コマンドの追加や変更が他の部分に影響を与えないように設計されています。 - 音源の抽象化 (
AudioSource): YouTube、SoundCloud、Spotifyなど、さまざまな音楽ソースを同じように扱えるように、AudioSourceという概念で抽象化されています。新しい音楽サービスに対応する場合でも、既存のコードを大幅に変更する必要はありません。
ボット本体のソースコードは srcディレクトリにあり、主に以下のディレクトリに分かれています。
| ディレクトリ名 | 役割 |
|---|---|
Commands/ |
playやskipなど、ユーザーが実行する全コマンドのロジックがここにあります。新しいコマンドを追加する際は、このフォルダにファイルを追加します。 |
Component/ |
**ボットの主要な機能部品(コンポーネント)**が集まっています。音楽再生、キュー管理、コマンド解釈など、ボットの中核をなすクラスが格納されています。 |
AudioSource/ |
YouTubeやSoundCloudなど、各音楽サービスから音源を取得するための処理がここにあります。このプロジェクトの最も特徴的な部分の一つです。 |
Structure/ |
プロジェクト全体の基本となる設計(アーキテクチャ)を定義するクラスがあります。GuildDataContainerなどが代表例です。 |
events/ |
Discord.jsライブラリから発火される生のイベント(メッセージ受信など)を最初に受け取るファイル群です。 |
handlers/ |
events/から受け取ったイベントを解釈し、具体的な処理(コマンド実行など)に振り分ける役割を担います。 |
なお、ボット本体とは関係ない、ビルドスクリプトや、ドキュメントの生成に役立つコードなどは、utilディレクトリに配置されています。
ボットの動作について、2つの主要な処理の流れを解説いたします。
ユーザーが >play <曲名> と入力してから、音楽が再生されるまでの内部的な流れです。
-
イベント受信 (
events/messageCreate.ts)- Discordからメッセージ受信イベントを受け取ります。
- メッセージがボットへのコマンドであるか(プレフィックスで始まるかなど)を判定します。
- なお、スラッシュコマンドを通じてコマンドが送信された場合、
events/interactionCreate.tsとなります。
-
コマンドの解釈 (
Component/commandManager.ts)- 受信したメッセージを
CommandManagerに渡します。 CommandManagerは、playという文字列から、Commands/play.tsにあるPlayクラスを特定(解決)します。
- 受信したメッセージを
-
権限チェックと実行 (
Commands/index.ts-BaseCommand)Playクラスの親であるBaseCommandが、コマンド実行に必要な権限(ボイスチャンネルにいるかなど)をチェックします。- 権限があれば、
Playクラスのrunメソッドを実行します。
-
コマンドロジックの実行 (
Commands/play.ts)runメソッド内で、再生に必要な処理(ボイスチャンネルへの参加、楽曲の検索・追加)をGuildDataContainerのメソッドを呼び出す形で行います。
play コマンドが GuildDataContainer の playFromUrl メソッドを呼び出した後の流れです。
-
音源の特定 (
AudioSource/resolver.ts)- 渡されたURLやキーワードがどのサービス(YouTube, SoundCloudなど)のものかを
resolver.tsが判定します。 - 例えばYouTubeのURLであれば、
AudioSource/youtube/index.tsのYouTubeクラスのインスタンスを生成します。
- 渡されたURLやキーワードがどのサービス(YouTube, SoundCloudなど)のものかを
-
音源情報の取得 (例:
AudioSource/youtube/index.ts)- この例では、
YouTubeクラスが、動画のタイトルや再生時間などの情報を取得します。
- この例では、
-
キューに追加 (
Component/queueManager.ts)- 取得した音源情報を
QueueManagerが再生待ちリスト(キュー)に追加します。
- 取得した音源情報を
-
音声ストリームの生成と再生 (
Component/playManager.ts&Component/streams/)PlayManagerがキューの先頭から曲を取り出します。streams/index.tsが、音源ソースから取得したデータをDiscordで再生可能な音声形式(Opus)に変換します。この際、ffmpegを利用して音声エフェクト(Component/audioEffectManager.ts)を適用することもできます。- 最終的に生成された音声ストリームが、Discordのボイスチャンネルに流されます。
貢献していただく上で、特に知っておくと良い設計思想を3つご紹介します。
YouTubeからの音源取得は複数の「戦略(Strategy)」を使い分けることで、できる限りの安定化を図っています。YouTube関連の修正を行う際は、src/AudioSource/youtube/strategies/ ディレクトリをご確認いただけるとスムーズだと思います。
src/AudioSource/audiosource.ts の AudioSource クラスが、すべての音源の「設計図」となっています。新しい音楽サービスに対応させたい場合、このクラスを継承して init (情報取得) と fetch (ストリーム取得) の2つのメソッドを実装することが主な作業になります。AudioSourceディレクトリにある、既存の各サービスを参考にするとわかりやすいと思います。
コンポーネント間の連携は、直接メソッドを呼び出さず、イベントの発行・購読によって行われることがあります。これにより、各コンポーネントは他のコンポーネントの詳細を知らなくても協調して動作できるほか、特定のタイミングでの処理をsetTimeout(ms)などを利用せず実行できます。
このプロジェクトでは、Node.js のEventEmitterを継承した、TypedEmitterクラス(TypedEmitter.ts)を基底クラスとして、様々なモジュール(コンポーネント)が作成されています。
詳しくは、「モジュールの継承関係について」をご参照ください。
このプロジェクトに貢献するための具体的なステップの例を説明いたします。
src/Commands/に、追加したいコマンドのファイルを作成します(例:newCommand.ts)。src/Commands/index.tsのBaseCommandを継承したクラスを作成します。constructorでコマンド名(alias)、カテゴリ(category)、権限(requiredPermissionsOr)などを定義します。runメソッドに、コマンドの具体的な処理を記述します。context引数からserver(GuildDataContainer)にアクセスし、既存の機能を呼び出すのが基本です。
- 再生に関する問題:
src/Component/playManager.tsや、関連する音源ソース(例:src/AudioSource/youtube/index.ts)、ストリーム処理(src/Component/streams/)を確認します。 - コマンドの挙動に関する問題:
src/Commands/以下の該当するコマンドファイルを確認します。 - キューに関する問題:
Component/queueManager.tsを確認します。
このプロジェクトの各モジュールの、継承関係グラフは以下のようになっています。プロジェクトのコードの理解に役立てていただければ幸いです。
graph TD
subgraph Core & Structure
A[EventEmitter] --> B[TypedEventEmitter];
B --> C[LogEmitter];
C --> D[MusicBotBase];
D --> E[MusicBot];
C --> F[ServerManagerBase];
C --> G[Component/collectors/InteractionCollector];
C --> H[Component/searchPanel.ts];
C --> I[Component/telemetry.ts];
C --> J[Component/binaryManager.ts];
C --> K[Component/commandManager.ts];
end
subgraph Server Managers
F --> L[Component/playManager.ts];
L --> M[Component/playManagerWithBgm.ts];
F --> N[Component/queueManager.ts];
N --> O[Component/queueManagerWithBGM.ts];
F --> P[Component/audioEffectManager.ts];
F --> Q[Component/preferencesManager.ts];
F --> R[Component/searchPanelManager.ts];
F --> S[Component/skipSession.ts];
end
subgraph Commands
B --> T["Commands/index.ts (BaseCommand)"];
T --> U["Commands/play.ts (Play)"];
T --> V["Commands/skip.ts (Skip)"];
T --> W["Commands/queue.ts (Queue)"];
T --> X[... 多数のコマンドクラス];
T --> Y["Commands/search.ts (SearchBase)"];
Y --> Z["Commands/search.ts (Search)"];
Y --> AA["Commands/searchnico.ts (SearchN)"];
Y --> AB["Commands/searchsoundcloud.ts (Searchs)"];
end
subgraph Audio Sources
AC(AudioSource) --> AD["AudioSource/youtube/index.ts (YouTube)"];
AC --> AE["AudioSource/soundcloud.ts (SoundCloudS)"];
AC --> AF["AudioSource/spotify.ts (Spotify)"];
AC --> AG["AudioSource/niconico.ts (NicoNicoS)"];
AC --> AH[... その他の音源クラス];
end
subgraph YouTube Strategies
AI(Strategy) --> AJ["AudioSource/youtube/strategies/ytdl-core.ts (ytdlCoreStrategy)"];
AI --> AK[AudioSource/youtube/strategies/baseYoutubeDlStrategy.ts];
AK --> AL["AudioSource/youtube/strategies/yt-dlp.ts (ytDlpStrategy)"];
AK --> AM["AudioSource/youtube/strategies/youtube-dl.ts (youtubeDlStrategy)"];
AI --> AN["AudioSource/youtube/strategies/baseYoutubeiStrategy.ts"];
AN --> AO["AudioSource/youtube/strategies/youtubei_web.ts (youtubeiWebStrategy)"];
AN --> AP["AudioSource/youtube/strategies/youtubei_embed.ts (youtubeiEmbedStrategy)"];
AI --> AQ[... その他の戦略クラス];
end
このプロジェクトの各モジュールの、依存性グラフは以下のようになっています。こちらも、プロジェクトのコードの理解に役立てていただければ幸いです。
graph TD
subgraph Core
A[index.ts] --> B[bot.ts];
B --> C[botBase.ts];
C --> D[Structure/GuildDataContainer.ts];
C --> E[Component/cacheController/index.ts];
C --> F[Component/backupper/index.ts];
end
subgraph Guild_Data
D --> G[Component/playManager.ts];
D --> H[Component/queueManager.ts];
D --> I[Component/searchPanelManager.ts];
D --> J[Component/audioEffectManager.ts];
D --> K[Component/preferencesManager.ts];
D --> L[Component/skipSession.ts];
D --> M[Component/taskCancellationManager.ts];
end
subgraph Audio_Playback
G --> N[AudioSource/audiosource.ts];
G --> O[Component/audioResource.ts];
G --> P[Component/streams/index.ts];
end
subgraph Queue_Management
H --> N;
H --> Q[AudioSource/resolver.ts];
end
subgraph Command_System
R[Component/commandManager.ts] --> S[Commands/index.ts];
B --> R;
T[events/messageCreate.ts] --> R;
U[events/interactionCreate.ts] --> R;
end
subgraph Audio_Sources
Q --> V[AudioSource/youtube/index.ts];
Q --> W[AudioSource/soundcloud.ts];
Q --> X[AudioSource/spotify.ts];
Q --> Y[AudioSource/custom.ts];
Q --> Z[AudioSource/niconico.ts];
Q --> AA[AudioSource/googledrive.ts];
Q --> AB[AudioSource/streamable.ts];
Q --> AC[AudioSource/twitter.ts];
Q --> AD[AudioSource/bestdori.ts];
Q --> AE[AudioSource/fs.ts];
end
subgraph Caching
E --> AF[Component/cacheController/audioSource.ts];
E --> AG[Component/cacheController/audioBinary.ts];
E --> AH[Component/cacheController/search.ts];
E --> AI[Component/cacheController/exportableAudioSource.ts];
end
Tip
グラフが小さすぎて、GitHub 上では小さすぎて見にくいことがあるので、コピーしてMermaid Liveで閲覧していただく方が見やすいかもしれません。
その他、ご不明な点がございましたら、Discordサーバーにてお問い合わせください。
なお、このファイルの内容の一部は、生成AIを用いて作成されています。
このドキュメントは、2025年10月時点の情報をもとに作成しています。更新が必要になった場合には、随時更新していますが、更新漏れや更新遅れなど、最新の情報を反映していない可能性があることを、予めご了承ください。