diff --git a/app/modules/filemanager/storages/alist.py b/app/modules/filemanager/storages/alist.py index 53d41d47..83c503ef 100644 --- a/app/modules/filemanager/storages/alist.py +++ b/app/modules/filemanager/storages/alist.py @@ -16,6 +16,10 @@ from app.utils.singleton import WeakSingleton from app.utils.url import UrlUtils +# OpenList/AList 在 per_page<=0 时会退回后端默认 200,显式指定最大页大小避免大目录被截断。 +OPENLIST_MAX_LIST_PAGE_SIZE = 500 + + class Alist(StorageBase, metaclass=WeakSingleton): """ Openlist相关操作 @@ -201,6 +205,8 @@ class Alist(StorageBase, metaclass=WeakSingleton): return [] items = [] current_page = page + auto_page = per_page <= 0 + effective_per_page = OPENLIST_MAX_LIST_PAGE_SIZE if auto_page else per_page while True: resp = RequestUtils(headers=self.__get_header_with_token()).post_res( self.__get_api_url("/api/fs/list"), @@ -208,7 +214,7 @@ class Alist(StorageBase, metaclass=WeakSingleton): "path": fileitem.path, "password": password, "page": current_page, - "per_page": per_page, + "per_page": effective_per_page, "refresh": refresh, }, ) @@ -267,7 +273,8 @@ class Alist(StorageBase, metaclass=WeakSingleton): ) return [] - page_content = result["data"].get("content") or [] + page_data = result["data"] + page_content = page_data.get("content") or [] items.extend( [ schemas.FileItem( @@ -286,12 +293,16 @@ class Alist(StorageBase, metaclass=WeakSingleton): ] ) - if per_page > 0: + if not auto_page: return items - total = result["data"].get("total") or 0 + total = page_data.get("filtered_total") or page_data.get("total") or 0 + pages_total = page_data.get("pages_total") or 0 + has_more = page_data.get("has_more") if not page_content or len(items) >= total: return items + if has_more is False or (pages_total and current_page >= pages_total): + return items current_page += 1 diff --git a/tests/test_alist_storage.py b/tests/test_alist_storage.py index f54c32d4..65c17231 100644 --- a/tests/test_alist_storage.py +++ b/tests/test_alist_storage.py @@ -172,8 +172,8 @@ class AlistStorageTest(unittest.TestCase): def test_list_fetches_all_pages_when_per_page_is_default(self): responses = [ - _FakeResponse(self._page_payload(0, 200, 205)), - _FakeResponse(self._page_payload(200, 5, 205)), + _FakeResponse(self._page_payload(0, 500, 505)), + _FakeResponse(self._page_payload(500, 5, 505)), ] request_utils = MagicMock() request_utils.post_res.side_effect = responses @@ -182,12 +182,14 @@ class AlistStorageTest(unittest.TestCase): with patch.object(alist_module, "RequestUtils", return_value=request_utils): items = self.storage.list(self._dir_item()) - self.assertEqual(205, len(items)) + self.assertEqual(505, len(items)) self.assertEqual("/dir-0/", items[0].path) - self.assertEqual("/dir-204/", items[-1].path) + self.assertEqual("/dir-504/", items[-1].path) self.assertEqual(2, request_utils.post_res.call_count) self.assertEqual(1, request_utils.post_res.call_args_list[0].kwargs["json"]["page"]) self.assertEqual(2, request_utils.post_res.call_args_list[1].kwargs["json"]["page"]) + self.assertEqual(500, request_utils.post_res.call_args_list[0].kwargs["json"]["per_page"]) + self.assertEqual(500, request_utils.post_res.call_args_list[1].kwargs["json"]["per_page"]) def test_list_respects_explicit_per_page_without_auto_paging(self): request_utils = MagicMock() @@ -199,6 +201,7 @@ class AlistStorageTest(unittest.TestCase): self.assertEqual(50, len(items)) self.assertEqual(1, request_utils.post_res.call_count) + self.assertEqual(50, request_utils.post_res.call_args.kwargs["json"]["per_page"]) def test_create_folder_returns_target_when_openlist_metadata_is_delayed(self): """