diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..efe86b4 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: /locales/en-US.json + translation: /locales/%locale%.%file_extension% diff --git a/locales/ar-SA.json b/locales/ar-SA.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/ar-SA.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/de-DE.json b/locales/de-DE.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/de-DE.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/en-US.json b/locales/en-US.json index ed9fcf9..03c5527 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -22,7 +22,23 @@ "was": "Was the impostor", "was_not": "Was not the impostor" }, - "embed_successfully": "Embed created and sent successfully.", + "embed": { + "successfully": "Embed created and sent successfully.", + "missing_permissions": "I don't have permissions to send messages in that channel. I need {permisions}", + "modal": { + "title": "Embed Creator", + "title_label": "Title", + "title_placeholder": "My Awesome Embed", + "description_label": "Description", + "description_placeholder": "This is my awesome embed!", + "color_label": "Color" + }, + "buttons": { + "send": "Send", + "edit": "Edit" + }, + "invalid_input": "Invalid input" + }, "github": { "write_username": "Please write an username.", "name": "🧑 Name:", @@ -111,7 +127,8 @@ "same": "You need to be on the same voice channel as the bot to execute this command.", "not_voice": "You need to be on a voice channel to execute this command.", "not_reproducible": "The attached link does not contain reproducible content.", - "added": "{song} added to the list" + "added": "{song} added to the list", + "cant_join": "I can't join your voice channel, make sure I have the necessary permissions." }, "reboot": { "all": "Rebooting all shards...", diff --git a/locales/es-ES.json b/locales/es-ES.json index 414bdd3..16a9156 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -22,7 +22,23 @@ "was": "¿Fue el impostor", "was_not": "¿No era el impostor" }, - "embed_successfully": "Incrustación creada y enviada correctamente.", + "embed": { + "successfully": "Embed creado y enviado correctamente.", + "missing_permissions": "No tengo permisos para enviar mensajes en este canal. Necesito {permisions}", + "modal": { + "title": "Creador de embed", + "title_label": "Título", + "title_placeholder": "El mejor embed", + "description_label": "Descripción", + "description_placeholder": "Este es el mejor embed del mundo", + "color_label": "Color" + }, + "buttons": { + "send": "Enviar", + "edit": "Editar" + }, + "invalid_input": "Entrada no válida" + }, "github": { "write_username": "Por favor, escriba un nombre de usuario.", "name": "🧑 Nombre:", @@ -120,7 +136,8 @@ "same": "Necesitas estar en el mismo canal de voz que el bot para ejecutar este comando.", "not_voice": "Necesitas estar en un canal de voz para ejecutar este comando.", "not_reproducible": "El enlace adjunto no contiene contenidos reproducibles.", - "added": "{song} añadido a la lista" + "added": "{song} añadido a la lista", + "cant_join": "No puedo unirme a tu canal de voz, ¿tengo permisos?" }, "reboot": { "all": "Reiniciando todos los fragmentos...", diff --git a/locales/fr-FR.json b/locales/fr-FR.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/fr-FR.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/ga-IE.json b/locales/ga-IE.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/ga-IE.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/it-IT.json b/locales/it-IT.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/it-IT.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/ja.json b/locales/ja.json index 72c63bf..9ef9e7a 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -22,7 +22,23 @@ "was": "詐欺師だったのか?", "was_not": "詐欺師ではなかった" }, - "embed_successfully": "エンベッドが作成され、正常に送信された。", + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, "github": { "write_username": "ユーザー名を書いてください。", "name": "🧑 名前:", @@ -111,7 +127,8 @@ "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", "not_voice": "音声チャンネルに入ってください。", "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", - "added": "リストに{song}を追加" + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" }, "reboot": { "all": "すべてのシャードを再起動...", diff --git a/locales/nl-NL.json b/locales/nl-NL.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/nl-NL.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/pt-BR.json b/locales/pt-BR.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/pt-BR.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/ru-RU.json b/locales/ru-RU.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/ru-RU.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/tr-TR.json b/locales/tr-TR.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/tr-TR.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/uk-UA.json b/locales/uk-UA.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/uk-UA.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/locales/zh-CN.json b/locales/zh-CN.json new file mode 100644 index 0000000..9ef9e7a --- /dev/null +++ b/locales/zh-CN.json @@ -0,0 +1,417 @@ +{ + "question_ball": { + "no_question": "答えるべき質問はないのか?", + "question": "ご質問の件", + "response": "私の答えはこうだ。", + "possibles": { + "0": "はい", + "1": "いいえ", + "2": "たぶん", + "3": "明らかに", + "4": "はい", + "5": "断る", + "6": "おそらく", + "7": "私は疑問を持っている...。", + "8": "疑ってはいけない", + "9": "聞くまでもないだろう;)", + "10": "全然違うよ...。", + "11": "私は信じない..." + } + }, + "impostor": { + "was": "詐欺師だったのか?", + "was_not": "詐欺師ではなかった" + }, + "embed": { + "successfully": "エンベッドが作成され、正常に送信された。", + "missing_permissions": "私はエンベッドを送信する権限がありません。 {permisions}つ必要だ", + "modal": { + "title": "埋め込みを作成する", + "title_label": "タイトル", + "title_placeholder": "私の素晴らしい埋め込み", + "description_label": "記述", + "description_placeholder": "これは私の素晴らしい埋め込みだ!", + "color_label": "色" + }, + "buttons": { + "send": "送信", + "edit": "編集" + }, + "invalid_input": "無効な入力" + }, + "github": { + "write_username": "ユーザー名を書いてください。", + "name": "🧑 名前:", + "account": "アカウントの種類", + "organization": "🏢 組織:", + "link": "☁️ リンク", + "location": "🗺 場所:", + "email": "📩 Eメール", + "biography": "バイオグラフィー", + "twitter": "ツイッター🐦:", + "repositories": "📂 公開リポジトリ", + "followers": "🧍 フォロワー", + "analizing": "アカウントを分析中です。", + "unknow": "ユーザーが見つかりません" + }, + "help": { + "presentation": "こんにちは、私は革新的なコマンドを持つオールインワンの多機能ボット、ノードです。", + "how_use": "コマンドはどうやって見るのですか?", + "how_use_answer": "簡単だ。", + "need_support": "サポートが必要な場合、どのようにサポートチームと連絡を取ればよいですか?", + "need_support_answer": "サポートサーバー!]({inviteURL})でお尋ねください。", + "how_vote": "ボットに投票するには?", + "how_vote_answer": " `/vote`コマンドか、[ここをクリック](https://vote.nodebot.xyz) 'We are waiting your vote :)' コマンドで実行できる。", + "title": "ヘルプメニュー" + }, + "avatar": "ここには{user}のアバターがある。", + "mchistory": { + "dont": "ユーザー名が存在しない", + "names": "名前の歴史", + "first": "名前" + }, + "ping": { + "global": "グローバル・ピン", + "internal": "内部処理(データベース+処理)" + }, + "roleinfo": { + "managed": "Discordによる管理" + }, + "serverinfo": { + "verification": { + "no": "検証はしていない。", + "low": "ロー(認証済みアカウント)。", + "medium": "ミディアム(+5分の認証済みアカウント)。", + "high": "高い(+10分間、認証済みアカウント)。", + "extreme": "エクストリーム(認証済みアカウントと認証済み電話番号のリンク)。" + }, + "explicit": { + "disabled": "メッセージはスキャンされない。", + "members_without_role": "ロールのないユーザーをスキャンします。", + "all_members": "すべてのメッセージをスキャンする。" + }, + "emoji_count": "絵文字数", + "tier_level": "ティアレベル", + "verification_level": "検証レベル", + "explicit_filter": "明示的コンテンツフィルターレベル" + }, + "ban": { + "not_found": "メンバーが見つかりません", + "self": "自分自身を禁止することはできない", + "owner": "オーナーを追放することはできない", + "higher": "自分より上位の役割を持つメンバーを追放することはできない", + "ban": "出入り禁止に成功", + "unbannable": "このメンバーを追放することはできない" + }, + "skip": { + "messages": { + "0": "ボイスチャンネルに曲がありません。追加したらどうですか?<:pepeblink:967941236029788160>", + "1": "音楽聴いてないみたいだし、どうする?<:pepeblink:967941236029788160>", + "2": "音楽を聴かずに何をしている?今すぐ曲を追加してください :)" + }, + "no_same": "私の音声チャンネルには入っていない。", + "skiped": "{song}はスキップされた" + }, + "queue": { + "no_queue": "このサーバーで演奏されている曲がありません。追加してみては?", + "current": "現在プレー中:", + "queue": "{name}のキュー", + "no_page": "ページが存在しません!", + "total": "全曲キュー:" + }, + "247": { + "enabled": "24時間365日モードが有効 ", + "disabled": "24/7モードは無効" + }, + "play": { + "same": "このコマンドを実行するには、ボットと同じ音声チャンネルにいる必要があります。", + "not_voice": "音声チャンネルに入ってください。", + "not_reproducible": "添付のリンク先には再現可能なコンテンツは含まれていません。", + "added": "リストに{song}を追加", + "cant_join": "私はあなたのボイスチャンネルに参加できません。権限を確認してください。" + }, + "reboot": { + "all": "すべてのシャードを再起動...", + "shard": "シャード{shard}を再起動中..." + }, + "stop": { + "resumed": "音楽は{user}によって再開された。", + "paused": "音楽は{user}で一時停止。", + "success": "音楽は停止された。" + }, + "paused": "スローミュージック", + "resumed": "音楽は再開された", + "voice_update": { + "leaving": "分後に{channel}を発つ{time}。", + "alone": "私は一人で、{channel}を後にした。" + }, + "automix": { + "generated": "オートミックスが生成された!", + "disabled": "オートミックス無効" + }, + "twitch": { + "no_streamer_found": "ストリーマーが見つかりません", + "already_following": "すでにこのストリーマーをフォローしています。", + "now_following": "あなたは今{streamer}をフォローしています。通知は{channel}に送信されます。", + "unfollowed": "あなたは{streamer}をフォローしていません。", + "role_mention": "{role}について言及しなければならない。", + "now_live": "今{streamer}はライブです!" + }, + "loop": { + "queue": "キューをループ", + "song": "現在の曲をループ", + "disabled": "ループ無効" + }, + "ERROREMBED": "Error", + "SUCCESSEMBED": "Success", + "PAUSE": "ポーズ", + "RESUME": "履歴書", + "STOP": "ストップ", + "SKIP": "スキップ", + "NEXT": "次のページ", + "QUEUE": "テール", + "TITLE": "タイトル", + "MEMBERS": "メンバー", + "REGULAR": "レギュラー", + "ANIMATED": "アニメーション", + "CHANNELS": "チャンネル", + "ROLES": "役割", + "CATEGORIES": "カテゴリー", + "SONGS": "曲目", + "TEXT": "テキスト", + "VOICE": "声", + "BOOSTERS": "ブースター", + "REGION": "地域", + "TIER": "動物", + "CREATED_AT": "で作成された。", + "OWNER": "オーナー", + "AUTHOR": "著者", + "REQUESTER": "要求者", + "DURATION": "期間", + "NO": "いいえ", + "API": "API", + "PING": "ピン", + "NAME": "名称", + "ID": "身分証明書", + "POSITION": "ポジション", + "COLOR": "カラー", + "MENTIONABLE": "言及可能", + "SEPARATED": "分離", + "YES": "はい", + "PLAYING": "プレー", + "GENERICERROR": "おっと、エラーがあったようだ。\n公式Discord]({inviteURL})で開発者に連絡してください。", + "commands": { + "reboot": { + "name": "再起動", + "description": "1つまたはすべてのシャードをリセットする", + "options": { + "shard": { + "name": "破片", + "description": "再起動するシャード" + } + } + }, + "8ball": { + "name": "ボール8", + "description": "魔球に質問する", + "options": { + "question": { + "name": "質問", + "description": "質問を書いてください。" + } + } + }, + "impostor": { + "name": "食わせ物", + "description": "あなたは詐欺師? SUS", + "options": { + "user": { + "name": "ユーザー", + "description": "このユーザーは偽者なのか? SUS na na na na na na na" + } + } + }, + "avatar": { + "name": "アバター", + "description": "あなたのプロフィール写真または他のユーザーの写真を送信します!", + "options": { + "user": { + "name": "ユーザー", + "description": "アバターを表示するユーザー" + } + } + }, + "twitch": { + "name": "twitch", + "description": "ストリーマーがライブを開始したときの通知を設定します!", + "options": { + "add": { + "name": "追加", + "description": "ストリーマーを追加する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + }, + "channel": { + "name": "チャンネル", + "description": "通知を受け取るチャンネル" + }, + "role": { + "name": "役割", + "description": "通知を受け取る役割" + } + } + }, + "remove": { + "name": "削除", + "description": "ストリーマーを削除する", + "options": { + "streamer": { + "name": "ストリーマー", + "description": "通知を受け取るストリーマー" + } + } + } + } + }, + "shards": { + "name": "破片", + "description": "ボットのシャードを表示します。" + }, + "serverinfo": { + "name": "サーバー情報", + "description": "サーバーの情報を表示します。" + }, + "roleinfo": { + "name": "役割情報", + "description": "役割の情報を表示します。", + "options": { + "role": { + "name": "役割", + "description": "役割の情報を表示します。" + } + } + }, + "ping": { + "name": "ピン", + "description": "ボットの待ち時間を表示" + }, + "mcserver": { + "name": "マインクラフトサーバー", + "description": "Minecraftサーバーから画像を送信する", + "options": { + "server": { + "name": "サーバー", + "description": "サーバーのIPまたはドメイン" + } + } + }, + "mchistory": { + "name": "マインクラフトの歴史", + "description": "Minecraftユーザーの名前の歴史を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "help": { + "name": "助けて", + "description": "私に関する情報を表示する" + }, + "github": { + "name": "ギットハブ", + "description": "GitHubユーザーの情報を表示します。", + "options": { + "account": { + "name": "アカウント", + "description": "アカウントの名前" + } + } + }, + "embed": { + "name": "埋め込み", + "description": "埋め込みを作成する", + "options": { + "channel": { + "name": "チャンネル", + "description": "埋め込みを送信するチャンネル" + }, + "color": { + "name": "カラー", + "description": "埋め込みの色" + }, + "title": { + "name": "タイトル", + "description": "埋め込みのタイトル" + }, + "description": { + "name": "説明", + "description": "埋め込みの説明" + } + } + }, + "ban": { + "name": "禁止", + "description": "ユーザーを禁止する", + "options": { + "user": { + "name": "ユーザー", + "description": "禁止するユーザー" + }, + "reason": { + "name": "理由", + "description": "追放の理由" + }, + "days": { + "name": "ディアス", + "description": "ユーザーメッセージの削除日数" + } + } + }, + "play": { + "name": "演奏", + "description": "好きな曲を、その曲名またはyoutube/spotifyのリンクとともに流す。", + "options": { + "song": { + "name": "曲", + "description": "演奏する曲" + } + } + }, + "stop": { + "name": "停止", + "description": "選手を止める!" + }, + "skip": { + "name": "スキップ", + "description": "現在の曲をスキップする" + }, + "resume": { + "name": "履歴書", + "description": "現在の曲を再開する!" + }, + "queue": { + "name": "キュー", + "description": "現在のキューを表示する" + }, + "pause": { + "name": "ポーズ", + "description": "現在の曲を一時停止する" + }, + "nowplaying": { + "name": "再生中", + "description": "現在の曲を表示する" + }, + "loop": { + "name": "ループ", + "description": "現在のキュー/曲を繰り返す" + }, + "247": { + "name": "247", + "description": "年中無休の音声チャンネル" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 86fc065..4779b5d 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "build/index.js", "engines": { - "node": ">=18.12.0" + "node": ">=18.17.0" }, "signale": { "displayScope": true, @@ -22,22 +22,21 @@ "scripts": { "start": "doppler run -- node build/index.js", "run": "node build/index.js", - "build": "tsc && doppler run --", - "dev": "concurrently \"tsc -w\" \"nodemon doppler run -- node build/index.js\"", - "tsc": "tsc", - "tsc:watch": "nodemon --watch src --exec tsc", + "build": "npm run type:locales && tsc", + "dev": "nodemon -e ts --exec \"npm start\"", + "tsc:watch": "nodemon -e ts --exec tsc", "type:locales": "cd locales && type-locales && mv locales.ts ../src/utils/locales.ts && cd .. && node build/utils/testLocales.js" }, "author": "", "license": "ISC", "dependencies": { "@sentry/node": "7.61.0", - "@sentry/profiling-node": "^1.1.2", + "@sentry/profiling-node": "1.1.2", "bindings": "1.5.0", "canvas": "2.11.2", "cors": "2.8.5", - "datadog-metrics": "^0.11.0", - "dd-trace": "^4.11.1", + "datadog-metrics": "0.11.0", + "dd-trace": "4.11.1", "discord-hybrid-sharding": "github:meister03/discord-hybrid-sharding", "discord.js": "14.12.1", "dotenv": "16.3.1", @@ -46,11 +45,11 @@ "i18n": "0.15.1", "jsonwebtoken": "9.0.1", "moment": "2.29.4", - "mongoose": "7.4.1", + "mongoose": "7.4.3", "mongoose-encryption": "2.1.2", "signale": "1.4.0", "statcord.js": "3.4.3", - "stripe": "12.16.0", + "stripe": "12.18.0", "yasha": "github:eliyya/ts-yasha#node", "youtubei.js": "5.8.0" }, @@ -109,11 +108,12 @@ "@typescript-eslint/no-floating-promises": "off", "@typescript-eslint/restrict-plus-operands": "off", "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/no-base-to-string": "off" + "@typescript-eslint/no-base-to-string": "off", + "curly": ["error", "multi"] } }, "prettier": { - "printWidth": 120, + "printWidth": 80, "tabWidth": 4, "useTabs": false, "semi": false, diff --git a/src/cache/autocomplete.ts b/src/cache/autocomplete.ts deleted file mode 100644 index b27cacb..0000000 --- a/src/cache/autocomplete.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Collection } from 'discord.js' -import Autocomplete from '../structures/Autocomplete' - -class AutocompleteCache { - private static instance: AutocompleteCache - private readonly cache: Collection - - private constructor () { - this.cache = new Collection() - } - - public static getInstance (): AutocompleteCache { - if (!AutocompleteCache.instance) { - AutocompleteCache.instance = new AutocompleteCache() - } - return AutocompleteCache.instance - } - - public getCache (): Collection { - return this.cache - } -} - -export default AutocompleteCache.getInstance() diff --git a/src/cache/autocompletes.ts b/src/cache/autocompletes.ts new file mode 100644 index 0000000..2c9ede2 --- /dev/null +++ b/src/cache/autocompletes.ts @@ -0,0 +1,44 @@ +import { Collection, Snowflake } from 'discord.js' +import Autocomplete from '#structures/Autocomplete.js' + +class AutocompleteCache { + private static instance: AutocompleteCache + #cache: Collection + #interactions = new Collection() + + private constructor () { + this.#cache = new Collection() + } + + static getInstance (): AutocompleteCache { + if (!AutocompleteCache.instance) + AutocompleteCache.instance = new AutocompleteCache() + + return AutocompleteCache.instance + } + + get cache (): Collection { + return this.#cache + } + + canProced (userId: Snowflake, interactionId: Snowflake): boolean { + const auto = this.#interactions.get(userId) + if (!auto) return true + if (auto.interactionId !== interactionId) return true + if (Date.now() - auto.timestamp < 3000) return true + return false + } + + registerInteraction (userId: Snowflake, interactionId: Snowflake): void { + this.#interactions.set(userId, { interactionId, timestamp: Date.now() }) + } + + removeInteraction (userId: Snowflake): void { + this.#interactions.delete(userId) + } +} + +export default AutocompleteCache.getInstance() diff --git a/src/cache/buttons.ts b/src/cache/buttons.ts index c4b5bbb..9717853 100644 --- a/src/cache/buttons.ts +++ b/src/cache/buttons.ts @@ -1,24 +1,24 @@ import { Collection } from 'discord.js' -import Button from '../structures/Button' +import Button from '#structures/Button.js' -class buttonCache { - private static instance: buttonCache - private cache: Collection +class ButtonCache { + private static instance: ButtonCache + #cache: Collection - private constructor() { - this.cache = new Collection() + private constructor () { + this.#cache = new Collection() } - public static getInstance(): buttonCache { - if (!buttonCache.instance) { - buttonCache.instance = new buttonCache() + static getInstance (): ButtonCache { + if (!ButtonCache.instance) { + ButtonCache.instance = new ButtonCache() } - return buttonCache.instance + return ButtonCache.instance } - public getCache(): Collection { - return this.cache + get cache (): Collection { + return this.#cache } } -export default buttonCache.getInstance() +export default ButtonCache.getInstance() diff --git a/src/cache/commands.ts b/src/cache/commands.ts index 0643f83..5a4245b 100644 --- a/src/cache/commands.ts +++ b/src/cache/commands.ts @@ -1,24 +1,24 @@ // commands.ts import { Collection } from 'discord.js' -import Command from '../structures/Command' +import Command from '#structures/Command.js' class CommandCache { private static instance: CommandCache - private readonly cache: Collection + #cache: Collection private constructor () { - this.cache = new Collection() + this.#cache = new Collection() } - public static getInstance (): CommandCache { + static getInstance (): CommandCache { if (!CommandCache.instance) { CommandCache.instance = new CommandCache() } return CommandCache.instance } - public getCache (): Collection { - return this.cache + get cache (): Collection { + return this.#cache } } diff --git a/src/cache/cooldowns.ts b/src/cache/cooldowns.ts new file mode 100644 index 0000000..0357e48 --- /dev/null +++ b/src/cache/cooldowns.ts @@ -0,0 +1,41 @@ +import { Collection, Snowflake } from 'discord.js' +import commands from './commands.js' + +class CooldownCache { + private static instance: CooldownCache + #cache = new Collection() + + static getInstance (): CooldownCache { + if (!CooldownCache.instance) + CooldownCache.instance = new CooldownCache() + + return CooldownCache.instance + } + + get cache (): Collection { + return this.#cache + } + + canProced (userId: Snowflake, interactionName: string): boolean { + if (!this.#cache.has(`${userId}:${interactionName}`)) return true + const commandCooldown = commands.cache.find(c => c.name === interactionName)?.cooldown ?? 0 + if (!commandCooldown) return true + const cooldown = this.#cache.get(`${userId}:${interactionName}`) ?? Date.now() + if (Date.now() - cooldown > (commandCooldown * 1000)) return true + return false + } + + registerInteraction (userId: Snowflake, interactionName: string): void { + this.#cache.set(`${userId}:${interactionName}`, Date.now()) + } + + leftTime (userId: Snowflake, interactionName: string): number { + if (!this.#cache.has(`${userId}:${interactionName}`)) return 0 + const commandCooldown = commands.cache.find(c => c.name === interactionName)?.cooldown ?? 0 + if (!commandCooldown) return 0 + const cooldown = this.#cache.get(`${userId}:${interactionName}`) ?? Date.now() + return (commandCooldown * 1000) - (Date.now() - cooldown) + } +} + +export default CooldownCache.getInstance() diff --git a/src/cache/events.ts b/src/cache/events.ts index 2ecdcc4..cb0903a 100644 --- a/src/cache/events.ts +++ b/src/cache/events.ts @@ -1,24 +1,24 @@ // commands.ts import { Collection } from 'discord.js' -import { BaseEvent } from '../structures/Events' -class eventCache { - private static instance: eventCache - private cache: Collection +import { BaseEvent } from '#structures/Events.js' +class EventCache { + private static instance: EventCache + #cache: Collection - private constructor() { - this.cache = new Collection() + private constructor () { + this.#cache = new Collection() } - public static getInstance(): eventCache { - if (!eventCache.instance) { - eventCache.instance = new eventCache() + static getInstance (): EventCache { + if (!EventCache.instance) { + EventCache.instance = new EventCache() } - return eventCache.instance + return EventCache.instance } - public getCache(): Collection { - return this.cache + get cache (): Collection { + return this.#cache } } -export default eventCache.getInstance() +export default EventCache.getInstance() diff --git a/src/cache/modals.ts b/src/cache/modals.ts new file mode 100644 index 0000000..1d82a38 --- /dev/null +++ b/src/cache/modals.ts @@ -0,0 +1,21 @@ +// commands.ts +import { Collection } from 'discord.js' +import Modal from '#structures/Modal.js' + +class ModalCache { + private static instance: ModalCache + #cache = new Collection() + + static getInstance (): ModalCache { + if (!ModalCache.instance) + ModalCache.instance = new ModalCache() + + return ModalCache.instance + } + + get cache (): Collection { + return this.#cache + } +} + +export default ModalCache.getInstance() diff --git a/src/cache/performanceMeters.ts b/src/cache/performanceMeters.ts index 7a4f12f..7c651f6 100644 --- a/src/cache/performanceMeters.ts +++ b/src/cache/performanceMeters.ts @@ -1,3 +1,4 @@ import { Collection } from 'discord.js' +import { PerformanceMeter } from '../handlers/performanceMeter.js' -export default new Collection() +export default new Collection() diff --git a/src/deleteSlashCommands.ts b/src/deleteSlashCommands.ts index 341de65..81c0604 100644 --- a/src/deleteSlashCommands.ts +++ b/src/deleteSlashCommands.ts @@ -1,5 +1,5 @@ import cachedCommands from './cache/commands.js' -let body = cachedCommands.getCache().each((command) => { return command }) +const body = cachedCommands.cache.each((command) => { return command }) console.log(body) fetch('https://discord.com/api/v9/applications/834164602694139985/guilds/862635336165097483/commands', { method: 'PUT', diff --git a/src/events/client/interactionCreate.ts b/src/events/client/interactionCreate.ts index 4510dd5..8498d04 100644 --- a/src/events/client/interactionCreate.ts +++ b/src/events/client/interactionCreate.ts @@ -1,33 +1,36 @@ -import autocomplete from '#cache/autocomplete.js' +import autocomplete from '#cache/autocompletes.js' import buttons from '#cache/buttons.js' import commands from '#cache/commands.js' import performanceMeters from '#cache/performanceMeters.js' import Client from '#structures/Client.js' import logger from '#utils/logger.js' -import { AutocompleteInteraction, ButtonInteraction, ChatInputCommandInteraction, Interaction } from 'discord.js' -import { Timer as PerformanceMeter } from '../../handlers/performanceMeter.js' +import { AutocompleteInteraction, ButtonInteraction, ChatInputCommandInteraction, Interaction, ModalSubmitInteraction } from 'discord.js' +import { PerformanceMeter } from '../../handlers/performanceMeter.js' import { BaseEvent } from '../../structures/Events.js' +import modals from '#cache/modals.js' +import cooldowns from '#cache/cooldowns.js' export class interactionCreate extends BaseEvent { async run (client: Client, interaction: Interaction) { - if (process.env.TESTINGGUILD) { + if (process.env.TESTINGGUILD) if (interaction.guild?.id !== process.env.TESTINGGUILD) return - } + if (interaction.member?.user.bot) return // return false if something went wrong, true if everything was okey - if (client.settings.debug === 'true' && interaction.type !== 2) { logger.debug('Interaction, type: ' + interaction.type + ' | ' + interaction.guild?.name ?? 'No guild' + ' | ' + interaction.user.username) } + if (client.settings.debug === 'true' && interaction.type !== 2) logger.debug('Interaction, type: ' + interaction.type + ' | ' + interaction.guild?.name ?? 'No guild' + ' | ' + interaction.user.username) if (!client.isReady()) return // <-- return statement here if (interaction.isChatInputCommand()) return await this.processChatImputCommand(interaction) else if (interaction.isButton()) return await this.processButtonInteraction(interaction) else if (interaction.isAutocomplete()) return await this.processAutocompleteInteraction(interaction) + else if (interaction.isModalSubmit()) return await this.processModalSubmitInteraction(interaction) } async processChatImputCommand (interaction: ChatInputCommandInteraction) { try { performanceMeters.set('interaction_' + interaction.id, new PerformanceMeter()) - performanceMeters.get('interaction_' + interaction.id).start() - const cmd = commands.getCache().find(c => c.name === interaction.commandName) + performanceMeters.get('interaction_' + interaction.id)?.start() + const cmd = commands.cache.find(c => c.name === interaction.commandName) if (!cmd) return if (interaction.guild && cmd?.only_dm) return // <-- return statement here @@ -35,33 +38,42 @@ export class interactionCreate extends BaseEvent { if (cmd.permissions) { // Check if the command is only for devs - if (cmd.permissions.dev && !(interaction.client as Client).devs.includes(interaction.user.id)) { + if (cmd.permissions.dev && !(interaction.client as Client).devs.includes(interaction.user.id)) return await interaction.reply({ content: 'Comando exclusivo para devs', ephemeral: true, }) - } + // Check if the bot has the needed permissions to run the command if (cmd.permissions.botPermissions) { const botMember = await interaction.guild?.members.fetchMe() const missingPermissions = botMember?.permissions.missing(cmd.permissions.botPermissions) // If there are missing permissions, return an error message - if (missingPermissions?.length) { + if (missingPermissions?.length) return await interaction.reply({ content: `No tengo los permisos necesarios para ejecutar este comando, Permisos necesarios: **${missingPermissions.join( ', ', )}**`, ephemeral: true, }) - } } - - // TODO: Add COOLDOWN functionality } - await cmd.run(interaction) - await performanceMeters.get('interaction_' + interaction.id)?.stop() // the ping command stop the process - return performanceMeters.delete('interaction_' + interaction.id) + if (!cooldowns.canProced(interaction.user.id, interaction.commandName)) return await interaction.reply({ + content: `Debes esperar ${Math.round(cooldowns.leftTime(interaction.user.id, interaction.commandName) / 1000)} segundos para volver a ejecutar este comando`, + }) + return await cmd.run(interaction) + .catch(e => { + logger.error(e, '\x1b[33mCommand Info\x1b[0m', { + cmd: cmd.name, + options: JSON.stringify(interaction.options.data, (key, value) => !['client', 'channel', 'guild', 'user', 'member', 'role'].includes(key) ? value : undefined, 4), + }) + }) + .finally(() => { + cooldowns.registerInteraction(interaction.user.id, interaction.commandName) + performanceMeters.get('interaction_' + interaction.id)?.stop() + performanceMeters.delete('interaction_' + interaction.id) + }) } catch (e) { return logger.error(e) } @@ -69,10 +81,16 @@ export class interactionCreate extends BaseEvent { async processButtonInteraction (interaction: ButtonInteraction) { logger.debug(`Button ${interaction.customId} pressed | ${interaction.user.username}`) - buttons.getCache().filter(b => b.match(interaction.customId)).map(async i => await i.run(interaction)) + await buttons.cache.find(b => b.match(interaction.customId))?.run(interaction).catch(logger.error) } async processAutocompleteInteraction (interaction: AutocompleteInteraction) { - autocomplete.getCache().filter(b => b.match(interaction.commandName)).map(async i => await i.run(interaction)) + autocomplete.registerInteraction(interaction.user.id, interaction.id) + const respond = await autocomplete.cache.find(b => b.match(interaction.commandName))?.run(interaction).catch(logger.error) + if (respond) autocomplete.removeInteraction(interaction.user.id) + } + + async processModalSubmitInteraction (interaction: ModalSubmitInteraction) { + await modals.cache.find(b => b.match(interaction.customId))?.run(interaction).catch(logger.error) } } diff --git a/src/events/client/ready.ts b/src/events/client/ready.ts index cb035f8..d66e928 100644 --- a/src/events/client/ready.ts +++ b/src/events/client/ready.ts @@ -14,26 +14,26 @@ export default class Ready extends BaseEvent { // ... //* ADD DATABASE CONNECTION - if (process.env.MONGOURL) { + if (process.env.MONGOURL) connect(process.env.MONGOURL.toString(), { // @ts-expect-error useUnifiedTopology: true, useNewUrlParser: true, }).then(() => logger.db('Se ha conectado la base de datos correctamente.')) - } + // cluster // client.cluster.triggerReady() const arr: Command[] = [] - for (const [,command] of commands.getCache()) arr.push(command) + for (const [,command] of commands.cache) arr.push(command) if (process.env.TESTINGGUILD) { const guild = await client.guilds.fetch(process.env.TESTINGGUILD) guild.commands.set(arr).catch(logger.error) - } else if (!process.env.TESTINGUILD) { + } else if (!process.env.TESTINGUILD) client.application?.commands.set(arr).catch(logger.error) - } + client.cluster.on('message', async (message2: any) => { const message = (message2 as IPCMessage).raw - if (message.content === 'statistics') { + if (message.content === 'statistics') try { // logger.debug(`Cluster's ${client.cluster.id} received statistics`) client.cluster @@ -72,13 +72,11 @@ export default class Ready extends BaseEvent { status: 500, }) } - } }) - if (!process.env.TESTINGUILD) { + if (!process.env.TESTINGUILD) setInterval(() => { updateStatus() }, 300000) - } async function updateStatus () { const promises = [ diff --git a/src/events/voice/voiceStateUpdate.ts b/src/events/voice/voiceStateUpdate.ts index 0fc6a64..4e02834 100644 --- a/src/events/voice/voiceStateUpdate.ts +++ b/src/events/voice/voiceStateUpdate.ts @@ -18,6 +18,8 @@ export default class VoiceStateUpdate extends BaseEvent { await player.destroy() return } + const vc = player.voiceChannel + if (newUserVoiceChannel.id !== vc.id) return // Check if there are more than 1 user in the voice channel, if not, pause the music if (newUserVoiceChannel.members.filter(member => !member.user.bot).size >= 1) { diff --git a/src/handlers/antiCrash.ts b/src/handlers/antiCrash.ts index efaaf81..eb724a9 100644 --- a/src/handlers/antiCrash.ts +++ b/src/handlers/antiCrash.ts @@ -7,7 +7,7 @@ import { EmbedBuilder, WebhookClient } from 'discord.js' class ErrorManager { client: Client - services: { sentry: { loggedIn: boolean } } + services = { sentry: { loggedIn: false } } webhookClient: WebhookClient constructor (client: Client) { this.client = client @@ -24,20 +24,10 @@ class ErrorManager { environment: process.env.NODE_ENV, tracesSampleRate: 0.5, }) - this.services = { - sentry: { - loggedIn: true, - }, - } + this.services.sentry.loggedIn = true Logger.log('Connected to Sentry') - } else { - this.services = { - sentry: { - loggedIn: false, - }, - } + } else Logger.warn('Sentry DSN missing or not in production environment.') - } this.webhookClient = new WebhookClient({ id: process.env.ERROR_WEBHOOK_ID ?? '', @@ -57,14 +47,13 @@ class ErrorManager { .setFields( { name: 'Razón', value: '```' + (await reason) + '```' }, { name: 'Error', value: '```' + (await p) + '```' }, - { name: 'Bot', value: this.client.user ? this.client.user.displayName : 'Unknown' }, + { name: 'Bot', value: this.client.user?.displayName ?? 'Unknown' }, ), ], }) - if (this.services.sentry.loggedIn) { + if (this.services.sentry.loggedIn) Sentry.captureException(p) - } Logger.warn(' [antiCrash] :: Unhandled Rejection/Catch') Logger.error(reason, p) @@ -79,14 +68,13 @@ class ErrorManager { name: 'Error', value: '```' + err + '```', }, - { name: 'Bot', value: this.client.user ? this.client.user.displayName : 'Unknown' }, + { name: 'Bot', value: this.client.user?.displayName ?? 'Unknown' }, ), ], }) - if (this.services.sentry.loggedIn) { + if (this.services.sentry.loggedIn) Sentry.captureException(err) - } Logger.warn(' [antiCrash] :: Uncaught Exception/Catch') Logger.error(err, origin) @@ -101,14 +89,13 @@ class ErrorManager { name: 'Error', value: '```' + err + '```', }, - { name: 'Bot', value: this.client.user ? this.client.user.displayName : 'Unknown' }, + { name: 'Bot', value: this.client.user?.displayName ?? 'Unknown' }, ), ], }) - if (this.services.sentry.loggedIn) { + if (this.services.sentry.loggedIn) Sentry.captureException(err) - } Logger.warn(' [antiCrash] :: Uncaught Exception/Catch (MONITOR)') Logger.error(err, origin) @@ -124,13 +111,33 @@ class ErrorManager { ], }) - if (this.services.sentry.loggedIn) { + if (this.services.sentry.loggedIn) Sentry.captureMessage('Multiple Resolves: ' + reason) - } Logger.warn(' [antiCrash] :: Multiple Resolves') Logger.error(reason) } + + captureException (error: Error) { + if (this.services.sentry.loggedIn) + Sentry.captureException(error) + const origin = error.stack?.split('\n')[1].trim().split(' ')[1] + const reason = error.stack?.split('\n')[0].trim() + this.webhookClient.send({ + embeds: [ + new EmbedBuilder() + .setColor(15548997) + .setFields( + { name: 'Origen', value: '```' + origin + '```' }, + { + name: 'Razón', + value: '```' + reason + '```', + }, + { name: 'Bot', value: this.client.user?.displayName ?? 'Unknown' }) + .setDescription('```\n' + error.stack + '\n```'), + ], + }) + } } export default ErrorManager diff --git a/src/handlers/commands.ts b/src/handlers/commands.ts index 0d8b3f6..9aad4ae 100644 --- a/src/handlers/commands.ts +++ b/src/handlers/commands.ts @@ -1,56 +1,33 @@ -import Autocomplete from '#structures/Autocomplete.js' -import autoCompleteCache from '#cache/autocomplete.js' -import Button from '#structures/Button.js' -import commands from '#cache/commands.js' import { readdir } from 'node:fs/promises' -import buttons from '#cache/buttons.js' +import { Collection } from 'discord.js' import logger from '#utils/logger.js' +import { join } from 'node:path' +// caches +import autocompletes from '#cache/autocompletes.js' +import commands from '#cache/commands.js' +import buttons from '#cache/buttons.js' +import modals from '#cache/modals.js' -// cache commands -for (const dir of await readdir('./build/slash/commands')) { - for (const file of await readdir(`./build/slash/commands/${dir}`)) { - if (file.endsWith('.js')) { - const { default: CommandFile } = await import(`../../build/slash/commands/${dir}/${file}`) - if (typeof CommandFile === 'function') { - try { - const command = new CommandFile() - if (!commands.getCache().has(command.name)) commands.getCache().set(command.name, command) - } catch (e) { - logger.error(CommandFile, e) - } - } - } - } -} -// cache buttons -for (const dir of await readdir('./build/slash/buttons')) { - for (const file of await readdir(`./build/slash/buttons/${dir}`)) { - if (file.endsWith('.js')) { - const { default: ButtonFile } = await import(`../../build/slash/buttons/${dir}/${file}`) - if (typeof ButtonFile === 'function') { - try { - const button = new ButtonFile() as Button - if (!buttons.getCache().has(button.pattern)) buttons.getCache().set(button.pattern, button) - } catch (e) { - logger.error(ButtonFile, e) - } - } - } - } -} -// cache autocomplete -for (const dir of await readdir('./build/slash/autocomplete')) { - for (const file of await readdir(`./build/slash/autocomplete/${dir}`)) { - if (file.endsWith('.js')) { - const { default: AutocompleteFile } = await import(`../../build/slash/autocomplete/${dir}/${file}`) - if (typeof AutocompleteFile === 'function') { - try { - const autocomplete = new AutocompleteFile() as Autocomplete - if (!autoCompleteCache.getCache().has(autocomplete.pattern)) autoCompleteCache.getCache().set(autocomplete.pattern, autocomplete) - } catch (e) { - logger.error(AutocompleteFile, e) - } - } +// load commands +await loadCache(commands.cache, join(process.cwd(), 'build', 'slash', 'commands')) +// load buttons +await loadCache(buttons.cache, join(process.cwd(), 'build', 'slash', 'buttons')) +// load autocompletes +await loadCache(autocompletes.cache, join(process.cwd(), 'build', 'slash', 'autocompletes')) +// load modals +await loadCache(modals.cache, join(process.cwd(), 'build', 'slash', 'modals')) + +// generic function to load cache +async function loadCache (cache: Collection, dir: string) { + const files = await readdir(join(dir), { recursive: true, withFileTypes: true }) + for (const file of files.filter(f => f.isFile() && f.name.endsWith('.js'))) { + const { default: File } = await import(join(file.path, file.name)) + if (typeof File !== 'function') continue + try { + const instance = new File() + if (!cache.has(instance.name)) cache.set(instance.name, instance) + } catch (error) { + logger.error(join(file.path, file.name), error) } } } diff --git a/src/handlers/performanceMeter.ts b/src/handlers/performanceMeter.ts index 8308184..bfa8180 100644 --- a/src/handlers/performanceMeter.ts +++ b/src/handlers/performanceMeter.ts @@ -1,5 +1,5 @@ -export class Timer { +export class PerformanceMeter { private startTime!: number private readonly endTime!: number diff --git a/src/slash/autocomplete/play/play.ts b/src/slash/autocomplete/play/play.ts deleted file mode 100644 index 7c04d63..0000000 --- a/src/slash/autocomplete/play/play.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AutocompleteInteraction } from 'discord.js' -import Client from '../../../structures/Client' -import logger from '#utils/logger.js' -import Autocomplete from '#structures/Autocomplete.js' - -export default class Repeat extends Autocomplete { - constructor () { - super('play') - } - - override async run (interaction: AutocompleteInteraction) { - try { - const client = interaction.client as Client - if (!interaction.options.getFocused()) return - const result = await (await client.music.youtubei).music.getSearchSuggestions(interaction.options.getFocused()) - - // TODO: Remove this any - interaction.respond(result.map((choice: any) => ({ name: choice.suggestion?.text, value: choice.suggestion?.text }))) - } catch (e) { - logger.error(e) - } - return true - } -} diff --git a/src/slash/autocompletes/embed.ts b/src/slash/autocompletes/embed.ts new file mode 100644 index 0000000..575e646 --- /dev/null +++ b/src/slash/autocompletes/embed.ts @@ -0,0 +1,66 @@ +import Autocomplete from '#structures/Autocomplete.js' +import Color from '#structures/Color.js' +import Translator, { keys } from '#utils/Translator.js' +import logger from '#utils/logger.js' +import { AutocompleteInteraction, Colors } from 'discord.js' + +export default class Embed extends Autocomplete { + constructor () { + super('embed') + } + + override async run (interaction: AutocompleteInteraction) { + const translate = Translator(interaction) + const invalidInput = translate(keys.embed.invalid_input) + const focused = interaction.options.getFocused()?.trim() + const suggestions: Array<{ name: string, value: string }> = [] + const values = Object.values(Colors) + if (!focused) { + if (!this.canProced(interaction.user.id, interaction.id)) return false + await interaction.respond([ + { name: 'Default', value: `${Colors.Default}` }, + { name: '#000', value: `${Colors.Default}` }, + { name: '0x000000', value: `${Colors.Default}` }, + { name: 'rgb(0, 0, 0)', value: `${Colors.Default}` }, + { name: 'White', value: `${Colors.White}` }, + { name: '#ffffff', value: `${Colors.White}` }, + { name: '0xffffff', value: `${Colors.White}` }, + { name: 'rgb(255, 255, 255)', value: `${Colors.White}` }, + { name: 'Red', value: `${Colors.Red}` }, + { name: '#FF0000', value: `${Colors.Red}` }, + { name: '0xFF0000', value: `${Colors.Red}` }, + { name: 'rgb 255, 0, 0', value: `${Colors.Red}` }, + { name: 'Green', value: `${Colors.Green}` }, + { name: '#00FF00', value: `${Colors.Green}` }, + { name: '0x00FF00', value: `${Colors.Green}` }, + { name: 'rgb(0 255 0)', value: `${Colors.Green}` }, + { name: 'Blue', value: `${Colors.Blue}` }, + { name: '#0000FF', value: `${Colors.Blue}` }, + { name: '0x0000ff', value: `${Colors.Blue}` }, + { name: 'rgb 0 0 255', value: `${Colors.Blue}` }, + ]).catch(logger.error) + return true + } else if (focused.startsWith('#')) { + if (!Color.isHex(focused)) suggestions.push({ name: invalidInput, value: '#000000' }) + for (let i = 0, random = Math.floor(Math.random() * values.length); i < 24; i++, random = Math.floor(Math.random() * values.length)) suggestions.push({ name: `#${values[random].toString(16)}`, value: `${values[random]}` }) + } else if (focused.startsWith('0x')) { + if (!Color.isHex0x(focused)) suggestions.push({ name: invalidInput, value: '0x000000' }) + for (let i = 0, random = Math.floor(Math.random() * values.length); i < 24; i++, random = Math.floor(Math.random() * values.length)) suggestions.push({ name: `0x${values[random].toString(16)}`, value: `${values[random]}` }) + } else if (focused.startsWith('rgb')) { + if (!Color.isRGB(focused)) suggestions.push({ name: invalidInput, value: 'rgb(0, 0, 0)' }) + for (let i = 0; i < 24; i++) { + const random = Math.floor(Math.random() * values.length) + const [r, g, b] = new Color(`${values[random]}`).rgb + suggestions.push({ name: `rgb(${r}, ${g}, ${b})`, value: `rgb(${r ?? 0}, ${g ?? 0}, ${b ?? 0})` }) + } + } else { + const colors = Object.entries(Colors) + suggestions.push(...colors.filter(([name]) => name.toLowerCase().includes(focused.toLowerCase())).map(([name, value]) => ({ name, value: `${value}` }))) + suggestions.push(...colors.filter(([key]) => suggestions.some(({ name }) => name !== key)).map(([name, value]) => ({ name, value: `${value}` }))) + } + if (suggestions.length > 25) suggestions.length = 25 + if (!this.canProced(interaction.user.id, interaction.id)) return false + await interaction.respond(suggestions).catch(logger.error) + return true + } +} diff --git a/src/slash/autocompletes/play/play.ts b/src/slash/autocompletes/play/play.ts new file mode 100644 index 0000000..355b320 --- /dev/null +++ b/src/slash/autocompletes/play/play.ts @@ -0,0 +1,34 @@ +import { AutocompleteInteraction } from 'discord.js' +import Autocomplete from '#structures/Autocomplete.js' +import yasha from 'yasha' +import logger from '#utils/logger.js' +import Client from '#structures/Client.js' + +export default class Repeat extends Autocomplete { + constructor () { + super('play') + } + + override async run (interaction: AutocompleteInteraction) { + const client = interaction.client as Client + try { + const query = interaction.options.getFocused() + const search = await yasha.Source.Youtube.search(query) + if (search.length > 25) search.length = 25 + if (!this.canProced(interaction.user.id, interaction.id)) return false + await interaction.respond(search.map(r => { + const title = r.title ?? '' + const url = r.url ?? '' + return { + name: title.length > 100 ? title.slice(0, 95) + '...' : title, + value: url.length > 100 ? url.slice(0, 95) + '...' : url, + } + })).catch(logger.error) + return true + } catch (error) { + logger.error(error) + client.errorHandler.captureException(error as Error) + return true + } + } +} diff --git a/src/slash/buttons/embed.ts b/src/slash/buttons/embed.ts new file mode 100644 index 0000000..d04aaa6 --- /dev/null +++ b/src/slash/buttons/embed.ts @@ -0,0 +1,74 @@ +import Button from '#structures/Button.js' +import Client from '#structures/Client.js' +import Color from '#structures/Color.js' +import Translator, { keys } from '#utils/Translator.js' + +import { ActionRowBuilder, ButtonInteraction, ModalBuilder, TextChannel, TextInputBuilder, TextInputStyle } from 'discord.js' + +export default class Embed extends Button { + constructor () { + super(/embed:(e)|(p):\d*/) + } + + override async run (interaction: ButtonInteraction): Promise { + const [,option] = interaction.customId.split(':') + if (option === 'e') return await this.edit(interaction) + if (option === 'p') return await this.publish(interaction) + } + + async edit (interaction: ButtonInteraction): Promise { + const [,, channelId] = interaction.customId.split(':') + const translate = Translator(interaction) + const { data: embed } = interaction.message.embeds[0] + return await interaction.showModal( + new ModalBuilder() + .setCustomId('embed:e:' + channelId) + .setTitle(translate(keys.embed.modal.title)) + .setComponents( + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('title') + .setPlaceholder(translate(keys.embed.modal.title_placeholder)) + .setLabel(translate(keys.embed.modal.title_label)) + .setMaxLength(256) + .setStyle(TextInputStyle.Short) + .setValue(embed.title ?? '') + .setRequired(false), + ), + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('description') + .setPlaceholder(translate(keys.embed.modal.description_placeholder)) + .setLabel(translate(keys.embed.modal.description_label)) + .setStyle(TextInputStyle.Paragraph) + .setValue(embed.description ?? '') + .setRequired(false), + ), + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('color') + .setPlaceholder('#0F99A7') + .setLabel(translate(keys.embed.modal.color_label)) + .setStyle(TextInputStyle.Short) + .setValue(new Color(`${embed.color}` ?? '#000000').hex) + .setRequired(false), + ), + )) + } + + async publish (interaction: ButtonInteraction): Promise { + const [,, channelId] = interaction.customId.split(':') + const translate = Translator(interaction) + const client = interaction.client as Client + const { data: embed } = interaction.message.embeds[0] + const channel = await client.channels.fetch(channelId) as TextChannel + channel?.send({ embeds: [embed] }) + .then(async () => await interaction.reply({ content: translate(keys.embed.successfully), ephemeral: true })) + .catch(async () => await interaction.reply({ + content: translate(keys.GENERICERROR, { + inviteURL: client.officialServerURL, + }), + ephemeral: true, + })) + } +} diff --git "a/src/slash/commands/Diversi\303\263n/8ball.ts" "b/src/slash/commands/Diversi\303\263n/8ball.ts" index da638d9..1c6a701 100644 --- "a/src/slash/commands/Diversi\303\263n/8ball.ts" +++ "b/src/slash/commands/Diversi\303\263n/8ball.ts" @@ -2,6 +2,7 @@ import { ApplicationCommandOptionType, ChatInputCommandInteraction, Colors, Embe import Client from '#structures/Client.js' import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' +import logger from '#utils/logger.js' export default class ball extends Command { constructor () { @@ -24,7 +25,7 @@ export default class ball extends Command { const translate = Translator(interaction) const client = interaction.client as Client const question = interaction.options.getString('question', true) - if (!question.endsWith('?')) { + if (!question.endsWith('?')) return await interaction.reply({ embeds: [ new EmbedBuilder() @@ -36,8 +37,7 @@ export default class ball extends Command { iconURL: interaction.user.displayAvatarURL({ extension: 'png' }), }), ], - }) - } + }).catch(logger.error) return await interaction.reply({ embeds: [ @@ -54,6 +54,6 @@ export default class ball extends Command { ) .setColor(client.settings.color), ], - }) + }).catch(logger.error) } } diff --git "a/src/slash/commands/Diversi\303\263n/impostor.ts" "b/src/slash/commands/Diversi\303\263n/impostor.ts" index 1a6f070..f357010 100644 --- "a/src/slash/commands/Diversi\303\263n/impostor.ts" +++ "b/src/slash/commands/Diversi\303\263n/impostor.ts" @@ -2,6 +2,7 @@ import { ApplicationCommandOptionType, ChatInputCommandInteraction } from 'discord.js' import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' +import logger from '#utils/logger.js' export default class impostor extends Command { constructor () { @@ -36,6 +37,6 @@ export default class impostor extends Command {   '        。 , ゚ , ゚ . , . , -   ゚   .   . ,    .  .`) +   ゚   .   . ,    .  .`).catch(logger.error) } } diff --git "a/src/slash/commands/Informaci\303\263n y Utilidad/embed.ts" "b/src/slash/commands/Informaci\303\263n y Utilidad/embed.ts" index a3fea0c..36c0ba7 100644 --- "a/src/slash/commands/Informaci\303\263n y Utilidad/embed.ts" +++ "b/src/slash/commands/Informaci\303\263n y Utilidad/embed.ts" @@ -1,13 +1,20 @@ import { ApplicationCommandOptionType, - ChannelType, ChatInputCommandInteraction, - Colors, - EmbedBuilder, PermissionsBitField, + PermissionFlagsBits, + TextInputBuilder, + ActionRowBuilder, + TextInputStyle, + ModalBuilder, + ChannelType, + GuildMember, + Colors, } from 'discord.js' -import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' +import Color from '#structures/Color.js' export default class embed extends Command { constructor () { @@ -29,237 +36,74 @@ export default class embed extends Command { name: 'channel', channel_types: [ChannelType.GuildText], description: 'Channel where the embed will be sent.', - required: true, }, { - type: ApplicationCommandOptionType.Number, + type: ApplicationCommandOptionType.String, name: 'color', description: 'Color of the embed', - choices: getColorChoices(), - required: true, - }, - { - type: ApplicationCommandOptionType.String, - name: 'title', - description: 'Title of the embed', - required: true, - }, - { - type: ApplicationCommandOptionType.String, - name: 'description', - description: 'Description of the embed', - required: true, + autocomplete: true, }, ], }) } override async run (interaction: ChatInputCommandInteraction) { - // TODO: Add more colors && make it work with hex colors - const canal = interaction.options.getChannel('channel', true, [ChannelType.GuildText]) - const descripcion = interaction.options.getString('description', true) - const color = interaction.options.getNumber('color', true) - const titulo = interaction.options.getString('title', true) - const embed = new EmbedBuilder().setDescription(`${descripcion}`).setColor(color).setTitle(titulo) - - canal.send({ embeds: [embed] }) - return await interaction.reply(Translator(interaction)(keys.embed_successfully)) + const translate = Translator(interaction) + const client = interaction.client as Client + if (!interaction.inCachedGuild()) { + return await interaction.reply({ + content: translate(keys.GENERICERROR, { + inviteURL: client.officialServerURL, + }), + ephemeral: true, + }) + } + const channel = interaction.options.getChannel('channel', false, [ChannelType.GuildText]) ?? interaction.channel + if (!channel?.permissionsFor(interaction.guild.members.me as GuildMember).has([PermissionFlagsBits.SendMessages, PermissionFlagsBits.EmbedLinks])) { + return await interaction.reply({ + content: Translator(interaction)(keys.embed.missing_permissions, { + permisions: new PermissionsBitField([PermissionFlagsBits.SendMessages, PermissionFlagsBits.EmbedLinks]) + .toArray() + .map(p => p.replace(/([A-Z])/g, ' $&').trim()) + .join(', '), + }), + ephemeral: true, + }) + } + const colorInput = interaction.options.getString('color') + let color = new Color(`${Colors.Default}`) + if (colorInput && Color.isColor(colorInput)) color = new Color(colorInput) + return await interaction.showModal( + new ModalBuilder() + .setCustomId('embed:n:' + channel.id) + .setTitle(translate(keys.embed.modal.title)) + .setComponents( + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('title') + .setPlaceholder(translate(keys.embed.modal.title_placeholder)) + .setLabel(translate(keys.embed.modal.title_label)) + .setMaxLength(256) + .setStyle(TextInputStyle.Short) + .setRequired(false), + ), + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('description') + .setPlaceholder(translate(keys.embed.modal.description_placeholder)) + .setLabel(translate(keys.embed.modal.description_label)) + .setStyle(TextInputStyle.Paragraph) + .setRequired(false), + ), + new ActionRowBuilder().setComponents( + new TextInputBuilder() + .setCustomId('color') + .setPlaceholder('#0F99A7') + .setLabel(translate(keys.embed.modal.color_label)) + .setStyle(TextInputStyle.Short) + .setRequired(true) + .setValue(color.hex), + ), + )) } } - -function getColorChoices () { - return [ - { - name: 'Default', - name_localizations: { - 'es-ES': 'Defecto', - 'en-US': 'Default', - }, - value: Colors.Default, - }, - { - name: 'Aqua', - name_localizations: { - 'es-ES': 'Agua', - 'en-US': 'Aqua', - }, - value: Colors.Aqua, - }, - { - name: 'Dark Aqua', - name_localizations: { - 'es-ES': 'Agua Oscuro', - 'en-US': 'Dark Aqua', - }, - value: Colors.DarkAqua, - }, - { - name: 'Green', - name_localizations: { - 'es-ES': 'Verde', - 'en-US': 'Green', - }, - value: Colors.Green, - }, - { - name: 'Dark Green', - name_localizations: { - 'es-ES': 'Verde Oscuro', - 'en-US': 'Dark Green', - }, - value: Colors.DarkGreen, - }, - { - name: 'Blue', - name_localizations: { - 'es-ES': 'Azul', - 'en-US': 'Blue', - }, - value: Colors.Blue, - }, - { - name: 'Dark Blue', - name_localizations: { - 'es-ES': 'Azul Oscuro', - 'en-US': 'Dark Blue', - }, - value: Colors.DarkBlue, - }, - { - name: 'Purple', - name_localizations: { - 'es-ES': 'Morado', - 'en-US': 'Purple', - }, - value: Colors.Purple, - }, - { - name: 'Dark Purple', - name_localizations: { - 'es-ES': 'Morado Oscuro', - 'en-US': 'Dark Purple', - }, - value: Colors.DarkPurple, - }, - { - name: 'Lumious Vivid Pink', - name_localizations: { - 'es-ES': 'Rosa Brillante', - 'en-US': 'Lumious Vivid Pink', - }, - value: Colors.LuminousVividPink, - }, - { - name: 'Dark Vivid Pink', - name_localizations: { - 'es-ES': 'Rosa Brillante Oscuro', - 'en-US': 'Dark Vivid Pink', - }, - value: Colors.DarkVividPink, - }, - { - name: 'Gold', - name_localizations: { - 'es-ES': 'Oro', - 'en-US': 'Gold', - }, - value: Colors.Gold, - }, - { - name: 'Dark Gold', - name_localizations: { - 'es-ES': 'Oro Oscuro', - 'en-US': 'Dark Gold', - }, - value: Colors.DarkGold, - }, - { - name: 'Orange', - name_localizations: { - 'es-ES': 'Naranja', - 'en-US': 'Orange', - }, - value: Colors.Orange, - }, - { - name: 'Dark Orange', - name_localizations: { - 'es-ES': 'Naranja Oscuro', - 'en-US': 'Dark Orange', - }, - value: Colors.DarkOrange, - }, - { - name: 'Red', - name_localizations: { - 'es-ES': 'Rojo', - 'en-US': 'Red', - }, - value: Colors.Red, - }, - { - name: 'Dark Red', - name_localizations: { - 'es-ES': 'Rojo Oscuro', - 'en-US': 'Dark Red', - }, - value: Colors.DarkRed, - }, - { - name: 'Grey', - name_localizations: { - 'es-ES': 'Gris', - 'en-US': 'Grey', - }, - value: Colors.Grey, - }, - { - name: 'Dark Grey', - name_localizations: { - 'es-ES': 'Gris Oscuro', - 'en-US': 'Dark Grey', - }, - value: Colors.DarkGrey, - }, - { - name: 'Darker Grey', - name_localizations: { - 'es-ES': 'Gris Oscuro', - 'en-US': 'Darker Grey', - }, - value: Colors.DarkerGrey, - }, - { - name: 'Light Grey', - name_localizations: { - 'es-ES': 'Gris Claro', - 'en-US': 'Light Grey', - }, - value: Colors.LightGrey, - }, - { - name: 'Navy', - name_localizations: { - 'es-ES': 'Azul Marino', - 'en-US': 'Navy', - }, - value: Colors.Navy, - }, - { - name: 'Dark Navy', - name_localizations: { - 'es-ES': 'Azul Marino Oscuro', - 'en-US': 'Dark Navy', - }, - value: Colors.DarkNavy, - }, - { - name: 'Yellow', - name_localizations: { - 'es-ES': 'Amarillo', - 'en-US': 'Yellow', - }, - value: Colors.Yellow, - }, - ] -} diff --git "a/src/slash/commands/Informaci\303\263n y Utilidad/ping.ts" "b/src/slash/commands/Informaci\303\263n y Utilidad/ping.ts" index bb64075..0938027 100644 --- "a/src/slash/commands/Informaci\303\263n y Utilidad/ping.ts" +++ "b/src/slash/commands/Informaci\303\263n y Utilidad/ping.ts" @@ -26,11 +26,11 @@ export default class ping extends Command { { cluster: client.cluster.id }, ) .then(async (results: any) => { - let performance = await performanceMeters.get('interaction_' + interaction.id) - if (performance) { - performance = await performance.stop() + const performance = performanceMeters.get('interaction_' + interaction.id) + const time = performance?.stop() ?? 0 + if (performance) performanceMeters.delete('interaction_' + interaction.id) - } + // Todo: process.env.mode === 'development' return await interaction .reply({ @@ -39,7 +39,7 @@ export default class ping extends Command { .setColor(Colors.Green) .setFields( { name: translate(keys.API), value: `${results[0].ping}ms`, inline: true }, - { name: translate(keys.ping.internal), value: performance + 'ms' }, + { name: translate(keys.ping.internal), value: time + 'ms' }, { name: translate(keys.ping.global), value: `${ping}ms`, inline: true }, ) .setTitle(translate(keys.PING)) diff --git "a/src/slash/commands/Informaci\303\263n y Utilidad/shards.ts" "b/src/slash/commands/Informaci\303\263n y Utilidad/shards.ts" index 777eb39..bc442d8 100644 --- "a/src/slash/commands/Informaci\303\263n y Utilidad/shards.ts" +++ "b/src/slash/commands/Informaci\303\263n y Utilidad/shards.ts" @@ -1,6 +1,7 @@ -import Client from '#structures/Client.js' -import Command from '#structures/Command.js' import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js' +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' +import logger from '#utils/logger.js' export default class shards extends Command { constructor () { @@ -11,34 +12,13 @@ export default class shards extends Command { }) } - /** - * @param {Client} client - * @param {CommandInteraction} interaction - * @param {String[]} args - */ override async run (interaction: ChatInputCommandInteraction<'cached'>) { await interaction.deferReply() const client = interaction.client as Client const embeds = [] - const membersCount = await client.cluster.broadcastEval(c => c.guilds.cache.reduce((prev, guild) => prev + guild.memberCount, 0)) - const totalMembers = membersCount.reduce((prev, guildCount) => prev + guildCount, 0) - const guildCount = await client.cluster.fetchClientValues('guilds.cache.size') - const totalGuilds = guildCount.reduce((prev: any, guildCount: any) => prev + guildCount, 0) - const shardInfo = await client.cluster.broadcastEval((c) => ({ - id: c.cluster.id, - status: c.cluster.client.user.presence.status, - guilds: c.guilds.cache.size, - channels: c.channels.cache.size, - members: c.guilds.cache.reduce( - (prev, guild) => prev + guild.memberCount, - 0, - ), - memoryUsage: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2), - players: c.music?.players?.size ?? 0, - playingPlayers: c.music?.players?.filter((p) => p.playing).size ?? 0, - ping: c.ws.ping, - } - )) + const totalMembers = await this.getMembersCount(client) + const totalGuilds = await this.getGuildsCount(client) + const shardInfo = await this.shardInfo(client) let totalPlayers = 0 let totalPlayingPlayers = 0 const totalMemory = shardInfo.reduce((prev, s) => prev + parseInt(s.memoryUsage), 0) @@ -82,6 +62,55 @@ export default class shards extends Command { ]) .setTimestamp(), ) - return await interaction.editReply({ embeds }) + try { + await interaction.editReply({ embeds }) + } catch (error) { + logger.error(error) + } + } + + async getMembersCount (client: Client) { + try { + const membersCount = await client.cluster.broadcastEval(c => c.guilds.cache.reduce((prev, guild) => prev + guild.memberCount, 0)) + const totalMembers = membersCount.reduce((prev, guildCount) => prev + guildCount, 0) + return totalMembers + } catch (error) { + logger.error(error) + return 0 + } + } + + async getGuildsCount (client: Client) { + try { + const guildCount = await client.cluster.fetchClientValues('guilds.cache.size') + const totalGuilds = guildCount.reduce((prev: any, guildCount: any) => prev + guildCount, 0) + return totalGuilds + } catch (error) { + logger.error(error) + return 0 + } + } + + async shardInfo (client: Client) { + try { + const shardInfo = await client.cluster.broadcastEval((c) => ({ + id: c.cluster.id, + status: c.cluster.client.user.presence.status, + guilds: c.guilds.cache.size, + channels: c.channels.cache.size, + members: c.guilds.cache.reduce( + (prev, guild) => prev + guild.memberCount, + 0, + ), + memoryUsage: (process.memoryUsage().heapUsed / 1024 / 1024).toFixed(2), + players: c.music?.players?.size ?? 0, + playingPlayers: c.music?.players?.filter((p) => p.playing).size ?? 0, + ping: c.ws.ping, + })) + return shardInfo + } catch (error) { + logger.error(error) + return [] + } } }; diff --git "a/src/slash/commands/M\303\272sica/247.ts" "b/src/slash/commands/M\303\272sica/247.ts" index af874da..07f10bc 100644 --- "a/src/slash/commands/M\303\272sica/247.ts" +++ "b/src/slash/commands/M\303\272sica/247.ts" @@ -1,9 +1,8 @@ -import { MessageHelper } from '../../../handlers/messageHandler.js' -import Client from '#structures/Client.js' -import Command from '#structures/Command.js' -import Translator, { keys, randomMessage } from '../../../utils/Translator.js' - +import Translator, { keys, randomMessage } from '#utils/Translator.js' import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js' +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' +import logger from '#utils/logger.js' export default class stayinvoice extends Command { constructor () { @@ -15,14 +14,14 @@ export default class stayinvoice extends Command { }) } - override async run (interaction: ChatInputCommandInteraction<'cached'>) { + override async run (interaction: ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) return const client = interaction.client as Client const translate = Translator(interaction) const msgr = randomMessage(translate, keys.skip.messages) - const message = new MessageHelper(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { - return await message.sendMessage( + if (!player) + return await interaction.reply( { embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -30,23 +29,33 @@ export default class stayinvoice extends Command { iconURL: interaction.user.displayAvatarURL(), }), ], + ephemeral: true, }, ) - } + .catch(logger.error) + if (player.stayInVc) { player.stayInVc = false - const embed = new EmbedBuilder() - .setColor(client.settings.color) - .setAuthor({ iconURL: interaction.user.displayAvatarURL(), name: interaction.user.displayName }) - .setTitle(translate(keys[247].disabled)) - return await message.sendMessage({ embeds: [embed] }) + return await interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(client.settings.color) + .setAuthor({ iconURL: interaction.user.displayAvatarURL(), name: interaction.user.displayName }) + .setTitle(translate(keys[247].disabled)), + ], + }) + .catch(logger.error) } else { player.stayInVc = true - const embed = new EmbedBuilder() - .setColor(client.settings.color) - .setAuthor({ iconURL: interaction.user.displayAvatarURL(), name: interaction.user.displayName }) - .setTitle(translate(keys[247].enabled)) - return await message.sendMessage({ embeds: [embed] }) + return await interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(client.settings.color) + .setAuthor({ iconURL: interaction.user.displayAvatarURL(), name: interaction.user.displayName }) + .setTitle(translate(keys[247].enabled)), + ], + }) + .catch(logger.error) } } } diff --git "a/src/slash/commands/M\303\272sica/loop.ts" "b/src/slash/commands/M\303\272sica/loop.ts" index 9356815..faf6b86 100644 --- "a/src/slash/commands/M\303\272sica/loop.ts" +++ "b/src/slash/commands/M\303\272sica/loop.ts" @@ -13,11 +13,12 @@ export default class Loop extends Command { }) } - override async run (interaction: ChatInputCommandInteraction<'cached'>) { + override async run (interaction: ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) return const client = interaction.client as Client const translate = Translator(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { + if (!player) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -27,10 +28,9 @@ export default class Loop extends Command { ], ephemeral: true, }) - } - await interaction.deferReply() + .catch(logger.error) - if (!interaction.member.voice) { + if (!interaction.member.voice) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -40,9 +40,9 @@ export default class Loop extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } - if (interaction.member.voice.channelId !== player.voiceChannel.id) { + .catch(logger.error) + + if (interaction.member.voice.channelId !== player.voiceChannel.id) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -52,9 +52,9 @@ export default class Loop extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } - if (!player.queue.current) { + .catch(logger.error) + + if (!player.queue.current) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -64,7 +64,8 @@ export default class Loop extends Command { ], ephemeral: true, }) - } + .catch(logger.error) + if (!player.trackRepeat) { player.setQueueRepeat(true) player.setTrackRepeat(false) @@ -79,5 +80,6 @@ export default class Loop extends Command { }), ], }) + .catch(logger.error) } } diff --git "a/src/slash/commands/M\303\272sica/nowplaying.ts" "b/src/slash/commands/M\303\272sica/nowplaying.ts" index f871282..873b265 100644 --- "a/src/slash/commands/M\303\272sica/nowplaying.ts" +++ "b/src/slash/commands/M\303\272sica/nowplaying.ts" @@ -1,5 +1,6 @@ -import Command from '#structures/Command.js' import { ChatInputCommandInteraction } from 'discord.js' +import Command from '#structures/Command.js' +import logger from '#utils/logger.js' // import Client from '#structures/Client.js' // import Translator, { keys } from '#utils/Translator.js' // import { MessageHelper } from '../../../handlers/messageHandler.js' @@ -30,7 +31,7 @@ export default class NowPlaying extends Command { ], }, true) } */ - return await interaction.reply({ content: 'En desarrollo, comando no disponible' }) + return await interaction.reply({ content: 'En desarrollo, comando no disponible' }).catch(logger.error) // const song = player.queue.current // const parsedCurrentDuration = moment // .duration(player.position, 'milliseconds') diff --git "a/src/slash/commands/M\303\272sica/pause.ts" "b/src/slash/commands/M\303\272sica/pause.ts" index 7089dcc..c12195c 100644 --- "a/src/slash/commands/M\303\272sica/pause.ts" +++ "b/src/slash/commands/M\303\272sica/pause.ts" @@ -1,8 +1,7 @@ import { ChatInputCommandInteraction, Colors, EmbedBuilder } from 'discord.js' -import Client from '#structures/Client.js' -import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' - +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' import logger from '#utils/logger.js' export default class Pause extends Command { @@ -15,11 +14,12 @@ export default class Pause extends Command { }) } - override async run (interaction: ChatInputCommandInteraction<'cached'>) { + override async run (interaction: ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) return const client = interaction.client as Client const translate = Translator(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { + if (!player) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -29,9 +29,9 @@ export default class Pause extends Command { ], ephemeral: true, }) - } + .catch(logger.error) - if (!interaction.member.voice) { + if (!interaction.member.voice) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -41,11 +41,10 @@ export default class Pause extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } + .catch(logger.error) const vc = player.voiceChannel - if (interaction.member.voice.channelId !== vc.id) { + if (interaction.member.voice.channelId !== vc.id) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -55,10 +54,9 @@ export default class Pause extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } + .catch(logger.error) - if (!player.queue.current) { + if (!player.queue.current) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -68,7 +66,8 @@ export default class Pause extends Command { ], ephemeral: true, }) - } + .catch(logger.error) + client.music.trackPause(player, interaction) return await interaction.reply({ @@ -81,6 +80,7 @@ export default class Pause extends Command { ) .setFooter({ text: interaction.user.username, iconURL: interaction.user.displayAvatarURL() }), ], - }).catch(e => logger.debug(e)) + }) + .catch(logger.error) } } diff --git "a/src/slash/commands/M\303\272sica/play.ts" "b/src/slash/commands/M\303\272sica/play.ts" index 170f3e4..5e4d2be 100644 --- "a/src/slash/commands/M\303\272sica/play.ts" +++ "b/src/slash/commands/M\303\272sica/play.ts" @@ -1,16 +1,19 @@ import { ApplicationCommandOptionType, ChatInputCommandInteraction, - Colors, EmbedBuilder, VoiceChannel, + GuildMember, + Colors, } from 'discord.js' -import { MusicCarouselShelf } from 'youtubei.js/dist/src/parser/nodes.js' +import { MusicCarouselShelf, MusicResponsiveListItem } from 'youtubei.js/dist/src/parser/nodes.js' import performanceMeters from '#cache/performanceMeters.js' -import Client from '#structures/Client.js' -import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' import formatTime from '#utils/formatTime.js' +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' +import Player from '#structures/Player.js' +import { randomInt } from 'node:crypto' import logger from '#utils/logger.js' export default class play extends Command { @@ -34,187 +37,125 @@ export default class play extends Command { override async run (interaction: ChatInputCommandInteraction<'cached'>) { const client = interaction.client as Client + try { + await interaction.deferReply() + } catch (error) { + logger.error(error) + return client.errorHandler.captureException(error as Error) + } const translate = Translator(interaction) - let player = client.music.players.get(interaction.guildId) - if (!interaction.member.voice.channelId) { - return await interaction.reply({ + if (!interaction.member.voice.channelId) + return await interaction.editReply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ text: translate(keys.play.not_voice), iconURL: client.user?.displayAvatarURL(), }), ], - ephemeral: true, }) - } + let player = client.music.players.get(interaction.guildId) if (!player) { player = await client.music.createNewPlayer( interaction.member.voice.channel as VoiceChannel, interaction.channelId, ) - await player.connect() + try { + await player.connect() + } catch (error) { + return await interaction.editReply({ + embeds: [ + new EmbedBuilder().setColor(Colors.Red).setFooter({ + text: translate(keys.play.cant_join), + iconURL: client.user?.displayAvatarURL(), + }), + ], + }) + } } - if (player.voiceChannel.id !== interaction.member.voice.channelId) { - return await interaction.reply({ + if (player.voiceChannel.id !== interaction.member.voice.channelId) + return await interaction.editReply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ text: translate(keys.play.same), iconURL: client.user?.displayAvatarURL(), }), ], - ephemeral: true, - }) - } + }).catch(logger.error) + player.textChannelId = interaction.channelId // Si el usuario está en el mismo canal de voz que el bot try { - await interaction.deferReply() - let search - const source = 'Youtube' const song = interaction.options.getString('song', false) - if (!song) { - const songs = ((await (await player.youtubei).music.getHomeFeed()).sections?.[0] as MusicCarouselShelf) - .contents - const songs2 = songs.filter((song: any) => song.item_type === 'song') - const randomIndex = Math.floor(Math.random() * songs2.length) - const song3 = songs2[randomIndex] - // @ts-expect-error - search = await client.music.search(song3.id, interaction.member, source) - // search = await client.music.search(song3.id, interaction.member, source) - // const playlist = await (await player.youtubei).getPlaylist() - // if(playlist) { - // search = playlist - // } - } else { - try { - search = await client.music.search(song, interaction.member, source) - } catch (e) { - logger.error(e) - return await interaction.editReply({ - embeds: [ - new EmbedBuilder().setColor(15548997).setFooter({ - text: translate(keys.play.not_reproducible), - iconURL: client.user?.displayAvatarURL(), - }), - ], - }) - } - } - // console.log(typeof search) - - // if (search instanceof TrackPlaylist) { - // const firstTrack = search.first_track; - // let list = []; - - // if (firstTrack) list.push - - // while (search && search.length) { - // if (firstTrack) { - // for (let i = 0; i < search.length; i++) { - // if (search[i].equals(firstTrack)) { - // search.splice(i, 1); - // break; - // } - // } - // } - // list = list.concat(search); - // try { - // search = await search.next(); - // } - // catch (e) { - // logger.error(e); - // throw e; - // } - // } - - // if (list.length) { - // for (const track of list) { - // if (!track.requester) track.requester = interaction.member; - // player.queue.add(track); - // } - // } - - // const totalDuration = list.reduce((acc, cur) => acc + cur.duration, 0); - - // if (!player.playing && !player.paused) player.play(); - - // const e = new MessageEmbed() - // .setTitle(interaction.language.PLAY[11]) - // .setColor("GREEN") - // .addField(interaction.language.PLAY[12], `${search.title}`, true) - // .addField( - // interaction.language.PLAY[13], - // `\`${list.length}\``, - // true - // ) - // .addField( - // interaction.language.PLAY[5], - // interaction.user.tag, - // true - // ) - // .addField(interaction.language.PLAY[6], `${totalDuration}`, true) - // if (search.platform === 'Youtube') { - // e.setThumbnail( - // `https://img.youtube.com/vi/${search.id}/maxresdefault.jpg` - // ) - // } else if (search.platform === 'Spotify') { - // if (search.thumbnails[0]) - // e.setThumbnail(search.thumbnails[0]) - // } - // interaction.reply({ embeds: [e], content: '' }) - // } + const search = song ? await this.search(song, interaction.member) : await this.getRecomended(player) + if (!search) return await interaction.editReply({ + embeds: [ + new EmbedBuilder() + .setColor(Colors.Red) + .setFooter({ + text: translate(keys.play.not_reproducible), + iconURL: client.user?.displayAvatarURL(), + }), + ], + }).catch(logger.error) // TODO: Add streaming support - if (search.streams?.live) { + if (search.streams?.live) return await interaction.editReply({ content: 'We are currently working on supporting Live Streaming videos. :D', - }) - } + }).catch(logger.error) + player.queue.add(search) - if (!player.playing && !player.paused) player.play() - const embed = new EmbedBuilder().setColor(client.settings.color).setFields( - { - name: translate(keys.AUTHOR), - value: search.author ?? '', - inline: true, - }, - { + if (!player.playing || player.paused) player.play() + const embed = new EmbedBuilder() + .setColor(client.settings.color) + .addFields( + { + name: translate(keys.AUTHOR), + value: search.author ?? 'unknown', + inline: true, + }, + ) + .addFields({ name: translate(keys.REQUESTER), - value: interaction.user.toString(), - inline: true, - }, - { - name: translate(keys.DURATION), - value: formatTime(Math.trunc(search.duration ?? 0), false), + value: `${interaction.user}`, inline: true, - }, - ) + }) + .addFields( + { + name: translate(keys.DURATION), + value: formatTime(Math.trunc(search.duration ?? 0), false), + inline: true, + }, + ) if (client.settings.mode === 'development') { - let executionTime = await performanceMeters.get('interaction_' + interaction.id) - executionTime = executionTime?.stop() + const execution = performanceMeters.get('interaction_' + interaction.id) + const executionTime = execution?.stop() const finaltext = 'Internal execution time: ' + executionTime + 'ms' embed.setFooter({ text: finaltext }) } - if (source === 'Youtube') { - embed.setThumbnail(`https://img.youtube.com/vi/${search.id}/maxresdefault.jpg`) - embed.setDescription( - `**${translate(keys.play.added, { - song: `[${search.title}](https://www.youtube.com/watch?v=${search.id})`, - })}** <:pepeblink:967941236029788160>`, - ) - } else if (source === 'Spotify') { - if (search.thumbnails?.[0]) { - embed.setDescription( - `**${translate(keys.play.added, { - song: `[${search.title}](https://open.spotify.com/track/${search.id})`, - })}** <:pepeblink:967941236029788160>`, - ) - } - embed.setThumbnail(search.thumbnails?.[0].url ?? null) - } - interaction.editReply({ embeds: [embed] }) + // if (source === 'Youtube') { + embed.setThumbnail(`https://img.youtube.com/vi/${search.id}/maxresdefault.jpg`) + embed.setDescription( + `**${translate(keys.play.added, { + song: `[${search.title}](https://www.youtube.com/watch?v=${search.id})`, + })}** <:pepeblink:967941236029788160>`, + ) + // } + // else if (source === 'Spotify') { + // if (search.thumbnails?.[0]) + // embed.setDescription( + // `**${translate(keys.play.added, { + // song: `[${search.title}](https://open.spotify.com/track/${search.id})`, + // })}** <:pepeblink:967941236029788160>`, + // ) + + // embed.setThumbnail(search.thumbnails?.[0].url ?? null) + // } + await interaction.editReply({ embeds: [embed] }).catch(logger.error) } catch (e) { logger.error(e) + // @ts-expect-error + if (e.errors) logger.error(e.errors) interaction.editReply({ content: translate(keys.GENERICERROR, { inviteURL: client.officialServerURL, @@ -224,6 +165,30 @@ export default class play extends Command { return true } + async getRecomended (player: Player) { + const client = player.guild.client as Client + try { + const home = await player.youtubei.music.getHomeFeed() + const songs = home.sections?.[0] as MusicCarouselShelf + return songs.contents?.[randomInt(songs.contents.length)] as MusicResponsiveListItem + } catch (error) { + logger.error(error) + client.errorHandler.captureException(error as Error) + return undefined + } + } + + async search (query: string, member: GuildMember) { + const client = member.client as Client + try { + return await client.music.search(query, member, 'Youtube') + } catch (error) { + logger.error(error) + client.errorHandler.captureException(error as Error) + return undefined + } + } + // override async autocomplete (interaction: AutocompleteInteraction): Promise { // const query = interaction.options.getFocused() // const search = await Source.Youtube.search(query) diff --git "a/src/slash/commands/M\303\272sica/queue.ts" "b/src/slash/commands/M\303\272sica/queue.ts" index 62c1615..d13db71 100644 --- "a/src/slash/commands/M\303\272sica/queue.ts" +++ "b/src/slash/commands/M\303\272sica/queue.ts" @@ -1,9 +1,9 @@ import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js' -import { MessageHelper } from '../../../handlers/messageHandler.js' -import Client from '#structures/Client.js' -import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' import formatTime from '#utils/formatTime.js' +import Command from '#structures/Command.js' +import Client from '#structures/Client.js' +import logger from '#utils/logger.js' export default class Queue extends Command { constructor () { @@ -18,35 +18,39 @@ export default class Queue extends Command { override async run (interaction: ChatInputCommandInteraction<'cached'>) { const client = interaction.client as Client const translate = Translator(interaction) - const message = new MessageHelper(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { - return await message.sendMessage({ + if (!player) + return await interaction.reply({ embeds: [ - new EmbedBuilder().setColor(client.settings.color).setFooter({ - text: translate(keys.queue.no_queue), - iconURL: interaction.user.displayAvatarURL(), - }), + new EmbedBuilder() + .setColor(client.settings.color) + .setFooter({ + text: translate(keys.queue.no_queue), + iconURL: interaction.user.displayAvatarURL(), + }), ], - }) - } - if (!player.queue.current) { + ephemeral: true, + }).catch(logger.error) + + if (!player.queue.current) return await interaction.reply({ embeds: [ - new EmbedBuilder().setColor(client.settings.color).setFooter({ - text: translate(keys.queue.no_queue), - iconURL: interaction.user.displayAvatarURL(), - }), + new EmbedBuilder() + .setColor(client.settings.color) + .setFooter({ + text: translate(keys.queue.no_queue), + iconURL: interaction.user.displayAvatarURL(), + }), ], + ephemeral: true, }) - } const { title } = player.queue.current const { queue } = player player.queue.retrieve(1) - if (!player.queue[0] && player.queue.current) { + if (!player.queue[0] && player.queue.current) return await interaction.reply({ embeds: [ new EmbedBuilder() @@ -68,7 +72,7 @@ export default class Queue extends Command { .setColor(client.settings.color), ], }) - } + .catch(logger.error) const x = 10 let i = -1 @@ -86,16 +90,18 @@ export default class Queue extends Command { ) .join('\n') - if (!queuelist) { + if (!queuelist) return await interaction.reply({ embeds: [ - new EmbedBuilder().setColor(client.settings.color).setFooter({ - text: translate(keys.queue.no_page), - iconURL: interaction.user.displayAvatarURL(), - }), + new EmbedBuilder() + .setColor(client.settings.color) + .setFooter({ + text: translate(keys.queue.no_page), + iconURL: interaction.user.displayAvatarURL(), + }), ], }) - } + .catch(logger.error) return await interaction.reply({ embeds: [ @@ -113,7 +119,7 @@ export default class Queue extends Command { .setThumbnail(client.user.displayAvatarURL()) .setAuthor({ name: `${translate(keys.queue.queue, { - name: interaction.user.username ?? 'Unknown', + name: interaction.user.username, })} (${Math.floor(x / 10)} / ${Math.floor((player.queue.slice(1).length + 10) / 10)})`, iconURL: 'https://i.imgur.com/CCqeomm.gif', }) @@ -124,5 +130,6 @@ export default class Queue extends Command { .setColor(client.settings.color), ], }) + .catch(logger.error) } } diff --git "a/src/slash/commands/M\303\272sica/resume.ts" "b/src/slash/commands/M\303\272sica/resume.ts" index b59733b..9494673 100644 --- "a/src/slash/commands/M\303\272sica/resume.ts" +++ "b/src/slash/commands/M\303\272sica/resume.ts" @@ -14,11 +14,12 @@ export default class Resume extends Command { }) } - override async run (interaction: ChatInputCommandInteraction<'cached'>) { + override async run (interaction: ChatInputCommandInteraction) { + if (!interaction.inCachedGuild()) return const client = interaction.client as Client const translate = Translator(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { + if (!player) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -28,10 +29,11 @@ export default class Resume extends Command { ], ephemeral: true, }) - } + .catch(logger.error) + await interaction.deferReply() - if (!interaction.member.voice) { + if (!interaction.member.voice) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -41,11 +43,10 @@ export default class Resume extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } + .catch(logger.error) const vc = player.voiceChannel - if (interaction.member.voice.channelId !== vc.id) { + if (interaction.member.voice.channelId !== vc.id) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(Colors.Red).setFooter({ @@ -55,10 +56,9 @@ export default class Resume extends Command { ], ephemeral: true, }) - .catch(e => logger.debug(e)) - } + .catch(logger.error) - if (!player.queue.current) { + if (!player.queue.current) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -68,7 +68,8 @@ export default class Resume extends Command { ], ephemeral: true, }) - } + .catch(logger.error) + player.pause(false) interaction.reply({ @@ -81,7 +82,8 @@ export default class Resume extends Command { ) .setFooter({ text: interaction.user.username, iconURL: interaction.user.displayAvatarURL() }), ], - }).catch(e => logger.debug(e)) + }) + .catch(logger.error) return player.skip() } } diff --git "a/src/slash/commands/M\303\272sica/skip.ts" "b/src/slash/commands/M\303\272sica/skip.ts" index 22faa9b..059e13b 100644 --- "a/src/slash/commands/M\303\272sica/skip.ts" +++ "b/src/slash/commands/M\303\272sica/skip.ts" @@ -1,5 +1,4 @@ import { ChatInputCommandInteraction, Colors, EmbedBuilder } from 'discord.js' -import { MessageHelper } from '../../../handlers/messageHandler.js' import Client from '#structures/Client.js' import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' @@ -19,60 +18,63 @@ export default class skip extends Command { override async run (interaction: ChatInputCommandInteraction<'cached'>) { const client = interaction.client as Client const translate = Translator(interaction) - const message = new MessageHelper(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { - return await message.sendMessage({ + if (!player) + return await interaction.reply({ embeds: [ - new EmbedBuilder().setColor(client.settings.color).setFooter({ - text: translate(keys.queue.no_queue), - iconURL: interaction.user.displayAvatarURL(), - }), + new EmbedBuilder() + .setColor(client.settings.color) + .setFooter({ + text: translate(keys.queue.no_queue), + iconURL: interaction.user.displayAvatarURL(), + }), ], + ephemeral: true, }) - } + .catch(logger.error) - if (!interaction.member.voice) { - return await message - .sendMessage({ - embeds: [ - new EmbedBuilder().setColor(Colors.Red).setFooter({ + if (!interaction.member.voice) + return await interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(Colors.Red) + .setFooter({ text: translate(keys.skip.no_same), iconURL: interaction.user.displayAvatarURL(), }), - ], - }) - .catch(e => logger.debug(e)) - } + ], + ephemeral: true, + }) + .catch(console.error) const vc = player.voiceChannel - if (interaction.member.voice.channelId !== vc.id) { - return await message - .sendMessage({ - embeds: [ - new EmbedBuilder().setColor(Colors.Red).setFooter({ - text: translate(keys.skip.no_same), - iconURL: interaction.user.displayAvatarURL(), - }), - ], - }) - .catch(e => logger.debug(e)) - } + if (interaction.member.voice.channelId !== vc.id) + return await interaction.reply({ + embeds: [ + new EmbedBuilder().setColor(Colors.Red).setFooter({ + text: translate(keys.skip.no_same), + iconURL: interaction.user.displayAvatarURL(), + }), + ], + ephemeral: true, + }) + .catch(logger.error) if (!player.queue.current) return if (player.trackRepeat) player.setTrackRepeat(false) if (player.queueRepeat) player.setQueueRepeat(false) - - const embed = new EmbedBuilder() - .setColor(client.settings.color) - .setTitle(translate(keys.SUCCESSEMBED)) - .setDescription( - translate(keys.skip.skiped, { - song: player.queue.current.title, - }), - ) - .setFooter({ text: interaction.user.username, iconURL: interaction.user.displayAvatarURL() }) - message.sendMessage({ embeds: [embed] }).catch(e => logger.debug(e)) + interaction.reply({ + embeds: [ + new EmbedBuilder() + .setColor(client.settings.color) + .setTitle(translate(keys.SUCCESSEMBED)) + .setDescription( + translate(keys.skip.skiped, { + song: player.queue.current.title, + }), + ) + .setFooter({ text: interaction.user.username, iconURL: interaction.user.displayAvatarURL() })], + }).catch(logger.error) return player.skip() } } diff --git "a/src/slash/commands/M\303\272sica/stop.ts" "b/src/slash/commands/M\303\272sica/stop.ts" index 591c6a9..d397848 100644 --- "a/src/slash/commands/M\303\272sica/stop.ts" +++ "b/src/slash/commands/M\303\272sica/stop.ts" @@ -1,5 +1,4 @@ import { ChatInputCommandInteraction, EmbedBuilder } from 'discord.js' -import { MessageHelper } from '../../../handlers/messageHandler.js' import Client from '#structures/Client.js' import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' @@ -18,10 +17,9 @@ export default class Stop extends Command { override async run (interaction: ChatInputCommandInteraction<'cached'>) { const client = interaction.client as Client const translate = Translator(interaction) - const message = new MessageHelper(interaction) const player = client.music.players.get(interaction.guild.id) - if (!player) { - return await message.sendMessage({ + if (!player) + return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ text: translate(keys.queue.no_queue), @@ -29,9 +27,9 @@ export default class Stop extends Command { }), ], }) - } + .catch(logger.error) - if (!player?.queue.current) { + if (!player?.queue.current) return await interaction.reply({ embeds: [ new EmbedBuilder().setColor(client.settings.color).setFooter({ @@ -39,13 +37,16 @@ export default class Stop extends Command { iconURL: interaction.user.displayAvatarURL(), }), ], - ephemeral: true, }) - } + .catch(logger.error) if (player.trackRepeat) player.setTrackRepeat(false) if (player.queueRepeat) player.setQueueRepeat(false) - await client.music.queueEnd(player) + try { + await client.music.queueEnd(player) + } catch (error) { + client.errorHandler.captureException(error as Error) + } return await interaction.reply({ embeds: [ @@ -57,6 +58,7 @@ export default class Stop extends Command { ) .setFooter({ text: interaction.user.username, iconURL: interaction.user.displayAvatarURL() }), ], - }).catch(e => logger.debug(e)) + }) + .catch(logger.error) } } diff --git a/src/slash/commands/dev/reboot.ts b/src/slash/commands/dev/reboot.ts index dc164e8..bcc7f83 100644 --- a/src/slash/commands/dev/reboot.ts +++ b/src/slash/commands/dev/reboot.ts @@ -2,6 +2,7 @@ import { ApplicationCommandOptionType, ChatInputCommandInteraction } from 'disco import Client from '#structures/Client.js' import Command from '#structures/Command.js' import Translator, { keys } from '#utils/Translator.js' +import logger from '#utils/logger.js' export default class reboot extends Command { constructor () { @@ -24,14 +25,19 @@ export default class reboot extends Command { override async run (interaction: ChatInputCommandInteraction) { // TODO: Change reboot system - const translate = Translator(interaction) const client = interaction.client as Client - const shard = interaction.options.getNumber('shard') - if (!shard) { - await interaction.reply(translate(keys.reboot.all)) - return await client.cluster.send({ type: 'reboot', shard: 'all' }) + try { + const translate = Translator(interaction) + const shard = interaction.options.getNumber('shard') + if (!shard) { + await interaction.reply(translate(keys.reboot.all)) + return await client.cluster.send({ type: 'reboot', shard: 'all' }) + } + await interaction.reply(translate(keys.reboot.shard, { shard })) + await client.cluster.send({ type: 'reboot', shard }) + } catch (error) { + logger.error(error) + client.errorHandler.captureException(error as Error) } - await interaction.reply(translate(keys.reboot.shard, { shard })) - client.cluster.send({ type: 'reboot', shard }) } } diff --git a/src/slash/modals/embed.ts b/src/slash/modals/embed.ts new file mode 100644 index 0000000..1329279 --- /dev/null +++ b/src/slash/modals/embed.ts @@ -0,0 +1,39 @@ +import { ModalSubmitInteraction, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js' +import Translator, { keys } from '#utils/Translator.js' +import Modal from '#structures/Modal.js' +import Color from '#structures/Color.js' +import logger from '#utils/logger.js' + +export default class Embed extends Modal { + constructor () { + super(/embed:(n)|(e):\d*/) + } + + override async run (interaction: ModalSubmitInteraction): Promise { + const translate = Translator(interaction) + const [,option, channelId] = interaction.customId.split(':') + const title = interaction.fields.getTextInputValue('title') + const description = interaction.fields.getTextInputValue('description') + const color = interaction.fields.getTextInputValue('color') + if (!title && !description) return // ignore if no title or description + const embed = new EmbedBuilder() + if (title) embed.setTitle(title) + if (description) embed.setDescription(description) + if (color && Color.isColor(color)) embed.setColor(new Color(color).hex) + if (option === 'n') + return await interaction.reply({ + content: !Color.isColor(color) ? translate(keys.embed.invalid_input) : undefined, + embeds: [embed], + ephemeral: true, + components: [ + new ActionRowBuilder().setComponents( + new ButtonBuilder().setCustomId('embed:e:' + channelId).setLabel('Edit').setStyle(ButtonStyle.Primary), + new ButtonBuilder().setCustomId('embed:p:' + channelId).setLabel('Publish').setStyle(ButtonStyle.Success), + ), + ], + }).catch(logger.error) + + if (interaction.isFromMessage()) return await interaction.update({ embeds: [embed], components: interaction.message?.components }).catch(logger.error) + await interaction.deferUpdate().catch(logger.error) + } +} diff --git a/src/structures/Autocomplete.ts b/src/structures/Autocomplete.ts index a17c054..7747750 100644 --- a/src/structures/Autocomplete.ts +++ b/src/structures/Autocomplete.ts @@ -1,3 +1,4 @@ +import autocompletes from '#cache/autocompletes.js' import { AutocompleteInteraction } from 'discord.js' export default class Autocomplete { @@ -6,21 +7,25 @@ export default class Autocomplete { this.#pattern = pattern } - get pattern () { + get name () { return this.#pattern } - async run (interaction: AutocompleteInteraction): Promise { - return await interaction.respond([ - { - name: 'notImplemented', - value: 'This autocomplete is not yet implemented.', - }, - ]) + /** + * Run the autocomplete and return if it was responded or not + * @param {AutocompleteInteraction} interaction + * @returns {Promise} + */ + async run (interaction: AutocompleteInteraction): Promise { + return true } match (id: string) { - if (typeof this.pattern === 'string') return this.pattern === id - else return this.pattern.test(id) + if (typeof this.#pattern === 'string') return this.#pattern === id + else return this.#pattern.test(id) + } + + canProced (userId: string, interactionId: string): boolean { + return autocompletes.canProced(userId, interactionId) } } diff --git a/src/structures/Button.ts b/src/structures/Button.ts index 796e909..f4b7284 100644 --- a/src/structures/Button.ts +++ b/src/structures/Button.ts @@ -1,4 +1,6 @@ +import Translator, { keys } from '#utils/Translator.js' import { ButtonInteraction } from 'discord.js' +import Client from './Client.js' export default class Button { #pattern: string | RegExp @@ -6,16 +8,23 @@ export default class Button { this.#pattern = pattern } - get pattern () { + get name () { return this.#pattern } async run (interaction: ButtonInteraction): Promise { - return await interaction.reply('This button is not yet implemented.') + const translate = Translator(interaction) + const client = interaction.client as Client + return await interaction.reply({ + content: translate(keys.GENERICERROR, { + inviteURL: client.officialServerURL, + }), + ephemeral: true, + }) } match (id: string) { - if (typeof this.pattern === 'string') return this.pattern === id - else return this.pattern.test(id) + if (typeof this.#pattern === 'string') return this.#pattern === id + else return this.#pattern.test(id) } } diff --git a/src/structures/Client.ts b/src/structures/Client.ts index 0b8c173..66b5e18 100644 --- a/src/structures/Client.ts +++ b/src/structures/Client.ts @@ -143,7 +143,7 @@ export default class Client extends ClientBase { shards: getInfo().SHARD_LIST, shardCount: getInfo().TOTAL_SHARDS, }) - if (!process.env.DEVS) { throw new Error('Add developers to the .env file, expected input (example): devs=123456789,987654321 ') } + if (!process.env.DEVS) throw new Error('Add developers to the .env file, expected input (example): devs=123456789,987654321 ') this.devs = process.env.DEVS.split(',') } diff --git a/src/structures/Color.ts b/src/structures/Color.ts new file mode 100644 index 0000000..a1ea3c4 --- /dev/null +++ b/src/structures/Color.ts @@ -0,0 +1,89 @@ +import { Colors } from 'discord.js' + +export default class Color { + #rgb!: [number, number, number] + constructor (color: string) { + if (!Color.isColor(color)) { + throw new TypeError('Invalid color') + } + if (Color.isHex(color)) { + if (color.length === 4) color = `#${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` + const match = color.match(/^#(?[A-Fa-f0-9]{2})(?[A-Fa-f0-9]{2})(?[A-Fa-f0-9]{2})$/) + const { r, g, b } = match?.groups ?? {} + this.#rgb = [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)] + } + if (Color.isHex0x(color)) { + if (color.length === 5) color = `0x${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}` + const match = color.match(/^0x(?[A-Fa-f0-9]{2})(?[A-Fa-f0-9]{2})(?[A-Fa-f0-9]{2})$/) + const { r, g, b } = match?.groups ?? {} + this.#rgb = [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)] + } + if (Color.isRGB(color)) { + const match = color.match(/^rgb\(?\s?(?\d{1,3}),?\s*(?\d{1,3}),?\s*(?\d{1,3})\)?$/) + const { r, g, b } = match?.groups ?? {} + this.#rgb = [parseInt(r), parseInt(g), parseInt(b)] + } + if (Color.isName(color)) { + const match = Colors[color as keyof typeof Colors].toString(16).match(/[0-9A-Za-z]{2}/g) ?? [] + const [r, g, b] = match + this.#rgb = [parseInt(r ?? '0', 16), parseInt(g ?? '0', 16), parseInt(b ?? '0', 16)] + } + if (Color.isNumber(color)) { + const match = parseInt(color).toString(16).match(/[0-9A-Za-z]{2}/g) ?? [] + const [r, g, b] = match + this.#rgb = [parseInt(r ?? '0', 16), parseInt(g ?? '0', 16), parseInt(b ?? '0', 16)] + } + } + + get hex (): `#${string}` { + const [r, g, b] = this.#rgb.map(n => n.toString(16)) + return `#${r.length === 1 ? '0' + r : r}${g.length === 1 ? '0' + g : g}${b.length === 1 ? '0' + b : b}` + } + + get hex0x (): `0x${string}` { + const [r, g, b] = this.#rgb.map(n => n.toString(16)) + return `0x${r.length === 1 ? '0' + r : r}${g.length === 1 ? '0' + g : g}${b.length === 1 ? '0' + b : b}` + } + + get rgbString (): `rgb(${number}, ${number}, ${number})` { + return `rgb(${this.#rgb.join(', ')})` as `rgb(${number}, ${number}, ${number})` + } + + get rgb (): [number, number, number] { + return this.#rgb + } + + get number (): number { + const [r, g, b] = this.#rgb + return parseInt(`${r}${g}${b}`, 16) + } + + static isColor (color: string): boolean { + return Color.isHex(color) || + Color.isHex0x(color) || + Color.isRGB(color) || + Color.isName(color) || + Color.isNumber(color) + } + + static isHex (color: string): boolean { + return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color) + } + + static isHex0x (color: string): boolean { + return /^0x([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color) + } + + static isRGB (color: string): boolean { + return /^rgb\(?\s?(?\d{1,3}),?\s*(?\d{1,3}),?\s*(?\d{1,3})\)?$/.test(color) + } + + static isName (color: string): boolean { + return Object.keys(Colors).some(c => c === color) + } + + static isNumber (color: string): boolean { + if (color === '0') return true + return /^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(parseInt(color).toString(16)) + } +} diff --git a/src/structures/Modal.ts b/src/structures/Modal.ts new file mode 100644 index 0000000..b248aed --- /dev/null +++ b/src/structures/Modal.ts @@ -0,0 +1,30 @@ +import { ModalSubmitInteraction } from 'discord.js' +import Translator, { keys } from '#utils/Translator.js' +import Client from './Client.js' + +export default class Modal { + #pattern: string | RegExp + constructor (pattern: string | RegExp) { + this.#pattern = pattern + } + + get name () { + return this.#pattern + } + + async run (interaction: ModalSubmitInteraction): Promise { + const translate = Translator(interaction) + const client = interaction.client as Client + return await interaction.reply({ + content: translate(keys.GENERICERROR, { + inviteURL: client.officialServerURL, + }), + ephemeral: true, + }) + } + + match (id: string) { + if (typeof this.#pattern === 'string') return this.#pattern === id + else return this.#pattern.test(id) + } +} diff --git a/src/structures/MusicManager.ts b/src/structures/MusicManager.ts index 317f04c..5a3c86e 100644 --- a/src/structures/MusicManager.ts +++ b/src/structures/MusicManager.ts @@ -46,6 +46,7 @@ export default class MusicManager extends EventEmitter { voiceChannel: vc, textChannelId, volume, + innertube: await Innertube.create(), }) // Imprime un mensaje de depuración // logger.debug('Sign in successful: ', credentials); @@ -91,24 +92,23 @@ export default class MusicManager extends EventEmitter { const actionRowComponents = player.message.components[0]?.components if (actionRowComponents) { const pauseButton = actionRowComponents.find((c) => c.customId === 'pauseMusic' && c.type === ComponentType.Button) - if (pauseButton && pauseButton.type === 2) { // Make sure it's a button component - if (player.playing) { + if (pauseButton && pauseButton.type === 2) // Make sure it's a button component + if (player.playing) (pauseButton.data.emoji as Writeable) = { name: client.settings.emojis.white.pause.name.toString(), id: client.settings.emojis.white.pause.id.toString(), animated: pauseButton.data.emoji?.animated, } - } else { + else (pauseButton.data.emoji as Writeable) = { name: client.settings.emojis.white.play.name.toString(), id: client.settings.emojis.white.play.id.toString(), animated: pauseButton.data.emoji?.animated, } - } - } } } - if (player.message) { return await player.message.edit({ components: player.message.components, embeds: [updatedEmbed2] }) } else return false + if (player.message) return await player.message.edit({ components: player.message.components, embeds: [updatedEmbed2] }) + else return false } async trackStart (player: Player) { @@ -148,7 +148,7 @@ export default class MusicManager extends EventEmitter { ) const embed = new EmbedBuilder().setColor(client.settings.color) - if (song.platform === 'Youtube') { + if (song.platform === 'Youtube') embed .setImage(song.thumbnails[0].url) .setDescription( @@ -156,17 +156,17 @@ export default class MusicManager extends EventEmitter { song.id })** [${formatDuration(song.duration ?? 0)}] • ${song.requester.toString()}`, ) - } else if (song.platform === 'Spotify') { + else if (song.platform === 'Spotify') if (song.thumbnails?.[0]) { embed.setDescription( `**${translate(keys.PLAYING)}\n[${song.title}](https://open.spotify.com/track/${song.id})**`, ) embed.setImage(song.thumbnails[0].url) } - } + // ^ Si no tenemos un mensaje ya enviado, lo enviamos, y si lo tenemos, borramos el anterior y enviamos uno nuevo <3 player.message?.delete() - if (client.settings.debug === 'true') { + if (client.settings.debug === 'true') logger.music( 'Playing | ' + player.queue.current?.title + @@ -175,7 +175,7 @@ export default class MusicManager extends EventEmitter { ' | ' + player.queue.current?.requester.displayName, ) - } + return (player.message = await (await player.getTextChannel())?.send({ embeds: [embed], components: [row], @@ -283,9 +283,8 @@ export default class MusicManager extends EventEmitter { embeds: [e], content: '', }) - } else { + } else return await this.destroy(player.guild) - } } get (guild: Guild) { @@ -306,7 +305,7 @@ export default class MusicManager extends EventEmitter { async search (query: any, requester: any, source: 'Spotify' | 'Youtube' | 'Soundcloud') { let track - if (requester.youtubei) { + if (requester.youtubei) if (requester.youtubei.session.logged_in) { const rawData = await (await requester.youtubei.music.search(query, { limit: 1 })).sections[0] track = rawData.contents[0].id @@ -314,21 +313,21 @@ export default class MusicManager extends EventEmitter { (await requester.youtubei) track = await (await yasha.Source.Youtube.search(query))[0] } - } else track = await (await yasha.Source.Youtube.search(query))[0] + else track = await (await yasha.Source.Youtube.search(query))[0] track = await yasha.Source.resolve( track ? `https://www.youtube.com/watch?v=${track.id ? track.id : track}` : query, ) if (!track) logger.debug('No track found') - else { - // logger.log('track: ', track) - // if (track instanceof TrackPlaylist) { - // track.forEach(t => { - // t.requester = requester; - // t.icon = null; - // t.thumbnail; - // }); - // } else { + else + // logger.log('track: ', track) + // if (track instanceof TrackPlaylist) { + // track.forEach(t => { + // t.requester = requester; + // t.icon = null; + // t.thumbnail; + // }); + // } else { /* if (track.streams) { // console.log(track.streams) const stream = getMax(track.streams, 'bitrate') @@ -336,7 +335,7 @@ export default class MusicManager extends EventEmitter { } */ track.requester = requester // track.icon = null - } + return track // } } diff --git "a/src/structures/M\303\272sica/functions/bot1missing.ts" "b/src/structures/M\303\272sica/functions/bot1missing.ts" deleted file mode 100644 index 5701c5d..0000000 --- "a/src/structures/M\303\272sica/functions/bot1missing.ts" +++ /dev/null @@ -1,37 +0,0 @@ -import bot2missing from '../../../slash/commands/Música/functions/bot2missing'; -export default async function bot1missing(client, interaction, data, reqEndpoint) { - let bot2Availability; - let addToQueue2; - await interaction.guild.members - .fetch(process.env.bot2id) - .then(member => { - member.voice.channel ? (bot2Availability = false) : (bot2Availability = true); - if (member.voice.channel && member.voice.channel != interaction.member.voice.channel) - bot2Availability = false; - if (member.voice.channel && member.voice.channel == interaction.member.voice.channel) addToQueue2 = true; - }) - .catch(e => { - bot2Availability = false; - }); - - if (bot2Availability || addToQueue2) { - fetch(`http://${process.env.IP}:${process.env.bot2Port}/api/v1/${reqEndpoint}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json', - }, - }) - .then(response => response.json()) - .then(embed => { - interaction.editReply({ - embeds: [embed], - }); - }) - .catch(() => { - bot2missing(client, interaction, data, reqEndpoint); - }); - } else { - bot2missing(client, interaction, data, reqEndpoint); - } -} diff --git "a/src/structures/M\303\272sica/functions/bot2missing.ts" "b/src/structures/M\303\272sica/functions/bot2missing.ts" deleted file mode 100644 index b23a2cd..0000000 --- "a/src/structures/M\303\272sica/functions/bot2missing.ts" +++ /dev/null @@ -1,37 +0,0 @@ -import bot3missing from '../../../slash/commands/Música/functions/bot3missing'; -export default async function bot1missing(client, interaction, data, reqEndpoint) { - let bot3Availability; - let addToQueue3; - await interaction.guild.members - .fetch(process.env.bot3id) - .then(member => { - member.voice.channel ? (bot3Availability = false) : (bot3Availability = true); - if (member.voice.channel && member.voice.channel != interaction.member.voice.channel) - bot3Availability = false; - if (member.voice.channel && member.voice.channel == interaction.member.voice.channel) addToQueue3 = true; - }) - .catch(e => { - bot3Availability = false; - }); - - if (bot3Availability || addToQueue3) { - fetch(`http://${process.env.IP}:${process.env.bot3Port}/api/v1/${reqEndpoint}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json', - }, - }) - .then(response => response.json()) - .then(embed => { - interaction.editReply({ - embeds: [embed], - }); - }) - .catch(() => { - bot3missing(client, interaction, data, reqEndpoint); - }); - } else { - bot3missing(client, interaction, data, reqEndpoint); - } -} diff --git "a/src/structures/M\303\272sica/functions/bot3missing.ts" "b/src/structures/M\303\272sica/functions/bot3missing.ts" deleted file mode 100644 index 3a3ff15..0000000 --- "a/src/structures/M\303\272sica/functions/bot3missing.ts" +++ /dev/null @@ -1,37 +0,0 @@ -import bot4missing from '../../../slash/commands/Música/functions/bot4missing'; -export default async function bot1missing(client, interaction, data, reqEndpoint) { - let bot4Availability; - let addToQueue4; - await interaction.guild.members - .fetch(process.env.bot4id) - .then(member => { - member.voice.channel ? (bot4Availability = false) : (bot4Availability = true); - if (member.voice.channel && member.voice.channel != interaction.member.voice.channel) - bot4Availability = false; - if (member.voice.channel && member.voice.channel == interaction.member.voice.channel) addToQueue4 = true; - }) - .catch(e => { - bot4Availability = false; - }); - - if (bot4Availability || addToQueue4) { - fetch(`http://${process.env.IP}:${process.env.bot4Port}/api/v1/${reqEndpoint}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json', - }, - }) - .then(response => response.json()) - .then(embed => { - interaction.editReply({ - embeds: [embed], - }); - }) - .catch(() => { - bot4missing(client, interaction, data, reqEndpoint); - }); - } else { - bot4missing(client, interaction, data, reqEndpoint); - } -} diff --git "a/src/structures/M\303\272sica/functions/bot4missing.ts" "b/src/structures/M\303\272sica/functions/bot4missing.ts" deleted file mode 100644 index dd11c45..0000000 --- "a/src/structures/M\303\272sica/functions/bot4missing.ts" +++ /dev/null @@ -1,96 +0,0 @@ -import { ColorResolvable, MessageActionRow, MessageButton, EmbedBuilder } from 'discord.js' -export default async function bot4missing(client, interaction, data, reqEndpoint) { - const embed = new EmbedBuilder().setColor(process.env.bot1Embed_Color as ColorResolvable) - - const desc = interaction.language.NOMUSICBOTS - const row = new MessageActionRow().addComponents( - new MessageButton().setStyle('PRIMARY').setLabel(`Leer más`).setCustomId('readMore'), - ) - - new Promise((resolve, reject) => { - interaction.guild.members - .fetch(process.env.bot2id) - .then(() => { - interaction.guild.members - .fetch(process.env.bot3id) - .then(() => { - interaction.guild.members - .fetch(process.env.bot4id) - .then(() => { - embed.setDescription(desc) - resolve(embed) - }) - .catch(() => { - embed.setDescription( - desc + - '[Node4 <:logonodeazul:968094477866659850>](https://discord.com/api/oauth2/authorize?client_id=853888393917497384&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - }) - .catch(() => { - interaction.guild.members - .fetch(process.env.bot4id) - .then(() => { - embed.setDescription( - desc + - '[Node3 <:logonodenaranja:968094477019402292>](https://discord.com/api/oauth2/authorize?client_id=963954741837201540&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - .catch(() => { - embed.setDescription( - desc + - '[Node3 <:logonodenaranja:968094477019402292>](https://discord.com/api/oauth2/authorize?client_id=963954741837201540&permissions=137475966272&scope=bot)\n\n[Node4 <:logonodeazul:968094477866659850>](https://discord.com/api/oauth2/authorize?client_id=853888393917497384&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - }) - }) - .catch(() => { - interaction.guild.members - .fetch(process.env.bot3id) - .then(() => { - interaction.guild.members - .fetch(process.env.bot4id) - .then(() => { - embed.setDescription( - desc + - '[Node2 <:logonodemorado:968094477480771584>](https://discord.com/api/oauth2/authorize?client_id=963496530818506802&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - .catch(() => { - embed.setDescription( - desc + - '[Node2 <:logonodemorado:968094477480771584>](https://discord.com/api/oauth2/authorize?client_id=963496530818506802&permissions=137475966272&scope=bot)\n\n[Node4 <:logonodeazul:968094477866659850>](https://discord.com/api/oauth2/authorize?client_id=853888393917497384&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - }) - .catch(() => { - interaction.guild.members - .fetch(process.env.bot4id) - .then(() => { - embed.setDescription( - desc + - '[Node2 <:logonodemorado:968094477480771584>](https://discord.com/api/oauth2/authorize?client_id=963496530818506802&permissions=137475966272&scope=bot)\n\n[Node3 <:logonodenaranja:968094477019402292>](https://discord.com/api/oauth2/authorize?client_id=963954741837201540&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - .catch(() => { - embed.setDescription( - desc + - '[Node2 <:logonodemorado:968094477480771584>](https://discord.com/api/oauth2/authorize?client_id=963496530818506802&permissions=137475966272&scope=bot)\n\n[Node3 <:logonodenaranja:968094477019402292>](https://discord.com/api/oauth2/authorize?client_id=963954741837201540&permissions=137475966272&scope=bot)\n\n[Node4 <:logonodeazul:968094477866659850>](https://discord.com/api/oauth2/authorize?client_id=853888393917497384&permissions=137475966272&scope=bot)', - ) - resolve(embed) - }) - }) - }) - }).then(resEmbed => { - interaction.editReply({ - embeds: [resEmbed], - components: [row], - }) - }) -} diff --git "a/src/structures/M\303\272sica/info.ts" "b/src/structures/M\303\272sica/info.ts" deleted file mode 100644 index 76b7207..0000000 --- "a/src/structures/M\303\272sica/info.ts" +++ /dev/null @@ -1,50 +0,0 @@ -import { Client, CommandInteraction, EmbedBuilder, ColorResolvable } from 'discord.js' -import Command from '#structures/Command.js' -module.exports = class info extends Command { - constructor(client) { - super(client, { - name: 'info', - description: 'Information about the multibot system.', - name_localizations: { - 'es-ES': 'info', - }, - description_localizations: { - 'es-ES': 'Información sobre el sistema multibot.', - }, - cooldown: 5, - }) - } - /**, - * @param {Client} client - * @param {CommandInteraction} interaction - * @param {String[]} args - */ - async run(client, interaction, args) { - const embed = new EmbedBuilder() - .setColor(process.env.bot1Embed_Color as ColorResolvable) - .setDescription( - `**¡Hola! ¿Buscabas una explicación verdad? Has llegado al sitio correcto **`, - ) - .addField( - '¿En qué consiste? <:monkaThink:969921099867508796>', - `Node dispone de un sistema de 4 bots, los cuales son gestionados desde una sola instancia. De esta manera, nosotros nos encargamos de gestionar vuestras solicitudes de escuchar música y que tengais un bot disponible.`, - ) - .addField( - '¿Por qué los 4 bots no tienen comandos? ', - 'Porque los bots son gestionados desde uno de ellos (normalmente Node Principal). Por lo tanto, no es necesario que cada bot tenga un comando para escuchar música.', - ) - .addField( - '¿Que ventajas me aporta? <:peepoBusinessTux:969921198181990440>', - `Gracias a este sistema, siempre usarás el mismo comando y nosotros elegiremos el bot que esté disponible. De esta manera evitamos que tengas que fijarte en qué bot está disponible para saber qué comando ejecutar.`, - ) - .setThumbnail( - interaction.member.displayAvatarURL({ - dynamic: true, - }), - ) - await interaction.editReply({ - embeds: [embed], - components: [], - }) - } -} diff --git a/src/structures/NodeManager.ts b/src/structures/NodeManager.ts index 454da52..b32c0c6 100644 --- a/src/structures/NodeManager.ts +++ b/src/structures/NodeManager.ts @@ -41,7 +41,7 @@ export default class NodeManager extends ClusterManager { this.players = new Collection() // eslint-disable-next-line @typescript-eslint/no-unused-vars let clusterList: any[] - if (!process.env.TOKEN) { throw new Error('No pudimos encontrar tu token, asegurate de añadirlo al .env con el nombre de TOKEN!') } + if (!process.env.TOKEN) throw new Error('No pudimos encontrar tu token, asegurate de añadirlo al .env con el nombre de TOKEN!') // Inicializa las colecciones para los clusters de diferentes nodos this.clustersArray.set('node', []) @@ -56,7 +56,7 @@ export default class NodeManager extends ClusterManager { const shardList = [...Array(data).keys()] // * Divide los shards en bloques - clusterList = chunk(shardList, 6) + clusterList = chunk(shardList, 2) this.queue.queue.shift() this.totalClusters = 0 @@ -150,7 +150,7 @@ export default class NodeManager extends ClusterManager { let shardList = [...Array(data).keys()] if (data === 1) shardList = [0] // * Divide los shards en bloques - const clusterList = chunk(shardList, 6) + const clusterList = chunk(shardList, 2) for (let i = 0; i < clusterList.length; i++) { const clusterIndex = this.totalClusters + 1 diff --git a/src/structures/Player.ts b/src/structures/Player.ts index c775fa6..ff608c1 100644 --- a/src/structures/Player.ts +++ b/src/structures/Player.ts @@ -28,7 +28,7 @@ export default class Player extends yasha.TrackPlayer { previouslyPaused = false pausedUser?: User resumedUser?: User - youtubei = Innertube.create() + youtubei: Innertube waitingMessage?: Message constructor (options: { musicManager: MusicManager @@ -38,12 +38,14 @@ export default class Player extends yasha.TrackPlayer { voiceChannel: VoiceChannel textChannelId: Snowflake guild?: Guild + innertube: Innertube }) { super({ external_packet_send: false, external_encrypt: false, normalize_volume: true, }) + this.youtubei = options.innertube this.manager = options.musicManager this.bitrate = options.bitrate this.volume = options.volume ?? 100 @@ -55,6 +57,8 @@ export default class Player extends yasha.TrackPlayer { if (this.guild.members.me?.permissionsIn(channel).has([PermissionFlagsBits.EmbedLinks, PermissionFlagsBits.SendMessages]) === false) return this.#textChannelId = options.textChannelId }).catch(() => null) + this.on('finish', () => (this.playing = false)) + this.on('error', (error: any) => (this.playing = false && logger.error(error))) } async connect () { @@ -72,6 +76,7 @@ export default class Player extends yasha.TrackPlayer { } override async play (track?: any) { + this.playing = true // TODO: Check if this code works if (!track && this.queue.current) super.play(this.queue.current) else super.play(track) diff --git a/src/utils/locales.ts b/src/utils/locales.ts index d56d374..d89967e 100644 --- a/src/utils/locales.ts +++ b/src/utils/locales.ts @@ -1,817 +1,851 @@ export default { - 247: { - enabled: '247.enabled', - disabled: '247.disabled', + '247': { + 'enabled': "247.enabled", + 'disabled': "247.disabled", + }, + 'question_ball': { + 'no_question': "question_ball.no_question", + 'question': "question_ball.question", + 'response': "question_ball.response", + 'possibles': { + '0': "question_ball.possibles.0", + '1': "question_ball.possibles.1", + '2': "question_ball.possibles.2", + '3': "question_ball.possibles.3", + '4': "question_ball.possibles.4", + '5': "question_ball.possibles.5", + '6': "question_ball.possibles.6", + '7': "question_ball.possibles.7", + '8': "question_ball.possibles.8", + '9': "question_ball.possibles.9", + '10': "question_ball.possibles.10", + '11': "question_ball.possibles.11", }, - question_ball: { - no_question: 'question_ball.no_question', - question: 'question_ball.question', - response: 'question_ball.response', - possibles: { - 0: 'question_ball.possibles.0', - 1: 'question_ball.possibles.1', - 2: 'question_ball.possibles.2', - 3: 'question_ball.possibles.3', - 4: 'question_ball.possibles.4', - 5: 'question_ball.possibles.5', - 6: 'question_ball.possibles.6', - 7: 'question_ball.possibles.7', - 8: 'question_ball.possibles.8', - 9: 'question_ball.possibles.9', - 10: 'question_ball.possibles.10', - 11: 'question_ball.possibles.11', - }, - }, - impostor: { - was: 'impostor.was', - was_not: 'impostor.was_not', + }, + 'impostor': { + 'was': "impostor.was", + 'was_not': "impostor.was_not", + }, + 'embed': { + 'successfully': "embed.successfully", + 'missing_permissions': "embed.missing_permissions", + 'modal': { + 'title': "embed.modal.title", + 'title_label': "embed.modal.title_label", + 'title_placeholder': "embed.modal.title_placeholder", + 'description_label': "embed.modal.description_label", + 'description_placeholder': "embed.modal.description_placeholder", + 'color_label': "embed.modal.color_label", }, - embed_successfully: 'embed_successfully', - github: { - write_username: 'github.write_username', - name: 'github.name', - account: 'github.account', - organization: 'github.organization', - link: 'github.link', - location: 'github.location', - email: 'github.email', - biography: 'github.biography', - twitter: 'github.twitter', - repositories: 'github.repositories', - followers: 'github.followers', - analizing: 'github.analizing', - unknow: 'github.unknow', + 'buttons': { + 'send': "embed.buttons.send", + 'edit': "embed.buttons.edit", }, - help: { - presentation: 'help.presentation', - how_use: 'help.how_use', - how_use_answer: 'help.how_use_answer', - need_support: 'help.need_support', - need_support_answer: 'help.need_support_answer', - how_vote: 'help.how_vote', - how_vote_answer: 'help.how_vote_answer', - title: 'help.title', + 'invalid_input': "embed.invalid_input", + }, + 'github': { + 'write_username': "github.write_username", + 'name': "github.name", + 'account': "github.account", + 'organization': "github.organization", + 'link': "github.link", + 'location': "github.location", + 'email': "github.email", + 'biography': "github.biography", + 'twitter': "github.twitter", + 'repositories': "github.repositories", + 'followers': "github.followers", + 'analizing': "github.analizing", + 'unknow': "github.unknow", + }, + 'help': { + 'presentation': "help.presentation", + 'how_use': "help.how_use", + 'how_use_answer': "help.how_use_answer", + 'need_support': "help.need_support", + 'need_support_answer': "help.need_support_answer", + 'how_vote': "help.how_vote", + 'how_vote_answer': "help.how_vote_answer", + 'title': "help.title", + }, + 'avatar': "avatar", + 'mchistory': { + 'dont': "mchistory.dont", + 'names': "mchistory.names", + 'first': "mchistory.first", + }, + 'ping': { + 'global': "ping.global", + 'internal': "ping.internal", + }, + 'roleinfo': { + 'managed': "roleinfo.managed", + }, + 'serverinfo': { + 'verification': { + 'no': "serverinfo.verification.no", + 'low': "serverinfo.verification.low", + 'medium': "serverinfo.verification.medium", + 'high': "serverinfo.verification.high", + 'extreme': "serverinfo.verification.extreme", }, - avatar: 'avatar', - mchistory: { - dont: 'mchistory.dont', - names: 'mchistory.names', - first: 'mchistory.first', + 'explicit': { + 'disabled': "serverinfo.explicit.disabled", + 'members_without_role': "serverinfo.explicit.members_without_role", + 'all_members': "serverinfo.explicit.all_members", }, - ping: { - global: 'ping.global', - internal: 'ping.internal', + 'emoji_count': "serverinfo.emoji_count", + 'tier_level': "serverinfo.tier_level", + 'verification_level': "serverinfo.verification_level", + 'explicit_filter': "serverinfo.explicit_filter", + }, + 'ban': { + 'not_found': "ban.not_found", + 'self': "ban.self", + 'owner': "ban.owner", + 'higher': "ban.higher", + 'ban': "ban.ban", + 'unbannable': "ban.unbannable", + }, + 'skip': { + 'messages': { + '0': "skip.messages.0", + '1': "skip.messages.1", + '2': "skip.messages.2", }, - roleinfo: { - managed: 'roleinfo.managed', + 'no_same': "skip.no_same", + 'skiped': "skip.skiped", + }, + 'queue': { + 'no_queue': "queue.no_queue", + 'current': "queue.current", + 'queue': "queue.queue", + 'no_page': "queue.no_page", + 'total': "queue.total", + }, + 'play': { + 'same': "play.same", + 'not_voice': "play.not_voice", + 'not_reproducible': "play.not_reproducible", + 'added': "play.added", + 'cant_join': "play.cant_join", + }, + 'reboot': { + 'all': "reboot.all", + 'shard': "reboot.shard", + }, + 'stop': { + 'resumed': "stop.resumed", + 'paused': "stop.paused", + 'success': "stop.success", + }, + 'paused': "paused", + 'resumed': "resumed", + 'voice_update': { + 'leaving': "voice_update.leaving", + 'alone': "voice_update.alone", + }, + 'automix': { + 'generated': "automix.generated", + 'disabled': "automix.disabled", + }, + 'twitch': { + 'no_streamer_found': "twitch.no_streamer_found", + 'already_following': "twitch.already_following", + 'now_following': "twitch.now_following", + 'unfollowed': "twitch.unfollowed", + 'role_mention': "twitch.role_mention", + 'now_live': "twitch.now_live", + }, + 'loop': { + 'queue': "loop.queue", + 'song': "loop.song", + 'disabled': "loop.disabled", + }, + 'ERROREMBED': "ERROREMBED", + 'SUCCESSEMBED': "SUCCESSEMBED", + 'PAUSE': "PAUSE", + 'RESUME': "RESUME", + 'STOP': "STOP", + 'SKIP': "SKIP", + 'NEXT': "NEXT", + 'QUEUE': "QUEUE", + 'TITLE': "TITLE", + 'MEMBERS': "MEMBERS", + 'REGULAR': "REGULAR", + 'ANIMATED': "ANIMATED", + 'CHANNELS': "CHANNELS", + 'ROLES': "ROLES", + 'CATEGORIES': "CATEGORIES", + 'SONGS': "SONGS", + 'TEXT': "TEXT", + 'VOICE': "VOICE", + 'BOOSTERS': "BOOSTERS", + 'REGION': "REGION", + 'TIER': "TIER", + 'CREATED_AT': "CREATED_AT", + 'OWNER': "OWNER", + 'AUTHOR': "AUTHOR", + 'REQUESTER': "REQUESTER", + 'DURATION': "DURATION", + 'NO': "NO", + 'API': "API", + 'PING': "PING", + 'NAME': "NAME", + 'ID': "ID", + 'POSITION': "POSITION", + 'COLOR': "COLOR", + 'MENTIONABLE': "MENTIONABLE", + 'SEPARATED': "SEPARATED", + 'YES': "YES", + 'PLAYING': "PLAYING", + 'GENERICERROR': "GENERICERROR", + 'commands': { + '247': { + 'name': "commands.247.name", + 'description': "commands.247.description", }, - serverinfo: { - verification: { - no: 'serverinfo.verification.no', - low: 'serverinfo.verification.low', - medium: 'serverinfo.verification.medium', - high: 'serverinfo.verification.high', - extreme: 'serverinfo.verification.extreme', - }, - explicit: { - disabled: 'serverinfo.explicit.disabled', - members_without_role: 'serverinfo.explicit.members_without_role', - all_members: 'serverinfo.explicit.all_members', + 'reboot': { + 'name': "commands.reboot.name", + 'description': "commands.reboot.description", + 'options': { + 'shard': { + 'name': "commands.reboot.options.shard.name", + 'description': "commands.reboot.options.shard.description", }, - emoji_count: 'serverinfo.emoji_count', - tier_level: 'serverinfo.tier_level', - verification_level: 'serverinfo.verification_level', - explicit_filter: 'serverinfo.explicit_filter', + }, }, - ban: { - not_found: 'ban.not_found', - self: 'ban.self', - owner: 'ban.owner', - higher: 'ban.higher', - ban: 'ban.ban', - unbannable: 'ban.unbannable', - }, - skip: { - messages: { - 0: 'skip.messages.0', - 1: 'skip.messages.1', - 2: 'skip.messages.2', + '8ball': { + 'name': "commands.8ball.name", + 'description': "commands.8ball.description", + 'options': { + 'question': { + 'name': "commands.8ball.options.question.name", + 'description': "commands.8ball.options.question.description", }, - no_same: 'skip.no_same', - skiped: 'skip.skiped', - }, - queue: { - no_queue: 'queue.no_queue', - current: 'queue.current', - queue: 'queue.queue', - no_page: 'queue.no_page', - total: 'queue.total', - }, - play: { - same: 'play.same', - not_voice: 'play.not_voice', - not_reproducible: 'play.not_reproducible', - added: 'play.added', - }, - reboot: { - all: 'reboot.all', - shard: 'reboot.shard', + }, }, - stop: { - resumed: 'stop.resumed', - paused: 'stop.paused', - success: 'stop.success', - }, - paused: 'paused', - resumed: 'resumed', - voice_update: { - leaving: 'voice_update.leaving', - alone: 'voice_update.alone', - }, - automix: { - generated: 'automix.generated', - disabled: 'automix.disabled', - }, - twitch: { - no_streamer_found: 'twitch.no_streamer_found', - already_following: 'twitch.already_following', - now_following: 'twitch.now_following', - unfollowed: 'twitch.unfollowed', - role_mention: 'twitch.role_mention', - now_live: 'twitch.now_live', - }, - loop: { - queue: 'loop.queue', - song: 'loop.song', - disabled: 'loop.disabled', - }, - ERROREMBED: 'ERROREMBED', - SUCCESSEMBED: 'SUCCESSEMBED', - PAUSE: 'PAUSE', - RESUME: 'RESUME', - STOP: 'STOP', - SKIP: 'SKIP', - NEXT: 'NEXT', - QUEUE: 'QUEUE', - TITLE: 'TITLE', - MEMBERS: 'MEMBERS', - REGULAR: 'REGULAR', - ANIMATED: 'ANIMATED', - CHANNELS: 'CHANNELS', - ROLES: 'ROLES', - CATEGORIES: 'CATEGORIES', - SONGS: 'SONGS', - TEXT: 'TEXT', - VOICE: 'VOICE', - BOOSTERS: 'BOOSTERS', - REGION: 'REGION', - TIER: 'TIER', - CREATED_AT: 'CREATED_AT', - OWNER: 'OWNER', - AUTHOR: 'AUTHOR', - REQUESTER: 'REQUESTER', - DURATION: 'DURATION', - NO: 'NO', - API: 'API', - PING: 'PING', - NAME: 'NAME', - ID: 'ID', - POSITION: 'POSITION', - COLOR: 'COLOR', - MENTIONABLE: 'MENTIONABLE', - SEPARATED: 'SEPARATED', - YES: 'YES', - PLAYING: 'PLAYING', - GENERICERROR: 'GENERICERROR', - commands: { - 247: { - name: 'commands.247.name', - description: 'commands.247.description', - }, - reboot: { - name: 'commands.reboot.name', - description: 'commands.reboot.description', - options: { - shard: { - name: 'commands.reboot.options.shard.name', - description: 'commands.reboot.options.shard.description', - }, - }, - }, - '8ball': { - name: 'commands.8ball.name', - description: 'commands.8ball.description', - options: { - question: { - name: 'commands.8ball.options.question.name', - description: 'commands.8ball.options.question.description', - }, - }, - }, - impostor: { - name: 'commands.impostor.name', - description: 'commands.impostor.description', - options: { - user: { - name: 'commands.impostor.options.user.name', - description: 'commands.impostor.options.user.description', - }, - }, + 'impostor': { + 'name': "commands.impostor.name", + 'description': "commands.impostor.description", + 'options': { + 'user': { + 'name': "commands.impostor.options.user.name", + 'description': "commands.impostor.options.user.description", }, - avatar: { - name: 'commands.avatar.name', - description: 'commands.avatar.description', - options: { - user: { - name: 'commands.avatar.options.user.name', - description: 'commands.avatar.options.user.description', - }, - }, + }, + }, + 'avatar': { + 'name': "commands.avatar.name", + 'description': "commands.avatar.description", + 'options': { + 'user': { + 'name': "commands.avatar.options.user.name", + 'description': "commands.avatar.options.user.description", }, - twitch: { - name: 'commands.twitch.name', - description: 'commands.twitch.description', - options: { - add: { - name: 'commands.twitch.options.add.name', - description: 'commands.twitch.options.add.description', - options: { - streamer: { - name: 'commands.twitch.options.add.options.streamer.name', - description: 'commands.twitch.options.add.options.streamer.description', - }, - channel: { - name: 'commands.twitch.options.add.options.channel.name', - description: 'commands.twitch.options.add.options.channel.description', - }, - role: { - name: 'commands.twitch.options.add.options.role.name', - description: 'commands.twitch.options.add.options.role.description', - }, - }, - }, - remove: { - name: 'commands.twitch.options.remove.name', - description: 'commands.twitch.options.remove.description', - options: { - streamer: { - name: 'commands.twitch.options.remove.options.streamer.name', - description: 'commands.twitch.options.remove.options.streamer.description', - }, - }, - }, + }, + }, + 'twitch': { + 'name': "commands.twitch.name", + 'description': "commands.twitch.description", + 'options': { + 'add': { + 'name': "commands.twitch.options.add.name", + 'description': "commands.twitch.options.add.description", + 'options': { + 'streamer': { + 'name': "commands.twitch.options.add.options.streamer.name", + 'description': "commands.twitch.options.add.options.streamer.description", }, - }, - shards: { - name: 'commands.shards.name', - description: 'commands.shards.description', - }, - serverinfo: { - name: 'commands.serverinfo.name', - description: 'commands.serverinfo.description', - }, - roleinfo: { - name: 'commands.roleinfo.name', - description: 'commands.roleinfo.description', - options: { - role: { - name: 'commands.roleinfo.options.role.name', - description: 'commands.roleinfo.options.role.description', - }, + 'channel': { + 'name': "commands.twitch.options.add.options.channel.name", + 'description': "commands.twitch.options.add.options.channel.description", }, - }, - ping: { - name: 'commands.ping.name', - description: 'commands.ping.description', - }, - mcserver: { - name: 'commands.mcserver.name', - description: 'commands.mcserver.description', - options: { - server: { - name: 'commands.mcserver.options.server.name', - description: 'commands.mcserver.options.server.description', - }, + 'role': { + 'name': "commands.twitch.options.add.options.role.name", + 'description': "commands.twitch.options.add.options.role.description", }, + }, }, - mchistory: { - name: 'commands.mchistory.name', - description: 'commands.mchistory.description', - options: { - account: { - name: 'commands.mchistory.options.account.name', - description: 'commands.mchistory.options.account.description', - }, + 'remove': { + 'name': "commands.twitch.options.remove.name", + 'description': "commands.twitch.options.remove.description", + 'options': { + 'streamer': { + 'name': "commands.twitch.options.remove.options.streamer.name", + 'description': "commands.twitch.options.remove.options.streamer.description", }, + }, }, - help: { - name: 'commands.help.name', - description: 'commands.help.description', + }, + }, + 'shards': { + 'name': "commands.shards.name", + 'description': "commands.shards.description", + }, + 'serverinfo': { + 'name': "commands.serverinfo.name", + 'description': "commands.serverinfo.description", + }, + 'roleinfo': { + 'name': "commands.roleinfo.name", + 'description': "commands.roleinfo.description", + 'options': { + 'role': { + 'name': "commands.roleinfo.options.role.name", + 'description': "commands.roleinfo.options.role.description", }, - github: { - name: 'commands.github.name', - description: 'commands.github.description', - options: { - account: { - name: 'commands.github.options.account.name', - description: 'commands.github.options.account.description', - }, - }, + }, + }, + 'ping': { + 'name': "commands.ping.name", + 'description': "commands.ping.description", + }, + 'mcserver': { + 'name': "commands.mcserver.name", + 'description': "commands.mcserver.description", + 'options': { + 'server': { + 'name': "commands.mcserver.options.server.name", + 'description': "commands.mcserver.options.server.description", }, - embed: { - name: 'commands.embed.name', - description: 'commands.embed.description', - options: { - channel: { - name: 'commands.embed.options.channel.name', - description: 'commands.embed.options.channel.description', - }, - color: { - name: 'commands.embed.options.color.name', - description: 'commands.embed.options.color.description', - }, - title: { - name: 'commands.embed.options.title.name', - description: 'commands.embed.options.title.description', - }, - description: { - name: 'commands.embed.options.description.name', - description: 'commands.embed.options.description.description', - }, - }, + }, + }, + 'mchistory': { + 'name': "commands.mchistory.name", + 'description': "commands.mchistory.description", + 'options': { + 'account': { + 'name': "commands.mchistory.options.account.name", + 'description': "commands.mchistory.options.account.description", }, - ban: { - name: 'commands.ban.name', - description: 'commands.ban.description', - options: { - user: { - name: 'commands.ban.options.user.name', - description: 'commands.ban.options.user.description', - }, - reason: { - name: 'commands.ban.options.reason.name', - description: 'commands.ban.options.reason.description', - }, - days: { - name: 'commands.ban.options.days.name', - description: 'commands.ban.options.days.description', - }, - }, + }, + }, + 'help': { + 'name': "commands.help.name", + 'description': "commands.help.description", + }, + 'github': { + 'name': "commands.github.name", + 'description': "commands.github.description", + 'options': { + 'account': { + 'name': "commands.github.options.account.name", + 'description': "commands.github.options.account.description", }, - play: { - name: 'commands.play.name', - description: 'commands.play.description', - options: { - song: { - name: 'commands.play.options.song.name', - description: 'commands.play.options.song.description', - }, - }, + }, + }, + 'embed': { + 'name': "commands.embed.name", + 'description': "commands.embed.description", + 'options': { + 'channel': { + 'name': "commands.embed.options.channel.name", + 'description': "commands.embed.options.channel.description", }, - stop: { - name: 'commands.stop.name', - description: 'commands.stop.description', + 'color': { + 'name': "commands.embed.options.color.name", + 'description': "commands.embed.options.color.description", }, - skip: { - name: 'commands.skip.name', - description: 'commands.skip.description', + 'title': { + 'name': "commands.embed.options.title.name", + 'description': "commands.embed.options.title.description", }, - resume: { - name: 'commands.resume.name', - description: 'commands.resume.description', + 'description': { + 'name': "commands.embed.options.description.name", + 'description': "commands.embed.options.description.description", }, - queue: { - name: 'commands.queue.name', - description: 'commands.queue.description', + }, + }, + 'ban': { + 'name': "commands.ban.name", + 'description': "commands.ban.description", + 'options': { + 'user': { + 'name': "commands.ban.options.user.name", + 'description': "commands.ban.options.user.description", }, - pause: { - name: 'commands.pause.name', - description: 'commands.pause.description', + 'reason': { + 'name': "commands.ban.options.reason.name", + 'description': "commands.ban.options.reason.description", }, - nowplaying: { - name: 'commands.nowplaying.name', - description: 'commands.nowplaying.description', + 'days': { + 'name': "commands.ban.options.days.name", + 'description': "commands.ban.options.days.description", }, - loop: { - name: 'commands.loop.name', - description: 'commands.loop.description', + }, + }, + 'play': { + 'name': "commands.play.name", + 'description': "commands.play.description", + 'options': { + 'song': { + 'name': "commands.play.options.song.name", + 'description': "commands.play.options.song.description", }, + }, + }, + 'stop': { + 'name': "commands.stop.name", + 'description': "commands.stop.description", + }, + 'skip': { + 'name': "commands.skip.name", + 'description': "commands.skip.description", }, - nowplaying: { - 1: 'nowplaying.1', - 2: 'nowplaying.2', - 3: 'nowplaying.3', - 4: 'nowplaying.4', - 5: 'nowplaying.5', - 6: 'nowplaying.6', - 7: 'nowplaying.7', + 'resume': { + 'name': "commands.resume.name", + 'description': "commands.resume.description", + }, + 'queue': { + 'name': "commands.queue.name", + 'description': "commands.queue.description", + }, + 'pause': { + 'name': "commands.pause.name", + 'description': "commands.pause.description", + }, + 'nowplaying': { + 'name': "commands.nowplaying.name", + 'description': "commands.nowplaying.description", + }, + 'loop': { + 'name': "commands.loop.name", + 'description': "commands.loop.description", }, + }, + 'nowplaying': { + '1': "nowplaying.1", + '2': "nowplaying.2", + '3': "nowplaying.3", + '4': "nowplaying.4", + '5': "nowplaying.5", + '6': "nowplaying.6", + '7': "nowplaying.7", + }, } satisfies { - '247': { - 'enabled': string - 'disabled': string + '247': { + 'enabled': string + 'disabled': string + } + 'question_ball': { + 'no_question': string + 'question': string + 'response': string + 'possibles': { + '0': string + '1': string + '2': string + '3': string + '4': string + '5': string + '6': string + '7': string + '8': string + '9': string + '10': string + '11': string } - 'question_ball': { - 'no_question': string - 'question': string - 'response': string - 'possibles': { - '0': string - '1': string - '2': string - '3': string - '4': string - '5': string - '6': string - '7': string - '8': string - '9': string - '10': string - '11': string - } + } + 'impostor': { + 'was': string + 'was_not': string + } + 'embed': { + 'successfully': string + 'missing_permissions': string + 'modal': { + 'title': string + 'title_label': string + 'title_placeholder': string + 'description_label': string + 'description_placeholder': string + 'color_label': string } - 'impostor': { - 'was': string - 'was_not': string + 'buttons': { + 'send': string + 'edit': string } - 'embed_successfully': string - 'github': { - 'write_username': string - 'name': string - 'account': string - 'organization': string - 'link': string - 'location': string - 'email': string - 'biography': string - 'twitter': string - 'repositories': string - 'followers': string - 'analizing': string - 'unknow': string + 'invalid_input': string + } + 'github': { + 'write_username': string + 'name': string + 'account': string + 'organization': string + 'link': string + 'location': string + 'email': string + 'biography': string + 'twitter': string + 'repositories': string + 'followers': string + 'analizing': string + 'unknow': string + } + 'help': { + 'presentation': string + 'how_use': string + 'how_use_answer': string + 'need_support': string + 'need_support_answer': string + 'how_vote': string + 'how_vote_answer': string + 'title': string + } + 'avatar': string + 'mchistory': { + 'dont': string + 'names': string + 'first': string + } + 'ping': { + 'global': string + 'internal': string + } + 'roleinfo': { + 'managed': string + } + 'serverinfo': { + 'verification': { + 'no': string + 'low': string + 'medium': string + 'high': string + 'extreme': string } - 'help': { - 'presentation': string - 'how_use': string - 'how_use_answer': string - 'need_support': string - 'need_support_answer': string - 'how_vote': string - 'how_vote_answer': string - 'title': string + 'explicit': { + 'disabled': string + 'members_without_role': string + 'all_members': string } - 'avatar': string - 'mchistory': { - 'dont': string - 'names': string - 'first': string - } - 'ping': { - 'global': string - 'internal': string + 'emoji_count': string + 'tier_level': string + 'verification_level': string + 'explicit_filter': string + } + 'ban': { + 'not_found': string + 'self': string + 'owner': string + 'higher': string + 'ban': string + 'unbannable': string + } + 'skip': { + 'messages': { + '0': string + '1': string + '2': string } - 'roleinfo': { - 'managed': string + 'no_same': string + 'skiped': string + } + 'queue': { + 'no_queue': string + 'current': string + 'queue': string + 'no_page': string + 'total': string + } + 'play': { + 'same': string + 'not_voice': string + 'not_reproducible': string + 'added': string + 'cant_join': string + } + 'reboot': { + 'all': string + 'shard': string + } + 'stop': { + 'resumed': string + 'paused': string + 'success': string + } + 'paused': string + 'resumed': string + 'voice_update': { + 'leaving': string + 'alone': string + } + 'automix': { + 'generated': string + 'disabled': string + } + 'twitch': { + 'no_streamer_found': string + 'already_following': string + 'now_following': string + 'unfollowed': string + 'role_mention': string + 'now_live': string + } + 'loop': { + 'queue': string + 'song': string + 'disabled': string + } + 'ERROREMBED': string + 'SUCCESSEMBED': string + 'PAUSE': string + 'RESUME': string + 'STOP': string + 'SKIP': string + 'NEXT': string + 'QUEUE': string + 'TITLE': string + 'MEMBERS': string + 'REGULAR': string + 'ANIMATED': string + 'CHANNELS': string + 'ROLES': string + 'CATEGORIES': string + 'SONGS': string + 'TEXT': string + 'VOICE': string + 'BOOSTERS': string + 'REGION': string + 'TIER': string + 'CREATED_AT': string + 'OWNER': string + 'AUTHOR': string + 'REQUESTER': string + 'DURATION': string + 'NO': string + 'API': string + 'PING': string + 'NAME': string + 'ID': string + 'POSITION': string + 'COLOR': string + 'MENTIONABLE': string + 'SEPARATED': string + 'YES': string + 'PLAYING': string + 'GENERICERROR': string + 'commands': { + '247': { + 'name': string + 'description': string } - 'serverinfo': { - 'verification': { - 'no': string - 'low': string - 'medium': string - 'high': string - 'extreme': string - } - 'explicit': { - 'disabled': string - 'members_without_role': string - 'all_members': string + 'reboot': { + 'name': string + 'description': string + 'options': { + 'shard': { + 'name': string + 'description': string } - 'emoji_count': string - 'tier_level': string - 'verification_level': string - 'explicit_filter': string - } - 'ban': { - 'not_found': string - 'self': string - 'owner': string - 'higher': string - 'ban': string - 'unbannable': string + } } - 'skip': { - 'messages': { - '0': string - '1': string - '2': string + '8ball': { + 'name': string + 'description': string + 'options': { + 'question': { + 'name': string + 'description': string } - 'no_same': string - 'skiped': string + } } - 'queue': { - 'no_queue': string - 'current': string - 'queue': string - 'no_page': string - 'total': string - } - 'play': { - 'same': string - 'not_voice': string - 'not_reproducible': string - 'added': string - } - 'reboot': { - 'all': string - 'shard': string - } - 'stop': { - 'resumed': string - 'paused': string - 'success': string - } - 'paused': string - 'resumed': string - 'voice_update': { - 'leaving': string - 'alone': string + 'impostor': { + 'name': string + 'description': string + 'options': { + 'user': { + 'name': string + 'description': string + } + } } - 'automix': { - 'generated': string - 'disabled': string + 'avatar': { + 'name': string + 'description': string + 'options': { + 'user': { + 'name': string + 'description': string + } + } } 'twitch': { - 'no_streamer_found': string - 'already_following': string - 'now_following': string - 'unfollowed': string - 'role_mention': string - 'now_live': string - } - 'loop': { - 'queue': string - 'song': string - 'disabled': string - } - 'ERROREMBED': string - 'SUCCESSEMBED': string - 'PAUSE': string - 'RESUME': string - 'STOP': string - 'SKIP': string - 'NEXT': string - 'QUEUE': string - 'TITLE': string - 'MEMBERS': string - 'REGULAR': string - 'ANIMATED': string - 'CHANNELS': string - 'ROLES': string - 'CATEGORIES': string - 'SONGS': string - 'TEXT': string - 'VOICE': string - 'BOOSTERS': string - 'REGION': string - 'TIER': string - 'CREATED_AT': string - 'OWNER': string - 'AUTHOR': string - 'REQUESTER': string - 'DURATION': string - 'NO': string - 'API': string - 'PING': string - 'NAME': string - 'ID': string - 'POSITION': string - 'COLOR': string - 'MENTIONABLE': string - 'SEPARATED': string - 'YES': string - 'PLAYING': string - 'GENERICERROR': string - 'commands': { - '247': { - 'name': string - 'description': string - } - 'reboot': { - 'name': string - 'description': string - 'options': { - 'shard': { - 'name': string - 'description': string - } - } - } - '8ball': { - 'name': string - 'description': string - 'options': { - 'question': { - 'name': string - 'description': string - } - } - } - 'impostor': { - 'name': string - 'description': string - 'options': { - 'user': { - 'name': string - 'description': string - } - } - } - 'avatar': { - 'name': string - 'description': string - 'options': { - 'user': { - 'name': string - 'description': string - } + 'name': string + 'description': string + 'options': { + 'add': { + 'name': string + 'description': string + 'options': { + 'streamer': { + 'name': string + 'description': string } - } - 'twitch': { - 'name': string - 'description': string - 'options': { - 'add': { - 'name': string - 'description': string - 'options': { - 'streamer': { - 'name': string - 'description': string - } - 'channel': { - 'name': string - 'description': string - } - 'role': { - 'name': string - 'description': string - } - } - } - 'remove': { - 'name': string - 'description': string - 'options': { - 'streamer': { - 'name': string - 'description': string - } - } - } - } - } - 'shards': { - 'name': string - 'description': string - } - 'serverinfo': { - 'name': string - 'description': string - } - 'roleinfo': { - 'name': string - 'description': string - 'options': { - 'role': { - 'name': string - 'description': string - } + 'channel': { + 'name': string + 'description': string } - } - 'ping': { - 'name': string - 'description': string - } - 'mcserver': { - 'name': string - 'description': string - 'options': { - 'server': { - 'name': string - 'description': string - } + 'role': { + 'name': string + 'description': string } + } } - 'mchistory': { - 'name': string - 'description': string - 'options': { - 'account': { - 'name': string - 'description': string - } + 'remove': { + 'name': string + 'description': string + 'options': { + 'streamer': { + 'name': string + 'description': string } + } } - 'help': { - 'name': string - 'description': string + } + } + 'shards': { + 'name': string + 'description': string + } + 'serverinfo': { + 'name': string + 'description': string + } + 'roleinfo': { + 'name': string + 'description': string + 'options': { + 'role': { + 'name': string + 'description': string } - 'github': { - 'name': string - 'description': string - 'options': { - 'account': { - 'name': string - 'description': string - } - } + } + } + 'ping': { + 'name': string + 'description': string + } + 'mcserver': { + 'name': string + 'description': string + 'options': { + 'server': { + 'name': string + 'description': string } - 'embed': { - 'name': string - 'description': string - 'options': { - 'channel': { - 'name': string - 'description': string - } - 'color': { - 'name': string - 'description': string - } - 'title': { - 'name': string - 'description': string - } - 'description': { - 'name': string - 'description': string - } - } + } + } + 'mchistory': { + 'name': string + 'description': string + 'options': { + 'account': { + 'name': string + 'description': string } - 'ban': { - 'name': string - 'description': string - 'options': { - 'user': { - 'name': string - 'description': string - } - 'reason': { - 'name': string - 'description': string - } - 'days': { - 'name': string - 'description': string - } - } + } + } + 'help': { + 'name': string + 'description': string + } + 'github': { + 'name': string + 'description': string + 'options': { + 'account': { + 'name': string + 'description': string } - 'play': { - 'name': string - 'description': string - 'options': { - 'song': { - 'name': string - 'description': string - } - } + } + } + 'embed': { + 'name': string + 'description': string + 'options': { + 'channel': { + 'name': string + 'description': string } - 'stop': { - 'name': string - 'description': string + 'color': { + 'name': string + 'description': string } - 'skip': { - 'name': string - 'description': string + 'title': { + 'name': string + 'description': string } - 'resume': { - 'name': string - 'description': string + 'description': { + 'name': string + 'description': string } - 'queue': { - 'name': string - 'description': string + } + } + 'ban': { + 'name': string + 'description': string + 'options': { + 'user': { + 'name': string + 'description': string } - 'pause': { - 'name': string - 'description': string + 'reason': { + 'name': string + 'description': string } - 'nowplaying': { - 'name': string - 'description': string + 'days': { + 'name': string + 'description': string } - 'loop': { - 'name': string - 'description': string + } + } + 'play': { + 'name': string + 'description': string + 'options': { + 'song': { + 'name': string + 'description': string } + } + } + 'stop': { + 'name': string + 'description': string + } + 'skip': { + 'name': string + 'description': string } - 'nowplaying'?: { - '1'?: string - '2'?: string - '3'?: string - '4'?: string - '5'?: string - '6'?: string - '7'?: string + 'resume': { + 'name': string + 'description': string + } + 'queue': { + 'name': string + 'description': string + } + 'pause': { + 'name': string + 'description': string + } + 'nowplaying': { + 'name': string + 'description': string + } + 'loop': { + 'name': string + 'description': string } -} + } + 'nowplaying'?: { + '1'?: string + '2'?: string + '3'?: string + '4'?: string + '5'?: string + '6'?: string + '7'?: string + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 8123501..816ef0f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,103 +1,34 @@ { - "exclude": [ - "src/structures/Música/*", - "build" - ], + "exclude": [ "src/structures/Música/*" ], "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - /* Projects */ - // "experimentalDecorators": true, - // "incremental": true, /* Enable incremental compilation */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - /* Modules */ - "target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "module": "ESNext" /* Specify what module code is generated. */, - "rootDir": "./src" /* Specify the root folder within your source files. */, - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ + "target": "esnext", + "module": "ESNext", + "rootDir": "./src", + "moduleResolution": "node", + "baseUrl": ".", "paths": { "#structures/*": ["./src/structures/*"], "#utils/*": ["./src/utils/*"], "#cache/*": ["./src/cache/*"], "#models/*": ["./src/models/*"] - }, /* Specify a set of entries that re-map imports to additional lookup locations. */ - "outDir": "./build" /* Specify an output folder for all emitted files. */, - // "rootDirs": ["/src", "/locales"], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true /* Enable importing .json files */, - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - "sourceMap": true /* Create source map files for emitted JavaScript files. */, - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "removeComments": true /* Disable emitting comments. */, - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - "inlineSources": true /* Include source code in the sourcemaps inside the emitted JavaScript. */, - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - "noEmitOnError": true /* Disable emitting files if any type checking errors are reported. */, - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied `any` type.. */, - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, - "noImplicitThis": true /* Enable error reporting when `this` is given the type `any`. */, - "useUnknownInCatchVariables": true /* Type catch clause variables as 'unknown' instead of 'any'. */, - "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, - "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - "noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */, - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "outDir": "./build", + "sourceMap": true, + "removeComments": true, + "inlineSources": true, + "noEmitOnError": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": true, + "strictFunctionTypes": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "useUnknownInCatchVariables": true, + "alwaysStrict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "skipLibCheck": true } }