|
6 | 6 | import struct |
7 | 7 | import time |
8 | 8 | from models import StorageAdapter |
| 9 | +from api.response import cursor_page |
9 | 10 | from telethon import TelegramClient, errors, utils |
10 | 11 | from telethon.crypto import AuthKey |
11 | 12 | from telethon.sessions import StringSession |
@@ -280,81 +281,79 @@ def _parse_message_id(rel: str) -> int: |
280 | 281 | def get_effective_root(self, sub_path: str | None) -> str: |
281 | 282 | return "" |
282 | 283 |
|
283 | | - async def list_dir(self, root: str, rel: str, page_num: int = 1, page_size: int = 50, sort_by: str = "name", sort_order: str = "asc") -> Tuple[List[Dict], int]: |
| 284 | + async def list_dir( |
| 285 | + self, |
| 286 | + root: str, |
| 287 | + rel: str, |
| 288 | + page_num: int = 1, |
| 289 | + page_size: int = 50, |
| 290 | + sort_by: str = "name", |
| 291 | + sort_order: str = "asc", |
| 292 | + cursor: str | None = None, |
| 293 | + ): |
284 | 294 | if rel: |
285 | | - return [], 0 |
| 295 | + return cursor_page([], page_size, cursor=cursor) |
286 | 296 |
|
287 | 297 | client = self._get_client() |
288 | 298 | entries = [] |
| 299 | + next_cursor = None |
289 | 300 | try: |
290 | 301 | await client.connect() |
291 | | - messages = await client.get_messages(self.chat_id, limit=200) |
292 | | - for message in messages: |
293 | | - if not message: |
294 | | - continue |
295 | | - |
296 | | - media = message.document or message.video or message.photo |
297 | | - if not media: |
298 | | - continue |
299 | | - |
300 | | - file_meta = message.file |
301 | | - if not file_meta: |
302 | | - continue |
303 | | - |
304 | | - filename = file_meta.name |
305 | | - if not filename: |
306 | | - if message.text and '.' in message.text and len(message.text) < 256 and '\n' not in message.text: |
307 | | - filename = message.text |
308 | | - else: |
309 | | - filename = f"unknown_{message.id}" |
310 | | - |
311 | | - size = file_meta.size |
312 | | - if size is None: |
313 | | - # 兼容缺失 size 的情况 |
314 | | - if hasattr(media, "size") and media.size is not None: |
315 | | - size = media.size |
316 | | - elif message.photo and getattr(message.photo, "sizes", None): |
317 | | - photo_size = message.photo.sizes[-1] |
318 | | - size = getattr(photo_size, "size", 0) or 0 |
319 | | - else: |
320 | | - size = 0 |
321 | | - |
322 | | - entries.append({ |
323 | | - "name": f"{message.id}_{filename}", |
324 | | - "is_dir": False, |
325 | | - "size": size, |
326 | | - "mtime": int(message.date.timestamp()), |
327 | | - "type": "file", |
328 | | - "has_thumbnail": False, |
329 | | - }) |
| 302 | + offset_id = int(cursor) if cursor else 0 |
| 303 | + batch_limit = min(max(page_size, 50), 200) |
| 304 | + while len(entries) < page_size: |
| 305 | + messages = await client.get_messages(self.chat_id, limit=batch_limit, offset_id=offset_id) |
| 306 | + if not messages: |
| 307 | + next_cursor = None |
| 308 | + break |
| 309 | + |
| 310 | + offset_id = messages[-1].id |
| 311 | + next_cursor = str(offset_id) |
| 312 | + for message in messages: |
| 313 | + if not message: |
| 314 | + continue |
| 315 | + |
| 316 | + media = message.document or message.video or message.photo |
| 317 | + if not media: |
| 318 | + continue |
| 319 | + |
| 320 | + file_meta = message.file |
| 321 | + if not file_meta: |
| 322 | + continue |
| 323 | + |
| 324 | + filename = file_meta.name |
| 325 | + if not filename: |
| 326 | + if message.text and '.' in message.text and len(message.text) < 256 and '\n' not in message.text: |
| 327 | + filename = message.text |
| 328 | + else: |
| 329 | + filename = f"unknown_{message.id}" |
| 330 | + |
| 331 | + size = file_meta.size |
| 332 | + if size is None: |
| 333 | + # 兼容缺失 size 的情况 |
| 334 | + if hasattr(media, "size") and media.size is not None: |
| 335 | + size = media.size |
| 336 | + elif message.photo and getattr(message.photo, "sizes", None): |
| 337 | + photo_size = message.photo.sizes[-1] |
| 338 | + size = getattr(photo_size, "size", 0) or 0 |
| 339 | + else: |
| 340 | + size = 0 |
| 341 | + |
| 342 | + entries.append({ |
| 343 | + "name": f"{message.id}_{filename}", |
| 344 | + "is_dir": False, |
| 345 | + "size": size, |
| 346 | + "mtime": int(message.date.timestamp()), |
| 347 | + "type": "file", |
| 348 | + "has_thumbnail": False, |
| 349 | + }) |
| 350 | + if len(entries) >= page_size: |
| 351 | + break |
330 | 352 | finally: |
331 | 353 | if client.is_connected(): |
332 | 354 | await client.disconnect() |
333 | 355 |
|
334 | | - # 排序 |
335 | | - reverse = sort_order.lower() == "desc" |
336 | | - def get_sort_key(item): |
337 | | - key = (not item["is_dir"],) |
338 | | - sort_field = sort_by.lower() |
339 | | - if sort_field == "name": |
340 | | - key += (item["name"].lower(),) |
341 | | - elif sort_field == "size": |
342 | | - key += (item["size"],) |
343 | | - elif sort_field == "mtime": |
344 | | - key += (item["mtime"],) |
345 | | - else: |
346 | | - key += (item["name"].lower(),) |
347 | | - return key |
348 | | - entries.sort(key=get_sort_key, reverse=reverse) |
349 | | - |
350 | | - total_count = len(entries) |
351 | | - |
352 | | - # 分页 |
353 | | - start_idx = (page_num - 1) * page_size |
354 | | - end_idx = start_idx + page_size |
355 | | - page_entries = entries[start_idx:end_idx] |
356 | | - |
357 | | - return page_entries, total_count |
| 356 | + return cursor_page(entries, page_size, cursor=cursor, next_cursor=next_cursor) |
358 | 357 |
|
359 | 358 | async def read_file(self, root: str, rel: str) -> bytes: |
360 | 359 | message_id = self._parse_message_id(rel) |
|
0 commit comments