chore: initial commit - CloudSearch v0.0.2

This commit is contained in:
2026-05-15 05:50:50 +08:00
commit d83225d736
102 changed files with 37926 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
/**
* Search Results Optimizer
*
* For each cloud type, keep only the top N most relevant results.
* Order groups by priority: real cloud storage > other providers > magnet/others.
*
* Goal: give users a manageable, high-quality result set instead of overwhelming them
* with hundreds of results dominated by magnet links.
*/
import { detectCloudType } from '../config/cloud-labels';
/** Minimal result shape the optimizer needs */
interface OptimizableResult {
title?: string;
url?: string;
source?: string;
score?: number;
[key: string]: any;
}
/** Priority tiers for result ordering */
const CLOUD_PRIORITY: Record<string, number> = {
// Tier 1: Major cloud storage (most useful for save-to-cloud feature)
baidu: 10,
quark: 10,
aliyun: 10,
// Tier 2: Other cloud storage
'115': 20,
tianyi: 20,
'123pan': 20,
uc: 20,
xunlei: 20,
pikpak: 20,
// Tier 3: Mobile/app links (not very useful)
mobile: 50,
// Tier 4: Direct links (lowest utility for cloud saving)
magnet: 100,
ed2k: 100,
others: 100,
};
const DEFAULT_PRIORITY = 50;
/** Get cloud type for a result, with an extra check for tracker URLs */
function getCloudType(result: OptimizableResult): string {
const url = result.url;
// Check for tracker/private-site URLs not covered by shared detection
if (url && /mteam|hdarea|hdsky/i.test(url)) return 'others';
return detectCloudType(url);
}
function getPriority(cloudType: string): number {
return CLOUD_PRIORITY[cloudType] ?? DEFAULT_PRIORITY;
}
export interface OptimizationResult {
results: OptimizableResult[];
/** Per-type stats for display */
perType: Array<{ type: string; count: number; total: number }>;
/** How many items were kept vs filtered */
keptCount: number;
filteredCount: number;
}
/**
* Optimize search results:
* 1. Group by cloud type
* 2. Sort by score descending within each group
* 3. Keep only top `maxPerType` results per type
* 4. Order groups by priority (cloud storage first)
*/
export function optimizeSearchResults(
items: OptimizableResult[],
maxPerType: number = 20
): OptimizationResult {
// Step 1: Group by cloud type
const grouped: Record<string, OptimizableResult[]> = {};
const typeTotals: Record<string, number> = {};
for (const item of items) {
const ct = getCloudType(item);
if (!grouped[ct]) {
grouped[ct] = [];
}
grouped[ct].push(item);
typeTotals[ct] = (typeTotals[ct] || 0) + 1;
}
// Step 2 & 3: Sort each group by score desc, take top N
const kept: OptimizableResult[] = [];
const perType: Array<{ type: string; count: number; total: number }> = [];
for (const [ct, groupItems] of Object.entries(grouped)) {
// Sort by score descending (higher score = more relevant)
groupItems.sort((a, b) => (b.score || 0) - (a.score || 0));
const top = groupItems.slice(0, maxPerType);
kept.push(...top);
perType.push({
type: ct,
count: top.length,
total: typeTotals[ct],
});
}
// Step 4: Sort kept results by cloud priority, then by score within same priority
kept.sort((a, b) => {
const pa = getPriority(getCloudType(a));
const pb = getPriority(getCloudType(b));
if (pa !== pb) return pa - pb;
return (b.score || 0) - (a.score || 0);
});
const keptCount = kept.length;
const filteredCount = items.length - keptCount;
return {
results: kept,
perType,
keptCount,
filteredCount,
};
}