| |
| |
| |
| |
|
|
| import type { VideoItem } from '@/lib/types'; |
|
|
| |
| |
| |
| |
| export function hasMinimumMatch(title: string, query: string): boolean { |
| const normalizedTitle = title.toLowerCase(); |
| const normalizedQuery = query.toLowerCase().trim(); |
|
|
| |
| for (let i = 0; i <= normalizedQuery.length - 2; i++) { |
| const substring = normalizedQuery.slice(i, i + 2); |
| if (normalizedTitle.includes(substring)) { |
| return true; |
| } |
| } |
|
|
| return false; |
| } |
|
|
| |
| |
| |
| |
| export function calculateRelevanceScore(item: VideoItem, query: string): number { |
| let score = 0; |
| const normalizedQuery = query.toLowerCase().trim(); |
| const normalizedTitle = item.vod_name.toLowerCase(); |
|
|
| |
| const queryWords = normalizedQuery.split(/\s+/); |
|
|
| |
| if (normalizedTitle === normalizedQuery) { |
| score += 1000; |
| return score; |
| } |
|
|
| |
| if (normalizedTitle.startsWith(normalizedQuery)) { |
| score += 500; |
| } |
|
|
| |
| if (normalizedTitle.includes(normalizedQuery)) { |
| score += 200; |
|
|
| |
| const position = normalizedTitle.indexOf(normalizedQuery); |
| score += Math.max(0, 50 - position * 2); |
| } |
|
|
| |
| const allWordsPresent = queryWords.every(word => |
| normalizedTitle.includes(word) |
| ); |
| if (allWordsPresent && queryWords.length > 1) { |
| score += 100; |
| } |
|
|
| |
| queryWords.forEach(word => { |
| if (word.length < 2) return; |
|
|
| if (normalizedTitle.includes(word)) { |
| score += 30; |
|
|
| |
| if (normalizedTitle.startsWith(word)) { |
| score += 20; |
| } |
| } |
| }); |
|
|
| |
| if (item.vod_actor) { |
| const normalizedActor = item.vod_actor.toLowerCase(); |
| if (normalizedActor.includes(normalizedQuery)) { |
| score += 80; |
| } |
| queryWords.forEach(word => { |
| if (word.length >= 2 && normalizedActor.includes(word)) { |
| score += 15; |
| } |
| }); |
| } |
|
|
| |
| if (item.vod_director) { |
| const normalizedDirector = item.vod_director.toLowerCase(); |
| if (normalizedDirector.includes(normalizedQuery)) { |
| score += 60; |
| } |
| queryWords.forEach(word => { |
| if (word.length >= 2 && normalizedDirector.includes(word)) { |
| score += 10; |
| } |
| }); |
| } |
|
|
| |
| if (item.vod_content) { |
| const normalizedContent = item.vod_content.toLowerCase(); |
| if (normalizedContent.includes(normalizedQuery)) { |
| score += 20; |
| } |
| } |
|
|
| |
| const currentYear = new Date().getFullYear(); |
| const itemYear = parseInt(item.vod_year || '0'); |
| if (itemYear > 0) { |
| const yearDiff = currentYear - itemYear; |
| if (yearDiff === 0) { |
| score += 15; |
| } else if (yearDiff === 1) { |
| score += 10; |
| } else if (yearDiff <= 3) { |
| score += 5; |
| } |
| } |
|
|
| |
| if (item.vod_name.length > 50) { |
| score -= 5; |
| } |
|
|
| |
| if (item.vod_remarks) { |
| const remarks = item.vod_remarks.toLowerCase(); |
| if (remarks.includes('hd') || remarks.includes('1080') || remarks.includes('4k')) { |
| score += 5; |
| } |
| if (remarks.includes('完结') || remarks.includes('全集')) { |
| score += 3; |
| } |
| } |
|
|
| return Math.max(0, score); |
| } |
|
|
|
|