diff --git a/app/beauty_main.py b/app/beauty_main.py index 1b85130..f00ecf2 100644 --- a/app/beauty_main.py +++ b/app/beauty_main.py @@ -155,6 +155,8 @@ async def enriched( site_type: str = Query(None), keyword: str = Query(None), tld: str = Query(None), + alpha_only: bool = Query(False), + no_sld: bool = Query(False), page: int = Query(1, ge=1), limit: int = Query(100, ge=1, le=1000), ): @@ -162,6 +164,7 @@ async def enriched( min_score=min_score, country=country, prescreen_status=prescreen_status, niche=niche, site_type=site_type, keyword=keyword, tld=tld, + alpha_only=alpha_only, no_sld=no_sld, page=page, limit=limit, ) return {"page": page, "limit": limit, "total": total, "results": rows} diff --git a/app/db.py b/app/db.py index c246750..4e89109 100644 --- a/app/db.py +++ b/app/db.py @@ -336,6 +336,7 @@ async def get_enriched(min_score=0, cms=None, country=None, kit_digital=None, ai_only=False, lead_quality=None, prescreen_status=None, niche=None, site_type=None, keyword=None, tld=None, + alpha_only=False, no_sld=False, page=1, limit=100): offset = (page - 1) * limit conditions = ["score >= ?"] @@ -378,6 +379,17 @@ async def get_enriched(min_score=0, cms=None, country=None, kit_digital=None, tld_clean = tld.lower().lstrip(".") conditions.append("LOWER(domain) LIKE ?") params.append(f"%.{tld_clean}") + if alpha_only: + # No hyphens, no digits anywhere in the domain name + conditions.append( + "domain NOT LIKE '%-%' AND domain NOT LIKE '%0%' AND domain NOT LIKE '%1%'" + " AND domain NOT LIKE '%2%' AND domain NOT LIKE '%3%' AND domain NOT LIKE '%4%'" + " AND domain NOT LIKE '%5%' AND domain NOT LIKE '%6%' AND domain NOT LIKE '%7%'" + " AND domain NOT LIKE '%8%' AND domain NOT LIKE '%9%'" + ) + if no_sld: + # Exactly one dot → only name.tld, excludes shop.com.es style + conditions.append("(LENGTH(domain) - LENGTH(REPLACE(domain, '.', ''))) = 1") where = "WHERE " + " AND ".join(conditions) async with aiosqlite.connect(SQLITE_PATH, timeout=30) as db: db.row_factory = aiosqlite.Row diff --git a/app/static/beauty/index.html b/app/static/beauty/index.html index 1af2d6d..ab481d9 100644 --- a/app/static/beauty/index.html +++ b/app/static/beauty/index.html @@ -492,16 +492,24 @@ function app() { if (this.f.tld) p.set('tld', this.f.tld.trim()); if (this.f.alpha_only) p.set('alpha_only', 'true'); if (this.f.no_sld) p.set('no_sld', 'true'); - const d = await fetch('/api/domains?' + p).then(r=>r.json()); + + const hasEnrichFilter = this.f.prescreen_status || this.f.niche || this.f.site_type || this.f.country; + let endpoint; + if (hasEnrichFilter) { + // Enrichment filters require the SQLite table — add them server-side + if (this.f.prescreen_status) p.set('prescreen_status', this.f.prescreen_status); + if (this.f.niche) p.set('niche', this.f.niche); + if (this.f.site_type) p.set('site_type', this.f.site_type); + if (this.f.country) p.set('country', this.f.country.trim().toUpperCase()); + endpoint = '/api/enriched'; + } else { + // Discovery mode: search full 72M DuckDB index (e.g. "Not checked" keyword search) + endpoint = '/api/domains'; + } + + const d = await fetch(endpoint + '?' + p).then(r=>r.json()); this.domainsTotal = d.total || 0; - let rows = d.results || []; - // Client-side filters (same pattern as main DomGod) - if (this.f.prescreen_status === 'none') rows = rows.filter(r => !r.prescreen_status); - else if (this.f.prescreen_status) rows = rows.filter(r => r.prescreen_status === this.f.prescreen_status); - if (this.f.niche) rows = rows.filter(r => r.niche === this.f.niche); - if (this.f.site_type) rows = rows.filter(r => r.site_type === this.f.site_type); - if (this.f.country) rows = rows.filter(r => r.ip_country === this.f.country.trim().toUpperCase()); - this.domains = rows; + this.domains = d.results || []; } catch(e) { this.notify('Failed to load: '+e.message, 'error'); } finally { this.loading = false; } }, @@ -596,7 +604,7 @@ function app() { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({domains:[domain]}), }).then(r=>r.json()); - this.notify(`${domain}: ${d.live?'live':'dead/parked'}, classified: ${d.classified}`, 'success'); + this.notify(`${domain}: ${d.live?'✅ live':'☠ dead/parked'}${d.classifying?' · classifying in background':''}`, 'success'); await this.loadDomains(); } catch(e) { this.notify('Failed: '+e.message, 'error'); } },