Public Access
feat(library): add a speedrun mood from speedrun.com
The picker takes mood=SPEEDRUN for backlog games with a speedrun.com game that has at least one verified run. The game detail returns the link as speedrunUrl. speedrun.com has no Steam or IGDB link, so games are matched by name and, when IGDB knows it, by release year (one year off at most). One queue serves all users at 1 request per second. Results are kept 30 days in game_speedrun.
This commit is contained in:
1 parent
3224257325
commit
393cdddf06
27 files changed
+1179
-22
No files matched your search
@@ -17,8 +17,13 @@ To Be Played is split into three repositories:
|
||||
sync. Resilience4j retries and rate-limits every Steam call; Caffeine caches game counts and player summaries.
|
||||
- **Backlog**: status (`BACKLOG`, `PLAYING`, `FINISHED`, `COMPLETED` = 100 %, `DROPPED`), rating 1–5, notes, priority,
|
||||
filters and sorting. "Pile of Shame" summary with a random suggestion of what to play.
|
||||
- **Picker**: up to 10 random backlog games for a time budget (IGDB normal time to beat), HIGH priority first, then
|
||||
MEDIUM, then the rest. Games already shown can be excluded for a reroll.
|
||||
- **Picker**: up to 10 random backlog games for a time budget (IGDB normal time to beat) and a mood, HIGH priority
|
||||
first, then MEDIUM, then the rest. Games already shown can be excluded for a reroll. Moods `STORY`, `COOP`,
|
||||
`CHILL`, `ACTION`, `SCARY` come from IGDB genres, themes and game modes; `SPEEDRUN` from speedrun.com.
|
||||
- **Speedrun games**: a backlog game counts as a speedrun game when speedrun.com has a game with the same name (and
|
||||
a release year at most one year off, when IGDB knows it) with at least one verified run. The game detail returns
|
||||
the speedrun.com link as `speedrunUrl`. speedrun.com has no Steam or IGDB link and no key, so one queue works for
|
||||
all users, with up to 3 requests per game and 1 request per second; a result is kept 30 days.
|
||||
- **Achievements**: after every library sync a background job fetches the achievement schema of each owned game
|
||||
and the user's unlocks of each game whose playtime changed. One Steam call per second, so user requests keep half
|
||||
of the rate limit; it stops after 3 Steam errors in a row or when Steam hides the achievements. A Steam error never
|
||||
@@ -52,7 +57,7 @@ accepted only by `GET /api/public/profiles/library` in the `X-Profile-Ticket` he
|
||||
| `PUT` | `/api/library/games/{appid}/backlog` | JWT |
|
||||
| `PUT` | `/api/library/games/{appid}/status` (status only, keeps rating, notes, priority) | JWT |
|
||||
| `POST` | `/api/library/sync` | JWT |
|
||||
| `GET` | `/api/library/picker?maxMinutes=&count=&exclude=` | JWT |
|
||||
| `GET` | `/api/library/picker?maxMinutes=&mood=&count=&exclude=` | JWT |
|
||||
| `GET` | `/api/library/achievements/summary` | JWT |
|
||||
| `GET` | `/api/library/sync-status`, `/summary`, `/activity`, `/wishlist`, `/steam-profile`, `/games-count` | JWT |
|
||||
| `GET` | `/api/public/profiles/library` | profile ticket |
|
||||
@@ -62,7 +67,7 @@ accepted only by `GET /api/public/profiles/library` in the `X-Profile-Ticket` he
|
||||
|
||||
- Java 25, Spring Boot 4.1 (Web MVC, Security, Data JPA, Validation, Cache with Caffeine), virtual threads
|
||||
- PostgreSQL 17, Flyway migrations
|
||||
- Resilience4j: retry and rate limiter for Steam, rate limiter for IGDB
|
||||
- Resilience4j: retry and rate limiter for Steam, rate limiters for IGDB and speedrun.com
|
||||
- JJWT with Ed25519 public key
|
||||
- Spring Boot Actuator + Micrometer (Prometheus)
|
||||
- Tests: JUnit 5, Testcontainers (PostgreSQL), ArchUnit
|
||||
@@ -84,14 +89,17 @@ flowchart LR
|
||||
Stats["stats"]
|
||||
Steam["steam_adapter"]
|
||||
Igdb["igdb_adapter"]
|
||||
Speedrun["speedrun_adapter"]
|
||||
LibService --> Steam
|
||||
LibService --> Igdb
|
||||
LibService --> Speedrun
|
||||
end
|
||||
Browser -->|"tbp_access cookie"| Security
|
||||
Security -->|"JWKS by kid"| Auth["ToBePlayed-Auth"]
|
||||
Steam --> SteamApi["Steam Web API"]
|
||||
Igdb --> IgdbApi["IGDB API"]
|
||||
Igdb -->|"OAuth token"| Twitch["Twitch"]
|
||||
Speedrun --> SpeedrunApi["speedrun.com API"]
|
||||
LibRepo --> Db[("PostgreSQL tbp_core")]
|
||||
Stats --> Db
|
||||
```
|
||||
@@ -101,12 +109,14 @@ flowchart LR
|
||||
| `library` | Sync, backlog, manual games, playtime history, wishlist, achievements, public profile data |
|
||||
| `stats` | Public numbers for the landing page |
|
||||
| `steam_adapter` | Steam Web API client |
|
||||
| `igdb_adapter` | IGDB client (Twitch OAuth): time to beat, game tags for moods, game search |
|
||||
| `igdb_adapter` | IGDB client (Twitch OAuth): time to beat, game tags for moods, release years, game search |
|
||||
| `speedrun_adapter` | speedrun.com client: game search by name, verified runs |
|
||||
|
||||
Inside a module: `api` (controllers, DTOs), `service` (business logic), `domain` (JPA entities) and `repo`
|
||||
(repositories). `src/test/java/core_service/architecture/ArchitectureTest.java` checks these rules on every build:
|
||||
|
||||
- Modules do not depend on each other. Only `library` may use `steam_adapter` and `igdb_adapter`.
|
||||
- Modules do not depend on each other. Only `library` may use `steam_adapter`, `igdb_adapter` and
|
||||
`speedrun_adapter`.
|
||||
- No cycles between `modules`, `shared` and `configuration`.
|
||||
- `api` never uses `repo`, and `repo` never uses `api`.
|
||||
- Every class in `repo` ends with `Repository`.
|
||||
@@ -126,7 +136,8 @@ Inside a module: `api` (controllers, DTOs), `service` (business logic), `domain`
|
||||
owns. When Steam returns no games, the library stays as it is.
|
||||
5. `TimeToBeatService` and `MoodService` ask IGDB for missing or old time-to-beat and mood data, for Steam games
|
||||
and manual games.
|
||||
6. After the commit, `LibrarySyncedEvent` starts `AchievementSyncService` in the background.
|
||||
6. After the commit, `LibrarySyncedEvent` starts `AchievementSyncService` and `SpeedrunService` (backlog games only)
|
||||
in the background.
|
||||
|
||||
The frontend polls `GET /api/library/sync-status` until the run ends.
|
||||
|
||||
@@ -180,8 +191,6 @@ Runs unit, WebMvc, persistence and integration tests plus the ArchUnit rules. Ne
|
||||
|
||||
## Roadmap
|
||||
|
||||
- Add a game by name from IGDB for platforms without Steam (needs an internal game id next to the Steam `appid`).
|
||||
- Mood filter for the picker (needs genres or themes from IGDB).
|
||||
- Sale alerts for wishlist games.
|
||||
- Move `steam_adapter` DTOs out of `api`, then turn on strict module independence in ArchUnit.
|
||||
|
||||
|
||||
Reference in new issue
Block a user