diff --git a/bili_cli/client.py b/bili_cli/client.py index 4edff44..b671dda 100644 --- a/bili_cli/client.py +++ b/bili_cli/client.py @@ -13,7 +13,7 @@ from typing import Any import aiohttp -from bilibili_api import comment, dynamic, favorite_list, homepage, hot, rank, search, user, video +from bilibili_api import comment, dynamic, favorite_list, hot, rank, search, user, video from bilibili_api.exceptions import ( ApiException, CredentialNoBiliJctException, @@ -520,19 +520,7 @@ async def get_watch_history( async def get_toview(credential: Credential) -> dict[str, Any]: """Fetch watch-later (稍后再看) list.""" - data = await _call_api("获取稍后再看列表", homepage.get_favorite_list_and_toview(credential)) - if not isinstance(data, list): - logger.warning("Unexpected toview payload type: %s", type(data).__name__) - return {"list": [], "count": 0} - # data is a list; the item with name="稍后再看" contains toview videos - for item in data: - if item.get("name") == "稍后再看" or item.get("id") == 2: - resp = item.get("mediaListResponse", {}) - return { - "list": resp.get("list", []), - "count": resp.get("count", 0), - } - return {"list": [], "count": 0} + return await _call_api("获取稍后再看列表", user.get_toview_list(credential)) # --------------------------------------------------------------------------- diff --git a/bili_cli/payloads.py b/bili_cli/payloads.py index 7f7b1ae..8625c35 100644 --- a/bili_cli/payloads.py +++ b/bili_cli/payloads.py @@ -196,11 +196,23 @@ def normalize_history_item(item: dict[str, Any]) -> dict[str, Any]: } +def _aid_to_bvid(aid: int) -> str: + """Convert AV号 to BV号.""" + try: + from bilibili_api.utils.aid_bvid_transformer import aid2bvid + return aid2bvid(aid) + except ImportError: + return "" + + def normalize_watch_later_item(item: dict[str, Any]) -> dict[str, Any]: + aid = _to_int(item.get("aid"), 0) + bvid = item.get("bvid", "") or (_aid_to_bvid(aid) if aid else "") owner = item.get("owner", {}) if isinstance(item.get("owner"), dict) else {} return { - "id": str(item.get("bvid", "")), - "bvid": item.get("bvid", ""), + "id": str(bvid or aid or ""), + "bvid": bvid, + "aid": aid, "title": item.get("title", ""), "author": owner.get("name", ""), "duration_seconds": _to_int(item.get("duration"), 0), diff --git a/tests/test_client.py b/tests/test_client.py index 386854c..81fb9dc 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -241,17 +241,21 @@ async def test_get_user_videos_raises_on_first_page_error(): @pytest.mark.asyncio -async def test_get_toview_by_name(mock_credential): - data = [ - { - "name": "稍后再看", - "mediaListResponse": {"list": [{"bvid": "BV1later"}], "count": 1}, - } - ] - with patch("bili_cli.client.homepage.get_favorite_list_and_toview", new_callable=AsyncMock, return_value=data): +async def test_get_toview_passthrough(mock_credential): + mock_data = {"list": [{"aid": 123, "title": "test video"}], "count": 1} + with patch("bili_cli.client.user.get_toview_list", new_callable=AsyncMock, return_value=mock_data): result = await client.get_toview(mock_credential) + assert result == mock_data assert result["count"] == 1 - assert result["list"][0]["bvid"] == "BV1later" + assert result["list"][0]["aid"] == 123 + + +@pytest.mark.asyncio +async def test_get_toview_empty_list(mock_credential): + mock_data = {"list": [], "count": 0} + with patch("bili_cli.client.user.get_toview_list", new_callable=AsyncMock, return_value=mock_data): + result = await client.get_toview(mock_credential) + assert result == mock_data @pytest.mark.asyncio @@ -269,34 +273,6 @@ async def test_get_watch_history_requires_credential(): await client.get_watch_history() -@pytest.mark.asyncio -async def test_get_toview_by_id(mock_credential): - data = [ - { - "id": 2, - "mediaListResponse": {"list": [{"bvid": "BV1id"}], "count": 1}, - } - ] - with patch("bili_cli.client.homepage.get_favorite_list_and_toview", new_callable=AsyncMock, return_value=data): - result = await client.get_toview(mock_credential) - assert result["count"] == 1 - assert result["list"][0]["bvid"] == "BV1id" - - -@pytest.mark.asyncio -async def test_get_toview_empty_when_not_found(mock_credential): - with patch("bili_cli.client.homepage.get_favorite_list_and_toview", new_callable=AsyncMock, return_value=[]): - result = await client.get_toview(mock_credential) - assert result == {"list": [], "count": 0} - - -@pytest.mark.asyncio -async def test_get_toview_unexpected_payload_type_returns_empty(mock_credential): - with patch("bili_cli.client.homepage.get_favorite_list_and_toview", new_callable=AsyncMock, return_value={"x": 1}): - result = await client.get_toview(mock_credential) - assert result == {"list": [], "count": 0} - - @pytest.mark.asyncio async def test_get_dynamic_feed_requires_credential(): with pytest.raises(AuthenticationError):