diff --git a/README.md b/README.md index 508cb8d..72b1fab 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ twitter list 1539453138322673664 twitter user elonmusk twitter user-posts elonmusk --max 20 twitter user-posts elonmusk -o tweets.json -twitter likes elonmusk --max 30 +twitter likes elonmusk --max 30 # ⚠️ own likes only (private since Jun 2024) twitter likes elonmusk -o likes.json twitter followers elonmusk --max 50 twitter following elonmusk --max 50 @@ -360,7 +360,7 @@ twitter list 1539453138322673664 twitter user elonmusk twitter user-posts elonmusk --max 20 twitter user-posts elonmusk -o tweets.json -twitter likes elonmusk --max 30 +twitter likes elonmusk --max 30 # ⚠️ 仅可查看自己的点赞(2024年6月起平台已私密化) twitter likes elonmusk -o likes.json twitter followers elonmusk twitter following elonmusk diff --git a/SKILL.md b/SKILL.md index 3af0fff..3da9654 100644 --- a/SKILL.md +++ b/SKILL.md @@ -145,7 +145,7 @@ twitter tweet 1234567890 # Tweet detail + replies twitter tweet https://x.com/user/status/12345 # Accepts URL twitter list 1539453138322673664 # List timeline twitter user-posts elonmusk --max 20 # User's tweets -twitter likes elonmusk --max 30 # User's likes +twitter likes elonmusk --max 30 # User's likes (own only, see note) twitter followers elonmusk --max 50 # Followers twitter following elonmusk --max 50 # Following ``` @@ -282,6 +282,7 @@ twitter bookmarks --filter - **No notifications** — can't read notifications - **No polls** — can't create polls - **Single account** — one set of credentials at a time +- **Likes are private** — Twitter/X made all likes private since June 2024. `twitter likes` only works for your own account ## Safety Notes diff --git a/twitter_cli/cli.py b/twitter_cli/cli.py index 2c1adee..704cef8 100644 --- a/twitter_cli/cli.py +++ b/twitter_cli/cli.py @@ -539,7 +539,11 @@ def search(ctx, query, product, max_count, as_json, as_yaml, output_file, do_fil @click.pass_context def likes(ctx, screen_name, max_count, as_json, as_yaml, output_file, do_filter): # type: (Any, str, int, bool, bool, Optional[str], bool) -> None - """Show tweets liked by a user. SCREEN_NAME is the @handle (without @).""" + """Show tweets liked by a user. SCREEN_NAME is the @handle (without @). + + NOTE: Twitter/X made all likes private since June 2024. You can only view + your own likes. Querying another user's likes will return empty results. + """ screen_name = screen_name.lstrip("@") compact = ctx.obj.get("compact", False) config = load_config() @@ -549,6 +553,26 @@ def likes(ctx, screen_name, max_count, as_json, as_yaml, output_file, do_filter) if rich_output: console.print("👤 Fetching @%s's profile..." % screen_name) profile = client.fetch_user(screen_name) + + # Warn if querying another user's likes (Twitter made likes private since June 2024) + try: + me = client.fetch_me() + if me.screen_name.lower() != screen_name.lower(): + if rich_output: + console.print( + "\n[yellow]⚠️ Twitter/X made all likes private since June 2024. " + "You can only view your own likes. " + "Querying @%s's likes will likely return empty results.[/yellow]\n" % screen_name + ) + else: + logger.warning( + "Twitter/X made likes private (June 2024). " + "Only your own likes are visible. @%s's likes will likely be empty.", + screen_name, + ) + except Exception: + pass # Don't block the command if whoami fails + _fetch_and_display( lambda count: client.fetch_user_likes(profile.id, count), "@%s likes" % screen_name, "❤️", max_count, as_json, as_yaml, output_file, do_filter, config,