|
1 | 1 | """Grass earnings collector. |
2 | 2 |
|
3 | | -Uses the Grass API with an access token (from browser session) to fetch |
4 | | -cumulative points. Grass uses OTP email login with no password, so users |
5 | | -must provide their access token from the browser. |
| 3 | +Uses the Grass API with an access token (from browser localStorage) to |
| 4 | +fetch cumulative points from the /retrieveUser endpoint. |
6 | 5 |
|
7 | 6 | To get the token: open app.grass.io, log in, press F12, go to |
8 | 7 | Application > Local Storage, and copy the `accessToken` value. |
@@ -42,25 +41,22 @@ async def collect(self) -> EarningsResult: |
42 | 41 |
|
43 | 42 | async with httpx.AsyncClient(timeout=30) as client: |
44 | 43 | resp = await client.get( |
45 | | - f"{API_BASE}/users/earnings/epochs", |
| 44 | + f"{API_BASE}/retrieveUser", |
46 | 45 | headers=headers, |
47 | 46 | ) |
48 | 47 |
|
49 | 48 | if resp.status_code in (401, 403): |
50 | 49 | return EarningsResult( |
51 | 50 | platform=self.platform, |
52 | 51 | balance=0.0, |
53 | | - error="Token expired — get a new one from app.grass.io browser console: localStorage.getItem('token')", |
| 52 | + error="Token expired — get a new accessToken from app.grass.io Local Storage", |
54 | 53 | ) |
55 | 54 |
|
56 | 55 | resp.raise_for_status() |
57 | 56 | data = resp.json() |
58 | 57 |
|
59 | | - # Extract total cumulative points from epochs |
60 | | - epoch_earnings = data.get("result", {}).get("data", {}).get("epochEarnings", []) |
61 | | - total_points = 0.0 |
62 | | - if epoch_earnings: |
63 | | - total_points = float(epoch_earnings[0].get("totalCumulativePoints", 0)) |
| 58 | + user = data.get("result", {}).get("data", {}) |
| 59 | + total_points = float(user.get("totalPoints", 0)) |
64 | 60 |
|
65 | 61 | return EarningsResult( |
66 | 62 | platform=self.platform, |
|
0 commit comments