Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 2 additions & 14 deletions bili_cli/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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))


# ---------------------------------------------------------------------------
Expand Down
16 changes: 14 additions & 2 deletions bili_cli/payloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
50 changes: 13 additions & 37 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down