{"id":31956770,"url":"https://github.com/mountaingod2/cb-events","last_synced_at":"2026-05-13T01:08:09.716Z","repository":{"id":317921918,"uuid":"1044633815","full_name":"MountainGod2/cb-events","owner":"MountainGod2","description":"Async Python client for the Chaturbate Events API","archived":false,"fork":false,"pushed_at":"2026-03-29T15:10:24.000Z","size":2706,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-29T17:56:31.251Z","etag":null,"topics":["api","chaturbate","client","events","longpoll","streaming"],"latest_commit_sha":null,"homepage":"https://cb-events.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MountainGod2.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-26T01:43:40.000Z","updated_at":"2026-03-29T15:10:05.000Z","dependencies_parsed_at":"2026-01-03T11:01:48.314Z","dependency_job_id":null,"html_url":"https://github.com/MountainGod2/cb-events","commit_stats":null,"previous_names":["mountaingod2/chaturbate-events"],"tags_count":107,"template":false,"template_full_name":null,"purl":"pkg:github/MountainGod2/cb-events","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MountainGod2%2Fcb-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MountainGod2%2Fcb-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MountainGod2%2Fcb-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MountainGod2%2Fcb-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MountainGod2","download_url":"https://codeload.github.com/MountainGod2/cb-events/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MountainGod2%2Fcb-events/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","chaturbate","client","events","longpoll","streaming"],"created_at":"2025-10-14T14:53:17.802Z","updated_at":"2026-05-06T01:07:52.931Z","avatar_url":"https://github.com/MountainGod2.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CB Events\n\nAsync Python client for the Chaturbate Events API.\n\n[![PyPI](https://img.shields.io/pypi/v/cb-events)](https://pypi.org/project/cb-events/)\n[![Tag](https://img.shields.io/github/v/tag/MountainGod2/cb-events)](https://github.com/MountainGod2/cb-events/releases)\n[![Python](https://img.shields.io/pypi/pyversions/cb-events)](https://pypi.org/project/cb-events/)\n[![OpenSSF Best Practices](https://img.shields.io/cii/summary/12375?label=openssf%20best%20practices)](https://www.bestpractices.dev/en/projects/12375)\n[![Builds](https://img.shields.io/github/actions/workflow/status/MountainGod2/cb-events/ci-cd.yml?label=builds)](https://github.com/MountainGod2/cb-events/actions/workflows/ci-cd.yml)\n[![License](https://img.shields.io/github/license/MountainGod2/cb-events?label=license)](https://github.com/MountainGod2/cb-events/blob/main/LICENSE)\n\n## Requirements\n\nPython 3.10+\n\n## Installation\n\n```bash\npip install cb-events\n```\n\nWith [uv](https://docs.astral.sh/uv/) (recommended):\n\n```bash\nuv add cb-events\n```\n\n## Quick Start\n\n```python\nimport asyncio\nfrom cb_events import EventClient, Router, EventType, Event\n\nrouter = Router()\n\nusername = \"your_username\"\ntoken = \"your_api_token\"\n\n@router.on(EventType.TIP)\nasync def handle_tip(event: Event) -\u003e None:\n    if event.user and event.tip:\n        print(f\"{event.user.username} tipped {event.tip.tokens} tokens\")\n\nasync def main():\n    async with EventClient(username, token) as client:\n        async for event in client:\n            await router.dispatch(event)\n\nasyncio.run(main())\n```\n\n```text\nmountaingod2 tipped 100 tokens\n```\n\nFor usage examples, see the [examples folder](https://github.com/MountainGod2/cb-events/blob/main/examples).\n\n\u003e [!NOTE]\n\u003e Generate an API token at https://chaturbate.com/statsapi/authtoken/ with `Events API` scope.\n\n## Working with Events\n\n### Event Types\n\n`TIP` · `FANCLUB_JOIN` · `MEDIA_PURCHASE` · `CHAT_MESSAGE` · `PRIVATE_MESSAGE` · `USER_ENTER` · `USER_LEAVE` · `FOLLOW` · `UNFOLLOW` · `BROADCAST_START` · `BROADCAST_STOP` · `ROOM_SUBJECT_CHANGE`\n\n### Event Object\n\n```python\nevent.user          # User object (most events)\nevent.tip           # Tip object (TIP only)\nevent.message       # Message object (CHAT_MESSAGE, PRIVATE_MESSAGE)\nevent.media         # Media object (MEDIA_PURCHASE)\nevent.room_subject  # RoomSubject object (ROOM_SUBJECT_CHANGE)\nevent.broadcaster   # Broadcaster username string or None\n```\n\n[See full docs for additional details](https://cb-events.readthedocs.io/latest/event_models.html).\n\n## Configuration\n\n```python\nfrom cb_events import ClientConfig\n\nconfig = ClientConfig(\n    timeout=10,                   # Server long-poll timeout (seconds)\n    use_testbed=False,            # Use testbed endpoint (https://www.testbed.cb.dev)\n    strict_validation=False,      # False skips \u0026 logs invalid events; True raises.\n    retry_attempts=8,             # Total attempts (initial + retries)\n    retry_backoff=1.0,            # Initial backoff (seconds)\n    retry_factor=2.0,             # Backoff multiplier\n    retry_max_delay=30.0,         # Max retry delay (seconds)\n)\n\nclient = EventClient(username, token, config=config)\n```\n\n\u003e **Testbed:** Register at \u003chttps://www.testbed.cb.dev\u003e. New accounts include preloaded tokens for testing. Generate an API token the same way as a live account, then pass `use_testbed=True` with those credentials.\n\n### Rate Limiting\n\nDefault: 2000 req/60s per client. Multiple clients each get an independent\nbudget unless a shared limiter is passed:\n\n```python\nfrom aiolimiter import AsyncLimiter\n\nlimiter = AsyncLimiter(max_rate=2000, time_period=60)\nclient1 = EventClient(username1, token1, rate_limiter=limiter)\nclient2 = EventClient(username2, token2, rate_limiter=limiter)\n```\n\n## Error Handling\n\n`AuthError` is a subclass of `EventsError` — `except EventsError` catches both. Put `AuthError` first if you need to distinguish them.\n\n```python\nimport logging\nimport sys\n\nfrom cb_events import AuthError, EventsError\n\nlogger = logging.getLogger(__name__)\n\ntry:\n    async with EventClient(username, token) as client:\n        async for event in client:\n            await router.dispatch(event)\nexcept AuthError:\n    # Authentication failed (401/403) — never retried\n    logger.error(\"Invalid credentials — check username and token\")\n    sys.exit(1)\nexcept EventsError as e:\n    # All other API/network errors — check e.status_code, e.response_text\n    logger.error(\"API error %s: %s\", e.status_code, e.response_text)\n    raise\n```\n\n**Retries:** 429, 5xx, Cloudflare 521-524. Not retriable: 401/403.\n\n**Handlers:** Sequential execution. Errors logged but don't stop processing.\n\n## Logging\n\nSet the logger to `DEBUG` for verbose polling data:\n\n```python\nimport logging\nlogging.getLogger(\"cb_events\").setLevel(logging.DEBUG)\n```\n\nExample output:\n\n```text\nDEBUG:cb_events.client:Polling https://eventsapi.chaturbate.com/events/user/************************/?timeout=10\nDEBUG:cb_events.client:Received 1 events for user\nDEBUG:cb_events.router:Dispatching chatMessage event 1775683684418-0 to 2 handlers\n```\n\n## Star History\n\n\u003ca href=\"https://www.star-history.com/?repos=mountaingod2%2Fcb-events\u0026type=timeline\u0026logscale=\u0026legend=top-left\"\u003e\n \u003cpicture\u003e\n   \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/chart?repos=mountaingod2/cb-events\u0026type=timeline\u0026theme=dark\u0026logscale\u0026legend=top-left\" /\u003e\n   \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/chart?repos=mountaingod2/cb-events\u0026type=timeline\u0026logscale\u0026legend=top-left\" /\u003e\n   \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/chart?repos=mountaingod2/cb-events\u0026type=timeline\u0026logscale\u0026legend=top-left\" /\u003e\n \u003c/picture\u003e\n\u003c/a\u003e\n\n## License\n\nMIT\n\n---\n\nNot affiliated with Chaturbate.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmountaingod2%2Fcb-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmountaingod2%2Fcb-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmountaingod2%2Fcb-events/lists"}