diff --git a/lagrange/client/client.py b/lagrange/client/client.py index 9ace844..e9ce010 100644 --- a/lagrange/client/client.py +++ b/lagrange/client/client.py @@ -257,6 +257,9 @@ async def upload_grp_audio(self, voice: BinaryIO, grp_id: int) -> Audio: async def upload_friend_audio(self, voice: BinaryIO, uid: str) -> Audio: return await self._highway.upload_voice(voice, uid=uid) + async def fetch_audio_url(self, file_key: str, uid=None, gid=None): + return await self._highway.get_audio_down_url(file_key, uid=uid, gid=gid) + async def down_grp_audio(self, audio: Audio, grp_id: int) -> BytesIO: return await self._highway.download_audio(audio, gid=grp_id) diff --git a/lagrange/client/highway/highway.py b/lagrange/client/highway/highway.py index b58a92e..0085edc 100644 --- a/lagrange/client/highway/highway.py +++ b/lagrange/client/highway/highway.py @@ -1,15 +1,14 @@ import asyncio import time -import uuid from hashlib import md5 from io import BytesIO -from typing import TYPE_CHECKING, BinaryIO, List, Optional, Tuple +from typing import TYPE_CHECKING, BinaryIO, List, Optional, Tuple, overload, Union from lagrange.client.message.elems import Audio, Image from lagrange.pb.highway.comm import IndexNode from lagrange.pb.highway.ext import NTV2RichMediaHighwayExt from lagrange.pb.highway.httpconn import HttpConn0x6ffReq, HttpConn0x6ffRsp -from lagrange.pb.highway.rsp import NTV2RichMediaResp, DownloadInfo, DownloadRsp +from lagrange.pb.highway.rsp import NTV2RichMediaResp, DownloadRsp from lagrange.utils.binary.protobuf import proto_decode from lagrange.utils.crypto.tea import qqtea_encrypt from lagrange.utils.httpcat import HttpCat @@ -341,25 +340,34 @@ async def upload_voice(self, file: BinaryIO, gid=0, uid="") -> Audio: size=fl, file_key=file_key.decode(), qmsg=None if gid else compat, + url=await self.get_audio_down_url(file_key.decode(), gid, uid), ) - async def get_audio_down_url(self, audio: Audio, gid=0, uid="") -> str: + @overload + async def get_audio_down_url(self, file_key_or_audio: str, gid: int = 0, uid: str = "") -> str: ... + + @overload + async def get_audio_down_url(self, file_key_or_audio: Audio, gid: int = 0, uid: str = "") -> str: ... + + async def get_audio_down_url(self, file_key_or_audio: Union[str, Audio], gid: int = 0, uid="") -> str: if not self._session_addr_list: await self._get_bdh_session() + audio_file_key = file_key_or_audio.file_key if isinstance(file_key_or_audio, Audio) else file_key_or_audio + ret = NTV2RichMediaResp.decode( ( await self._client.send_oidb_svc( 0x126E if gid else 0x126D, 200, encode_audio_down_req( - audio.file_key, gid, uid + audio_file_key, gid, uid ).encode(), True ) ).data ) - if not ret: + if not (ret and ret.download): raise ConnectionError("Internal error, check log for more detail") return self._down_url(ret.download) diff --git a/lagrange/client/message/decoder.py b/lagrange/client/message/decoder.py index e91a02e..4b3a1f2 100644 --- a/lagrange/client/message/decoder.py +++ b/lagrange/client/message/decoder.py @@ -1,5 +1,5 @@ import zlib -from typing import List, Tuple, Sequence, TYPE_CHECKING, cast, Literal +from typing import List, Tuple, Sequence, TYPE_CHECKING, cast, Literal, Union from lagrange.client.events.group import GroupMessage from lagrange.client.events.friend import FriendMessage @@ -37,7 +37,8 @@ def parse_friend_info(pkg: MsgPushBody) -> Tuple[int, str, int, str]: return from_uin, from_uid, to_uin, to_uid -async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element]: +async def parse_msg_new(client: "Client", pkg: MsgPushBody, + fri_id: Union[str, None] = None, grp_id: Union[int, None] = None) -> Sequence[Element]: if not pkg.message or not pkg.message.body: if pkg.content_head.sub_type == 4: data = FileExtra.decode(pkg.message.buf2) @@ -53,6 +54,7 @@ async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element] rich: RichText = pkg.message.body if rich.ptt: ptt = rich.ptt + file_key = ptt.group_file_key if ptt.group_file_key else ptt.friend_file_key return [ elems.Audio( name=ptt.name, @@ -61,8 +63,9 @@ async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element] md5=ptt.md5, text=f"[audio:{ptt.name}]", time=ptt.time, - file_key=ptt.group_file_key if not ptt.to_uin else ptt.friend_file_key, + file_key=ptt.group_file_key if ptt.group_file_key else ptt.friend_file_key, qmsg=None, + url=await client.fetch_audio_url(file_key, uid=fri_id, gid=grp_id) ) ] el: List[Elems] = rich.content @@ -280,6 +283,7 @@ async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element] width=video.width, height=video.height, qmsg=None, + url="" # TODO: fetch video url ) ) else: @@ -294,7 +298,7 @@ async def parse_friend_msg(client: "Client", pkg: MsgPushBody) -> FriendMessage: seq = pkg.content_head.seq msg_id = pkg.content_head.msg_id timestamp = pkg.content_head.timestamp - parsed_msg = await parse_msg_new(client, pkg) + parsed_msg = await parse_msg_new(client, pkg, fri_id=from_uid, grp_id=None) msg_text = "".join([getattr(msg, "text", "") for msg in parsed_msg]) return FriendMessage( @@ -322,7 +326,7 @@ async def parse_grp_msg(client: "Client", pkg: MsgPushBody) -> GroupMessage: if isinstance(grp_name, bytes): # unexpected end of data grp_name = grp_name.decode("utf-8", errors="ignore") - parsed_msg = await parse_msg_new(client, pkg) + parsed_msg = await parse_msg_new(client, pkg, fri_id=None, grp_id=grp_id) msg_text = "".join([getattr(msg, "text", "") for msg in parsed_msg]) return GroupMessage( diff --git a/lagrange/client/message/elems.py b/lagrange/client/message/elems.py index 90f30ac..e11567a 100644 --- a/lagrange/client/message/elems.py +++ b/lagrange/client/message/elems.py @@ -21,6 +21,7 @@ def type(self) -> str: class MediaInfo: name: str size: int + url: str id: int = field(repr=False) md5: bytes = field(repr=False) qmsg: Optional[bytes] = field(repr=False) # not online image @@ -86,7 +87,6 @@ def build(cls, ev: GroupMessage) -> "At": class Image(Text, MediaInfo): width: int height: int - url: str is_emoji: bool diff --git a/lagrange/client/server_push/msg.py b/lagrange/client/server_push/msg.py index e44b6ce..d63cc55 100644 --- a/lagrange/client/server_push/msg.py +++ b/lagrange/client/server_push/msg.py @@ -57,7 +57,7 @@ async def msg_push_handler(client: "Client", sso: SSOPacket): logger.debug("msg_push received, type: {}.{}".format(typ, sub_typ)) if typ == 82: # grp msg return await parse_grp_msg(client, pkg) - elif typ in [166, 529]: # frd msg + elif typ in [166, 208, 529]: # frd msg return await parse_friend_msg(client, pkg) elif typ == 33: # member joined pb = MemberChanged.decode(pkg.message.buf2) @@ -220,8 +220,9 @@ async def msg_push_handler(client: "Client", sso: SSOPacket): ) else: logger.debug( - "unknown type %d: %s" + "unknown type %d, sub type %d: %s" % ( + typ, sub_typ, pkg.message.buf2.hex() if getattr(pkg.message, "buf2", None) else pkg, )