backloggd-py 0.1.0__tar.gz

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.
Files changed (31) hide show
  1. backloggd_py-0.1.0/.gitignore +74 -0
  2. backloggd_py-0.1.0/LICENSE +21 -0
  3. backloggd_py-0.1.0/PKG-INFO +409 -0
  4. backloggd_py-0.1.0/README.md +373 -0
  5. backloggd_py-0.1.0/pyproject.toml +75 -0
  6. backloggd_py-0.1.0/src/backloggd/__init__.py +74 -0
  7. backloggd_py-0.1.0/src/backloggd/analytics/__init__.py +3 -0
  8. backloggd_py-0.1.0/src/backloggd/analytics/matcher.py +152 -0
  9. backloggd_py-0.1.0/src/backloggd/cache.py +621 -0
  10. backloggd_py-0.1.0/src/backloggd/client.py +791 -0
  11. backloggd_py-0.1.0/src/backloggd/exceptions.py +34 -0
  12. backloggd_py-0.1.0/src/backloggd/models/__init__.py +31 -0
  13. backloggd_py-0.1.0/src/backloggd/models/comparison.py +31 -0
  14. backloggd_py-0.1.0/src/backloggd/models/game.py +83 -0
  15. backloggd_py-0.1.0/src/backloggd/models/journal.py +23 -0
  16. backloggd_py-0.1.0/src/backloggd/models/library.py +157 -0
  17. backloggd_py-0.1.0/src/backloggd/models/list.py +28 -0
  18. backloggd_py-0.1.0/src/backloggd/models/review.py +23 -0
  19. backloggd_py-0.1.0/src/backloggd/models/user.py +48 -0
  20. backloggd_py-0.1.0/src/backloggd/parsers/__init__.py +29 -0
  21. backloggd_py-0.1.0/src/backloggd/parsers/game_page.py +90 -0
  22. backloggd_py-0.1.0/src/backloggd/parsers/games.py +149 -0
  23. backloggd_py-0.1.0/src/backloggd/parsers/journal.py +94 -0
  24. backloggd_py-0.1.0/src/backloggd/parsers/lists.py +112 -0
  25. backloggd_py-0.1.0/src/backloggd/parsers/profile.py +124 -0
  26. backloggd_py-0.1.0/src/backloggd/parsers/reviews.py +222 -0
  27. backloggd_py-0.1.0/src/backloggd/parsers/search.py +112 -0
  28. backloggd_py-0.1.0/src/backloggd/parsers/social.py +54 -0
  29. backloggd_py-0.1.0/src/backloggd/py.typed +1 -0
  30. backloggd_py-0.1.0/src/backloggd/sync_client.py +794 -0
  31. backloggd_py-0.1.0/src/backloggd/utils.py +134 -0
@@ -0,0 +1,74 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # C extensions
8
+ *.so
9
+
10
+ # Distribution / packaging
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # Virtual environments
30
+ .venv/
31
+ env/
32
+ venv/
33
+ ENV/
34
+ env.bak/
35
+ venv.bak/
36
+
37
+ # Testing & Coverage
38
+ .pytest_cache/
39
+ .tox/
40
+ .nox/
41
+ .coverage
42
+ .coverage.*
43
+ .cache
44
+ nosetests.xml
45
+ coverage.xml
46
+ *.cover
47
+ *.py,cover
48
+ .hypothesis/
49
+
50
+ # Agent & AI tool metadata
51
+ .agents/
52
+ .gemini/
53
+
54
+ # IDE & Editor files
55
+ .idea/
56
+ .vscode/
57
+ *.swp
58
+ *.swo
59
+ *~
60
+ .DS_Store
61
+ Thumbs.db
62
+
63
+ # Output & Cache files
64
+ *.csv
65
+ .cache/
66
+ *.db
67
+ *.sqlite3
68
+
69
+ # Local credentials & secrets
70
+ cookies.local.json
71
+ *.local.json
72
+ .env
73
+ .env.*
74
+ !.env.example
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Arda Günaydın
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,409 @@
1
+ Metadata-Version: 2.5
2
+ Name: backloggd-py
3
+ Version: 0.1.0
4
+ Summary: Fast, typed async & sync Python SDK, web scraper, and taste-matching engine for Backloggd.
5
+ Project-URL: Homepage, https://github.com/ardax12/backloggd-matcher
6
+ Project-URL: Documentation, https://github.com/ardax12/backloggd-matcher#readme
7
+ Project-URL: Repository, https://github.com/ardax12/backloggd-matcher
8
+ Project-URL: Issues, https://github.com/ardax12/backloggd-matcher/issues
9
+ Project-URL: Changelog, https://github.com/ardax12/backloggd-matcher/releases
10
+ Author: Arda
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: backloggd,gaming,letterboxd,recommendation-engine,scraper,sdk,taste-matcher,video-games
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Natural Language :: English
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Games/Entertainment
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
26
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.11
29
+ Requires-Dist: beautifulsoup4>=4.12.0
30
+ Requires-Dist: httpx[http2]>=0.28.1
31
+ Requires-Dist: lxml>=6.1.3
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
34
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # backloggd-py
38
+
39
+ [![PyPI version](https://img.shields.io/badge/pypi-v0.1.0-blue.svg)](https://pypi.org/project/backloggd-py/)
40
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-3776ab.svg)](https://www.python.org/)
41
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
42
+ [![Tests: 28 Passing](https://img.shields.io/badge/tests-28%20passing-brightgreen.svg)](#testing)
43
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
44
+
45
+ A modern, high-performance async & sync Python SDK, web scraper, and taste-matching recommendation engine for [Backloggd](https://backloggd.com).
46
+
47
+ Because Backloggd has no public REST API, `backloggd-py` provides an ergonomic, fully-typed interface to extract user libraries, profile cards, play journals, game reviews, and catalog queries—complete with an offline SQLite cache and Bayesian taste similarity analysis.
48
+
49
+ ---
50
+
51
+ ## Highlights
52
+
53
+ - **Dual Sync & Async Engines**: Use `Backloggd` for scripts, notebooks, and ETL, or `BackloggdClient` with `async`/`await` for Discord bots and FastAPI services.
54
+ - **Sub-Second Profile Scraping**: Direct `/u/<username>/` parser fetches avatars, bios, badges, pinned favorites, and quick counters in ~300ms without paginating thousands of library items.
55
+ - **Path-Based Sorting & Filtering**: Natural Python dictionaries that map cleanly to Backloggd's native URL path segments (`sort="rating"`, `filter={"genre": "rpg", "platform": "ps5"}`).
56
+ - **Targeted Collections**: Rapidly query active play statuses (`playing`, `backlog`, `wishlist`) without fetching entire backlogs.
57
+ - **Global Catalog Browsing**: Search any game or explore top games filtered by platform, genre, and release year.
58
+ - **Social Graph & Mutuals**: Extract followers and following lists, and automatically compute mutual friends.
59
+ - **Taste Recommendation Engine**: Bayesian Pearson correlation, Szymkiewicz-Simpson overlap, and Jaccard metrics to compare gaming tastes and recommend unplayed gems.
60
+ - **Transparent Multi-Table SQLite Cache**: Built-in TTL caching per entity (Profiles, Libraries, Games, Reviews, Lists) with instant invalidation.
61
+
62
+ ---
63
+
64
+ ## Quickstart
65
+
66
+ ```python
67
+ from backloggd import Backloggd, GameStatus
68
+
69
+ with Backloggd() as client:
70
+ # 1. Instant profile overview (~300ms)
71
+ profile = client.get_user_profile("ardax12")
72
+ print(f"{profile.username} | {profile.played_count} played | Bio: {profile.bio}")
73
+
74
+ # 2. Paginated user library
75
+ library = client.get_user_library("ardax12", max_pages=2)
76
+ top_games = library.filter(status=GameStatus.PLAYED, min_rating=4.5)
77
+ print(f"Top rated games ({len(top_games)}): {[g.title for g in top_games]}")
78
+
79
+ # 3. Taste comparison between two users
80
+ match = client.compare_users("ardax12", "nehir")
81
+ print(f"Compatibility: {match.similarity_score}%")
82
+ print("Mutual Favorites:", [g.title for g in match.mutual_favorites[:3]])
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Installation
88
+
89
+ ### From Source (Current)
90
+
91
+ ```bash
92
+ git clone https://github.com/ardax12/backloggd-matcher.git
93
+ cd backloggd-matcher
94
+ pip install -e .
95
+ ```
96
+
97
+ Or using [`uv`](https://github.com/astral-sh/uv):
98
+ ```bash
99
+ uv pip install -e ".[dev]"
100
+ ```
101
+
102
+ ### From PyPI (Upcoming v0.1.0 release)
103
+
104
+ ```bash
105
+ pip install backloggd-py
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Authentication
111
+
112
+ Backloggd uses Cloudflare / Anubis bot verification. Providing your active session cookie bypasses challenge gates and unlocks full, unthrottled access.
113
+
114
+ ### 1. Environment Variable (Recommended for CI / Docker / Cloud)
115
+
116
+ ```bash
117
+ export BACKLOGGD_SESSION="your_cookie_value_here"
118
+ ```
119
+
120
+ ### 2. `cookies.json` File
121
+
122
+ Extract `_backloggd_session` from DevTools (`F12` -> Application -> Cookies -> `https://backloggd.com`) and save to `cookies.json`:
123
+
124
+ ```json
125
+ [
126
+ {
127
+ "name": "_backloggd_session",
128
+ "value": "your_cookie_value_here",
129
+ "domain": "backloggd.com"
130
+ }
131
+ ]
132
+ ```
133
+
134
+ *(A flat dictionary `{"_backloggd_session": "..."}` is also supported.)*
135
+
136
+ ---
137
+
138
+ ## Usage Guide
139
+
140
+ ### 1. User Profiles (`get_user_profile`)
141
+
142
+ Fetches user metadata from the root profile page without scanning the game library:
143
+
144
+ ```python
145
+ with Backloggd() as client:
146
+ profile = client.get_user_profile("ardax12")
147
+
148
+ print(profile.username) # "ardax12"
149
+ print(profile.avatar_url) # "https://images.backloggd.com/..."
150
+ print(profile.bio) # User bio text
151
+ print(profile.badges) # ["goty_2025", "total_played3", ...]
152
+ print(profile.short_url) # "https://bckl.gg/..."
153
+ print(profile.played_count) # 248
154
+ print(profile.playing_count) # 3
155
+ print(profile.backlog_count) # 112
156
+ print(profile.wishlist_count) # 54
157
+
158
+ # Pinned favorite games (list[GameEntry])
159
+ for game in profile.favorite_games:
160
+ print(f"★ {game.title} (Cover: {game.cover_url})")
161
+ ```
162
+
163
+ ### 2. User Libraries & Collections
164
+
165
+ ```python
166
+ with Backloggd() as client:
167
+ # Full library with pagination limit
168
+ library = client.get_user_library("ardax12", max_pages=3)
169
+
170
+ # Filter in-memory
171
+ played_5_stars = library.filter(status="played", min_rating=5.0)
172
+
173
+ # Export to CSV or Python dict
174
+ library.to_csv("my_library.csv")
175
+ records = library.to_dict()
176
+
177
+ # Fast targeted queries (bypasses full library pagination)
178
+ playing = client.get_user_playing("ardax12")
179
+ backlog = client.get_user_backlog("ardax12", max_pages=1)
180
+ wishlist = client.get_user_wishlist("ardax12", max_pages=1)
181
+ ```
182
+
183
+ ### 3. Path-Based Sorting & Filtering
184
+
185
+ Backloggd organizes filters as URL path segments (e.g. `/games/rating/type:played;release_platform:ps5/`). The SDK translates standard Python dictionaries:
186
+
187
+ ```python
188
+ with Backloggd() as client:
189
+ # Supported sort keys: "popular", "rating", "release", "title", "last_played", "played"
190
+ top_ps5_played = client.get_user_library(
191
+ "ardax12",
192
+ sort="rating",
193
+ filter={"type": "played", "platform": "ps5"},
194
+ max_pages=2,
195
+ )
196
+
197
+ # Sort targeted collections
198
+ wishlist_by_popularity = client.get_user_wishlist("ardax12", sort="popular")
199
+ ```
200
+
201
+ ### 4. Global Games Catalog Browsing
202
+
203
+ Explore or search games across Backloggd:
204
+
205
+ ```python
206
+ with Backloggd() as client:
207
+ # Search for a specific title
208
+ results = client.search_games("Metaphor ReFantazio")
209
+ for r in results:
210
+ print(f"{r.title} ({r.release_year}) -> {r.slug}")
211
+
212
+ # Browse catalog with sorting & category filtering
213
+ popular_rpgs = client.browse_games(
214
+ sort="popular",
215
+ filter={"genre": "role-playing-rpg", "platform": "win"},
216
+ max_pages=1,
217
+ )
218
+
219
+ # Game details
220
+ elden_ring = client.get_game("elden-ring")
221
+ print(f"{elden_ring.title}: {elden_ring.rating_stars}* ({elden_ring.plays_count} plays)")
222
+ ```
223
+
224
+ ### 5. Social Graph: Followers, Following & Friends
225
+
226
+ ```python
227
+ with Backloggd() as client:
228
+ following = client.get_user_following("ardax12", max_pages=1)
229
+ followers = client.get_user_followers("ardax12", max_pages=1)
230
+
231
+ # Automatically compute mutual friends (followers ∩ following)
232
+ friends = client.get_user_friends("ardax12")
233
+ for friend in friends:
234
+ print(f"Mutual friend: {friend.username} ({friend.url})")
235
+ ```
236
+
237
+ ### 6. Play Journal & Community Reviews
238
+
239
+ ```python
240
+ with Backloggd() as client:
241
+ # Completion journal
242
+ journal = client.get_user_journal("ardax12", max_pages=1)
243
+ for entry in journal:
244
+ replay = " [Replay]" if entry.is_replay else ""
245
+ print(f"{entry.played_date}: {entry.game_title} - {entry.rating}*{replay}")
246
+
247
+ # Game reviews
248
+ reviews = client.get_game_reviews("hollow-knight", max_pages=1)
249
+ for rev in reviews[:3]:
250
+ print(f"{rev.author} ({rev.rating}*): {rev.review_text[:100]}...")
251
+ ```
252
+
253
+ ### 7. Taste Matching & Recommendations
254
+
255
+ Computes taste compatibility using normalized Bayesian Pearson correlation, Jaccard overlap, and relative rating agreement:
256
+
257
+ ```python
258
+ with Backloggd() as client:
259
+ match = client.compare_users("ardax12", "nehir", max_pages=2)
260
+
261
+ print(f"Match Score: {match.similarity_score}%")
262
+ print(f"Shared Games: {match.overlap_count}")
263
+
264
+ print("Mutual Favorites:")
265
+ for g in match.mutual_favorites:
266
+ print(f" - {g.title}")
267
+
268
+ print("Polarizing Disagreements:")
269
+ for d in match.disagreements:
270
+ print(f" - {d.title}: {d.user1_rating}* vs {d.user2_rating}*")
271
+
272
+ print("Recommendations for User 1:")
273
+ for rec in match.recommendations_for_user1[:5]:
274
+ print(f" - {rec.title}")
275
+ ```
276
+
277
+ ### 8. Asynchronous Client (`BackloggdClient`)
278
+
279
+ For high-throughput bots, crawlers, or asynchronous web frameworks:
280
+
281
+ ```python
282
+ import asyncio
283
+ from backloggd import BackloggdClient
284
+
285
+ async def main():
286
+ async with BackloggdClient(cookies_file="cookies.json") as client:
287
+ # Run requests concurrently
288
+ profile, playing, catalog = await asyncio.gather(
289
+ client.get_user_profile("ardax12"),
290
+ client.get_user_playing("ardax12"),
291
+ client.browse_games(sort="popular", max_pages=1),
292
+ )
293
+ print(f"Profile: {profile.username}")
294
+ print(f"Currently playing: {len(playing)} games")
295
+ print(f"Top game: {catalog[0].title}")
296
+
297
+ asyncio.run(main())
298
+ ```
299
+
300
+ ### 9. SQLite Caching & Invalidation
301
+
302
+ All responses are cached locally in SQLite (`.cache/backloggd_cache.db`) with granular TTLs:
303
+
304
+ | Entity | SQLite Table | Default TTL |
305
+ |:---|:---|:---|
306
+ | User Profile | `profile_cache` | 24 Hours (`86400s`) |
307
+ | User Library | `library_cache` | 24 Hours (`86400s`) |
308
+ | Game Details | `game_cache` | 7 Days (`604800s`) |
309
+ | Game Reviews | `review_cache` | 24 Hours (`86400s`) |
310
+ | Custom Lists | `list_cache` | 24 Hours (`86400s`) |
311
+
312
+ ```python
313
+ # Custom TTL configuration
314
+ client = Backloggd(
315
+ profile_ttl=3600.0, # 1 hour
316
+ library_ttl=3600.0, # 1 hour
317
+ game_ttl=86400.0 * 14, # 14 days
318
+ cache_path="data/custom_cache.db",
319
+ )
320
+
321
+ # Invalidation helpers
322
+ client.cache.delete_profile("ardax12")
323
+ client.cache.delete_library("ardax12")
324
+ client.cache.delete_game("elden-ring")
325
+ client.cache.clear() # Flush entire database
326
+ ```
327
+
328
+ ### 10. Error Handling
329
+
330
+ ```python
331
+ from backloggd import Backloggd
332
+ from backloggd.exceptions import (
333
+ BackloggdError,
334
+ ChallengeResponseError,
335
+ RateLimitError,
336
+ UserNotFoundError,
337
+ GameNotFoundError,
338
+ )
339
+
340
+ with Backloggd() as client:
341
+ try:
342
+ game = client.get_game("unknown-slug-xyz")
343
+ except GameNotFoundError:
344
+ print("Game not found on Backloggd.")
345
+ except ChallengeResponseError:
346
+ print("Cloudflare anti-bot challenge encountered. Update your session cookie.")
347
+ except RateLimitError:
348
+ print("HTTP 429 Rate limited. Automatic backoff failed.")
349
+ except BackloggdError as e:
350
+ print(f"SDK error: {e}")
351
+ ```
352
+
353
+ ---
354
+
355
+ ## API Parity Matrix
356
+
357
+ Both sync and async clients share identical capabilities and signatures:
358
+
359
+ | Capability | Synchronous (`Backloggd`) | Asynchronous (`BackloggdClient`) |
360
+ |:---|:---|:---|
361
+ | Profile Lookup | `get_user_profile(user)` | `await get_user_profile(user)` |
362
+ | Full Library | `get_user_library(user, ...)` | `await get_user_library(user, ...)` |
363
+ | Targeted Collections | `get_user_playing()`, `get_user_backlog()`, `get_user_wishlist()` | `await get_user_playing()`, `get_user_backlog()`, `get_user_wishlist()` |
364
+ | Browse Catalog | `browse_games(sort=..., filter=...)` | `await browse_games(sort=..., filter=...)` |
365
+ | Search Games | `search_games(query)` | `await search_games(query)` |
366
+ | Game Details | `get_game(slug)` | `await get_game(slug)` |
367
+ | Game Reviews | `get_game_reviews(slug)` | `await get_game_reviews(slug)` |
368
+ | User Reviews | `get_user_reviews(user)` | `await get_user_reviews(user)` |
369
+ | User Lists | `get_user_lists(user)`, `get_list(url)` | `await get_user_lists(user)`, `get_list(url)` |
370
+ | Social Graph | `get_user_followers()`, `get_user_following()`, `get_user_friends()` | `await get_user_followers()`, `get_user_following()`, `get_user_friends()` |
371
+ | Play Journal | `get_user_journal(user)` | `await get_user_journal(user)` |
372
+ | Taste Matching | `compare_users(user1, user2)` | `await compare_users(user1, user2)` |
373
+
374
+ ---
375
+
376
+ ## Testing
377
+
378
+ Run the full test suite with 28 unit and integration tests:
379
+
380
+ ```bash
381
+ # Using pytest
382
+ pytest
383
+
384
+ # Or via uv
385
+ uv run pytest
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Roadmap
391
+
392
+ - [x] Dual sync & async client architecture with 100% method parity
393
+ - [x] Sub-second profile scraping (`get_user_profile`)
394
+ - [x] Full paginated library retrieval with bounded concurrency
395
+ - [x] Path-based URL sorting and multi-criteria filtering
396
+ - [x] Targeted instant collections (`playing`, `backlog`, `wishlist`)
397
+ - [x] Social network scraping and mutual friends calculation
398
+ - [x] Playthrough journal & community review extraction
399
+ - [x] Global games catalog browsing (`browse_games`)
400
+ - [x] Persistent multi-table SQLite cache with customizable TTLs
401
+ - [x] Bayesian taste similarity engine & recommendations
402
+ - [ ] Rich terminal CLI (`backloggd-cli`)
403
+ - [ ] PyPI publishing via GitHub Actions CI/CD
404
+
405
+ ---
406
+
407
+ ## License
408
+
409
+ Distributed under the [MIT License](LICENSE).