diff --git a/xhs_cli/cli.py b/xhs_cli/cli.py index a33a08e..a48508a 100644 --- a/xhs_cli/cli.py +++ b/xhs_cli/cli.py @@ -108,6 +108,7 @@ def cli(ctx, verbose: bool, cookie_source: str): cli.add_command(creator.post) cli.add_command(creator.my_notes) +cli.add_command(creator.my_notes_data) cli.add_command(creator.delete) # ─── Notification commands ────────────────────────────────────────────────── diff --git a/xhs_cli/client_mixins.py b/xhs_cli/client_mixins.py index b4dada7..b7b7a98 100644 --- a/xhs_cli/client_mixins.py +++ b/xhs_cli/client_mixins.py @@ -627,6 +627,13 @@ def get_creator_note_list(self, tab: int = 0, page: int = 0) -> dict[str, Any]: "page": page, }) + def get_creator_note_analyze_list(self, type: int = 0, page_size: int = 10, page_num: int = 1) -> dict[str, Any]: + return self._creator_get("/api/galaxy/creator/datacenter/note/analyze/list", { + "type": type, + "page_size": page_size, + "page_num": page_num, + }) + class SocialEndpointsMixin: """Social graph and saved-content endpoints.""" diff --git a/xhs_cli/commands/creator.py b/xhs_cli/commands/creator.py index 63237f5..b35a4bd 100644 --- a/xhs_cli/commands/creator.py +++ b/xhs_cli/commands/creator.py @@ -10,6 +10,7 @@ maybe_print_structured, print_info, print_success, + render_creator_note_data, render_creator_notes, ) from ..note_refs import save_index_from_notes @@ -105,6 +106,25 @@ def _my_notes_action(client): ) +@click.command("my-notes-data") +@click.option("--page", default=1, help="Page number (1-indexed)") +@click.option("--page-size", default=10, help="Page size") +@structured_output_options +@click.pass_context +def my_notes_data(ctx, page: int, page_size: int, as_json: bool, as_yaml: bool): + """List your own published notes data.""" + def _my_notes_data_action(client): + return client.get_creator_note_analyze_list(page_num=page, page_size=page_size) + + handle_command( + ctx, + action=_my_notes_data_action, + render=render_creator_note_data, + as_json=as_json, + as_yaml=as_yaml, + ) + + @click.command("delete") @click.argument("id_or_url") @structured_output_options diff --git a/xhs_cli/formatter.py b/xhs_cli/formatter.py index d7d8766..ce1693a 100644 --- a/xhs_cli/formatter.py +++ b/xhs_cli/formatter.py @@ -7,6 +7,7 @@ from .formatter_renderers import ( # noqa: F401 render_comments, + render_creator_note_data, render_creator_notes, render_feed, render_note, diff --git a/xhs_cli/formatter_normalizers.py b/xhs_cli/formatter_normalizers.py index 0e1e8b9..7c9044b 100644 --- a/xhs_cli/formatter_normalizers.py +++ b/xhs_cli/formatter_normalizers.py @@ -173,6 +173,24 @@ def normalize_creator_notes(data: Any) -> list[dict[str, Any]]: return normalized +def normalize_creator_note_data(data: Any) -> list[dict[str, Any]]: + notes = data if isinstance(data, list) else data.get("notes", data.get("note_list", data.get("note_infos", []))) + normalized = [] + for note in notes: + normalized.append({ + "title": note.get("title", "")[:40], + "note_id": note.get("id", note.get("note_id", "")), + "view_count": str(note.get("read_count", note.get("view_count", ""))), + "imp_count": str(note.get("imp_count", "")), + "liked_count": str(note.get("like_count", note.get("liked_count", ""))), + "collected_count": str(note.get("fav_count", note.get("collected_count", ""))), + "comment_count": str(note.get("comment_count", "")), + "share_count": str(note.get("share_count", "")), + "click_rate": f"{note['coverClickRate'] * 100:.1f}%" if "coverClickRate" in note else "-", + }) + return normalized + + def normalize_notifications(data: dict[str, Any]) -> list[dict[str, Any]]: normalized = [] for message in data.get("message_list", []): diff --git a/xhs_cli/formatter_renderers.py b/xhs_cli/formatter_renderers.py index c29669a..8fb88ea 100644 --- a/xhs_cli/formatter_renderers.py +++ b/xhs_cli/formatter_renderers.py @@ -9,6 +9,7 @@ from .formatter_normalizers import ( normalize_comments, + normalize_creator_note_data, normalize_creator_notes, normalize_feed, normalize_note_detail, @@ -286,6 +287,40 @@ def render_creator_notes(data: Any) -> None: console.print(table) +def render_creator_note_data(data: Any) -> None: + """Render creator's note analyze data.""" + notes = normalize_creator_note_data(data) + if not notes: + print_info("No data found") + return + + table = Table(title="笔记分析数据", show_lines=True) + table.add_column("#", style="dim", width=3) + table.add_column("标题", width=30) + table.add_column("点击率", justify="right", width=8) + table.add_column("曝光", justify="right", width=8) + table.add_column("👁️", justify="right", width=8) + table.add_column("❤️", justify="right", width=6) + table.add_column("⭐", justify="right", width=6) + table.add_column("💬", justify="right", width=6) + table.add_column("🔗", justify="right", width=6) + + for i, note in enumerate(notes, 1): + table.add_row( + str(i), + note["title"], + note["click_rate"], + note["imp_count"], + note["view_count"], + note["liked_count"], + note["collected_count"], + note["comment_count"], + note["share_count"], + ) + + console.print(table) + + def render_notifications(data: dict[str, Any], notif_type: str) -> None: """Render notification messages.""" import time as _time