From 973061b01efed370ba6fa2e2f0db54be58861711 Mon Sep 17 00:00:00 2001 From: FloRa <2862182666@qq.com> Date: Sun, 22 Feb 2026 17:15:00 +0800 Subject: [PATCH 1/3] fix(feishu): replace file.get with message_resource.get to fix file download permission issue --- nanobot/channels/feishu.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 815d853..0376e57 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -503,18 +503,28 @@ class FeishuChannel(BaseChannel): logger.error("Error downloading image {}: {}", image_key, e) return None, None - def _download_file_sync(self, file_key: str) -> tuple[bytes | None, str | None]: - """Download a file from Feishu by file_key.""" + def _download_file_sync(self, message_id: str, file_key: str, resource_type: str = "file") -> tuple[ + bytes | None, str | None]: + """Download a file or audio from a Feishu message by message_id and file_key.""" try: - request = GetFileRequest.builder().file_key(file_key).build() - response = self._client.im.v1.file.get(request) + request = GetMessageResourceRequest.builder() \ + .message_id(message_id) \ + .file_key(file_key) \ + .type(resource_type) \ + .build() + response = self._client.im.v1.message_resource.get(request) + if response.success(): - return response.file, response.file_name + file_data = response.file + # GetMessageResourceRequest 返回的是类似 BytesIO 的对象,需要 read() + if hasattr(file_data, 'read'): + file_data = file_data.read() + return file_data, response.file_name else: - logger.error("Failed to download file: code={}, msg={}", response.code, response.msg) + logger.error("Failed to download {}: code={}, msg={}", resource_type, response.code, response.msg) return None, None except Exception as e: - logger.error("Error downloading file {}: {}", file_key, e) + logger.error("Error downloading {} {}: {}", resource_type, file_key, e) return None, None async def _download_and_save_media( @@ -544,14 +554,18 @@ class FeishuChannel(BaseChannel): if not filename: filename = f"{image_key[:16]}.jpg" + elif msg_type in ("audio", "file"): + file_key = content_json.get("file_key") - if file_key: + + if file_key and message_id: data, filename = await loop.run_in_executor( - None, self._download_file_sync, file_key + None, self._download_file_sync, message_id, file_key, msg_type ) if not filename: ext = ".opus" if msg_type == "audio" else "" + filename = f"{file_key[:16]}{ext}" if data and filename: From 0d3a2963d0d57b66b14f5d2b9c25fb494e6d62f8 Mon Sep 17 00:00:00 2001 From: FloRa <2862182666@qq.com> Date: Sun, 22 Feb 2026 17:37:33 +0800 Subject: [PATCH 2/3] fix(feishu): replace file.get with message_resource.get to fix file download permission issue --- nanobot/channels/feishu.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index 0376e57..d1eeb2e 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -555,23 +555,29 @@ class FeishuChannel(BaseChannel): filename = f"{image_key[:16]}.jpg" - elif msg_type in ("audio", "file"): + elif msg_type in ("audio", "file", "media"): file_key = content_json.get("file_key") - if file_key and message_id: data, filename = await loop.run_in_executor( - None, self._download_file_sync, message_id, file_key, msg_type + None, self._download_file_sync, message_id, file_key ) if not filename: - ext = ".opus" if msg_type == "audio" else "" - + if msg_type == "audio": + ext = ".opus" + elif msg_type == "media": + ext = ".mp4" + else: + ext = "" filename = f"{file_key[:16]}{ext}" if data and filename: file_path = media_dir / filename + file_path.write_bytes(data) + logger.debug("Downloaded {} to {}", msg_type, file_path) + return str(file_path), f"[{msg_type}: {filename}]" return None, f"[{msg_type}: download failed]" @@ -698,7 +704,7 @@ class FeishuChannel(BaseChannel): if text: content_parts.append(text) - elif msg_type in ("image", "audio", "file"): + elif msg_type in ("image", "audio", "file", "media"): file_path, content_text = await self._download_and_save_media(msg_type, content_json, message_id) if file_path: media_paths.append(file_path) From efe89c90913d3fd7b8415b13e577021932a60795 Mon Sep 17 00:00:00 2001 From: Re-bin Date: Sun, 22 Feb 2026 18:16:45 +0000 Subject: [PATCH 3/3] fix(feishu): pass msg_type as resource_type and clean up style --- nanobot/channels/feishu.py | 39 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index d1eeb2e..2d50d74 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -503,28 +503,29 @@ class FeishuChannel(BaseChannel): logger.error("Error downloading image {}: {}", image_key, e) return None, None - def _download_file_sync(self, message_id: str, file_key: str, resource_type: str = "file") -> tuple[ - bytes | None, str | None]: - """Download a file or audio from a Feishu message by message_id and file_key.""" + def _download_file_sync( + self, message_id: str, file_key: str, resource_type: str = "file" + ) -> tuple[bytes | None, str | None]: + """Download a file/audio/media from a Feishu message by message_id and file_key.""" try: - request = GetMessageResourceRequest.builder() \ - .message_id(message_id) \ - .file_key(file_key) \ - .type(resource_type) \ + request = ( + GetMessageResourceRequest.builder() + .message_id(message_id) + .file_key(file_key) + .type(resource_type) .build() + ) response = self._client.im.v1.message_resource.get(request) - if response.success(): file_data = response.file - # GetMessageResourceRequest 返回的是类似 BytesIO 的对象,需要 read() - if hasattr(file_data, 'read'): + if hasattr(file_data, "read"): file_data = file_data.read() return file_data, response.file_name else: logger.error("Failed to download {}: code={}, msg={}", resource_type, response.code, response.msg) return None, None - except Exception as e: - logger.error("Error downloading {} {}: {}", resource_type, file_key, e) + except Exception: + logger.exception("Error downloading {} {}", resource_type, file_key) return None, None async def _download_and_save_media( @@ -554,30 +555,20 @@ class FeishuChannel(BaseChannel): if not filename: filename = f"{image_key[:16]}.jpg" - - elif msg_type in ("audio", "file", "media"): file_key = content_json.get("file_key") if file_key and message_id: data, filename = await loop.run_in_executor( - None, self._download_file_sync, message_id, file_key + None, self._download_file_sync, message_id, file_key, msg_type ) if not filename: - if msg_type == "audio": - ext = ".opus" - elif msg_type == "media": - ext = ".mp4" - else: - ext = "" + ext = {"audio": ".opus", "media": ".mp4"}.get(msg_type, "") filename = f"{file_key[:16]}{ext}" if data and filename: file_path = media_dir / filename - file_path.write_bytes(data) - logger.debug("Downloaded {} to {}", msg_type, file_path) - return str(file_path), f"[{msg_type}: {filename}]" return None, f"[{msg_type}: download failed]"