haixunMaster/lib/scan-recency.ts

83 lines
3.1 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** 置入模式:超過此天數的貼文不適合留言推薦(求助通常已解決) */
export const PLACEMENT_MAX_POST_AGE_DAYS = 30;
/** 置入黃金窗口7 天內留言區仍活躍、需求多半未關閉 */
export const PLACEMENT_IDEAL_MAX_AGE_DAYS = 7;
/** 網搜 after: 篩選用,略寬於黃金窗口以補足結果 */
export const PLACEMENT_WEB_SEARCH_MAX_AGE_DAYS = 14;
/** 置入模式Brave 網搜單次海巡最多查詢次數 */
export const PLACEMENT_WEB_SEARCH_MAX_QUERIES = 8;
/** 置入模式Brave 網搜找到足夠貼文後即停止 */
export const PLACEMENT_WEB_SEARCH_TARGET_POSTS = 20;
/** 置入模式Threads API瀏覽器已找到足夠貼文時跳過 Brave 網搜 */
export const PLACEMENT_WEB_SEARCH_SKIP_IF_POSTS = 15;
/** 一般模式Brave 網搜單次海巡最多查詢次數 */
export const DEFAULT_WEB_SEARCH_MAX_QUERIES = 12;
export function postAgeDays(postedAt: Date, now = Date.now()): number {
return (now - postedAt.getTime()) / (1000 * 60 * 60 * 24);
}
export function postAgeHours(postedAt: Date, now = Date.now()): number {
return (now - postedAt.getTime()) / (1000 * 60 * 60);
}
export function isPostFreshEnough(
postedAt: Date | null | undefined,
maxAgeDays: number = PLACEMENT_MAX_POST_AGE_DAYS
): boolean {
if (!postedAt) return true;
return postAgeDays(postedAt) <= maxAgeDays;
}
/** 0100置入排序用越近期分數越高 */
export function computePlacementRecencyScore(
postedAt: Date | null | undefined,
now = Date.now()
): number {
if (!postedAt) return 35;
const hours = postAgeHours(postedAt, now);
if (hours <= 6) return 100;
if (hours <= 24) return 95;
if (hours <= 48) return 88;
if (hours <= 72) return 80;
const days = postAgeDays(postedAt, now);
if (days <= PLACEMENT_IDEAL_MAX_AGE_DAYS) return 70;
if (days <= 14) return 50;
if (days <= PLACEMENT_MAX_POST_AGE_DAYS) return 30;
return 0;
}
export function formatGoogleAfterDate(maxAgeDays: number, now = Date.now()): string {
const date = new Date(now - maxAgeDays * 24 * 60 * 60 * 1000);
const y = date.getUTCFullYear();
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
const d = String(date.getUTCDate()).padStart(2, "0");
return `${y}-${m}-${d}`;
}
export function formatPostAgeLabel(postedAt?: Date | null): string {
if (!postedAt) return "發文日期未知";
const days = Math.floor(postAgeDays(postedAt));
if (days <= 0) return "今天";
if (days === 1) return "昨天";
if (days < 7) return `${days} 天前`;
if (days < 30) return `${Math.floor(days / 7)} 週前`;
return `${days} 天前`;
}
export function formatPlacementTimingHint(postedAt?: Date | null): string {
if (!postedAt) return "發文時間未知(置入窗口不明,需保守評估)";
const hours = postAgeHours(postedAt);
if (hours <= 24) return "剛發不久,置入窗口最佳";
if (hours <= 72) return "近 3 天內,置入窗口良好";
const days = Math.floor(postAgeDays(postedAt));
if (days <= PLACEMENT_IDEAL_MAX_AGE_DAYS) return "一週內,仍可置入";
if (days <= PLACEMENT_MAX_POST_AGE_DAYS) return "已超過一週,置入窗口收窄";
return "過舊,不建議置入";
}