Brings up the pull-model scraper: the .NET C2 hands skin+wear jobs to Python nodriver workers that scrape cs.money and post results back, plus the supporting Core/EFCore data model, migrations, and docker-compose orchestration. IPRoyal proxying lets workers scale horizontally with a distinct residential exit IP each: every worker process mints its own sticky session at startup, and an in-process forwarding proxy injects the gateway auth so Chromium talks only to an auth-free localhost endpoint (zero CDP). On a Cloudflare challenge a worker rotates to a fresh session/IP and re-warms. Verified end-to-end against live IPRoyal: distinct US residential exits per worker and IP rotation on demand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
60 lines
2.4 KiB
SQL
60 lines
2.4 KiB
SQL
-- ============================================================
|
||
-- CS2 Skin Tracker — populate skin_conditions (per-skin wear tiers)
|
||
-- Run against the skintracker database as the app role.
|
||
-- Idempotent: re-running only inserts rows that don't exist yet.
|
||
--
|
||
-- The five CS2 wear tiers have fixed global float boundaries, but a
|
||
-- skin only appears in the tiers its own float range reaches, and the
|
||
-- achievable float within a tier is the intersection of the skin's
|
||
-- range with the tier's range. So for each skin we insert one row per
|
||
-- OVERLAPPING tier, with min/max clamped to that intersection.
|
||
--
|
||
-- Factory New 0.00 – 0.07
|
||
-- Minimal Wear 0.07 – 0.15
|
||
-- Field-Tested 0.15 – 0.38
|
||
-- Well-Worn 0.38 – 0.45
|
||
-- Battle-Scarred 0.45 – 1.00
|
||
--
|
||
-- Skins with no float bounds (e.g. Vanilla knives) get no rows.
|
||
-- ============================================================
|
||
|
||
SET search_path = skintracker;
|
||
|
||
INSERT INTO skin_conditions (skin_id, condition, min_float, max_float)
|
||
SELECT
|
||
s.id,
|
||
t.name,
|
||
GREATEST(s.float_min, t.lo) AS min_float, -- clamp the tier to the skin's range
|
||
LEAST(s.float_max, t.hi) AS max_float
|
||
FROM skins s
|
||
CROSS JOIN (VALUES
|
||
('Factory New', 0.00, 0.07),
|
||
('Minimal Wear', 0.07, 0.15),
|
||
('Field-Tested', 0.15, 0.38),
|
||
('Well-Worn', 0.38, 0.45),
|
||
('Battle-Scarred', 0.45, 1.00)
|
||
) AS t(name, lo, hi)
|
||
WHERE s.float_min IS NOT NULL
|
||
AND s.float_max IS NOT NULL
|
||
AND s.float_min < t.hi -- skin's range overlaps this tier...
|
||
AND s.float_max > t.lo -- ...(strict, so a skin starting exactly at a
|
||
-- boundary doesn't get the tier below it)
|
||
AND NOT EXISTS ( -- idempotent: skip tiers already recorded
|
||
SELECT 1
|
||
FROM skin_conditions sc
|
||
WHERE sc.skin_id = s.id
|
||
AND sc.condition = t.name
|
||
)
|
||
ORDER BY s.id, t.lo;
|
||
|
||
-- ------------------------------------------------------------
|
||
-- Sanity checks (optional)
|
||
-- ------------------------------------------------------------
|
||
-- Rows per condition:
|
||
-- SELECT condition, count(*) FROM skin_conditions GROUP BY condition ORDER BY min(min_float);
|
||
--
|
||
-- Spot-check a capped skin (e.g. an Asiimov) shows clamped FT bounds:
|
||
-- SELECT s.name, sc.condition, sc.min_float, sc.max_float
|
||
-- FROM skin_conditions sc JOIN skins s ON s.id = sc.skin_id
|
||
-- WHERE s.name ILIKE 'Asiimov' ORDER BY sc.min_float;
|