discord-py-help-lib 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- discord_py_help_lib-0.0.1/LICENSE +21 -0
- discord_py_help_lib-0.0.1/PKG-INFO +84 -0
- discord_py_help_lib-0.0.1/README.md +46 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib/__init__.py +4 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib/select/category_select.py +138 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib/select/role_select.py +177 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib/select/vc_select.py +175 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib/webhook_sender.py +238 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/PKG-INFO +84 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/SOURCES.txt +15 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/dependency_links.txt +1 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/entry_points.txt +2 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/not-zip-safe +1 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/requires.txt +1 -0
- discord_py_help_lib-0.0.1/discord_py_help_lib.egg-info/top_level.txt +1 -0
- discord_py_help_lib-0.0.1/setup.cfg +4 -0
- discord_py_help_lib-0.0.1/setup.py +77 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 hashimotok
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: discord-py-help-lib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A library to assist with Discord.py development
|
|
5
|
+
Home-page: https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
6
|
+
Download-URL: https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
7
|
+
Author: hashimotok
|
|
8
|
+
Author-email: contact@hashimotok.dev
|
|
9
|
+
License: MIT
|
|
10
|
+
Project-URL: Documentation, https://discord-py-help-lib.readthedocs.io/
|
|
11
|
+
Project-URL: Source, https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
12
|
+
Project-URL: Tracker, https://github.com/hashimotok-ecsv/discord-py-help-lib/issues
|
|
13
|
+
Keywords: discord.py help library
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.10.6
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: discord.py>=2.5.2
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: download-url
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
38
|
+
|
|
39
|
+
# Auxiliary for discord.py Library
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 📦 概要
|
|
48
|
+
|
|
49
|
+
`discord-py-auxiliary-lib` は、discord.pyで役職パネルを簡単に実装するための Python ライブラリです。
|
|
50
|
+
|
|
51
|
+
主な機能は以下のとおりです:
|
|
52
|
+
|
|
53
|
+
- 後日更新
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## ✨ 特徴
|
|
58
|
+
|
|
59
|
+
- ✅ 簡単に使用が可能
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🔧 インストール
|
|
64
|
+
|
|
65
|
+
### PyPIからインストール:
|
|
66
|
+
```bash
|
|
67
|
+
pip install discord-py-auxiliary-lib
|
|
68
|
+
```
|
|
69
|
+
### githubからインストール:
|
|
70
|
+
```bash
|
|
71
|
+
pip install git+https://github.com/hashimotok-ecsv/discord_py_auxiliary_lib.git
|
|
72
|
+
```
|
|
73
|
+
## 使い方
|
|
74
|
+
```python
|
|
75
|
+
# 後日更新
|
|
76
|
+
```
|
|
77
|
+
#### 管理者用
|
|
78
|
+
##### 更新方法
|
|
79
|
+
```bash
|
|
80
|
+
py setup.py sdist
|
|
81
|
+
py setup.py bdist_wheel
|
|
82
|
+
py -m twine upload --repository testpypi dist/*
|
|
83
|
+
py -m twine upload --repository pypi dist/*
|
|
84
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Auxiliary for discord.py Library
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 📦 概要
|
|
10
|
+
|
|
11
|
+
`discord-py-auxiliary-lib` は、discord.pyで役職パネルを簡単に実装するための Python ライブラリです。
|
|
12
|
+
|
|
13
|
+
主な機能は以下のとおりです:
|
|
14
|
+
|
|
15
|
+
- 後日更新
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## ✨ 特徴
|
|
20
|
+
|
|
21
|
+
- ✅ 簡単に使用が可能
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🔧 インストール
|
|
26
|
+
|
|
27
|
+
### PyPIからインストール:
|
|
28
|
+
```bash
|
|
29
|
+
pip install discord-py-auxiliary-lib
|
|
30
|
+
```
|
|
31
|
+
### githubからインストール:
|
|
32
|
+
```bash
|
|
33
|
+
pip install git+https://github.com/hashimotok-ecsv/discord_py_auxiliary_lib.git
|
|
34
|
+
```
|
|
35
|
+
## 使い方
|
|
36
|
+
```python
|
|
37
|
+
# 後日更新
|
|
38
|
+
```
|
|
39
|
+
#### 管理者用
|
|
40
|
+
##### 更新方法
|
|
41
|
+
```bash
|
|
42
|
+
py setup.py sdist
|
|
43
|
+
py setup.py bdist_wheel
|
|
44
|
+
py -m twine upload --repository testpypi dist/*
|
|
45
|
+
py -m twine upload --repository pypi dist/*
|
|
46
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
import traceback
|
|
3
|
+
from discord.ext import commands
|
|
4
|
+
from typing import Callable, Optional, Awaitable
|
|
5
|
+
|
|
6
|
+
def select_category(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> dict:
|
|
7
|
+
category_list = guild.categories
|
|
8
|
+
total_categories = len(category_list)
|
|
9
|
+
|
|
10
|
+
# 1ページあたりの項目数
|
|
11
|
+
items_per_page = 25
|
|
12
|
+
# ページの範囲を計算
|
|
13
|
+
start = items_per_page * (page - 1)
|
|
14
|
+
end = items_per_page * page
|
|
15
|
+
last_page = (total_categories + items_per_page - 1) // items_per_page # ページ数を計算
|
|
16
|
+
print(f"start: {start}, end: {end}, total_categories: {total_categories}")
|
|
17
|
+
# 範囲外なら最後のページを選ぶ
|
|
18
|
+
if start >= total_categories:
|
|
19
|
+
start = items_per_page * (last_page - 1)
|
|
20
|
+
end = total_categories
|
|
21
|
+
page = last_page
|
|
22
|
+
options = []
|
|
23
|
+
count: int = 0
|
|
24
|
+
for category in category_list[start:end]:
|
|
25
|
+
options.append(discord.SelectOption(label="📂"+category.name, value=str(category.id)))
|
|
26
|
+
count += 1
|
|
27
|
+
if not multiselect:
|
|
28
|
+
count = 1
|
|
29
|
+
select_ui = discord.ui.Select(custom_id=select_ui_id + "_" + str(page), placeholder=placeholder, options=options, max_values=count)
|
|
30
|
+
return {"select_ui": select_ui, "page": page, "last_page": last_page}
|
|
31
|
+
|
|
32
|
+
def get_category_select(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> discord.ui.View:
|
|
33
|
+
try:
|
|
34
|
+
data = select_category(guild, select_ui_id, placeholder, page, multiselect)
|
|
35
|
+
view: discord.ui.View = discord.ui.View()
|
|
36
|
+
select_category_ui: discord.ui.Select = data["select_ui"]
|
|
37
|
+
view.add_item(select_category_ui)
|
|
38
|
+
prev_button: discord.ui.Button = discord.ui.Button(style=discord.ButtonStyle.red, label="前へ", custom_id=f"{select_ui_id}_back_select_{page - 1}", disabled=False if page > 1 else True)
|
|
39
|
+
view.add_item(prev_button)
|
|
40
|
+
next_button: discord.ui.Button = discord.ui.Button(style=discord.ButtonStyle.green, label="次へ", custom_id=f"{select_ui_id}_next_select_{page + 1}")
|
|
41
|
+
view.add_item(next_button)
|
|
42
|
+
cancel_button: discord.ui.Button = discord.ui.Button(style=discord.ButtonStyle.red, label="キャンセル", custom_id=f"{select_ui_id}_cancel_select")
|
|
43
|
+
view.add_item(cancel_button)
|
|
44
|
+
return view
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(f"Error in get_category_select: {e}")
|
|
47
|
+
traceback.print_exc()
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
class CategorySelectHandler:
|
|
51
|
+
def __init__(self,
|
|
52
|
+
bot: commands.Bot,
|
|
53
|
+
custom_id: str,
|
|
54
|
+
placeholder: str = "カテゴリーを選択してください。",
|
|
55
|
+
multiselect: bool = False,
|
|
56
|
+
on_select: Optional[Callable[[discord.Interaction, list[discord.CategoryChannel]], Awaitable[None]]] = None
|
|
57
|
+
):
|
|
58
|
+
"""
|
|
59
|
+
Initialize the CategorySelectHandler.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
bot: Discord bot instance
|
|
63
|
+
custom_id: Unique identifier for this handler
|
|
64
|
+
placeholder: Placeholder text for the select menu
|
|
65
|
+
multiselect: Whether to allow multiple selections
|
|
66
|
+
on_select: Callback function when categories are selected
|
|
67
|
+
"""
|
|
68
|
+
self.bot: commands.Bot = bot
|
|
69
|
+
self.custom_id = custom_id
|
|
70
|
+
self.placeholder = placeholder
|
|
71
|
+
self.multiselect = multiselect
|
|
72
|
+
self.on_select = on_select
|
|
73
|
+
|
|
74
|
+
def get_custom_id(self) -> str:
|
|
75
|
+
return self.custom_id
|
|
76
|
+
|
|
77
|
+
def get_view(self, guild: discord.Guild, page: int = 1) -> discord.ui.View:
|
|
78
|
+
return get_category_select(guild, self.custom_id, self.placeholder, page, self.multiselect)
|
|
79
|
+
|
|
80
|
+
async def call(self, inter: discord.Interaction):
|
|
81
|
+
try:
|
|
82
|
+
custom_id: str = inter.data["custom_id"]
|
|
83
|
+
|
|
84
|
+
if custom_id == f"{self.custom_id}_cancel_select":
|
|
85
|
+
await inter.response.edit_message(content="キャンセルしました。", view=None)
|
|
86
|
+
|
|
87
|
+
elif custom_id.startswith(f"{self.custom_id}_next_select_") or custom_id.startswith(f"{self.custom_id}_back_select_"):
|
|
88
|
+
page: int = int(custom_id.split("_")[-1])
|
|
89
|
+
view = self.get_view(inter.guild, page)
|
|
90
|
+
if not view:
|
|
91
|
+
await inter.response.edit_message("カテゴリーが設定されていません。", view=None)
|
|
92
|
+
return
|
|
93
|
+
await inter.response.edit_message(content=f"{self.placeholder}", view=view)
|
|
94
|
+
|
|
95
|
+
elif custom_id.startswith(f"{self.custom_id}_"):
|
|
96
|
+
# セレクトメニューが選択された場合
|
|
97
|
+
if inter.data.get("component_type") == 3: # Select Menu
|
|
98
|
+
selected_ids = inter.data["values"]
|
|
99
|
+
selected_categories = []
|
|
100
|
+
for category_id in selected_ids:
|
|
101
|
+
category = inter.guild.get_channel(int(category_id))
|
|
102
|
+
if category and isinstance(category, discord.CategoryChannel):
|
|
103
|
+
selected_categories.append(category)
|
|
104
|
+
|
|
105
|
+
if self.on_select:
|
|
106
|
+
await self.on_select(inter, selected_categories)
|
|
107
|
+
else:
|
|
108
|
+
category_names = [cat.name for cat in selected_categories]
|
|
109
|
+
await inter.response.edit_message(
|
|
110
|
+
content=f"選択されたカテゴリー: {', '.join(category_names)}",
|
|
111
|
+
view=None
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
except Exception:
|
|
115
|
+
traceback.print_exc()
|
|
116
|
+
|
|
117
|
+
# グローバルなハンドラー管理辞書
|
|
118
|
+
_category_handlers: dict[str, CategorySelectHandler] = {}
|
|
119
|
+
|
|
120
|
+
def register_category_handler(handler: CategorySelectHandler):
|
|
121
|
+
"""ハンドラーを登録"""
|
|
122
|
+
_category_handlers[handler.get_custom_id()] = handler
|
|
123
|
+
|
|
124
|
+
def get_category_handler(custom_id: str) -> Optional[CategorySelectHandler]:
|
|
125
|
+
"""登録されたハンドラーを取得"""
|
|
126
|
+
for handler_id, handler in _category_handlers.items():
|
|
127
|
+
if custom_id.startswith(handler_id):
|
|
128
|
+
return handler
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
async def handle_category_interaction(inter: discord.Interaction):
|
|
132
|
+
"""統一されたインタラクションハンドラー"""
|
|
133
|
+
custom_id = inter.data["custom_id"]
|
|
134
|
+
handler = get_category_handler(custom_id)
|
|
135
|
+
if handler:
|
|
136
|
+
await handler.call(inter)
|
|
137
|
+
else:
|
|
138
|
+
await inter.response.send_message("ハンドラーが見つかりません。", ephemeral=True)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
import traceback
|
|
3
|
+
from discord.ext import commands
|
|
4
|
+
from typing import Callable, Optional, Awaitable
|
|
5
|
+
|
|
6
|
+
def select_role(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> dict:
|
|
7
|
+
# @everyoneロールを除外してロール一覧を取得
|
|
8
|
+
role_list = [role for role in guild.roles if role.name != "@everyone"]
|
|
9
|
+
# 位置順でソート(上位のロールが先頭)
|
|
10
|
+
role_list.sort(key=lambda role: role.position, reverse=True)
|
|
11
|
+
|
|
12
|
+
total_roles = len(role_list)
|
|
13
|
+
|
|
14
|
+
# 1ページあたりの項目数
|
|
15
|
+
items_per_page = 25
|
|
16
|
+
# ページの範囲を計算
|
|
17
|
+
start = items_per_page * (page - 1)
|
|
18
|
+
end = items_per_page * page
|
|
19
|
+
last_page = (total_roles + items_per_page - 1) // items_per_page # ページ数を計算
|
|
20
|
+
print(f"start: {start}, end: {end}, total_roles: {total_roles}")
|
|
21
|
+
# 範囲外なら最後のページを選ぶ
|
|
22
|
+
if start >= total_roles:
|
|
23
|
+
start = items_per_page * (last_page - 1)
|
|
24
|
+
end = total_roles
|
|
25
|
+
page = last_page
|
|
26
|
+
|
|
27
|
+
options = []
|
|
28
|
+
count: int = 0
|
|
29
|
+
for role in role_list[start:end]:
|
|
30
|
+
# ロールの色を表示に使用
|
|
31
|
+
emoji = "🔴" if role.color != discord.Color.default() else "⚪"
|
|
32
|
+
label = f"{emoji}{role.name}"
|
|
33
|
+
# ラベルが100文字を超える場合は切り詰める
|
|
34
|
+
if len(label) > 100:
|
|
35
|
+
label = label[:97] + "..."
|
|
36
|
+
options.append(discord.SelectOption(label=label, value=str(role.id)))
|
|
37
|
+
count += 1
|
|
38
|
+
|
|
39
|
+
if not multiselect:
|
|
40
|
+
count = 1
|
|
41
|
+
|
|
42
|
+
select_ui = discord.ui.Select(custom_id=select_ui_id + "_" + str(page), placeholder=placeholder, options=options, max_values=count)
|
|
43
|
+
return {"select_ui": select_ui, "page": page, "last_page": last_page}
|
|
44
|
+
|
|
45
|
+
def get_role_select(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> discord.ui.View:
|
|
46
|
+
try:
|
|
47
|
+
data = select_role(guild, select_ui_id, placeholder, page, multiselect)
|
|
48
|
+
view: discord.ui.View = discord.ui.View()
|
|
49
|
+
select_role_ui: discord.ui.Select = data["select_ui"]
|
|
50
|
+
view.add_item(select_role_ui)
|
|
51
|
+
|
|
52
|
+
page = data["page"]
|
|
53
|
+
last_page = data["last_page"]
|
|
54
|
+
|
|
55
|
+
prev_button: discord.ui.Button = discord.ui.Button(
|
|
56
|
+
style=discord.ButtonStyle.red,
|
|
57
|
+
label="前へ",
|
|
58
|
+
custom_id=f"{select_ui_id}_back_select_{page - 1}",
|
|
59
|
+
disabled=page <= 1
|
|
60
|
+
)
|
|
61
|
+
view.add_item(prev_button)
|
|
62
|
+
|
|
63
|
+
next_button: discord.ui.Button = discord.ui.Button(
|
|
64
|
+
style=discord.ButtonStyle.green,
|
|
65
|
+
label="次へ",
|
|
66
|
+
custom_id=f"{select_ui_id}_next_select_{page + 1}",
|
|
67
|
+
disabled=page >= last_page
|
|
68
|
+
)
|
|
69
|
+
view.add_item(next_button)
|
|
70
|
+
|
|
71
|
+
cancel_button: discord.ui.Button = discord.ui.Button(
|
|
72
|
+
style=discord.ButtonStyle.red,
|
|
73
|
+
label="キャンセル",
|
|
74
|
+
custom_id=f"{select_ui_id}_cancel_select"
|
|
75
|
+
)
|
|
76
|
+
view.add_item(cancel_button)
|
|
77
|
+
|
|
78
|
+
return view
|
|
79
|
+
except Exception as e:
|
|
80
|
+
print(f"Error in get_role_select: {e}")
|
|
81
|
+
traceback.print_exc()
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
class RoleSelectHandler:
|
|
85
|
+
def __init__(self,
|
|
86
|
+
bot: commands.Bot,
|
|
87
|
+
custom_id: str,
|
|
88
|
+
placeholder: str = "ロールを選択してください。",
|
|
89
|
+
multiselect: bool = False,
|
|
90
|
+
on_select: Optional[Callable[[discord.Interaction, list[discord.Role]], Awaitable[None]]] = None
|
|
91
|
+
):
|
|
92
|
+
"""
|
|
93
|
+
Initialize the RoleSelectHandler.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
bot: Discord bot instance
|
|
97
|
+
custom_id: Unique identifier for this handler
|
|
98
|
+
placeholder: Placeholder text for the select menu
|
|
99
|
+
multiselect: Whether to allow multiple selections
|
|
100
|
+
on_select: Callback function when roles are selected
|
|
101
|
+
"""
|
|
102
|
+
self.bot: commands.Bot = bot
|
|
103
|
+
self.custom_id = custom_id
|
|
104
|
+
self.placeholder = placeholder
|
|
105
|
+
self.multiselect = multiselect
|
|
106
|
+
self.on_select = on_select
|
|
107
|
+
|
|
108
|
+
def get_custom_id(self) -> str:
|
|
109
|
+
return self.custom_id
|
|
110
|
+
|
|
111
|
+
def get_view(self, guild: discord.Guild, page: int = 1) -> discord.ui.View:
|
|
112
|
+
return get_role_select(guild, self.custom_id, self.placeholder, page, self.multiselect)
|
|
113
|
+
|
|
114
|
+
async def call(self, inter: discord.Interaction):
|
|
115
|
+
try:
|
|
116
|
+
custom_id: str = inter.data["custom_id"]
|
|
117
|
+
|
|
118
|
+
if custom_id == f"{self.custom_id}_cancel_select":
|
|
119
|
+
await inter.response.edit_message(content="キャンセルしました。", view=None)
|
|
120
|
+
|
|
121
|
+
elif custom_id.startswith(f"{self.custom_id}_next_select_") or custom_id.startswith(f"{self.custom_id}_back_select_"):
|
|
122
|
+
page: int = int(custom_id.split("_")[-1])
|
|
123
|
+
view = self.get_view(inter.guild, page)
|
|
124
|
+
if not view:
|
|
125
|
+
await inter.response.edit_message("ロールが設定されていません。", view=None)
|
|
126
|
+
return
|
|
127
|
+
await inter.response.edit_message(content=f"{self.placeholder}", view=view)
|
|
128
|
+
|
|
129
|
+
elif custom_id.startswith(f"{self.custom_id}_"):
|
|
130
|
+
# セレクトメニューが選択された場合
|
|
131
|
+
if inter.data.get("component_type") == 3: # Select Menu
|
|
132
|
+
selected_ids = inter.data["values"]
|
|
133
|
+
selected_roles = []
|
|
134
|
+
for role_id in selected_ids:
|
|
135
|
+
role = inter.guild.get_role(int(role_id))
|
|
136
|
+
if role:
|
|
137
|
+
selected_roles.append(role)
|
|
138
|
+
|
|
139
|
+
if self.on_select:
|
|
140
|
+
await self.on_select(inter, selected_roles)
|
|
141
|
+
else:
|
|
142
|
+
role_names = [role.name for role in selected_roles]
|
|
143
|
+
await inter.response.edit_message(
|
|
144
|
+
content=f"選択されたロール: {', '.join(role_names)}",
|
|
145
|
+
view=None
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
except Exception:
|
|
149
|
+
traceback.print_exc()
|
|
150
|
+
|
|
151
|
+
# グローバルなハンドラー管理辞書
|
|
152
|
+
_role_handlers: dict[str, RoleSelectHandler] = {}
|
|
153
|
+
|
|
154
|
+
def register_role_handler(handler: RoleSelectHandler):
|
|
155
|
+
"""ハンドラーを登録"""
|
|
156
|
+
_role_handlers[handler.get_custom_id()] = handler
|
|
157
|
+
|
|
158
|
+
def get_role_handler(custom_id: str) -> Optional[RoleSelectHandler]:
|
|
159
|
+
"""登録されたハンドラーを取得"""
|
|
160
|
+
for handler_id, handler in _role_handlers.items():
|
|
161
|
+
if custom_id.startswith(handler_id):
|
|
162
|
+
return handler
|
|
163
|
+
return None
|
|
164
|
+
|
|
165
|
+
async def handle_role_interaction(inter: discord.Interaction):
|
|
166
|
+
"""統一されたインタラクションハンドラー"""
|
|
167
|
+
try:
|
|
168
|
+
custom_id = inter.data["custom_id"]
|
|
169
|
+
handler = get_role_handler(custom_id)
|
|
170
|
+
if handler:
|
|
171
|
+
await handler.call(inter)
|
|
172
|
+
else:
|
|
173
|
+
await inter.response.send_message("ハンドラーが見つかりません。", ephemeral=True)
|
|
174
|
+
except Exception as e:
|
|
175
|
+
print(f"Error in handle_role_interaction: {e}")
|
|
176
|
+
traceback.print_exc()
|
|
177
|
+
await inter.response.send_message("エラーが発生しました。", ephemeral=True)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
import traceback
|
|
3
|
+
from discord.ext import commands
|
|
4
|
+
from typing import Callable, Optional, Awaitable
|
|
5
|
+
|
|
6
|
+
def select_vc(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> dict:
|
|
7
|
+
# ボイスチャンネルの一覧を取得
|
|
8
|
+
vc_list = [channel for channel in guild.channels if isinstance(channel, discord.VoiceChannel)]
|
|
9
|
+
# カテゴリー順、位置順でソート
|
|
10
|
+
vc_list.sort(key=lambda vc: (vc.category.name if vc.category else "", vc.position))
|
|
11
|
+
|
|
12
|
+
total_vcs = len(vc_list)
|
|
13
|
+
|
|
14
|
+
# 1ページあたりの項目数
|
|
15
|
+
items_per_page = 25
|
|
16
|
+
# ページの範囲を計算
|
|
17
|
+
start = items_per_page * (page - 1)
|
|
18
|
+
end = items_per_page * page
|
|
19
|
+
last_page = (total_vcs + items_per_page - 1) // items_per_page # ページ数を計算
|
|
20
|
+
print(f"start: {start}, end: {end}, total_vcs: {total_vcs}")
|
|
21
|
+
# 範囲外なら最後のページを選ぶ
|
|
22
|
+
if start >= total_vcs:
|
|
23
|
+
start = items_per_page * (last_page - 1)
|
|
24
|
+
end = total_vcs
|
|
25
|
+
page = last_page
|
|
26
|
+
|
|
27
|
+
options = []
|
|
28
|
+
count: int = 0
|
|
29
|
+
for vc in vc_list[start:end]:
|
|
30
|
+
# カテゴリー名を含めて表示
|
|
31
|
+
if vc.category:
|
|
32
|
+
label = f"🔊[{vc.category.name}] {vc.name}"
|
|
33
|
+
else:
|
|
34
|
+
label = f"🔊{vc.name}"
|
|
35
|
+
|
|
36
|
+
# ラベルが100文字を超える場合は切り詰める
|
|
37
|
+
if len(label) > 100:
|
|
38
|
+
label = label[:97] + "..."
|
|
39
|
+
|
|
40
|
+
options.append(discord.SelectOption(label=label, value=str(vc.id)))
|
|
41
|
+
count += 1
|
|
42
|
+
|
|
43
|
+
if not multiselect:
|
|
44
|
+
count = 1
|
|
45
|
+
|
|
46
|
+
select_ui = discord.ui.Select(custom_id=select_ui_id + "_" + str(page), placeholder=placeholder, options=options, max_values=count)
|
|
47
|
+
return {"select_ui": select_ui, "page": page, "last_page": last_page}
|
|
48
|
+
|
|
49
|
+
def get_vc_select(guild: discord.Guild, select_ui_id: str, placeholder: str, page: int = 1, multiselect: bool = False) -> discord.ui.View:
|
|
50
|
+
try:
|
|
51
|
+
data = select_vc(guild, select_ui_id, placeholder, page, multiselect)
|
|
52
|
+
view: discord.ui.View = discord.ui.View()
|
|
53
|
+
select_vc_ui: discord.ui.Select = data["select_ui"]
|
|
54
|
+
view.add_item(select_vc_ui)
|
|
55
|
+
|
|
56
|
+
page = data["page"]
|
|
57
|
+
last_page = data["last_page"]
|
|
58
|
+
|
|
59
|
+
prev_button: discord.ui.Button = discord.ui.Button(
|
|
60
|
+
style=discord.ButtonStyle.red,
|
|
61
|
+
label="前へ",
|
|
62
|
+
custom_id=f"{select_ui_id}_back_select_{page - 1}",
|
|
63
|
+
disabled=page <= 1
|
|
64
|
+
)
|
|
65
|
+
view.add_item(prev_button)
|
|
66
|
+
|
|
67
|
+
next_button: discord.ui.Button = discord.ui.Button(
|
|
68
|
+
style=discord.ButtonStyle.green,
|
|
69
|
+
label="次へ",
|
|
70
|
+
custom_id=f"{select_ui_id}_next_select_{page + 1}",
|
|
71
|
+
disabled=page >= last_page
|
|
72
|
+
)
|
|
73
|
+
view.add_item(next_button)
|
|
74
|
+
|
|
75
|
+
cancel_button: discord.ui.Button = discord.ui.Button(
|
|
76
|
+
style=discord.ButtonStyle.red,
|
|
77
|
+
label="キャンセル",
|
|
78
|
+
custom_id=f"{select_ui_id}_cancel_select"
|
|
79
|
+
)
|
|
80
|
+
view.add_item(cancel_button)
|
|
81
|
+
|
|
82
|
+
return view
|
|
83
|
+
except Exception as e:
|
|
84
|
+
print(f"Error in get_vc_select: {e}")
|
|
85
|
+
traceback.print_exc()
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
class VCSelectHandler:
|
|
89
|
+
def __init__(self,
|
|
90
|
+
bot: commands.Bot,
|
|
91
|
+
custom_id: str,
|
|
92
|
+
placeholder: str = "ボイスチャンネルを選択してください。",
|
|
93
|
+
multiselect: bool = False,
|
|
94
|
+
on_select: Optional[Callable[[discord.Interaction, list[discord.VoiceChannel]], Awaitable[None]]] = None):
|
|
95
|
+
"""
|
|
96
|
+
Initialize the VCSelectHandler.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
bot: Discord bot instance
|
|
100
|
+
custom_id: Unique identifier for this handler
|
|
101
|
+
placeholder: Placeholder text for the select menu
|
|
102
|
+
multiselect: Whether to allow multiple selections
|
|
103
|
+
on_select: Callback function when voice channels are selected
|
|
104
|
+
"""
|
|
105
|
+
self.bot: commands.Bot = bot
|
|
106
|
+
self.custom_id = custom_id
|
|
107
|
+
self.placeholder = placeholder
|
|
108
|
+
self.multiselect = multiselect
|
|
109
|
+
self.on_select = on_select
|
|
110
|
+
|
|
111
|
+
def get_custom_id(self) -> str:
|
|
112
|
+
return self.custom_id
|
|
113
|
+
|
|
114
|
+
def get_view(self, guild: discord.Guild, page: int = 1) -> discord.ui.View:
|
|
115
|
+
return get_vc_select(guild, self.custom_id, self.placeholder, page, self.multiselect)
|
|
116
|
+
|
|
117
|
+
async def call(self, inter: discord.Interaction):
|
|
118
|
+
try:
|
|
119
|
+
custom_id: str = inter.data["custom_id"]
|
|
120
|
+
|
|
121
|
+
if custom_id == f"{self.custom_id}_cancel_select":
|
|
122
|
+
await inter.response.edit_message(content="キャンセルしました。", view=None)
|
|
123
|
+
|
|
124
|
+
elif custom_id.startswith(f"{self.custom_id}_next_select_") or custom_id.startswith(f"{self.custom_id}_back_select_"):
|
|
125
|
+
page: int = int(custom_id.split("_")[-1])
|
|
126
|
+
view = self.get_view(inter.guild, page)
|
|
127
|
+
if not view:
|
|
128
|
+
await inter.response.edit_message("ボイスチャンネルが設定されていません。", view=None)
|
|
129
|
+
return
|
|
130
|
+
await inter.response.edit_message(content=f"{self.placeholder}", view=view)
|
|
131
|
+
|
|
132
|
+
elif custom_id.startswith(f"{self.custom_id}_"):
|
|
133
|
+
# セレクトメニューが選択された場合
|
|
134
|
+
if inter.data.get("component_type") == 3: # Select Menu
|
|
135
|
+
selected_ids = inter.data["values"]
|
|
136
|
+
selected_vcs = []
|
|
137
|
+
for vc_id in selected_ids:
|
|
138
|
+
vc = inter.guild.get_channel(int(vc_id))
|
|
139
|
+
if vc and isinstance(vc, discord.VoiceChannel):
|
|
140
|
+
selected_vcs.append(vc)
|
|
141
|
+
|
|
142
|
+
if self.on_select:
|
|
143
|
+
await self.on_select(inter, selected_vcs)
|
|
144
|
+
else:
|
|
145
|
+
vc_names = [vc.name for vc in selected_vcs]
|
|
146
|
+
await inter.response.edit_message(
|
|
147
|
+
content=f"選択されたボイスチャンネル: {', '.join(vc_names)}",
|
|
148
|
+
view=None
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
except Exception:
|
|
152
|
+
traceback.print_exc()
|
|
153
|
+
|
|
154
|
+
# グローバルなハンドラー管理辞書
|
|
155
|
+
_vc_handlers: dict[str, VCSelectHandler] = {}
|
|
156
|
+
|
|
157
|
+
def register_vc_handler(handler: VCSelectHandler):
|
|
158
|
+
"""ハンドラーを登録"""
|
|
159
|
+
_vc_handlers[handler.get_custom_id()] = handler
|
|
160
|
+
|
|
161
|
+
def get_vc_handler(custom_id: str) -> Optional[VCSelectHandler]:
|
|
162
|
+
"""登録されたハンドラーを取得"""
|
|
163
|
+
for handler_id, handler in _vc_handlers.items():
|
|
164
|
+
if custom_id.startswith(handler_id):
|
|
165
|
+
return handler
|
|
166
|
+
return None
|
|
167
|
+
|
|
168
|
+
async def handle_vc_interaction(inter: discord.Interaction):
|
|
169
|
+
"""統一されたインタラクションハンドラー"""
|
|
170
|
+
custom_id = inter.data["custom_id"]
|
|
171
|
+
handler = get_vc_handler(custom_id)
|
|
172
|
+
if handler:
|
|
173
|
+
await handler.call(inter)
|
|
174
|
+
else:
|
|
175
|
+
await inter.response.send_message("ハンドラーが見つかりません。", ephemeral=True)
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import discord
|
|
2
|
+
import traceback
|
|
3
|
+
from typing import Union, Optional
|
|
4
|
+
|
|
5
|
+
async def send_webhook_message(
|
|
6
|
+
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.Thread],
|
|
7
|
+
content: str = None,
|
|
8
|
+
embed: discord.Embed = None,
|
|
9
|
+
embeds: list[discord.Embed] = None,
|
|
10
|
+
username: str = "Webhook Bot",
|
|
11
|
+
avatar_url: str = None,
|
|
12
|
+
file: discord.File = None,
|
|
13
|
+
files: list[discord.File] = None
|
|
14
|
+
) -> Optional[discord.WebhookMessage]:
|
|
15
|
+
"""
|
|
16
|
+
指定されたチャンネルにWebhookメッセージを送信する
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
channel: 送信先チャンネル (TextChannel/VoiceChannel/Thread)
|
|
20
|
+
content: メッセージ内容
|
|
21
|
+
embed: 埋め込み (単体)
|
|
22
|
+
embeds: 埋め込み (複数)
|
|
23
|
+
username: Webhookの表示名
|
|
24
|
+
avatar_url: Webhookのアイコン画像URL
|
|
25
|
+
file: 添付ファイル (単体)
|
|
26
|
+
files: 添付ファイル (複数)
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
WebhookMessage: 送信されたメッセージ (失敗時はNone)
|
|
30
|
+
"""
|
|
31
|
+
try:
|
|
32
|
+
webhook = None
|
|
33
|
+
target_channel = None
|
|
34
|
+
|
|
35
|
+
# チャンネルタイプに応じて処理を分岐
|
|
36
|
+
if isinstance(channel, discord.Thread):
|
|
37
|
+
# スレッドの場合、親チャンネルのWebhookを使用
|
|
38
|
+
target_channel = channel.parent
|
|
39
|
+
if not isinstance(target_channel, (discord.TextChannel, discord.VoiceChannel)):
|
|
40
|
+
print(f"Error: スレッドの親チャンネルが無効です: {target_channel}")
|
|
41
|
+
return None
|
|
42
|
+
elif isinstance(channel, discord.VoiceChannel):
|
|
43
|
+
# VCの場合、VCチャットのWebhookを使用
|
|
44
|
+
target_channel = channel
|
|
45
|
+
elif isinstance(channel, discord.TextChannel):
|
|
46
|
+
# テキストチャンネルの場合
|
|
47
|
+
target_channel = channel
|
|
48
|
+
else:
|
|
49
|
+
print(f"Error: サポートされていないチャンネルタイプです: {type(channel)}")
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
# 既存のWebhookを検索
|
|
53
|
+
webhooks = await target_channel.webhooks()
|
|
54
|
+
for wh in webhooks:
|
|
55
|
+
if wh.name == "MPEventBot Webhook":
|
|
56
|
+
webhook = wh
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
# Webhookが存在しない場合は新規作成
|
|
60
|
+
if not webhook:
|
|
61
|
+
try:
|
|
62
|
+
webhook = await target_channel.create_webhook(
|
|
63
|
+
name="MPEventBot Webhook",
|
|
64
|
+
reason="MPEventBot用のWebhook"
|
|
65
|
+
)
|
|
66
|
+
print(f"新しいWebhookを作成しました: {target_channel.name}")
|
|
67
|
+
except discord.Forbidden:
|
|
68
|
+
print(f"Error: Webhook作成権限がありません: {target_channel.name}")
|
|
69
|
+
return None
|
|
70
|
+
except discord.HTTPException as e:
|
|
71
|
+
print(f"Error: Webhook作成に失敗しました: {e}")
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
# メッセージ送信の準備
|
|
75
|
+
kwargs = {
|
|
76
|
+
"username": username,
|
|
77
|
+
"wait": True # 送信されたメッセージを取得するため
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if avatar_url:
|
|
81
|
+
kwargs["avatar_url"] = avatar_url
|
|
82
|
+
|
|
83
|
+
if content:
|
|
84
|
+
kwargs["content"] = content
|
|
85
|
+
|
|
86
|
+
if embed:
|
|
87
|
+
kwargs["embed"] = embed
|
|
88
|
+
elif embeds:
|
|
89
|
+
kwargs["embeds"] = embeds
|
|
90
|
+
|
|
91
|
+
if file:
|
|
92
|
+
kwargs["file"] = file
|
|
93
|
+
elif files:
|
|
94
|
+
kwargs["files"] = files
|
|
95
|
+
|
|
96
|
+
# スレッドの場合はthread_idを指定
|
|
97
|
+
if isinstance(channel, discord.Thread):
|
|
98
|
+
kwargs["thread"] = channel
|
|
99
|
+
|
|
100
|
+
# メッセージ送信
|
|
101
|
+
message = await webhook.send(**kwargs)
|
|
102
|
+
print(f"Webhookメッセージを送信しました: {target_channel.name}")
|
|
103
|
+
return message
|
|
104
|
+
|
|
105
|
+
except discord.Forbidden:
|
|
106
|
+
print(f"Error: 権限が不足しています: {channel.name if hasattr(channel, 'name') else channel}")
|
|
107
|
+
return None
|
|
108
|
+
except discord.HTTPException as e:
|
|
109
|
+
print(f"Error: HTTP例外が発生しました: {e}")
|
|
110
|
+
return None
|
|
111
|
+
except Exception as e:
|
|
112
|
+
print(f"Error: 予期しないエラーが発生しました: {e}")
|
|
113
|
+
traceback.print_exc()
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
async def send_webhook_message_simple(
|
|
117
|
+
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.Thread],
|
|
118
|
+
content: str,
|
|
119
|
+
username: str = "MPEventBot",
|
|
120
|
+
avatar_url: str = None
|
|
121
|
+
) -> Optional[discord.WebhookMessage]:
|
|
122
|
+
"""
|
|
123
|
+
シンプルなWebhookメッセージ送信 (テキストのみ)
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
channel: 送信先チャンネル
|
|
127
|
+
content: メッセージ内容
|
|
128
|
+
username: Webhookの表示名
|
|
129
|
+
avatar_url: Webhookのアイコン画像URL
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
WebhookMessage: 送信されたメッセージ (失敗時はNone)
|
|
133
|
+
"""
|
|
134
|
+
return await send_webhook_message(
|
|
135
|
+
channel=channel,
|
|
136
|
+
content=content,
|
|
137
|
+
username=username,
|
|
138
|
+
avatar_url=avatar_url
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
async def send_webhook_embed(
|
|
142
|
+
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.Thread],
|
|
143
|
+
embed: discord.Embed,
|
|
144
|
+
username: str = "MPEventBot",
|
|
145
|
+
avatar_url: str = None
|
|
146
|
+
) -> Optional[discord.WebhookMessage]:
|
|
147
|
+
"""
|
|
148
|
+
Embed付きWebhookメッセージ送信
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
channel: 送信先チャンネル
|
|
152
|
+
embed: 埋め込み
|
|
153
|
+
username: Webhookの表示名
|
|
154
|
+
avatar_url: Webhookのアイコン画像URL
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
WebhookMessage: 送信されたメッセージ (失敗時はNone)
|
|
158
|
+
"""
|
|
159
|
+
return await send_webhook_message(
|
|
160
|
+
channel=channel,
|
|
161
|
+
embed=embed,
|
|
162
|
+
username=username,
|
|
163
|
+
avatar_url=avatar_url
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
async def send_webhook_file(
|
|
167
|
+
channel: Union[discord.TextChannel, discord.VoiceChannel, discord.Thread],
|
|
168
|
+
file: discord.File,
|
|
169
|
+
content: str = None,
|
|
170
|
+
username: str = "MPEventBot",
|
|
171
|
+
avatar_url: str = None
|
|
172
|
+
) -> Optional[discord.WebhookMessage]:
|
|
173
|
+
"""
|
|
174
|
+
ファイル付きWebhookメッセージ送信
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
channel: 送信先チャンネル
|
|
178
|
+
file: 添付ファイル
|
|
179
|
+
content: メッセージ内容 (オプション)
|
|
180
|
+
username: Webhookの表示名
|
|
181
|
+
avatar_url: Webhookのアイコン画像URL
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
WebhookMessage: 送信されたメッセージ (失敗時はNone)
|
|
185
|
+
"""
|
|
186
|
+
return await send_webhook_message(
|
|
187
|
+
channel=channel,
|
|
188
|
+
content=content,
|
|
189
|
+
file=file,
|
|
190
|
+
username=username,
|
|
191
|
+
avatar_url=avatar_url
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# 使用例
|
|
195
|
+
"""
|
|
196
|
+
# テキストチャンネルに送信
|
|
197
|
+
channel = bot.get_channel(channel_id)
|
|
198
|
+
await send_webhook_message_simple(
|
|
199
|
+
channel=channel,
|
|
200
|
+
content="こんにちは!",
|
|
201
|
+
username="カスタムBot",
|
|
202
|
+
avatar_url="https://example.com/avatar.png"
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# VCチャットに送信
|
|
206
|
+
vc = bot.get_channel(vc_id)
|
|
207
|
+
await send_webhook_message_simple(
|
|
208
|
+
channel=vc,
|
|
209
|
+
content="VCチャットメッセージ",
|
|
210
|
+
username="VC Bot"
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# スレッドに送信
|
|
214
|
+
thread = channel.get_thread(thread_id)
|
|
215
|
+
await send_webhook_message_simple(
|
|
216
|
+
channel=thread,
|
|
217
|
+
content="スレッドメッセージ",
|
|
218
|
+
username="Thread Bot"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Embed付きで送信
|
|
222
|
+
embed = discord.Embed(title="タイトル", description="説明", color=0x00ff00)
|
|
223
|
+
await send_webhook_embed(
|
|
224
|
+
channel=channel,
|
|
225
|
+
embed=embed,
|
|
226
|
+
username="Embed Bot",
|
|
227
|
+
avatar_url="https://example.com/avatar.png"
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# ファイル付きで送信
|
|
231
|
+
file = discord.File("path/to/file.txt")
|
|
232
|
+
await send_webhook_file(
|
|
233
|
+
channel=channel,
|
|
234
|
+
file=file,
|
|
235
|
+
content="ファイルを送信します",
|
|
236
|
+
username="File Bot"
|
|
237
|
+
)
|
|
238
|
+
"""
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: discord-py-help-lib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A library to assist with Discord.py development
|
|
5
|
+
Home-page: https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
6
|
+
Download-URL: https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
7
|
+
Author: hashimotok
|
|
8
|
+
Author-email: contact@hashimotok.dev
|
|
9
|
+
License: MIT
|
|
10
|
+
Project-URL: Documentation, https://discord-py-help-lib.readthedocs.io/
|
|
11
|
+
Project-URL: Source, https://github.com/hashimotok-ecsv/discord-py-help-lib
|
|
12
|
+
Project-URL: Tracker, https://github.com/hashimotok-ecsv/discord-py-help-lib/issues
|
|
13
|
+
Keywords: discord.py help library
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Requires-Python: >=3.10.6
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: discord.py>=2.5.2
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: download-url
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: keywords
|
|
33
|
+
Dynamic: license
|
|
34
|
+
Dynamic: project-url
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
38
|
+
|
|
39
|
+
# Auxiliary for discord.py Library
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 📦 概要
|
|
48
|
+
|
|
49
|
+
`discord-py-auxiliary-lib` は、discord.pyで役職パネルを簡単に実装するための Python ライブラリです。
|
|
50
|
+
|
|
51
|
+
主な機能は以下のとおりです:
|
|
52
|
+
|
|
53
|
+
- 後日更新
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## ✨ 特徴
|
|
58
|
+
|
|
59
|
+
- ✅ 簡単に使用が可能
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 🔧 インストール
|
|
64
|
+
|
|
65
|
+
### PyPIからインストール:
|
|
66
|
+
```bash
|
|
67
|
+
pip install discord-py-auxiliary-lib
|
|
68
|
+
```
|
|
69
|
+
### githubからインストール:
|
|
70
|
+
```bash
|
|
71
|
+
pip install git+https://github.com/hashimotok-ecsv/discord_py_auxiliary_lib.git
|
|
72
|
+
```
|
|
73
|
+
## 使い方
|
|
74
|
+
```python
|
|
75
|
+
# 後日更新
|
|
76
|
+
```
|
|
77
|
+
#### 管理者用
|
|
78
|
+
##### 更新方法
|
|
79
|
+
```bash
|
|
80
|
+
py setup.py sdist
|
|
81
|
+
py setup.py bdist_wheel
|
|
82
|
+
py -m twine upload --repository testpypi dist/*
|
|
83
|
+
py -m twine upload --repository pypi dist/*
|
|
84
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
discord_py_help_lib/__init__.py
|
|
5
|
+
discord_py_help_lib/webhook_sender.py
|
|
6
|
+
discord_py_help_lib.egg-info/PKG-INFO
|
|
7
|
+
discord_py_help_lib.egg-info/SOURCES.txt
|
|
8
|
+
discord_py_help_lib.egg-info/dependency_links.txt
|
|
9
|
+
discord_py_help_lib.egg-info/entry_points.txt
|
|
10
|
+
discord_py_help_lib.egg-info/not-zip-safe
|
|
11
|
+
discord_py_help_lib.egg-info/requires.txt
|
|
12
|
+
discord_py_help_lib.egg-info/top_level.txt
|
|
13
|
+
discord_py_help_lib/select/category_select.py
|
|
14
|
+
discord_py_help_lib/select/role_select.py
|
|
15
|
+
discord_py_help_lib/select/vc_select.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
discord.py>=2.5.2
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
discord_py_help_lib
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
def derive_version() -> str:
|
|
5
|
+
version = ''
|
|
6
|
+
with open('discord_py_help_lib/__init__.py', encoding='utf-8') as f:
|
|
7
|
+
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1)
|
|
8
|
+
|
|
9
|
+
if not version:
|
|
10
|
+
raise RuntimeError('version is not set')
|
|
11
|
+
|
|
12
|
+
if version.endswith(('a', 'b', 'rc')):
|
|
13
|
+
# append version identifier based on commit count
|
|
14
|
+
try:
|
|
15
|
+
import subprocess
|
|
16
|
+
|
|
17
|
+
p = subprocess.Popen(['git', 'rev-list', '--count', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
18
|
+
out, err = p.communicate()
|
|
19
|
+
if out:
|
|
20
|
+
version += out.decode('utf-8').strip()
|
|
21
|
+
p = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
22
|
+
out, err = p.communicate()
|
|
23
|
+
if out:
|
|
24
|
+
version += '+g' + out.decode('utf-8').strip()
|
|
25
|
+
except Exception:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
return version
|
|
29
|
+
|
|
30
|
+
NAME='discord-py-help-lib'
|
|
31
|
+
|
|
32
|
+
PACKAGES = [
|
|
33
|
+
'discord_py_help_lib',
|
|
34
|
+
'discord_py_help_lib.select'
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
setup(
|
|
38
|
+
name=NAME,
|
|
39
|
+
version=derive_version(),
|
|
40
|
+
packages=PACKAGES,
|
|
41
|
+
install_requires=[
|
|
42
|
+
'discord.py>=2.5.2',
|
|
43
|
+
# Add other dependencies here
|
|
44
|
+
],
|
|
45
|
+
author='hashimotok',
|
|
46
|
+
author_email='contact@hashimotok.dev',
|
|
47
|
+
url=f'https://github.com/hashimotok-ecsv/{NAME}',
|
|
48
|
+
download_url=f'https://github.com/hashimotok-ecsv/{NAME}',
|
|
49
|
+
python_requires=">=3.10.6",
|
|
50
|
+
description='A library to assist with Discord.py development',
|
|
51
|
+
long_description=open('README.md', encoding='utf-8').read(),
|
|
52
|
+
long_description_content_type='text/markdown',
|
|
53
|
+
classifiers=[
|
|
54
|
+
'Development Status :: 5 - Production/Stable',
|
|
55
|
+
'Intended Audience :: Developers',
|
|
56
|
+
'License :: OSI Approved :: MIT License',
|
|
57
|
+
'Programming Language :: Python :: 3.10',
|
|
58
|
+
'Programming Language :: Python :: 3.11',
|
|
59
|
+
'Programming Language :: Python :: 3.12',
|
|
60
|
+
'Operating System :: OS Independent',
|
|
61
|
+
],
|
|
62
|
+
keywords='discord.py help library',
|
|
63
|
+
include_package_data=True,
|
|
64
|
+
zip_safe=False,
|
|
65
|
+
entry_points={
|
|
66
|
+
'console_scripts': [
|
|
67
|
+
'discord-py-help-lib=discord_py_help_lib.__main__:main',
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
project_urls={
|
|
71
|
+
'Documentation': f'https://{NAME}.readthedocs.io/',
|
|
72
|
+
'Source': f'https://github.com/hashimotok-ecsv/{NAME}',
|
|
73
|
+
'Tracker': f'https://github.com/hashimotok-ecsv/{NAME}/issues',
|
|
74
|
+
},
|
|
75
|
+
license='MIT',
|
|
76
|
+
license_files=('LICENSE',),
|
|
77
|
+
)
|