cordscript 1.0.0__py3-none-any.whl
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.
- cordscript/__init__.py +6 -0
- cordscript/client.py +590 -0
- cordscript/core/__init__.py +9 -0
- cordscript/core/context.py +33 -0
- cordscript/core/runtime.py +55 -0
- cordscript/core/variables.py +16 -0
- cordscript/exceptions/__init__.py +3 -0
- cordscript/exceptions/errors.py +9 -0
- cordscript/functions/__init__.py +45 -0
- cordscript/functions/database/__init__.py +4 -0
- cordscript/functions/database/database.py +846 -0
- cordscript/functions/database/store.py +69 -0
- cordscript/functions/discord/__init__.py +15 -0
- cordscript/functions/discord/components.py +134 -0
- cordscript/functions/discord/componentsv2.py +92 -0
- cordscript/functions/discord/embed.py +63 -0
- cordscript/functions/discord/interaction.py +48 -0
- cordscript/functions/discord/logic.py +87 -0
- cordscript/functions/discord/message.py +51 -0
- cordscript/functions/discord/moderation.py +179 -0
- cordscript/functions/discord/status.py +56 -0
- cordscript/functions/users/__init__.py +3 -0
- cordscript/functions/users/user.py +103 -0
- cordscript/functions/utility/__init__.py +14 -0
- cordscript/functions/utility/cooldown.py +35 -0
- cordscript/functions/utility/http.py +73 -0
- cordscript/functions/utility/json.py +201 -0
- cordscript/functions/utility/math.py +102 -0
- cordscript/functions/utility/random.py +27 -0
- cordscript/functions/utility/strings.py +201 -0
- cordscript/functions/utility/time.py +41 -0
- cordscript/parser.py +190 -0
- cordscript/setup.py +38 -0
- cordscript-1.0.0.dist-info/METADATA +17 -0
- cordscript-1.0.0.dist-info/RECORD +37 -0
- cordscript-1.0.0.dist-info/WHEEL +5 -0
- cordscript-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import asyncio
|
|
3
|
+
import re
|
|
4
|
+
import discord
|
|
5
|
+
from datetime import timedelta
|
|
6
|
+
from ...core.context import get_guild
|
|
7
|
+
|
|
8
|
+
_DURATION_PATTERN = re.compile(r"(\d+)\s*([smhdw])", re.IGNORECASE)
|
|
9
|
+
_DURATION_UNITS = {"s": 1, "m": 60, "h": 3600, "d": 86400, "w": 604800}
|
|
10
|
+
|
|
11
|
+
_PENDING_UNBANS: dict[tuple[int, int], asyncio.Task] = {}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _parse_duration(text: str) -> int | None:
|
|
15
|
+
if not text or not text.strip():
|
|
16
|
+
return None
|
|
17
|
+
matches = _DURATION_PATTERN.findall(text.strip())
|
|
18
|
+
if not matches:
|
|
19
|
+
return None
|
|
20
|
+
total = 0
|
|
21
|
+
for value, unit in matches:
|
|
22
|
+
total += int(value) * _DURATION_UNITS[unit.lower()]
|
|
23
|
+
return total if total > 0 else None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _cancel_pending_unban(guild_id: int, user_id: int):
|
|
27
|
+
task = _PENDING_UNBANS.pop((guild_id, user_id), None)
|
|
28
|
+
if task and not task.done():
|
|
29
|
+
task.cancel()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _schedule_unban(guild, user_id: int, delay: int):
|
|
33
|
+
_cancel_pending_unban(guild.id, user_id)
|
|
34
|
+
|
|
35
|
+
async def _runner():
|
|
36
|
+
try:
|
|
37
|
+
await asyncio.sleep(delay)
|
|
38
|
+
await guild.unban(discord.Object(id=user_id), reason="Tempo de banimento expirado")
|
|
39
|
+
except asyncio.CancelledError:
|
|
40
|
+
pass
|
|
41
|
+
except discord.NotFound:
|
|
42
|
+
pass
|
|
43
|
+
except Exception as e:
|
|
44
|
+
print(f"[cordscript] Failed to auto-unban {user_id}: {e}")
|
|
45
|
+
finally:
|
|
46
|
+
_PENDING_UNBANS.pop((guild.id, user_id), None)
|
|
47
|
+
|
|
48
|
+
_PENDING_UNBANS[(guild.id, user_id)] = asyncio.create_task(_runner())
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async def handle_moderation(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
52
|
+
if fn not in ("ban", "unban", "kick", "timeout", "untimeout"):
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
guild = get_guild(parser.ctx)
|
|
56
|
+
if guild is None:
|
|
57
|
+
return f"[Error in ${fn}: no guild in this context]"
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
match fn:
|
|
61
|
+
case "ban":
|
|
62
|
+
user_id = args[0].strip() if args else ""
|
|
63
|
+
reason = args[1] if len(args) > 1 and args[1].strip() else None
|
|
64
|
+
duration_raw = args[2] if len(args) > 2 else ""
|
|
65
|
+
if not user_id:
|
|
66
|
+
return "[Error in $ban: user id required]"
|
|
67
|
+
try:
|
|
68
|
+
uid = int(user_id)
|
|
69
|
+
except ValueError:
|
|
70
|
+
return "[Error in $ban: invalid user id]"
|
|
71
|
+
duration = _parse_duration(duration_raw)
|
|
72
|
+
if duration_raw.strip() and duration is None:
|
|
73
|
+
return "[Error in $ban: invalid time format, use e.g. 7s, 1m, 10h, 1d]"
|
|
74
|
+
try:
|
|
75
|
+
await guild.ban(discord.Object(id=uid), reason=reason)
|
|
76
|
+
except discord.Forbidden:
|
|
77
|
+
return "[Error in $ban: missing permissions]"
|
|
78
|
+
except discord.HTTPException as e:
|
|
79
|
+
return f"[Error in $ban: {e}]"
|
|
80
|
+
if duration:
|
|
81
|
+
_schedule_unban(guild, uid, duration)
|
|
82
|
+
return ""
|
|
83
|
+
|
|
84
|
+
case "unban":
|
|
85
|
+
user_id = args[0].strip() if args else ""
|
|
86
|
+
reason = args[1] if len(args) > 1 and args[1].strip() else None
|
|
87
|
+
if not user_id:
|
|
88
|
+
return "[Error in $unban: user id required]"
|
|
89
|
+
try:
|
|
90
|
+
uid = int(user_id)
|
|
91
|
+
except ValueError:
|
|
92
|
+
return "[Error in $unban: invalid user id]"
|
|
93
|
+
_cancel_pending_unban(guild.id, uid)
|
|
94
|
+
try:
|
|
95
|
+
await guild.unban(discord.Object(id=uid), reason=reason)
|
|
96
|
+
except discord.Forbidden:
|
|
97
|
+
return "[Error in $unban: missing permissions]"
|
|
98
|
+
except discord.NotFound:
|
|
99
|
+
return "[Error in $unban: user is not banned]"
|
|
100
|
+
except discord.HTTPException as e:
|
|
101
|
+
return f"[Error in $unban: {e}]"
|
|
102
|
+
return ""
|
|
103
|
+
|
|
104
|
+
case "kick":
|
|
105
|
+
user_id = args[0].strip() if args else ""
|
|
106
|
+
reason = args[1] if len(args) > 1 and args[1].strip() else None
|
|
107
|
+
if not user_id:
|
|
108
|
+
return "[Error in $kick: user id required]"
|
|
109
|
+
try:
|
|
110
|
+
uid = int(user_id)
|
|
111
|
+
except ValueError:
|
|
112
|
+
return "[Error in $kick: invalid user id]"
|
|
113
|
+
member = guild.get_member(uid)
|
|
114
|
+
if member is None:
|
|
115
|
+
try:
|
|
116
|
+
member = await guild.fetch_member(uid)
|
|
117
|
+
except discord.NotFound:
|
|
118
|
+
return "[Error in $kick: member not found]"
|
|
119
|
+
try:
|
|
120
|
+
await guild.kick(member, reason=reason)
|
|
121
|
+
except discord.Forbidden:
|
|
122
|
+
return "[Error in $kick: missing permissions]"
|
|
123
|
+
except discord.HTTPException as e:
|
|
124
|
+
return f"[Error in $kick: {e}]"
|
|
125
|
+
return ""
|
|
126
|
+
|
|
127
|
+
case "timeout":
|
|
128
|
+
user_id = args[0].strip() if args else ""
|
|
129
|
+
reason = args[1] if len(args) > 1 and args[1].strip() else None
|
|
130
|
+
duration_raw = args[2] if len(args) > 2 else ""
|
|
131
|
+
if not user_id:
|
|
132
|
+
return "[Error in $timeout: user id required]"
|
|
133
|
+
duration = _parse_duration(duration_raw)
|
|
134
|
+
if duration is None:
|
|
135
|
+
return "[Error in $timeout: invalid or missing time, use e.g. 7s, 1m, 10h, 1d]"
|
|
136
|
+
try:
|
|
137
|
+
uid = int(user_id)
|
|
138
|
+
except ValueError:
|
|
139
|
+
return "[Error in $timeout: invalid user id]"
|
|
140
|
+
member = guild.get_member(uid)
|
|
141
|
+
if member is None:
|
|
142
|
+
try:
|
|
143
|
+
member = await guild.fetch_member(uid)
|
|
144
|
+
except discord.NotFound:
|
|
145
|
+
return "[Error in $timeout: member not found]"
|
|
146
|
+
try:
|
|
147
|
+
until = discord.utils.utcnow() + timedelta(seconds=duration)
|
|
148
|
+
await member.timeout(until, reason=reason)
|
|
149
|
+
except discord.Forbidden:
|
|
150
|
+
return "[Error in $timeout: missing permissions]"
|
|
151
|
+
except discord.HTTPException as e:
|
|
152
|
+
return f"[Error in $timeout: {e}]"
|
|
153
|
+
return ""
|
|
154
|
+
|
|
155
|
+
case "untimeout":
|
|
156
|
+
user_id = args[0].strip() if args else ""
|
|
157
|
+
reason = args[1] if len(args) > 1 and args[1].strip() else None
|
|
158
|
+
if not user_id:
|
|
159
|
+
return "[Error in $untimeout: user id required]"
|
|
160
|
+
try:
|
|
161
|
+
uid = int(user_id)
|
|
162
|
+
except ValueError:
|
|
163
|
+
return "[Error in $untimeout: invalid user id]"
|
|
164
|
+
member = guild.get_member(uid)
|
|
165
|
+
if member is None:
|
|
166
|
+
try:
|
|
167
|
+
member = await guild.fetch_member(uid)
|
|
168
|
+
except discord.NotFound:
|
|
169
|
+
return "[Error in $untimeout: member not found]"
|
|
170
|
+
try:
|
|
171
|
+
await member.timeout(None, reason=reason)
|
|
172
|
+
except discord.Forbidden:
|
|
173
|
+
return "[Error in $untimeout: missing permissions]"
|
|
174
|
+
except discord.HTTPException as e:
|
|
175
|
+
return f"[Error in $untimeout: {e}]"
|
|
176
|
+
return ""
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import discord
|
|
3
|
+
|
|
4
|
+
_STATUS_MAP = {
|
|
5
|
+
"online": discord.Status.online,
|
|
6
|
+
"idle": discord.Status.idle,
|
|
7
|
+
"dnd": discord.Status.dnd,
|
|
8
|
+
"invisible": discord.Status.invisible,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
_TYPE_MAP = {
|
|
12
|
+
"competing": discord.ActivityType.competing,
|
|
13
|
+
"watching": discord.ActivityType.watching,
|
|
14
|
+
"listening": discord.ActivityType.listening,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def handle_status(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
19
|
+
if fn != "setstatus":
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
presence_raw = args[0].strip().lower() if len(args) > 0 else ""
|
|
23
|
+
type_raw = args[1].strip().lower() if len(args) > 1 else ""
|
|
24
|
+
name = args[2] if len(args) > 2 else ""
|
|
25
|
+
state = args[3] if len(args) > 3 and args[3].strip() else None
|
|
26
|
+
url = args[4].strip() if len(args) > 4 and args[4].strip() else None
|
|
27
|
+
|
|
28
|
+
status = _STATUS_MAP.get(presence_raw)
|
|
29
|
+
if status is None:
|
|
30
|
+
return "[Error in $setStatus: invalid presence, use online, idle, dnd or invisible]"
|
|
31
|
+
|
|
32
|
+
if type_raw not in ("competing", "custom", "watching", "streaming", "listening"):
|
|
33
|
+
return "[Error in $setStatus: invalid type, use competing, custom, watching, streaming or listening]"
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
if type_raw == "custom":
|
|
37
|
+
text = state or name
|
|
38
|
+
if not text:
|
|
39
|
+
return "[Error in $setStatus: name or state required for custom]"
|
|
40
|
+
activity = discord.CustomActivity(name=text)
|
|
41
|
+
elif type_raw == "streaming":
|
|
42
|
+
if not name or not url:
|
|
43
|
+
return "[Error in $setStatus: name and url required for streaming]"
|
|
44
|
+
activity = discord.Streaming(name=name, url=url)
|
|
45
|
+
else:
|
|
46
|
+
if not name:
|
|
47
|
+
return "[Error in $setStatus: name required]"
|
|
48
|
+
activity = discord.Activity(type=_TYPE_MAP[type_raw], name=name, state=state)
|
|
49
|
+
|
|
50
|
+
await parser.client.change_presence(status=status, activity=activity)
|
|
51
|
+
except discord.HTTPException as e:
|
|
52
|
+
return f"[Error in $setStatus: {e}]"
|
|
53
|
+
except Exception as e:
|
|
54
|
+
return f"[Unexpected error in $setStatus: {e}]"
|
|
55
|
+
|
|
56
|
+
return ""
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from ...core.context import get_author, get_author_id, get_guild
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _resolve_member(parser, args, index=0):
|
|
6
|
+
guild = get_guild(parser.ctx)
|
|
7
|
+
if len(args) > index and args[index].strip():
|
|
8
|
+
target = args[index].strip()
|
|
9
|
+
if guild and target.isdigit():
|
|
10
|
+
member = guild.get_member(int(target))
|
|
11
|
+
if member:
|
|
12
|
+
return member
|
|
13
|
+
return None
|
|
14
|
+
return get_author(parser.ctx)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def handle_user(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
18
|
+
try:
|
|
19
|
+
match fn:
|
|
20
|
+
case "authorid":
|
|
21
|
+
return get_author_id(parser.ctx)
|
|
22
|
+
|
|
23
|
+
case "author":
|
|
24
|
+
user = get_author(parser.ctx)
|
|
25
|
+
return str(user) if user else ""
|
|
26
|
+
|
|
27
|
+
case "username":
|
|
28
|
+
user = get_author(parser.ctx)
|
|
29
|
+
return user.name if user else ""
|
|
30
|
+
|
|
31
|
+
case "nickname":
|
|
32
|
+
user = _resolve_member(parser, args)
|
|
33
|
+
if user is None:
|
|
34
|
+
return ""
|
|
35
|
+
return getattr(user, "display_name", getattr(user, "name", ""))
|
|
36
|
+
|
|
37
|
+
case "mention":
|
|
38
|
+
user = _resolve_member(parser, args)
|
|
39
|
+
return user.mention if user else ""
|
|
40
|
+
|
|
41
|
+
case "avatar" | "useravatar":
|
|
42
|
+
user = _resolve_member(parser, args)
|
|
43
|
+
if user is None:
|
|
44
|
+
return ""
|
|
45
|
+
avatar = getattr(user, "display_avatar", None)
|
|
46
|
+
return str(avatar.url) if avatar else ""
|
|
47
|
+
|
|
48
|
+
case "tag" | "usertag":
|
|
49
|
+
user = _resolve_member(parser, args)
|
|
50
|
+
return str(user) if user else ""
|
|
51
|
+
|
|
52
|
+
case "isbot":
|
|
53
|
+
user = _resolve_member(parser, args)
|
|
54
|
+
return "true" if (user and getattr(user, "bot", False)) else "false"
|
|
55
|
+
|
|
56
|
+
case "userid":
|
|
57
|
+
user = _resolve_member(parser, args)
|
|
58
|
+
return str(user.id) if user else ""
|
|
59
|
+
|
|
60
|
+
case "joinedat":
|
|
61
|
+
user = _resolve_member(parser, args)
|
|
62
|
+
joined = getattr(user, "joined_at", None) if user else None
|
|
63
|
+
return str(int(joined.timestamp())) if joined else ""
|
|
64
|
+
|
|
65
|
+
case "createdat":
|
|
66
|
+
user = _resolve_member(parser, args)
|
|
67
|
+
created = getattr(user, "created_at", None) if user else None
|
|
68
|
+
return str(int(created.timestamp())) if created else ""
|
|
69
|
+
|
|
70
|
+
case "hasrole":
|
|
71
|
+
role_id = args[0].strip() if args else ""
|
|
72
|
+
user = _resolve_member(parser, args, index=1)
|
|
73
|
+
if not user or not role_id:
|
|
74
|
+
return "false"
|
|
75
|
+
roles = getattr(user, "roles", [])
|
|
76
|
+
return "true" if any(str(r.id) == role_id for r in roles) else "false"
|
|
77
|
+
|
|
78
|
+
case "highestrole":
|
|
79
|
+
user = _resolve_member(parser, args)
|
|
80
|
+
if not user:
|
|
81
|
+
return ""
|
|
82
|
+
roles = [r for r in getattr(user, "roles", []) if r.name != "@everyone"]
|
|
83
|
+
if not roles:
|
|
84
|
+
return ""
|
|
85
|
+
return max(roles, key=lambda r: r.position).name
|
|
86
|
+
|
|
87
|
+
case "membercount" | "guildmembercount":
|
|
88
|
+
guild = get_guild(parser.ctx)
|
|
89
|
+
return str(guild.member_count) if guild else ""
|
|
90
|
+
|
|
91
|
+
case "guildname" | "servername":
|
|
92
|
+
guild = get_guild(parser.ctx)
|
|
93
|
+
return guild.name if guild else ""
|
|
94
|
+
|
|
95
|
+
case "guildid" | "serverid":
|
|
96
|
+
guild = get_guild(parser.ctx)
|
|
97
|
+
return str(guild.id) if guild else ""
|
|
98
|
+
|
|
99
|
+
case _:
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .math import handle_math, safe_math
|
|
2
|
+
from .time import handle_time
|
|
3
|
+
from .random import handle_random
|
|
4
|
+
from .http import handle_http
|
|
5
|
+
from .cooldown import handle_cooldown
|
|
6
|
+
from .json import handle_json
|
|
7
|
+
from .strings import handle_strings
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"handle_math", "safe_math",
|
|
11
|
+
"handle_time", "handle_random",
|
|
12
|
+
"handle_http", "handle_cooldown",
|
|
13
|
+
"handle_json", "handle_strings",
|
|
14
|
+
]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time as time_module
|
|
3
|
+
from ...exceptions import CooldownError
|
|
4
|
+
from ...core.context import get_author_id
|
|
5
|
+
|
|
6
|
+
_COOLDOWNS: dict[str, float] = {}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def handle_cooldown(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
10
|
+
try:
|
|
11
|
+
match fn:
|
|
12
|
+
case "cooldown":
|
|
13
|
+
try:
|
|
14
|
+
seconds = float(args[0].strip()) if args and args[0].strip() else 0
|
|
15
|
+
except ValueError:
|
|
16
|
+
return f"[Error in $cooldown: invalid duration]"
|
|
17
|
+
msg = args[1] if len(args) > 1 else ""
|
|
18
|
+
uid = get_author_id(parser.ctx)
|
|
19
|
+
cmd = getattr(parser, "_command_name", "unknown")
|
|
20
|
+
key = f"{uid}:{cmd}"
|
|
21
|
+
now = time_module.monotonic()
|
|
22
|
+
last = _COOLDOWNS.get(key, 0)
|
|
23
|
+
remaining = seconds - (now - last)
|
|
24
|
+
if remaining > 0:
|
|
25
|
+
raise CooldownError(msg or f"{round(remaining, 1)}s")
|
|
26
|
+
_COOLDOWNS[key] = now
|
|
27
|
+
return ""
|
|
28
|
+
|
|
29
|
+
case _:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
except CooldownError:
|
|
33
|
+
raise
|
|
34
|
+
except Exception as e:
|
|
35
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import json
|
|
3
|
+
import aiohttp
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def handle_http(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
7
|
+
try:
|
|
8
|
+
match fn:
|
|
9
|
+
case "httprequest" | "http":
|
|
10
|
+
url = args[0].strip() if args else ""
|
|
11
|
+
method = args[1].strip().upper() if len(args) > 1 and args[1].strip() else "GET"
|
|
12
|
+
body = args[2] if len(args) > 2 and args[2].strip() else None
|
|
13
|
+
headers_raw = args[3] if len(args) > 3 and args[3].strip() else None
|
|
14
|
+
key = args[4].strip() if len(args) > 4 and args[4].strip() else None
|
|
15
|
+
if not url:
|
|
16
|
+
return f"[Error in $http: URL required]"
|
|
17
|
+
try:
|
|
18
|
+
headers = json.loads(headers_raw) if headers_raw else {}
|
|
19
|
+
async with aiohttp.ClientSession() as session:
|
|
20
|
+
kwargs: dict = {"headers": headers}
|
|
21
|
+
if body:
|
|
22
|
+
try:
|
|
23
|
+
kwargs["json"] = json.loads(body)
|
|
24
|
+
except Exception:
|
|
25
|
+
kwargs["data"] = body
|
|
26
|
+
resp = await getattr(session, method.lower())(url, **kwargs)
|
|
27
|
+
text = await resp.text()
|
|
28
|
+
if key:
|
|
29
|
+
try:
|
|
30
|
+
parsed = json.loads(text)
|
|
31
|
+
keys = key.split(".")
|
|
32
|
+
val = parsed
|
|
33
|
+
for k in keys:
|
|
34
|
+
if isinstance(val, list):
|
|
35
|
+
val = val[int(k)]
|
|
36
|
+
else:
|
|
37
|
+
val = val[k]
|
|
38
|
+
return json.dumps(val) if isinstance(val, (dict, list)) else str(val)
|
|
39
|
+
except Exception as e:
|
|
40
|
+
return f"[Error in $http: key parse failed — {e}]"
|
|
41
|
+
return text
|
|
42
|
+
except Exception as e:
|
|
43
|
+
return f"[Error in $http: {e}]"
|
|
44
|
+
|
|
45
|
+
case "httpstatus":
|
|
46
|
+
url = args[0].strip() if args else ""
|
|
47
|
+
method = args[1].strip().upper() if len(args) > 1 and args[1].strip() else "GET"
|
|
48
|
+
if not url:
|
|
49
|
+
return f"[Error in $httpStatus: URL required]"
|
|
50
|
+
try:
|
|
51
|
+
async with aiohttp.ClientSession() as session:
|
|
52
|
+
resp = await getattr(session, method.lower())(url)
|
|
53
|
+
return str(resp.status)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
return f"[Error in $httpStatus: {e}]"
|
|
56
|
+
|
|
57
|
+
case "httpheader":
|
|
58
|
+
url = args[0].strip() if args else ""
|
|
59
|
+
header = args[1].strip() if len(args) > 1 else ""
|
|
60
|
+
if not url or not header:
|
|
61
|
+
return f"[Error in $httpHeader: URL and header name required]"
|
|
62
|
+
try:
|
|
63
|
+
async with aiohttp.ClientSession() as session:
|
|
64
|
+
resp = await session.get(url)
|
|
65
|
+
return resp.headers.get(header, "")
|
|
66
|
+
except Exception as e:
|
|
67
|
+
return f"[Error in $httpHeader: {e}]"
|
|
68
|
+
|
|
69
|
+
case _:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
except Exception as e:
|
|
73
|
+
return f"[Unexpected error in ${fn}: {e}]"
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import json as _json
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
async def handle_json(fn: str, args: list[str], raw: str, parser) -> str | None:
|
|
6
|
+
try:
|
|
7
|
+
match fn:
|
|
8
|
+
case "jsonparse":
|
|
9
|
+
raw_json = args[0] if args else ""
|
|
10
|
+
key = args[1].strip() if len(args) > 1 and args[1].strip() else None
|
|
11
|
+
try:
|
|
12
|
+
parsed = _json.loads(raw_json)
|
|
13
|
+
if key is None:
|
|
14
|
+
return _json.dumps(parsed)
|
|
15
|
+
keys = key.split(".")
|
|
16
|
+
val = parsed
|
|
17
|
+
for k in keys:
|
|
18
|
+
val = val[int(k)] if isinstance(val, list) else val[k]
|
|
19
|
+
return _json.dumps(val) if isinstance(val, (dict, list)) else str(val)
|
|
20
|
+
except Exception as e:
|
|
21
|
+
return f"[Error in $jsonParse: {e}]"
|
|
22
|
+
|
|
23
|
+
case "jsonset":
|
|
24
|
+
raw_json = args[0] if args else "{}"
|
|
25
|
+
key = args[1].strip() if len(args) > 1 else ""
|
|
26
|
+
value = args[2] if len(args) > 2 else ""
|
|
27
|
+
try:
|
|
28
|
+
parsed = _json.loads(raw_json)
|
|
29
|
+
keys = key.split(".")
|
|
30
|
+
obj = parsed
|
|
31
|
+
for k in keys[:-1]:
|
|
32
|
+
obj = obj[k]
|
|
33
|
+
try:
|
|
34
|
+
obj[keys[-1]] = _json.loads(value)
|
|
35
|
+
except Exception:
|
|
36
|
+
obj[keys[-1]] = value
|
|
37
|
+
return _json.dumps(parsed)
|
|
38
|
+
except Exception as e:
|
|
39
|
+
return f"[Error in $jsonSet: {e}]"
|
|
40
|
+
|
|
41
|
+
case "jsonkeys":
|
|
42
|
+
try:
|
|
43
|
+
return _json.dumps(list(_json.loads(args[0] if args else "{}").keys()))
|
|
44
|
+
except Exception as e:
|
|
45
|
+
return f"[Error in $jsonKeys: {e}]"
|
|
46
|
+
|
|
47
|
+
case "jsonvalues":
|
|
48
|
+
try:
|
|
49
|
+
return _json.dumps(list(_json.loads(args[0] if args else "{}").values()))
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return f"[Error in $jsonValues: {e}]"
|
|
52
|
+
|
|
53
|
+
case "jsondelete":
|
|
54
|
+
raw_json = args[0] if args else "{}"
|
|
55
|
+
key = args[1].strip() if len(args) > 1 else ""
|
|
56
|
+
try:
|
|
57
|
+
parsed = _json.loads(raw_json)
|
|
58
|
+
keys = key.split(".")
|
|
59
|
+
obj = parsed
|
|
60
|
+
for k in keys[:-1]:
|
|
61
|
+
obj = obj[k]
|
|
62
|
+
del obj[keys[-1]]
|
|
63
|
+
return _json.dumps(parsed)
|
|
64
|
+
except Exception as e:
|
|
65
|
+
return f"[Error in $jsonDelete: {e}]"
|
|
66
|
+
|
|
67
|
+
case "arraycreate":
|
|
68
|
+
return _json.dumps(list(args))
|
|
69
|
+
|
|
70
|
+
case "arraypush":
|
|
71
|
+
raw_arr = args[0] if args else "[]"
|
|
72
|
+
value = args[1] if len(args) > 1 else ""
|
|
73
|
+
try:
|
|
74
|
+
arr = _json.loads(raw_arr)
|
|
75
|
+
try:
|
|
76
|
+
arr.append(_json.loads(value))
|
|
77
|
+
except Exception:
|
|
78
|
+
arr.append(value)
|
|
79
|
+
return _json.dumps(arr)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
return f"[Error in $arrayPush: {e}]"
|
|
82
|
+
|
|
83
|
+
case "arraypop":
|
|
84
|
+
try:
|
|
85
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
86
|
+
arr.pop()
|
|
87
|
+
return _json.dumps(arr)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
return f"[Error in $arrayPop: {e}]"
|
|
90
|
+
|
|
91
|
+
case "arrayshift":
|
|
92
|
+
try:
|
|
93
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
94
|
+
arr.pop(0)
|
|
95
|
+
return _json.dumps(arr)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
return f"[Error in $arrayShift: {e}]"
|
|
98
|
+
|
|
99
|
+
case "arrayget":
|
|
100
|
+
try:
|
|
101
|
+
index = int(args[1].strip()) - 1 if len(args) > 1 else 0
|
|
102
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
103
|
+
val = arr[index]
|
|
104
|
+
return _json.dumps(val) if isinstance(val, (dict, list)) else str(val)
|
|
105
|
+
except Exception as e:
|
|
106
|
+
return f"[Error in $arrayGet: {e}]"
|
|
107
|
+
|
|
108
|
+
case "arrayset":
|
|
109
|
+
try:
|
|
110
|
+
index = int(args[1].strip()) - 1 if len(args) > 1 else 0
|
|
111
|
+
value = args[2] if len(args) > 2 else ""
|
|
112
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
113
|
+
try:
|
|
114
|
+
arr[index] = _json.loads(value)
|
|
115
|
+
except Exception:
|
|
116
|
+
arr[index] = value
|
|
117
|
+
return _json.dumps(arr)
|
|
118
|
+
except Exception as e:
|
|
119
|
+
return f"[Error in $arraySet: {e}]"
|
|
120
|
+
|
|
121
|
+
case "arrayremove":
|
|
122
|
+
try:
|
|
123
|
+
index = int(args[1].strip()) - 1 if len(args) > 1 else 0
|
|
124
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
125
|
+
arr.pop(index)
|
|
126
|
+
return _json.dumps(arr)
|
|
127
|
+
except Exception as e:
|
|
128
|
+
return f"[Error in $arrayRemove: {e}]"
|
|
129
|
+
|
|
130
|
+
case "arrayincludes":
|
|
131
|
+
try:
|
|
132
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
133
|
+
value = args[1] if len(args) > 1 else ""
|
|
134
|
+
try:
|
|
135
|
+
val = _json.loads(value)
|
|
136
|
+
except Exception:
|
|
137
|
+
val = value
|
|
138
|
+
return "true" if val in arr else "false"
|
|
139
|
+
except Exception as e:
|
|
140
|
+
return f"[Error in $arrayIncludes: {e}]"
|
|
141
|
+
|
|
142
|
+
case "arraylength":
|
|
143
|
+
try:
|
|
144
|
+
return str(len(_json.loads(args[0] if args else "[]")))
|
|
145
|
+
except Exception as e:
|
|
146
|
+
return f"[Error in $arrayLength: {e}]"
|
|
147
|
+
|
|
148
|
+
case "arrayjoin":
|
|
149
|
+
sep = args[1] if len(args) > 1 else ","
|
|
150
|
+
try:
|
|
151
|
+
return sep.join(str(x) for x in _json.loads(args[0] if args else "[]"))
|
|
152
|
+
except Exception as e:
|
|
153
|
+
return f"[Error in $arrayJoin: {e}]"
|
|
154
|
+
|
|
155
|
+
case "arraysort":
|
|
156
|
+
order = args[1].strip().lower() if len(args) > 1 else "asc"
|
|
157
|
+
try:
|
|
158
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
159
|
+
arr.sort(reverse=(order == "desc"))
|
|
160
|
+
return _json.dumps(arr)
|
|
161
|
+
except Exception as e:
|
|
162
|
+
return f"[Error in $arraySort: {e}]"
|
|
163
|
+
|
|
164
|
+
case "arrayreverse":
|
|
165
|
+
try:
|
|
166
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
167
|
+
arr.reverse()
|
|
168
|
+
return _json.dumps(arr)
|
|
169
|
+
except Exception as e:
|
|
170
|
+
return f"[Error in $arrayReverse: {e}]"
|
|
171
|
+
|
|
172
|
+
case "arrayfind":
|
|
173
|
+
try:
|
|
174
|
+
arr = _json.loads(args[0] if args else "[]")
|
|
175
|
+
value = args[1] if len(args) > 1 else ""
|
|
176
|
+
try:
|
|
177
|
+
val = _json.loads(value)
|
|
178
|
+
except Exception:
|
|
179
|
+
val = value
|
|
180
|
+
return str(arr.index(val) + 1) if val in arr else "-1"
|
|
181
|
+
except Exception as e:
|
|
182
|
+
return f"[Error in $arrayFind: {e}]"
|
|
183
|
+
|
|
184
|
+
case "arrayfromjson":
|
|
185
|
+
raw_json = args[0] if args else "{}"
|
|
186
|
+
key = args[1].strip() if len(args) > 1 else ""
|
|
187
|
+
try:
|
|
188
|
+
parsed = _json.loads(raw_json)
|
|
189
|
+
if key:
|
|
190
|
+
for k in key.split("."):
|
|
191
|
+
parsed = parsed[k]
|
|
192
|
+
return _json.dumps(parsed if isinstance(parsed, list) else list(parsed))
|
|
193
|
+
return _json.dumps(list(parsed.values()))
|
|
194
|
+
except Exception as e:
|
|
195
|
+
return f"[Error in $arrayFromJson: {e}]"
|
|
196
|
+
|
|
197
|
+
case _:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
return f"[Unexpected error in ${fn}: {e}]"
|