sylvia-api 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
sylvia/__init__.py ADDED
@@ -0,0 +1,22 @@
1
+ """
2
+ Sylvia Reddit API Client — fastest way to access Reddit data at scale.
3
+ No OAuth. No rate limit headaches. Just an API key.
4
+
5
+ pip install sylvia-api
6
+ export SYLVIA_API_KEY=syl_xxx
7
+
8
+ from sylvia import Sylvia
9
+ s = Sylvia()
10
+ python = s.subreddit("python")
11
+ print(f"{python['name']}: {python['members']:,} members")
12
+ for post in s.subreddit_posts("python", sort="hot", limit=5):
13
+ print(f" {post['score']} — {post['title']}")
14
+
15
+ License: MIT
16
+ """
17
+
18
+ from .client import Sylvia
19
+ from .exceptions import SylviaError, AuthenticationError, RateLimitError, InsufficientCreditsError
20
+
21
+ __version__ = "1.0.0"
22
+ __all__ = ["Sylvia", "SylviaError", "AuthenticationError", "RateLimitError", "InsufficientCreditsError"]
sylvia/client.py ADDED
@@ -0,0 +1,117 @@
1
+ import os
2
+ import time
3
+ from typing import Optional, Iterator, Dict, Any, List
4
+
5
+ import requests
6
+
7
+
8
+ class Sylvia:
9
+ """Reddit data API client. No OAuth. Just works."""
10
+
11
+ BASE_URL = "https://api.sylvia-api.com/v1/reddit/"
12
+
13
+ def __init__(
14
+ self,
15
+ api_key: Optional[str] = None,
16
+ max_retries: int = 3,
17
+ timeout: int = 60,
18
+ ):
19
+ self.api_key = api_key or os.environ.get("SYLVIA_API_KEY")
20
+ if not self.api_key:
21
+ raise ValueError(
22
+ "API key required. Set SYLVIA_API_KEY env var or pass api_key=..."
23
+ )
24
+ self.max_retries = max_retries
25
+ self.timeout = timeout
26
+ self._session = requests.Session()
27
+ self._session.headers.update({"X-API-KEY": self.api_key})
28
+
29
+ def _request(self, path: str, params: Optional[Dict] = None) -> Dict[str, Any]:
30
+ url = f"{self.BASE_URL}{path}"
31
+ for attempt in range(self.max_retries + 1):
32
+ resp = self._session.get(url, params=params, timeout=self.timeout)
33
+ if resp.status_code == 200:
34
+ return resp.json()
35
+ if resp.status_code == 401:
36
+ raise AuthenticationError("Invalid API key. Get one at https://sylvia-api.com")
37
+ if resp.status_code == 429:
38
+ retry = int(resp.headers.get("Retry-After", 5))
39
+ if attempt < self.max_retries:
40
+ time.sleep(retry)
41
+ continue
42
+ raise RateLimitError(retry)
43
+ if resp.status_code == 402:
44
+ raise InsufficientCreditsError("Add credits at https://sylvia-api.com/dashboard")
45
+ resp.raise_for_status()
46
+ raise SylviaError("Max retries exceeded")
47
+
48
+ def subreddit(self, name: str) -> Dict[str, Any]:
49
+ data = self._request(f"r/{name}/about")
50
+ return data.get("data", data)
51
+
52
+ def subreddit_posts(
53
+ self, name: str, sort: str = "hot", limit: int = 25, after: Optional[str] = None,
54
+ ) -> List[Dict[str, Any]]:
55
+ params = {"limit": min(limit, 100)}
56
+ if after:
57
+ params["after"] = after
58
+ data = self._request(f"r/{name}/{sort}", params=params)
59
+ return data.get("data", {}).get("posts", [])
60
+
61
+ def subreddit_posts_iter(
62
+ self, name: str, sort: str = "hot", limit: int = 100,
63
+ ) -> Iterator[Dict[str, Any]]:
64
+ yielded = 0
65
+ after = None
66
+ while yielded < limit:
67
+ batch = self.subreddit_posts(name, sort=sort, limit=min(limit - yielded, 100), after=after)
68
+ if not batch:
69
+ break
70
+ for post in batch:
71
+ yield post
72
+ yielded += 1
73
+ if yielded >= limit:
74
+ return
75
+ after = batch[-1].get("name")
76
+
77
+ def user(self, username: str) -> Dict[str, Any]:
78
+ data = self._request(f"u/{username}/about")
79
+ return data.get("data", data)
80
+
81
+ def user_posts(self, username: str, where: str = "submitted", limit: int = 25) -> List[Dict[str, Any]]:
82
+ params = {"limit": min(limit, 100)}
83
+ data = self._request(f"u/{username}/{where}", params=params)
84
+ return data.get("data", {}).get("children", [])
85
+
86
+ def search(
87
+ self, query: str, sort: str = "relevance", limit: int = 25,
88
+ subreddit: Optional[str] = None, include_over_18: bool = False,
89
+ ) -> List[Dict[str, Any]]:
90
+ params = {"q": query, "sort": sort, "limit": min(limit, 100)}
91
+ if subreddit:
92
+ params["subreddit"] = subreddit
93
+ if include_over_18:
94
+ params["include_over_18"] = "true"
95
+ data = self._request("search", params=params)
96
+ return data.get("data", {}).get("results", [])
97
+
98
+ def post(self, url: str) -> Dict[str, Any]:
99
+ data = self._request("submission", params={"url": url})
100
+ return data.get("data", data)
101
+
102
+ def comment(self, url: str) -> Dict[str, Any]:
103
+ data = self._request("comment", params={"url": url})
104
+ return data.get("data", data)
105
+
106
+ def thread(self, post_id: str) -> Dict[str, Any]:
107
+ data = self._request(f"submission/{post_id}/full")
108
+ return data.get("data", data)
109
+
110
+ def live_comments(self, limit: int = 25) -> List[Dict[str, Any]]:
111
+ data = self._request("comments/live", params={"limit": min(limit, 100)})
112
+ return data.get("data", {}).get("comments", [])
113
+
114
+ def domain(self, domain: str, sort: str = "hot", limit: int = 25) -> List[Dict[str, Any]]:
115
+ params = {"domain": domain, "sort": sort, "limit": min(limit, 100)}
116
+ data = self._request("domain", params=params)
117
+ return data.get("data", {}).get("posts", [])
sylvia/exceptions.py ADDED
@@ -0,0 +1,13 @@
1
+ class SylviaError(Exception):
2
+ pass
3
+
4
+ class AuthenticationError(SylviaError):
5
+ pass
6
+
7
+ class RateLimitError(SylviaError):
8
+ def __init__(self, retry_after: int = 0):
9
+ self.retry_after = retry_after
10
+ super().__init__(f"Rate limited. Retry after {retry_after}s")
11
+
12
+ class InsufficientCreditsError(SylviaError):
13
+ pass
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.4
2
+ Name: sylvia-api
3
+ Version: 1.0.0
4
+ Summary: Reddit data API client — no OAuth, no rate limits. Subreddits, users, search, live comments.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://sylvia-api.com
7
+ Project-URL: Documentation, https://sylvia-api.com/docs
8
+ Project-URL: Repository, https://github.com/emraan-harshme/sylvia-sdk
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Topic :: Internet :: WWW/HTTP
11
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: requests>=2.25
15
+
16
+ # Sylvia Reddit API
17
+
18
+ **The fastest way to access Reddit data at scale.** No OAuth. No rate limit headaches. No browser automation. Just an API key.
19
+
20
+ ```bash
21
+ pip install sylvia-api
22
+ ```
23
+
24
+ ## Quickstart
25
+
26
+ ```python
27
+ from sylvia import Sylvia
28
+
29
+ # Sign up at https://sylvia-api.com to get your key
30
+ sylvia = Sylvia(api_key="syl_...")
31
+
32
+ # Subreddit info
33
+ python_sub = sylvia.subreddit("python")
34
+ print(f"r/{python_sub['name']}: {python_sub['members']:,} members")
35
+
36
+ # Get top posts
37
+ for post in sylvia.subreddit_posts("programming", sort="hot", limit=5):
38
+ print(f"🔥 {post['score']} — {post['title']}")
39
+
40
+ # User profile
41
+ spez = sylvia.user("spez")
42
+ print(f"u/spez: {spez['comment_karma']:,} comment karma")
43
+
44
+ # Global search (not available in Reddit's own API!)
45
+ results = sylvia.search("llama 4 model", limit=10)
46
+ for post in results:
47
+ print(f"r/{post['subreddit']} — {post['title']}")
48
+
49
+ # Live comment firehose
50
+ for comment in sylvia.live_comments(limit=10):
51
+ print(f"u/{comment['author']}: {comment['body'][:100]}")
52
+
53
+ # Thread with ALL nested comments expanded
54
+ thread = sylvia.thread("1tlh5aj")
55
+ ```
56
+
57
+ ## How It Works
58
+
59
+ Sylvia operates a fleet of real residential proxy engines that fetch Reddit data through actual browsers. This means:
60
+ - **No OAuth** needed — just an API key
61
+ - **480 req/min free** (with free tier API key)
62
+ - **Global search** across all of Reddit
63
+ - **Live comment firehose** in real-time
64
+ - **Automatic IP rotation** — Reddit never blocks you
65
+
66
+ ## Pricing
67
+
68
+ | Tier | Rate Limit | Price |
69
+ |------|-----------|-------|
70
+ | Free | 8 req/s (480/min) | $0 |
71
+ | Strela | 20 req/s | $50/mo |
72
+ | Svetka | 40 req/s | $200/mo |
73
+ | Enterprise | 60+ req/s | Custom |
74
+
75
+ Per-request billing: **$0.0005/request** ($0.50 per 1,000 requests). Failed requests are not charged.
76
+
77
+ [Sign up free →](https://sylvia-api.com)
78
+
79
+ ## Comparison
80
+
81
+ | | Sylvia | Reddit API | Bright Data | Apify |
82
+ |---|---|---|---|---|
83
+ | OAuth required | ❌ No | ✅ Yes | ❌ No | ❌ No |
84
+ | Global search | ✅ Yes | ❌ No | ❌ No | Limited |
85
+ | Live comments | ✅ Yes | ❌ No | ❌ No | ✅ Yes |
86
+ | Auto IP rotation | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes |
87
+ | Free tier | 480 req/min | 60 req/min | None | 100 req/mo |
88
+ | Per-1K cost | $0.50 | Free (limited) | $8.40/GB | ~$5/1K |
89
+
90
+ ## License
91
+
92
+ MIT
@@ -0,0 +1,7 @@
1
+ sylvia/__init__.py,sha256=xN_-CJNjzsPYFn9k-Ceq02SjhOhX-Lfwqr-zuCOTXps,731
2
+ sylvia/client.py,sha256=JOFeVn8or-WCOAcz_m5SKelvskDYaBX9DcrGm5ktkKA,4631
3
+ sylvia/exceptions.py,sha256=YPgZyRBGcPBQyxlcYsa-j8jo4-MKsDMiboae7IB42FU,335
4
+ sylvia_api-1.0.0.dist-info/METADATA,sha256=PQv3gzg4gw_nblDrBdpNgbmmFvhfoH1T4KWlQiLrteg,2872
5
+ sylvia_api-1.0.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
6
+ sylvia_api-1.0.0.dist-info/top_level.txt,sha256=BuiI5LL-PXD444cHUXAFgxx-fDpUjvU_-KXq4w9K1L4,7
7
+ sylvia_api-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ sylvia