← back to Adsense Command Post
adsense command post: grid renderer + synced shots/data (TK-11322)
c2f837ff5db45e940a5f1c3ae21321257b3cacfb · 2026-09-09 16:34:55 -0700 · Steve Abrams
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M data/audit-latest.jsonA data/shots/1800wallcoverings.com.pngA data/shots/asseeninhotels.com.pngA data/shots/asseeninla.com.pngA data/shots/asseeninmovies.com.pngA data/shots/asseeninshowrooms.com.pngA data/shots/barwallpaper.com.pngA data/shots/blankstocklining.com.pngA data/shots/carmelwallpaper.com.pngA data/shots/classawallcovering.com.pngA data/shots/commercialsalesreps.com.pngA data/shots/commercialwallcovering.com.pngA data/shots/designermagnetics.com.pngA data/shots/etciemurals.com.pngA data/shots/fabricfridays.com.pngA data/shots/fireratedwallcovering.com.pngA data/shots/handmadewallcovering.com.pngA data/shots/hospitalitysalesagency.com.pngA data/shots/montereywallpaper.com.pngA data/shots/naturalwalltextures.com.pngA data/shots/printmurals.com.pngA data/shots/restaurantfabrics.com.pngA data/shots/restaurantmurals.com.pngA data/shots/roomsettings.com.pngA data/shots/sheltermagazines.com.pngA data/shots/specifywallpaper.com.pngA data/shots/thehotelwallpaper.com.pngA data/shots/traditionalwhimsy.com.pngA data/shots/unitedstateswallpaper.com.pngA data/shots/wallcovering.net.pngA data/shots/wallpaperexports.com.pngA data/shots/wallpaperfromthe80s.com.pngA data/shots/wallpaperny.com.pngA data/shots/wallpaperpurchasing.com.pngA data/shots/wallpaperweekly.com.pngA data/shots/wc01wallcoverings.com.pngM server.mjs
Diff
commit c2f837ff5db45e940a5f1c3ae21321257b3cacfb
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 9 16:34:55 2026 -0700
adsense command post: grid renderer + synced shots/data (TK-11322)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
data/audit-latest.json | 107 ++++++++++++++++++++-
data/shots/1800wallcoverings.com.png | Bin 0 -> 1278490 bytes
data/shots/asseeninhotels.com.png | Bin 0 -> 817498 bytes
data/shots/asseeninla.com.png | Bin 0 -> 1276046 bytes
data/shots/asseeninmovies.com.png | Bin 0 -> 262811 bytes
data/shots/asseeninshowrooms.com.png | Bin 0 -> 1283570 bytes
data/shots/barwallpaper.com.png | Bin 0 -> 1060050 bytes
data/shots/blankstocklining.com.png | Bin 0 -> 778924 bytes
data/shots/carmelwallpaper.com.png | Bin 0 -> 1583928 bytes
data/shots/classawallcovering.com.png | Bin 0 -> 1061227 bytes
data/shots/commercialsalesreps.com.png | Bin 0 -> 614519 bytes
data/shots/commercialwallcovering.com.png | Bin 0 -> 614827 bytes
data/shots/designermagnetics.com.png | Bin 0 -> 1066114 bytes
data/shots/etciemurals.com.png | Bin 0 -> 1354102 bytes
data/shots/fabricfridays.com.png | Bin 0 -> 1278244 bytes
data/shots/fireratedwallcovering.com.png | Bin 0 -> 980608 bytes
data/shots/handmadewallcovering.com.png | Bin 0 -> 1583339 bytes
data/shots/hospitalitysalesagency.com.png | Bin 0 -> 825937 bytes
data/shots/montereywallpaper.com.png | Bin 0 -> 1582853 bytes
data/shots/naturalwalltextures.com.png | Bin 0 -> 1584714 bytes
data/shots/printmurals.com.png | Bin 0 -> 1354006 bytes
data/shots/restaurantfabrics.com.png | Bin 0 -> 1276256 bytes
data/shots/restaurantmurals.com.png | Bin 0 -> 1356057 bytes
data/shots/roomsettings.com.png | Bin 0 -> 1278258 bytes
data/shots/sheltermagazines.com.png | Bin 0 -> 1277168 bytes
data/shots/specifywallpaper.com.png | Bin 0 -> 613605 bytes
data/shots/thehotelwallpaper.com.png | Bin 0 -> 816998 bytes
data/shots/traditionalwhimsy.com.png | Bin 0 -> 974069 bytes
data/shots/unitedstateswallpaper.com.png | Bin 0 -> 1280070 bytes
data/shots/wallcovering.net.png | Bin 0 -> 1275586 bytes
data/shots/wallpaperexports.com.png | Bin 0 -> 1279052 bytes
data/shots/wallpaperfromthe80s.com.png | Bin 0 -> 1032262 bytes
data/shots/wallpaperny.com.png | Bin 0 -> 1279465 bytes
data/shots/wallpaperpurchasing.com.png | Bin 0 -> 613122 bytes
data/shots/wallpaperweekly.com.png | Bin 0 -> 1278305 bytes
data/shots/wc01wallcoverings.com.png | Bin 0 -> 611804 bytes
server.mjs | 154 +++++++++++++++++++-----------
37 files changed, 204 insertions(+), 57 deletions(-)
diff --git a/data/audit-latest.json b/data/audit-latest.json
index 60c0bb1..7ca7477 100644
--- a/data/audit-latest.json
+++ b/data/audit-latest.json
@@ -1,11 +1,14 @@
{
- "ts": "2026-09-09T23:28:01.087Z",
+ "ts": "2026-09-09T23:31:41.522Z",
"publisher": "pub-5278231299883833",
"count": 35,
"ready": 35,
"results": [
{
"domain": "1800wallcoverings.com",
+ "name": "1-800 Wallcoverings",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/1800wallcoverings.com.png",
"words": 644,
"passed": 12,
"total": 12,
@@ -29,6 +32,9 @@
},
{
"domain": "asseeninhotels.com",
+ "name": "As Seen In Hotels",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2026-08-24at11.27.02AM_3a1177ad-f0bb-42cc-b784-c27e73d8c85d.png?v=1787596059",
+ "shot": "/shots/asseeninhotels.com.png",
"words": 610,
"passed": 12,
"total": 12,
@@ -52,6 +58,9 @@
},
{
"domain": "asseeninla.com",
+ "name": "As Seen In LA",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/asseeninla.com.png",
"words": 645,
"passed": 12,
"total": 12,
@@ -75,6 +84,9 @@
},
{
"domain": "asseeninmovies.com",
+ "name": "As Seen In Movies",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/0065257_vogue-black-and-metallic-gold_650.jpg?v=1776906916",
+ "shot": "/shots/asseeninmovies.com.png",
"words": 630,
"passed": 12,
"total": 12,
@@ -98,6 +110,9 @@
},
{
"domain": "asseeninshowrooms.com",
+ "name": "As Seen In Showrooms",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/asseeninshowrooms.com.png",
"words": 619,
"passed": 12,
"total": 12,
@@ -121,6 +136,9 @@
},
{
"domain": "barwallpaper.com",
+ "name": "Bar Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/VV240_circles_SCARLET_1031x_2c1424d9-e2e8-456a-beb8-cd6ac0df55d9.webp?v=1781638431",
+ "shot": "/shots/barwallpaper.com.png",
"words": 620,
"passed": 12,
"total": 12,
@@ -144,6 +162,9 @@
},
{
"domain": "blankstocklining.com",
+ "name": "Blankstock Lining",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/8502GR.jpg?v=1785089689",
+ "shot": "/shots/blankstocklining.com.png",
"words": 637,
"passed": 12,
"total": 12,
@@ -167,6 +188,9 @@
},
{
"domain": "carmelwallpaper.com",
+ "name": "Carmel Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/dwnat-100153_2570b5ca-f3a2-41ab-a8a9-09d8a0a11bad.jpg?v=1788903844",
+ "shot": "/shots/carmelwallpaper.com.png",
"words": 578,
"passed": 12,
"total": 12,
@@ -190,6 +214,9 @@
},
{
"domain": "classawallcovering.com",
+ "name": "Class A Wallcovering",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/VV240_circles_SCARLET_1031x_2c1424d9-e2e8-456a-beb8-cd6ac0df55d9.webp?v=1781638431",
+ "shot": "/shots/classawallcovering.com.png",
"words": 633,
"passed": 12,
"total": 12,
@@ -213,6 +240,9 @@
},
{
"domain": "commercialsalesreps.com",
+ "name": "Commercial Sales Reps",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/7e15d64102f5502083f5aa8db2f95189.jpg?v=1572310604",
+ "shot": "/shots/commercialsalesreps.com.png",
"words": 628,
"passed": 12,
"total": 12,
@@ -236,6 +266,9 @@
},
{
"domain": "commercialwallcovering.com",
+ "name": "Commercial Wallcovering",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/7e15d64102f5502083f5aa8db2f95189.jpg?v=1572310604",
+ "shot": "/shots/commercialwallcovering.com.png",
"words": 595,
"passed": 12,
"total": 12,
@@ -259,6 +292,9 @@
},
{
"domain": "designermagnetics.com",
+ "name": "Designer Magnetics",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/ENV1242.jpg?v=1785091068",
+ "shot": "/shots/designermagnetics.com.png",
"words": 650,
"passed": 12,
"total": 12,
@@ -282,6 +318,9 @@
},
{
"domain": "etciemurals.com",
+ "name": "Et Cie Murals",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21147_interior1.jpg?v=1785862226",
+ "shot": "/shots/etciemurals.com.png",
"words": 715,
"passed": 12,
"total": 12,
@@ -305,6 +344,9 @@
},
{
"domain": "fabricfridays.com",
+ "name": "Fabric Fridays",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/fabricfridays.com.png",
"words": 719,
"passed": 12,
"total": 12,
@@ -328,6 +370,9 @@
},
{
"domain": "fireratedwallcovering.com",
+ "name": "Fire-Rated Wallcovering",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/c8020e929ff4b8b73c7f99f0f1e91df5.jpg?v=1787151495",
+ "shot": "/shots/fireratedwallcovering.com.png",
"words": 682,
"passed": 12,
"total": 12,
@@ -351,6 +396,9 @@
},
{
"domain": "handmadewallcovering.com",
+ "name": "Hand-Made Wallcovering",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/dwnat-100153_2570b5ca-f3a2-41ab-a8a9-09d8a0a11bad.jpg?v=1788903844",
+ "shot": "/shots/handmadewallcovering.com.png",
"words": 698,
"passed": 12,
"total": 12,
@@ -374,6 +422,9 @@
},
{
"domain": "hospitalitysalesagency.com",
+ "name": "Hospitality Sales Agency",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2026-08-24at11.27.02AM_3a1177ad-f0bb-42cc-b784-c27e73d8c85d.png?v=1787596059",
+ "shot": "/shots/hospitalitysalesagency.com.png",
"words": 732,
"passed": 12,
"total": 12,
@@ -397,6 +448,9 @@
},
{
"domain": "montereywallpaper.com",
+ "name": "Monterey Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/dwnat-100153_2570b5ca-f3a2-41ab-a8a9-09d8a0a11bad.jpg?v=1788903844",
+ "shot": "/shots/montereywallpaper.com.png",
"words": 673,
"passed": 12,
"total": 12,
@@ -420,6 +474,9 @@
},
{
"domain": "naturalwalltextures.com",
+ "name": "Natural Wall Textures",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/dwnat-100153_2570b5ca-f3a2-41ab-a8a9-09d8a0a11bad.jpg?v=1788903844",
+ "shot": "/shots/naturalwalltextures.com.png",
"words": 666,
"passed": 12,
"total": 12,
@@ -443,6 +500,9 @@
},
{
"domain": "printmurals.com",
+ "name": "Print Murals",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21147_interior1.jpg?v=1785862226",
+ "shot": "/shots/printmurals.com.png",
"words": 702,
"passed": 12,
"total": 12,
@@ -466,6 +526,9 @@
},
{
"domain": "restaurantfabrics.com",
+ "name": "Restaurant Fabrics",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/restaurantfabrics.com.png",
"words": 683,
"passed": 12,
"total": 12,
@@ -489,6 +552,9 @@
},
{
"domain": "restaurantmurals.com",
+ "name": "Restaurant Murals",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/R21147_interior1.jpg?v=1785862226",
+ "shot": "/shots/restaurantmurals.com.png",
"words": 708,
"passed": 12,
"total": 12,
@@ -512,6 +578,9 @@
},
{
"domain": "roomsettings.com",
+ "name": "Room Settings",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/roomsettings.com.png",
"words": 731,
"passed": 12,
"total": 12,
@@ -535,6 +604,9 @@
},
{
"domain": "sheltermagazines.com",
+ "name": "Shelter Magazines",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/sheltermagazines.com.png",
"words": 793,
"passed": 12,
"total": 12,
@@ -558,6 +630,9 @@
},
{
"domain": "specifywallpaper.com",
+ "name": "Specify Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/7e15d64102f5502083f5aa8db2f95189.jpg?v=1572310604",
+ "shot": "/shots/specifywallpaper.com.png",
"words": 782,
"passed": 12,
"total": 12,
@@ -581,6 +656,9 @@
},
{
"domain": "thehotelwallpaper.com",
+ "name": "The Hotel Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/Screenshot2026-08-24at11.27.02AM_3a1177ad-f0bb-42cc-b784-c27e73d8c85d.png?v=1787596059",
+ "shot": "/shots/thehotelwallpaper.com.png",
"words": 755,
"passed": 12,
"total": 12,
@@ -604,6 +682,9 @@
},
{
"domain": "traditionalwhimsy.com",
+ "name": "Traditional Whimsy",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/c8020e929ff4b8b73c7f99f0f1e91df5.jpg?v=1787151495",
+ "shot": "/shots/traditionalwhimsy.com.png",
"words": 779,
"passed": 12,
"total": 12,
@@ -627,6 +708,9 @@
},
{
"domain": "unitedstateswallpaper.com",
+ "name": "United States Wallpaper",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/unitedstateswallpaper.com.png",
"words": 734,
"passed": 12,
"total": 12,
@@ -650,6 +734,9 @@
},
{
"domain": "wallcovering.net",
+ "name": "Wallcovering",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/wallcovering.net.png",
"words": 793,
"passed": 12,
"total": 12,
@@ -673,6 +760,9 @@
},
{
"domain": "wallpaperexports.com",
+ "name": "Wallpaper Exports",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/wallpaperexports.com.png",
"words": 718,
"passed": 12,
"total": 12,
@@ -696,6 +786,9 @@
},
{
"domain": "wallpaperfromthe80s.com",
+ "name": "Wallpaper From The 80s",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/VV248_retro_blocks_WHITESILVER_1050x_92d07f40-9743-41a3-abb0-7c689d407c74.jpg?v=1781638402",
+ "shot": "/shots/wallpaperfromthe80s.com.png",
"words": 662,
"passed": 12,
"total": 12,
@@ -719,6 +812,9 @@
},
{
"domain": "wallpaperny.com",
+ "name": "Wallpaper NY",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/wallpaperny.com.png",
"words": 667,
"passed": 12,
"total": 12,
@@ -742,6 +838,9 @@
},
{
"domain": "wallpaperpurchasing.com",
+ "name": "Wallpaper Purchasing",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/7e15d64102f5502083f5aa8db2f95189.jpg?v=1572310604",
+ "shot": "/shots/wallpaperpurchasing.com.png",
"words": 718,
"passed": 12,
"total": 12,
@@ -765,6 +864,9 @@
},
{
"domain": "wallpaperweekly.com",
+ "name": "Wallpaper Weekly",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/morris-acorn-morris-and-co-ochre-fabric-236827-image01.jpg?v=1788956952",
+ "shot": "/shots/wallpaperweekly.com.png",
"words": 704,
"passed": 12,
"total": 12,
@@ -788,6 +890,9 @@
},
{
"domain": "wc01wallcoverings.com",
+ "name": "WC-01 Wallcoverings",
+ "hero": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/7e15d64102f5502083f5aa8db2f95189.jpg?v=1572310604",
+ "shot": "/shots/wc01wallcoverings.com.png",
"words": 685,
"passed": 12,
"total": 12,
diff --git a/data/shots/1800wallcoverings.com.png b/data/shots/1800wallcoverings.com.png
new file mode 100644
index 0000000..8d568dd
Binary files /dev/null and b/data/shots/1800wallcoverings.com.png differ
diff --git a/data/shots/asseeninhotels.com.png b/data/shots/asseeninhotels.com.png
new file mode 100644
index 0000000..07ad2ef
Binary files /dev/null and b/data/shots/asseeninhotels.com.png differ
diff --git a/data/shots/asseeninla.com.png b/data/shots/asseeninla.com.png
new file mode 100644
index 0000000..ee6a712
Binary files /dev/null and b/data/shots/asseeninla.com.png differ
diff --git a/data/shots/asseeninmovies.com.png b/data/shots/asseeninmovies.com.png
new file mode 100644
index 0000000..128be2c
Binary files /dev/null and b/data/shots/asseeninmovies.com.png differ
diff --git a/data/shots/asseeninshowrooms.com.png b/data/shots/asseeninshowrooms.com.png
new file mode 100644
index 0000000..9e6af26
Binary files /dev/null and b/data/shots/asseeninshowrooms.com.png differ
diff --git a/data/shots/barwallpaper.com.png b/data/shots/barwallpaper.com.png
new file mode 100644
index 0000000..9bb8b67
Binary files /dev/null and b/data/shots/barwallpaper.com.png differ
diff --git a/data/shots/blankstocklining.com.png b/data/shots/blankstocklining.com.png
new file mode 100644
index 0000000..6adb94c
Binary files /dev/null and b/data/shots/blankstocklining.com.png differ
diff --git a/data/shots/carmelwallpaper.com.png b/data/shots/carmelwallpaper.com.png
new file mode 100644
index 0000000..e7162af
Binary files /dev/null and b/data/shots/carmelwallpaper.com.png differ
diff --git a/data/shots/classawallcovering.com.png b/data/shots/classawallcovering.com.png
new file mode 100644
index 0000000..cb4283c
Binary files /dev/null and b/data/shots/classawallcovering.com.png differ
diff --git a/data/shots/commercialsalesreps.com.png b/data/shots/commercialsalesreps.com.png
new file mode 100644
index 0000000..beb727f
Binary files /dev/null and b/data/shots/commercialsalesreps.com.png differ
diff --git a/data/shots/commercialwallcovering.com.png b/data/shots/commercialwallcovering.com.png
new file mode 100644
index 0000000..ab5c0a9
Binary files /dev/null and b/data/shots/commercialwallcovering.com.png differ
diff --git a/data/shots/designermagnetics.com.png b/data/shots/designermagnetics.com.png
new file mode 100644
index 0000000..1f9ce8b
Binary files /dev/null and b/data/shots/designermagnetics.com.png differ
diff --git a/data/shots/etciemurals.com.png b/data/shots/etciemurals.com.png
new file mode 100644
index 0000000..af4dff2
Binary files /dev/null and b/data/shots/etciemurals.com.png differ
diff --git a/data/shots/fabricfridays.com.png b/data/shots/fabricfridays.com.png
new file mode 100644
index 0000000..2e622d2
Binary files /dev/null and b/data/shots/fabricfridays.com.png differ
diff --git a/data/shots/fireratedwallcovering.com.png b/data/shots/fireratedwallcovering.com.png
new file mode 100644
index 0000000..8edb44d
Binary files /dev/null and b/data/shots/fireratedwallcovering.com.png differ
diff --git a/data/shots/handmadewallcovering.com.png b/data/shots/handmadewallcovering.com.png
new file mode 100644
index 0000000..22eaf14
Binary files /dev/null and b/data/shots/handmadewallcovering.com.png differ
diff --git a/data/shots/hospitalitysalesagency.com.png b/data/shots/hospitalitysalesagency.com.png
new file mode 100644
index 0000000..7eddd46
Binary files /dev/null and b/data/shots/hospitalitysalesagency.com.png differ
diff --git a/data/shots/montereywallpaper.com.png b/data/shots/montereywallpaper.com.png
new file mode 100644
index 0000000..05a8633
Binary files /dev/null and b/data/shots/montereywallpaper.com.png differ
diff --git a/data/shots/naturalwalltextures.com.png b/data/shots/naturalwalltextures.com.png
new file mode 100644
index 0000000..d0e7a24
Binary files /dev/null and b/data/shots/naturalwalltextures.com.png differ
diff --git a/data/shots/printmurals.com.png b/data/shots/printmurals.com.png
new file mode 100644
index 0000000..d1081ac
Binary files /dev/null and b/data/shots/printmurals.com.png differ
diff --git a/data/shots/restaurantfabrics.com.png b/data/shots/restaurantfabrics.com.png
new file mode 100644
index 0000000..504f95f
Binary files /dev/null and b/data/shots/restaurantfabrics.com.png differ
diff --git a/data/shots/restaurantmurals.com.png b/data/shots/restaurantmurals.com.png
new file mode 100644
index 0000000..0b45901
Binary files /dev/null and b/data/shots/restaurantmurals.com.png differ
diff --git a/data/shots/roomsettings.com.png b/data/shots/roomsettings.com.png
new file mode 100644
index 0000000..69bb03a
Binary files /dev/null and b/data/shots/roomsettings.com.png differ
diff --git a/data/shots/sheltermagazines.com.png b/data/shots/sheltermagazines.com.png
new file mode 100644
index 0000000..ea15b61
Binary files /dev/null and b/data/shots/sheltermagazines.com.png differ
diff --git a/data/shots/specifywallpaper.com.png b/data/shots/specifywallpaper.com.png
new file mode 100644
index 0000000..81d3a77
Binary files /dev/null and b/data/shots/specifywallpaper.com.png differ
diff --git a/data/shots/thehotelwallpaper.com.png b/data/shots/thehotelwallpaper.com.png
new file mode 100644
index 0000000..eb0eb94
Binary files /dev/null and b/data/shots/thehotelwallpaper.com.png differ
diff --git a/data/shots/traditionalwhimsy.com.png b/data/shots/traditionalwhimsy.com.png
new file mode 100644
index 0000000..f3757c3
Binary files /dev/null and b/data/shots/traditionalwhimsy.com.png differ
diff --git a/data/shots/unitedstateswallpaper.com.png b/data/shots/unitedstateswallpaper.com.png
new file mode 100644
index 0000000..e3ad383
Binary files /dev/null and b/data/shots/unitedstateswallpaper.com.png differ
diff --git a/data/shots/wallcovering.net.png b/data/shots/wallcovering.net.png
new file mode 100644
index 0000000..afdb86c
Binary files /dev/null and b/data/shots/wallcovering.net.png differ
diff --git a/data/shots/wallpaperexports.com.png b/data/shots/wallpaperexports.com.png
new file mode 100644
index 0000000..e5326c7
Binary files /dev/null and b/data/shots/wallpaperexports.com.png differ
diff --git a/data/shots/wallpaperfromthe80s.com.png b/data/shots/wallpaperfromthe80s.com.png
new file mode 100644
index 0000000..b53ba75
Binary files /dev/null and b/data/shots/wallpaperfromthe80s.com.png differ
diff --git a/data/shots/wallpaperny.com.png b/data/shots/wallpaperny.com.png
new file mode 100644
index 0000000..5cdfef2
Binary files /dev/null and b/data/shots/wallpaperny.com.png differ
diff --git a/data/shots/wallpaperpurchasing.com.png b/data/shots/wallpaperpurchasing.com.png
new file mode 100644
index 0000000..26116f3
Binary files /dev/null and b/data/shots/wallpaperpurchasing.com.png differ
diff --git a/data/shots/wallpaperweekly.com.png b/data/shots/wallpaperweekly.com.png
new file mode 100644
index 0000000..8e775a9
Binary files /dev/null and b/data/shots/wallpaperweekly.com.png differ
diff --git a/data/shots/wc01wallcoverings.com.png b/data/shots/wc01wallcoverings.com.png
new file mode 100644
index 0000000..6660e74
Binary files /dev/null and b/data/shots/wc01wallcoverings.com.png differ
diff --git a/server.mjs b/server.mjs
index 5c7ac18..1d56a4c 100644
--- a/server.mjs
+++ b/server.mjs
@@ -1,7 +1,8 @@
#!/usr/bin/env node
-// AdSense Manager dashboard — Basic-auth page showing, per monetize domain:
-// approval status (live console), readiness audit %, ads.txt state, and blockers.
-// Reads data/audit-latest.json + data/status-latest.json. Port: env PORT or 9971.
+// AdSense Manager command post — Basic-auth GRID of all monetize sites (thumbnail +
+// approval status + readiness + ads.txt), plus a table view. Sort + density slider
+// (localStorage-persisted). Reads data/audit-latest.json + data/status-latest.json,
+// serves screenshots from data/shots/. Port: env PORT or 9971.
import http from 'http';
import fs from 'fs';
import path from 'path';
@@ -9,75 +10,111 @@ import { fileURLToPath } from 'url';
import { execFile } from 'child_process';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
-const SKILL = __dirname; // command post: reads ./data synced from Mac2
+const SKILL = __dirname; // command post: ./data synced from Mac2
+const DATA = path.join(SKILL, 'data');
+const SHOTS = path.join(DATA, 'shots');
const PORT = process.env.PORT || 9971;
const USER = 'admin', PASS = 'DW2024!';
-const read = f => { try { return JSON.parse(fs.readFileSync(path.join(SKILL, 'data', f), 'utf8')); } catch { return null; } };
+const read = f => { try { return JSON.parse(fs.readFileSync(path.join(DATA, f), 'utf8')); } catch { return null; } };
const esc = s => String(s == null ? '' : s).replace(/[&<>"]/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"' }[c]));
-function page() {
- const audit = read('audit-latest.json') || { results: [], ready: 0, count: 0, ts: '' };
+function data() {
+ const audit = read('audit-latest.json') || { results: [], ready: 0, ts: '' };
const status = read('status-latest.json') || { rows: [], tally: {}, ts: '', source: '?' };
const sMap = Object.fromEntries((status.rows || []).map(r => [r.domain, r]));
- const rows = (audit.results || []).map(a => ({ ...a, ...(sMap[a.domain] || {}) }))
- .sort((a, b) => (a.approval === 'Ready' ? -1 : 0) - (b.approval === 'Ready' ? -1 : 0) || a.readiness - b.readiness);
- const badge = s => {
- const m = { 'Ready': ['#16794a', '#e6f2ea'], 'Getting ready': ['#a9761a', '#f6eeda'], 'Requires review': ['#5b6470', '#eef0f3'], 'Needs attention': ['#b0413a', '#f7e7e5'] };
- const [c, b] = m[s] || ['#8a8f98', '#eef0f2'];
- return `<span class="pill" style="color:${c};background:${b}">${esc(s || '—')}</span>`;
- };
- const tr = r => `<tr>
- <td class="dom">${esc(r.domain)}</td>
- <td>${badge(r.approval)}</td>
- <td class="num ${r.ready ? 'ok' : 'warn'}">${r.readiness}%</td>
- <td class="ads ${/(Authorized)/i.test(r.ads_txt) ? 'ok' : 'muted'}">${esc(r.ads_txt || '—')}</td>
- <td class="blk">${r.blockers && r.blockers.length ? esc(r.blockers.join('; ')) : '<span class="ok">all checks pass</span>'}</td></tr>`;
+ const rows = (audit.results || []).map(a => ({ ...a, approval: (sMap[a.domain] || {}).approval || 'UNKNOWN', ads_txt: (sMap[a.domain] || {}).ads_txt || '—' }));
+ return { rows, audit, status };
+}
+
+function page() {
+ const { rows, audit, status } = data();
const tally = status.tally || {};
+ const shotExists = d => { try { return fs.existsSync(path.join(SHOTS, d + '.png')); } catch { return false; } };
+ const cards = rows.map(r => {
+ const thumb = shotExists(r.domain) ? `/shots/${encodeURIComponent(r.domain)}.png` : (r.hero || '');
+ return { ...r, thumb };
+ });
+ const DATAJSON = JSON.stringify(cards.map(r => ({ domain: r.domain, name: r.name, thumb: r.thumb, approval: r.approval, ads_txt: r.ads_txt, readiness: r.readiness, ready: r.ready, blockers: r.blockers || [] })));
const tile = (n, l, cls = '') => `<div class="tile ${cls}"><div class="n">${n}</div><div class="l">${l}</div></div>`;
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
-<title>AdSense Manager</title><style>
-:root{--bg:#f6f5f2;--panel:#fff;--ink:#1b1917;--muted:#6b6560;--rule:#e6e2db;--accent:#2f7a4f;--mono:ui-monospace,Menlo,monospace}
+<title>AdSense Command Post</title><style>
+:root{--bg:#f5f4f1;--panel:#fff;--ink:#1b1917;--muted:#6b6560;--rule:#e5e1da;--accent:#2f7a4f;--mono:ui-monospace,Menlo,monospace;--cols:5}
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.5 -apple-system,'Segoe UI',Roboto,sans-serif}
-.wrap{max-width:1150px;margin:0 auto;padding:28px 22px 70px}
-h1{font-size:23px;margin:0 0 3px}.sub{color:var(--muted);font-size:13px;margin-bottom:18px}
-.tiles{display:grid;grid-template-columns:repeat(5,1fr);gap:11px;margin-bottom:18px}
+.wrap{max-width:1320px;margin:0 auto;padding:26px 20px 80px}
+h1{font-size:23px;margin:0 0 3px}.sub{color:var(--muted);font-size:13px;margin-bottom:16px}
+.tiles{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:16px}
@media(max-width:720px){.tiles{grid-template-columns:repeat(2,1fr)}}
-.tile{background:var(--panel);border:1px solid var(--rule);border-radius:9px;padding:13px 15px}
-.tile .n{font-size:25px;font-weight:600}.tile .l{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-top:6px}
-.tile.ready .n{color:#16794a}
-.bar{display:flex;gap:10px;align-items:center;margin-bottom:12px}
-button{font:inherit;background:var(--accent);color:#fff;border:0;border-radius:7px;padding:8px 15px;cursor:pointer}
-button:disabled{opacity:.5}
-table{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--rule);border-radius:10px;overflow:hidden;font-size:13px}
-th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);padding:10px 13px;border-bottom:1px solid var(--rule)}
-td{padding:9px 13px;border-bottom:1px solid #f0ede8;vertical-align:top}
-tr:last-child td{border-bottom:0}
-.dom{font-family:var(--mono);font-weight:600;white-space:nowrap}
-.pill{font-size:11px;font-weight:600;padding:2px 9px;border-radius:5px;white-space:nowrap}
-.num{font-weight:600;font-variant-numeric:tabular-nums}.num.ok{color:#16794a}.num.warn{color:#b0413a}
-.ads.ok{color:#16794a}.ads.muted{color:var(--muted)}.blk{color:var(--muted);max-width:420px}
-.ok{color:#16794a}.foot{color:var(--muted);font-size:12px;margin-top:16px;line-height:1.7}
+.tile{background:var(--panel);border:1px solid var(--rule);border-radius:9px;padding:12px 14px}
+.tile .n{font-size:24px;font-weight:600}.tile .l{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin-top:5px}
+.tile.ready .n{color:#16794a}.tile.rev .n{color:#5b6470}
+.ctl{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
+.ctl label{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
+select,button{font:inherit;border:1px solid var(--rule);background:var(--panel);color:var(--ink);border-radius:7px;padding:8px 11px;cursor:pointer}
+button.pri{background:var(--accent);color:#fff;border-color:var(--accent)}
+input[type=range]{accent-color:var(--accent)}
+.grid{display:grid;grid-template-columns:repeat(var(--cols),1fr);gap:16px}
+.card{background:var(--panel);border:1px solid var(--rule);border-radius:11px;overflow:hidden;display:flex;flex-direction:column;transition:transform .15s,box-shadow .15s}
+.card:hover{transform:translateY(-3px);box-shadow:0 12px 28px rgba(0,0,0,.12)}
+.thumb{aspect-ratio:1.4/1;background:#e9e6e0 center/cover no-repeat;position:relative;border-bottom:1px solid var(--rule)}
+.thumb .badge{position:absolute;top:8px;left:8px;font-size:10.5px;font-weight:700;padding:3px 8px;border-radius:5px;color:#fff;letter-spacing:.02em}
+.thumb .rd{position:absolute;top:8px;right:8px;font-size:10.5px;font-weight:700;padding:3px 7px;border-radius:5px;background:rgba(0,0,0,.62);color:#fff;font-variant-numeric:tabular-nums}
+.card .body{padding:10px 12px 12px}
+.card .nm{font-weight:600;font-size:13.5px;line-height:1.2}
+.card .dm{font-family:var(--mono);font-size:11.5px;color:var(--muted);margin-top:2px;word-break:break-all}
+.card .meta{display:flex;gap:8px;align-items:center;margin-top:8px;font-size:11px;color:var(--muted)}
+.card a{color:var(--accent);text-decoration:none}
+.noshot{display:flex;align-items:center;justify-content:center;height:100%;color:var(--muted);font-size:12px}
+.foot{color:var(--muted);font-size:12px;margin-top:22px;line-height:1.7}
</style></head><body><div class="wrap">
-<h1>AdSense Manager</h1>
-<div class="sub">Publisher pub-5278231299883833 · ${(audit.results||[]).length} monetize domains · audit ${esc((audit.ts||'').slice(0,16))}Z · status ${esc(status.source)} ${esc((status.ts||'').slice(11,16))}</div>
+<h1>AdSense Command Post</h1>
+<div class="sub">pub-5278231299883833 · ${audit.results ? audit.results.length : 0} monetize sites · audit ${esc((audit.ts||'').slice(0,16))}Z · console ${esc((status.ts||'').slice(11,16))}</div>
<div class="tiles">
- ${tile((audit.results||[]).length, 'Sites')}
+ ${tile(audit.results ? audit.results.length : 0, 'Sites')}
${tile(audit.ready ?? 0, 'Audit 100%', 'ready')}
${tile(tally['Ready'] || 0, 'Approved', 'ready')}
- ${tile(tally['Requires review'] || 0, 'In review')}
- ${tile((tally['Needs attention'] || 0), 'Needs attention')}
+ ${tile(tally['Requires review'] || 0, 'In review', 'rev')}
+ ${tile(tally['Needs attention'] || 0, 'Needs attention')}
+</div>
+<div class="ctl">
+ <label>Sort</label>
+ <select id="sort"><option value="approval">Approval</option><option value="readiness">Readiness</option><option value="domain">Domain A→Z</option><option value="ads">ads.txt</option></select>
+ <label>Density</label><input type="range" id="dens" min="2" max="7" value="5">
+ <span style="flex:1"></span>
+ <button class="pri" onclick="rc(this)">Re-check</button><span class="sub" id="msg"></span>
</div>
-<div class="bar"><button onclick="rc(this)">Re-check now</button><span class="sub" id="msg"></span></div>
-<table><thead><tr><th>Domain</th><th>AdSense status</th><th>Readiness</th><th>ads.txt (Google)</th><th>Blockers</th></tr></thead>
-<tbody>${rows.map(tr).join('')}</tbody></table>
-<p class="foot"><b>Readiness</b> = our own audit vs the AdSense approval checklist (content, required pages, ads.txt, code, no for-sale banner). 100% = nothing on our side blocks approval.
-<b>AdSense status</b> = live from your console; "Requires review" is normal until Google finishes its review. ads.txt "Not found" clears once Google re-crawls (it's live).
-Re-check re-runs the audit + reads the console.</p>
+<div class="grid" id="grid"></div>
+<p class="foot"><b>Grid</b> shows every monetize site with a live screenshot (ads render in the shot once a site is AdSense-approved). Badge = AdSense status, corner = our readiness audit. "Requires review" is normal until Google finishes review; ads.txt "Not found" clears when Google re-crawls (it's live). Sort + density persist. Re-check re-runs the audit + reads the console.</p>
</div>
<script>
-async function rc(b){b.disabled=true;document.getElementById('msg').textContent='re-checking…';
- try{const r=await fetch('/api/refresh',{method:'POST'});await r.json();location.reload();}catch(e){document.getElementById('msg').textContent='error';b.disabled=false;}}
-setTimeout(()=>location.reload(),120000);
+const DATA=${DATAJSON};
+const BADGE={'Ready':'#16794a','Getting ready':'#a9761a','Requires review':'#5b6470','Needs attention':'#b0413a','UNKNOWN':'#8a8f98'};
+const g=document.getElementById('grid'),sortSel=document.getElementById('sort'),dens=document.getElementById('dens');
+try{const s=localStorage.getItem('acp_sort');if(s)sortSel.value=s;const d=localStorage.getItem('acp_dens');if(d)dens.value=d;}catch(e){}
+document.documentElement.style.setProperty('--cols',dens.value);
+const order={'Ready':0,'Needs attention':1,'Getting ready':2,'Requires review':3,'UNKNOWN':4};
+function render(){
+ const k=sortSel.value;
+ let r=DATA.slice();
+ r.sort((a,b)=> k==='approval'?(order[a.approval]-order[b.approval]||a.domain.localeCompare(b.domain))
+ : k==='readiness'?(a.readiness-b.readiness||a.domain.localeCompare(b.domain))
+ : k==='ads'?String(a.ads_txt).localeCompare(String(b.ads_txt))
+ : a.domain.localeCompare(b.domain));
+ g.innerHTML=r.map(x=>{
+ const th=x.thumb?('background-image:url("'+x.thumb+'")'):'';
+ const badge=BADGE[x.approval]||'#8a8f98';
+ return '<div class="card"><a href="https://'+x.domain+'" target="_blank" rel="noopener">'
+ +'<div class="thumb" style="'+th+'">'+(x.thumb?'':'<div class=noshot>no preview</div>')
+ +'<span class="badge" style="background:'+badge+'">'+x.approval+'</span>'
+ +'<span class="rd">'+x.readiness+'%</span></div></a>'
+ +'<div class="body"><div class="nm">'+x.name+'</div><div class="dm">'+x.domain+'</div>'
+ +'<div class="meta">ads.txt: '+x.ads_txt+' · <a href="https://'+x.domain+'" target="_blank" rel="noopener">open ↗</a></div></div></div>';
+ }).join('');
+}
+sortSel.onchange=()=>{try{localStorage.setItem('acp_sort',sortSel.value)}catch(e){}render()};
+dens.oninput=()=>{document.documentElement.style.setProperty('--cols',dens.value);try{localStorage.setItem('acp_dens',dens.value)}catch(e){}};
+async function rc(b){b.disabled=true;document.getElementById('msg').textContent='re-checking…';try{await fetch('/api/refresh',{method:'POST'});location.reload();}catch(e){b.disabled=false;document.getElementById('msg').textContent='err';}}
+setTimeout(()=>location.reload(),180000);
+render();
</script></body></html>`;
}
@@ -85,6 +122,11 @@ http.createServer((req, res) => {
const auth = (req.headers.authorization || '').split(' ')[1] || '';
const [u, p] = Buffer.from(auth, 'base64').toString().split(':');
if (u !== USER || p !== PASS) { res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="adsense"' }); return res.end('Auth required'); }
- if (req.method === 'POST' && req.url === '/api/refresh') { res.writeHead(200,{'content-type':'application/json'}); return res.end('{"ok":true,"note":"data refreshed by the Mac2 poller every 6h"}'); }
+ if (req.url.startsWith('/shots/')) {
+ const f = path.join(SHOTS, path.basename(decodeURIComponent(req.url.slice(7))));
+ if (f.endsWith('.png') && fs.existsSync(f)) { res.writeHead(200, { 'content-type': 'image/png', 'cache-control': 'public,max-age=300' }); return fs.createReadStream(f).pipe(res); }
+ res.writeHead(404); return res.end();
+ }
+ if (req.method === 'POST' && req.url === '/api/refresh'){res.writeHead(200,{'content-type':'application/json'});return res.end('{"ok":true,"note":"refreshed by Mac2 poller"}');}
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); res.end(page());
-}).listen(PORT, () => console.log(`AdSense Manager dashboard on http://127.0.0.1:${PORT} (admin/DW2024!)`));
+}).listen(PORT, () => console.log(`AdSense Command Post on http://127.0.0.1:${PORT} (admin/DW2024!)`));
← bf278cf adsense command post: dashboard app reading synced audit/sta
·
back to Adsense Command Post
·
adsense command post: Kamatera remote-deploy script (pm2+ngi be41f3f →