@@ -1913,12 +1913,19 @@ async def send(
19131913 return None
19141914
19151915 segments : list [dict ] = []
1916+ msg_ids : list [str ] = []
1917+ deferred_file_uploads = []
19161918
19171919 reply_to_id = kwargs .get ("reply_to_id" )
19181920 if reply_to_id :
19191921 segments .append ({"type" : "reply" , "data" : {"id" : str (reply_to_id )}})
19201922
19211923 rich_header = kwargs .get ("rich_header" )
1924+ # Video/Record cannot be mixed with text in QQ, so if there are such attachments,
1925+ # we still want to make sure the header goes with the text, but the whole text
1926+ # message must be sent separately from the video/record message.
1927+ # We will handle the separation later, so we just prepend the header to the text if there is text.
1928+ # If there is NO text but there ARE non-image attachments, we send the header separately.
19221929 has_non_image_attachments = any (
19231930 att .type != "image"
19241931 for att in (attachments or [])
@@ -1947,6 +1954,10 @@ async def send(
19471954 f"NapCat [{ self .instance_id } ] failed to send standalone rich header "
19481955 f"before media message: { header_resp } "
19491956 )
1957+ else :
1958+ data = header_resp .get ("data" ) or {}
1959+ if "message_id" in data :
1960+ msg_ids .append (str (data ["message_id" ]))
19501961
19511962 # Process mentions: replace @Name with at segments
19521963 mentions = kwargs .get ("mentions" , [])
@@ -2063,50 +2074,44 @@ async def send(
20632074 if result :
20642075 data_bytes , _ = result
20652076 fname = att .name or "file"
2066- if self ._supports_stream_file_upload ():
2067- mode = self ._resolve_send_mode (len (data_bytes ))
2068- if mode == "base64" :
2069- b64 = base64 .b64encode (data_bytes ).decode ()
2070- await self ._call (
2071- "upload_group_file" ,
2072- {
2073- "group_id" : int (group_id ),
2074- "file" : f"base64://{ b64 } " ,
2075- "name" : fname ,
2076- },
2077- )
2078- else : # stream (default)
2079- file_path = await self ._upload_file_stream (
2080- data_bytes , fname
2081- )
2082- if file_path :
2077+
2078+ async def _do_upload (d = data_bytes , fn = fname , gid = group_id ):
2079+ if self ._supports_stream_file_upload ():
2080+ mode = self ._resolve_send_mode (len (d ))
2081+ if mode == "base64" :
2082+ b64 = base64 .b64encode (d ).decode ()
20832083 await self ._call (
20842084 "upload_group_file" ,
20852085 {
2086- "group_id" : int (group_id ),
2087- "file" : file_path ,
2088- "name" : fname ,
2086+ "group_id" : int (gid ),
2087+ "file" : f"base64:// { b64 } " ,
2088+ "name" : fn ,
20892089 },
20902090 )
2091- else :
2092- segments .append (
2093- {
2094- "type" : "text" ,
2095- "data" : {"text" : f"\n [文件: { att .name } ]" },
2096- }
2091+ else : # stream (default)
2092+ file_path = await self ._upload_file_stream (
2093+ d , fn
20972094 )
2098- else :
2099- if not await self ._upload_group_file_from_bytes (
2100- data_bytes ,
2101- fname ,
2102- str (group_id ),
2103- ):
2104- segments .append (
2105- {
2106- "type" : "text" ,
2107- "data" : {"text" : f"\n [文件: { att .name } ]" },
2108- }
2109- )
2095+ if file_path :
2096+ await self ._call (
2097+ "upload_group_file" ,
2098+ {
2099+ "group_id" : int (gid ),
2100+ "file" : file_path ,
2101+ "name" : fn ,
2102+ },
2103+ )
2104+ else :
2105+ await self ._call ("send_group_msg" , {"group_id" : int (gid ), "message" : [{"type" : "text" , "data" : {"text" : f"\n [文件发送失败: { fn } ]" }}]})
2106+ else :
2107+ if not await self ._upload_group_file_from_bytes (
2108+ d ,
2109+ fn ,
2110+ str (gid ),
2111+ ):
2112+ await self ._call ("send_group_msg" , {"group_id" : int (gid ), "message" : [{"type" : "text" , "data" : {"text" : f"\n [文件发送失败: { fn } ]" }}]})
2113+
2114+ deferred_file_uploads .append (_do_upload )
21102115 else :
21112116 segments .append (
21122117 {
@@ -2115,20 +2120,54 @@ async def send(
21152120 }
21162121 )
21172122
2118- if not segments :
2119- return None
2123+ main_segments = []
2124+ standalone_segments = []
2125+ for seg in segments :
2126+ if seg ["type" ] in ("video" , "record" ):
2127+ standalone_segments .append (seg )
2128+ else :
2129+ main_segments .append (seg )
21202130
2121- resp = await self ._call (
2122- "send_group_msg" ,
2123- {
2124- "group_id" : int (group_id ),
2125- "message" : segments ,
2126- },
2127- )
2128- if resp and resp .get ("status" ) == "ok" :
2129- data = resp .get ("data" ) or {}
2130- return str (data .get ("message_id" , "" ))
2131- return None
2131+ if main_segments :
2132+ if (
2133+ len (main_segments ) == 1
2134+ and main_segments [0 ]["type" ] == "reply"
2135+ and standalone_segments
2136+ ):
2137+ # If only reply segment remains, attach it to the first standalone segment
2138+ standalone_segments [0 ] = [main_segments [0 ], standalone_segments [0 ]]
2139+ main_segments = []
2140+ else :
2141+ resp = await self ._call (
2142+ "send_group_msg" ,
2143+ {
2144+ "group_id" : int (group_id ),
2145+ "message" : main_segments ,
2146+ },
2147+ )
2148+ if resp and resp .get ("status" ) == "ok" :
2149+ data = resp .get ("data" ) or {}
2150+ if "message_id" in data :
2151+ msg_ids .append (str (data ["message_id" ]))
2152+
2153+ for seg in standalone_segments :
2154+ msg_to_send = seg if isinstance (seg , list ) else [seg ]
2155+ resp = await self ._call (
2156+ "send_group_msg" ,
2157+ {
2158+ "group_id" : int (group_id ),
2159+ "message" : msg_to_send ,
2160+ },
2161+ )
2162+ if resp and resp .get ("status" ) == "ok" :
2163+ data = resp .get ("data" ) or {}
2164+ if "message_id" in data :
2165+ msg_ids .append (str (data ["message_id" ]))
2166+
2167+ for upload_func in deferred_file_uploads :
2168+ await upload_func ()
2169+
2170+ return msg_ids if msg_ids else None
21322171
21332172
21342173register ("qq" , QqConfig , QqDriver )
0 commit comments