import { createError, defineEventHandler, readBody } from 'h3' import { db } from '~/drizzle/db' import { songBlacklists, systemSettings } from '~/drizzle/schema' import { eq } from 'drizzle-orm' function isCJK(text: string): boolean { return /[\u4e00-\u9fa5]/.test(text) } function isLatin(text: string): boolean { return /[A-Za-z]/.test(text) } function isKana(text: string): boolean { return /[\u3040-\u30ff]/.test(text) } function isHangul(text: string): boolean { return /[\uac00-\ud7af]/.test(text) } function isCyrillic(text: string): boolean { return /[\u0400-\u04ff]/.test(text) } function isArabic(text: string): boolean { return /[\u0600-\u06ff]/.test(text) } function detectLanguages(text: string): string[] { const result: string[] = [] if (!text) return result if (isCJK(text)) result.push('zh', '中文', 'chinese', 'cjk') if (isLatin(text)) result.push('en', '英文', 'english', 'latin') if (isKana(text)) result.push('ja', '日文', 'japanese') if (isHangul(text)) result.push('ko', '韩文', 'korean') if (isCyrillic(text)) result.push('ru', '俄文', 'russian', 'cyrillic') if (isArabic(text)) result.push('ar', '阿拉伯文', 'arabic') return result } export default defineEventHandler(async (event) => { const body = await readBody(event) const { title, artist, genre } = body if (!title) { throw createError({ statusCode: 400, message: '歌曲标题不能为空' }) } try { const systemSettingsResult = await db.select().from(systemSettings).limit(1) const systemSettingsData = systemSettingsResult[0] const showBlacklistKeywords = systemSettingsData?.showBlacklistKeywords ?? false const blacklistItems = await db .select() .from(songBlacklists) .where(eq(songBlacklists.isActive, true)) const songFullName = `${title} - ${artist || ''}`.toLowerCase() const genreLower = (genre || '').toLowerCase() const combinedText = `${title} ${artist || ''} ${genre || ''}` const textLanguages = new Set([ ...detectLanguages(title || ''), ...detectLanguages(artist || ''), ...detectLanguages(genre || '') ]) const blocked: Array<{ type: string; value: string | null; reason: string }> = [] for (const item of blacklistItems) { const valueLower = item.value.toLowerCase() if (item.type === 'SONG') { if (songFullName.includes(valueLower)) { blocked.push({ type: 'song', value: item.value, reason: item.reason || '该歌曲已被加入黑名单' }) } } else if (item.type === 'KEYWORD') { if (songFullName.includes(valueLower) || (genreLower && genreLower.includes(valueLower))) { blocked.push({ type: 'keyword', value: showBlacklistKeywords ? item.value : null, reason: item.reason || (showBlacklistKeywords ? `包含关键词:${item.value}` : '包含关键词') }) } } else if (item.type === 'LANGUAGE') { const tokens = [ valueLower, ...valueLower.split(/[,,\/|\s]+/).map((s) => s.trim()).filter(Boolean) ] const hit = tokens.some((lang) => textLanguages.has(lang)) if (hit) { blocked.push({ type: 'language', value: showBlacklistKeywords ? item.value : null, reason: item.reason || `该语种歌曲已被限制:${showBlacklistKeywords ? item.value : ''}`.trim() }) } } else if (item.type === 'GENRE') { const combinedForGenre = `${genreLower} ${combinedText}`.toLowerCase() const tokens = valueLower.split(/[,,\/|\s]+/).map((s) => s.trim()).filter(Boolean) const hit = tokens.some((tok) => combinedForGenre.includes(tok)) if (hit) { blocked.push({ type: 'genre', value: showBlacklistKeywords ? item.value : null, reason: item.reason || `该曲风歌曲已被限制:${showBlacklistKeywords ? item.value : ''}`.trim() }) } } } return { isBlocked: blocked.length > 0, reasons: blocked, song: { title, artist, genre: genre || null } } } catch (error) { console.error('检查黑名单失败:', error) throw createError({ statusCode: 500, message: '检查黑名单失败' }) } })