Skip to content

Fix the issue when fetch the audio url & support parse c2c audio #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lagrange/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
20 changes: 14 additions & 6 deletions lagrange/client/highway/highway.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 9 additions & 5 deletions lagrange/client/message/decoder.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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(
Expand Down Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion lagrange/client/message/elems.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -86,7 +87,6 @@ def build(cls, ev: GroupMessage) -> "At":
class Image(Text, MediaInfo):
width: int
height: int
url: str
is_emoji: bool


Expand Down
5 changes: 3 additions & 2 deletions lagrange/client/server_push/msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
)
Expand Down