Skip to content

Commit d940af4

Browse files
wyf9Copilot
andcommitted
fix: voice / video messges forwarded to qq will not send header
Co-authored-by: Copilot <copilot@github.com>
1 parent 6ae88af commit d940af4

2 files changed

Lines changed: 1171 additions & 1112 deletions

File tree

drivers/qq.py

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,7 +1069,7 @@ async def _resolve_forward_file_download_url(
10691069
action_candidates.append(("get_file", {"file_id": file_id}))
10701070

10711071
for action, params in action_candidates:
1072-
response = await self._call(action, params, timeout=12.0)
1072+
response = await self._call(action, params, timeout=12.0, retries=2)
10731073
if not response or response.get("status") != "ok":
10741074
continue
10751075

@@ -1652,7 +1652,12 @@ async def _render_forward_segment(
16521652
f"NapCat [{self.instance_id}] rendering forward segment id={forward_id}"
16531653
)
16541654

1655-
response = await self._call("get_forward_msg", {"id": forward_id}, timeout=30.0)
1655+
response = await self._call(
1656+
"get_forward_msg",
1657+
{"id": forward_id},
1658+
timeout=30.0,
1659+
retries=2,
1660+
)
16561661
if not response or response.get("status") != "ok":
16571662
logger.warning(
16581663
f"NapCat [{self.instance_id}] get_forward_msg failed for id={forward_id}: {response}"
@@ -1727,26 +1732,53 @@ def _resolve_send_mode(self, size: int) -> str:
17271732
return self.config.file_send_mode
17281733

17291734
async def _call(
1730-
self, action: str, params: dict, timeout: float = 30.0
1735+
self,
1736+
action: str,
1737+
params: dict,
1738+
timeout: float = 30.0,
1739+
retries: int = 0,
17311740
) -> dict | None:
17321741
"""Send a OneBot action and await its echo response."""
17331742
if self._ws is None:
17341743
return None
1735-
echo = str(uuid.uuid4())
1736-
fut: asyncio.Future = asyncio.get_event_loop().create_future()
1737-
self._pending[echo] = fut
1738-
payload = {"action": action, "params": params, "echo": echo}
1739-
try:
1740-
await self._ws.send(json.dumps(payload, ensure_ascii=False))
1741-
return await asyncio.wait_for(fut, timeout=timeout)
1742-
except TimeoutError:
1743-
logger.warning(f"NapCat [{self.instance_id}] action '{action}' timed out")
1744-
self._pending.pop(echo, None)
1745-
return None
1746-
except Exception as e:
1747-
logger.error(f"NapCat [{self.instance_id}] action '{action}' error: {e}")
1748-
self._pending.pop(echo, None)
1749-
return None
1744+
max_attempts = max(1, int(retries) + 1)
1745+
1746+
for attempt in range(1, max_attempts + 1):
1747+
echo = str(uuid.uuid4())
1748+
fut: asyncio.Future = asyncio.get_event_loop().create_future()
1749+
self._pending[echo] = fut
1750+
payload = {"action": action, "params": params, "echo": echo}
1751+
try:
1752+
await self._ws.send(json.dumps(payload, ensure_ascii=False))
1753+
return await asyncio.wait_for(fut, timeout=timeout)
1754+
except TimeoutError:
1755+
self._pending.pop(echo, None)
1756+
if attempt >= max_attempts:
1757+
logger.warning(
1758+
f"NapCat [{self.instance_id}] action '{action}' timed out "
1759+
f"after {attempt} attempt(s)"
1760+
)
1761+
return None
1762+
logger.warning(
1763+
f"NapCat [{self.instance_id}] action '{action}' timed out, "
1764+
f"retrying ({attempt}/{max_attempts - 1})"
1765+
)
1766+
await asyncio.sleep(min(2.0, 0.3 * (2 ** (attempt - 1))))
1767+
except Exception as e:
1768+
self._pending.pop(echo, None)
1769+
if attempt >= max_attempts:
1770+
logger.error(
1771+
f"NapCat [{self.instance_id}] action '{action}' error "
1772+
f"after {attempt} attempt(s): {e}"
1773+
)
1774+
return None
1775+
logger.warning(
1776+
f"NapCat [{self.instance_id}] action '{action}' error, "
1777+
f"retrying ({attempt}/{max_attempts - 1}): {e}"
1778+
)
1779+
await asyncio.sleep(min(2.0, 0.3 * (2 ** (attempt - 1))))
1780+
1781+
return None
17501782

17511783
async def _get_qid(self, user_id: str, group_id: str | None = None) -> str:
17521784
"""Get user's qid using NapCat API with caching."""
@@ -1757,7 +1789,10 @@ async def _get_qid(self, user_id: str, group_id: str | None = None) -> str:
17571789
try:
17581790
# Use get_stranger_info to get qid
17591791
result = await self._call(
1760-
"get_stranger_info", {"user_id": user_id}, timeout=30.0
1792+
"get_stranger_info",
1793+
{"user_id": user_id},
1794+
timeout=30.0,
1795+
retries=2,
17611796
)
17621797
# logger.debug(
17631798
# f"NapCat [{self.instance_id}] get_stranger_info result for {user_id}: {result}"
@@ -1880,10 +1915,34 @@ async def send(
18801915
segments.append({"type": "reply", "data": {"id": str(reply_to_id)}})
18811916

18821917
rich_header = kwargs.get("rich_header")
1918+
has_non_image_attachments = any(
1919+
att.type != "image"
1920+
for att in (attachments or [])
1921+
if att.url or att.data is not None
1922+
)
1923+
send_header_separately = bool(
1924+
rich_header and has_non_image_attachments and not str(text or "").strip()
1925+
)
18831926
if rich_header:
1884-
t, c = rich_header.get("title", ""), rich_header.get("content", "")
1885-
prefix = f"[{t}" + (f" · {c}" if c else "") + "]"
1886-
text = f"{prefix}\n{text}" if text else prefix
1927+
if not send_header_separately:
1928+
t, c = rich_header.get("title", ""), rich_header.get("content", "")
1929+
prefix = f"[{t}" + (f" · {c}" if c else "") + "]"
1930+
text = f"{prefix}\n{text}" if text else prefix
1931+
else:
1932+
t, c = rich_header.get("title", ""), rich_header.get("content", "")
1933+
prefix = f"[{t}" + (f" · {c}" if c else "") + "]"
1934+
header_resp = await self._call(
1935+
"send_group_msg",
1936+
{
1937+
"group_id": int(group_id),
1938+
"message": [{"type": "text", "data": {"text": prefix}}],
1939+
},
1940+
)
1941+
if not header_resp or header_resp.get("status") != "ok":
1942+
logger.warning(
1943+
f"NapCat [{self.instance_id}] failed to send standalone rich header "
1944+
f"before media message: {header_resp}"
1945+
)
18871946

18881947
# Process mentions: replace @Name with at segments
18891948
mentions = kwargs.get("mentions", [])

0 commit comments

Comments
 (0)