mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-10-05 01:25:33 -03:00
CivitAI's public API deliberately omits prices — paidAccess is trimmed to
{permanent, endsAt} because "pricing belongs to the purchase flow" — but the
public model page embeds the site's own model.getById result, including
paidAccess.terms, in its server-rendered payload. That is read anonymously
(no API key, no internal endpoint, no forged Origin), one request per gated
model, so only the ~2% of models that actually carry a gate pay for it.
- optional capture, off by default: price_tracking_enabled,
price_alert_threshold_buzz (0 = alert on "became free" only) and
price_check_ttl_hours; prices refresh on their own TTL and immediately when a
gate changes, and a failed fetch keeps the stored price instead of blanking it
- versions that stop carrying a gate are marked free (persisted gate_lapsed_at)
and gate transitions are reported as events on the refresh response, so a
version already in the library can announce that it became free
- price_alert_state plus a price_drop edge event; new
GET /api/lm/{type}/updates/price-alerts lists what is under the threshold
- versions tab shows the price (effective, with the list price struck through
and a Blue Buzz note) and a Free Now badge; an update check toasts the
transitions in one message
- the parser and the alerts query are unit-tested against a trimmed page
fixture, and every route definition is now asserted to resolve to a handler
Plan, verification notes and the deviations from it are in
docs/plans/paid-model-price-tracking.md.
109 lines
4.2 KiB
HTML
109 lines
4.2 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Trimmed stand-in for a CivitAI model page, mirroring the shape verified against
|
|
civitai.com / civitai.red. Values are synthetic; the structure (unrelated query
|
|
first, then the model.getById query, tombstones included) is what matters.
|
|
-->
|
|
<html>
|
|
<head>
|
|
<title>Fixture model</title>
|
|
</head>
|
|
<body>
|
|
<script id="__NEXT_DATA__" type="application/json">
|
|
{
|
|
"props": {
|
|
"pageProps": {
|
|
"trpcState": {
|
|
"json": {
|
|
"queries": [
|
|
{
|
|
"queryKey": [["common", "getEntityAccess"], { "entityId": 1001 }],
|
|
"state": { "data": [] }
|
|
},
|
|
{
|
|
"queryKey": [
|
|
["model", "getById"],
|
|
{ "input": { "id": 4242, "browsingLevel": 1 }, "type": "query" }
|
|
],
|
|
"state": {
|
|
"data": {
|
|
"id": 4242,
|
|
"name": "Fixture model",
|
|
"modelVersions": [
|
|
{
|
|
"id": 1001,
|
|
"name": "permanent paid",
|
|
"canDownload": false,
|
|
"paidAccess": {
|
|
"endsAt": null,
|
|
"timeframeDays": null,
|
|
"terms": {
|
|
"download": { "price": 5000 },
|
|
"generation": { "price": 100, "trialLimit": 5 }
|
|
},
|
|
"sale": null
|
|
}
|
|
},
|
|
{
|
|
"id": 1002,
|
|
"name": "timed gate on sale",
|
|
"canDownload": false,
|
|
"paidAccess": {
|
|
"endsAt": "2999-10-10T13:10:17.404Z",
|
|
"timeframeDays": 7,
|
|
"terms": {
|
|
"download": { "price": 125 },
|
|
"generation": { "trialLimit": 10 },
|
|
"acceptsBlueBuzz": true
|
|
},
|
|
"sale": {
|
|
"listTerms": { "download": { "price": 125 } },
|
|
"buyerTerms": { "download": { "price": 100 } },
|
|
"endsAt": "2999-09-01T00:00:00.000Z",
|
|
"discountType": "percent",
|
|
"discountAmount": 20
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"id": 1003,
|
|
"name": "timed gate with no recorded end",
|
|
"canDownload": false,
|
|
"paidAccess": {
|
|
"endsAt": null,
|
|
"timeframeDays": 7,
|
|
"terms": { "download": { "price": 300 } },
|
|
"sale": null
|
|
}
|
|
},
|
|
{
|
|
"id": 1004,
|
|
"name": "lapsed gate (tombstone)",
|
|
"canDownload": true,
|
|
"paidAccess": {
|
|
"endsAt": "2000-08-27T16:56:57.438Z",
|
|
"timeframeDays": 3,
|
|
"terms": { "download": { "price": 200 } },
|
|
"sale": null
|
|
}
|
|
},
|
|
{
|
|
"id": 1005,
|
|
"name": "never gated",
|
|
"canDownload": true,
|
|
"paidAccess": null
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|