ads: pin aja-colorbox-300x250 as the first banner in every 300x250 rotation

This commit is contained in:
2026-06-16 18:11:13 +00:00
parent b9621ede1a
commit 2623fbe4ac

View File

@@ -196,10 +196,38 @@ export function shuffle<T>(arr: T[]): T[] {
return out;
}
// Slugs (or campaign_ids) that must be the FIRST banner of their size in
// every rotation, ahead of the shuffled pool. AJA 2026 sits at the top of
// every 300x250 stack per Ryan 2026-06-16.
const PINNED_SLUGS_BY_SIZE: Partial<Record<Ad["size"], string[]>> = {
"300x250": ["aja-colorbox-300x250"],
};
export function rotateAll(size: Ad["size"], exclude: Set<string> = new Set()): Ad[] {
const pool = readCachedAds().filter((a) => a.size === size);
const key = (a: Ad) => a.src ?? a.label;
return shuffle(pool.filter((a) => !exclude.has(key(a))));
const remaining = pool.filter((a) => !exclude.has(key(a)));
const pinnedSlugs = PINNED_SLUGS_BY_SIZE[size] || [];
if (pinnedSlugs.length === 0) return shuffle(remaining);
const pinned: Ad[] = [];
const rest: Ad[] = [];
for (const ad of remaining) {
const slugMatch = ad.slug && pinnedSlugs.includes(ad.slug);
const idMatch = ad.campaign_id && pinnedSlugs.includes(ad.campaign_id);
if (slugMatch || idMatch) {
pinned.push(ad);
} else {
rest.push(ad);
}
}
pinned.sort((a, b) => {
const ai = pinnedSlugs.indexOf((a.slug || a.campaign_id) ?? "");
const bi = pinnedSlugs.indexOf((b.slug || b.campaign_id) ?? "");
return ai - bi;
});
return [...pinned, ...shuffle(rest)];
}
export function pickAds(