diff --git a/pyproject.toml b/pyproject.toml index ef02b8b..ff0456e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "twitter-cli" -version = "0.3.1" +version = "0.3.2" description = "A CLI for Twitter/X — feed, bookmarks, and user timeline in terminal" readme = "README.md" license = "Apache-2.0" diff --git a/twitter_cli/client.py b/twitter_cli/client.py index 1e5f102..df386e3 100644 --- a/twitter_cli/client.py +++ b/twitter_cli/client.py @@ -731,7 +731,26 @@ class TwitterClient: ) time.sleep(wait) continue + # Write operation rate limits (retweet/like/bookmark limits) + # Code 348 = "retweet limit", 327 = "already retweeted" + # Provide user-friendly message + if err_code in (348, 349): + raise TwitterAPIError( + 429, "Rate limited: %s (try again later, recommended wait: 15+ minutes)" % err_msg + ) raise TwitterAPIError(0, "Twitter API returned errors: %s" % err_msg) + + # GraphQL write mutations return errors in data.errors (separate from top-level) + if isinstance(parsed, dict) and "data" in parsed: + data_obj = parsed["data"] + if isinstance(data_obj, dict): + for key, val in data_obj.items(): + if isinstance(val, dict) and val.get("errors"): + inner_errors = val["errors"] + if inner_errors: + inner_msg = inner_errors[0].get("message", "Unknown error") + raise TwitterAPIError(0, "Twitter API: %s" % inner_msg) + return parsed # Should not be reached, but just in case diff --git a/uv.lock b/uv.lock index ed5b5b4..4528ab3 100644 --- a/uv.lock +++ b/uv.lock @@ -1116,7 +1116,7 @@ wheels = [ [[package]] name = "twitter-cli" -version = "0.3.0" +version = "0.3.1" source = { editable = "." } dependencies = [ { name = "beautifulsoup4" },