using System.Text; namespace BlueLaminate.Core.SkinLand; /// /// Builds a skin.land market URL from the catalogue's weapon + skin + wear. skin.land's /// market routes are /market/csgo/{slug}/ where the slug is simply /// {weapon}-{skin}-{wear} kebab-cased — verified against the live site (e.g. /// "M4A4" + "Global Offensive" + "Battle-Scarred" → m4a4-global-offensive-battle-scarred, /// "AK-47" + "Redline" + "Field-Tested" → ak-47-redline-field-tested). No discovery /// or stored mapping is needed. /// /// StatTrak and Souvenir are separate pages on skin.land (stattrak-/ /// souvenir- prefixed slugs); this builds the base (non-special) page, which is the /// unit v1 sweeps per SkinCondition. /// /// public static class SkinLandSlug { private const string MarketBase = "https://skin.land/market/csgo/"; /// "M4A4", "Global Offensive", "Battle-Scarred" → the full market URL. public static string MarketUrl(string weapon, string skinName, string condition) => $"{MarketBase}{Slugify($"{weapon} {skinName} {condition}")}/"; /// /// Lowercase, collapse every run of non-alphanumeric characters to a single hyphen, /// and trim leading/trailing hyphens. So "AK-47 | Redline (Field-Tested)" and the /// catalogue's "AK-47 Redline Field-Tested" both reduce to "ak-47-redline-field-tested". /// /// The apostrophe is the one exception: skin.land keeps it literally in the slug rather /// than collapsing it to a hyphen (verified live — "AWP | Man-o'-war" → /// awp-man-o'-war, "AUG | Lil' Pig" → aug-lil'-pig; the collapsed /// man-o-war/lil-pig forms 404). Both the ASCII (') and typographic (’) /// apostrophe normalize to a literal ASCII apostrophe in the slug. /// /// public static string Slugify(string value) { var sb = new StringBuilder(value.Length); var pendingHyphen = false; foreach (var ch in value) { if (ch is '\'' or '’') { // skin.land preserves the apostrophe as part of the word — emit it literally, // and don't let it trigger a hyphen on either side. sb.Append('\''); pendingHyphen = false; } else if (char.IsLetterOrDigit(ch)) { if (pendingHyphen && sb.Length > 0) { sb.Append('-'); } sb.Append(char.ToLowerInvariant(ch)); pendingHyphen = false; } else { pendingHyphen = true; } } return sb.ToString(); } }