Files
BYW-VoiceHub/server/services/meowNotificationService.ts
T
Henry_Du 4ce4649aaf
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s
初次提交
2026-09-06 08:19:02 +08:00

222 lines
6.3 KiB
TypeScript
Raw 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.
import { db } from '~/drizzle/db'
import { notificationSettings, users } from '~/drizzle/schema'
import { and, eq, inArray, isNotNull, ne } from 'drizzle-orm'
import { getSiteTitle } from '~~/server/utils/siteUtils'
/**
* 发送 MeoW 通知
*/
async function sendMeowNotification(
meowNickname: string,
title: string,
message: string,
url?: string
): Promise<boolean> {
try {
// URL 编码参数
const encodedNickname = encodeURIComponent(meowNickname)
const encodedTitle = encodeURIComponent(title)
const encodedMessage = encodeURIComponent(message)
// 构建请求 URL
let meowUrl = `https://api.chuckfang.com/${encodedNickname}/${encodedTitle}/${encodedMessage}`
if (url) {
meowUrl += `?url=${encodeURIComponent(url)}`
}
const response = await fetch(meowUrl, {
method: 'GET',
headers: {
'User-Agent': 'VoiceHub-Notification-Service'
}
})
if (response.ok) {
const result = await response.json()
console.log('MeoW 通知发送成功:', result)
return true
} else {
console.error('MeoW 通知发送失败:', response.status, response.statusText)
return false
}
} catch (error) {
console.error('发送 MeoW 通知时出错:', error)
return false
}
}
/**
* 为用户发送 MeoW 通知(如果已绑定)
*/
export async function sendMeowNotificationToUser(
userId: number,
notificationTitle: string,
notificationMessage: string,
url?: string
): Promise<boolean> {
try {
// 获取用户信息
const userResult = await db
.select({
name: users.name,
meowNickname: users.meowNickname,
id: users.id
})
.from(users)
.where(eq(users.id, userId))
.limit(1)
const user = userResult[0]
// 获取用户通知设置
let userNotificationSettings = null
if (user) {
const settingsResult = await db
.select({
enabled: notificationSettings.enabled
})
.from(notificationSettings)
.where(eq(notificationSettings.userId, userId))
.limit(1)
userNotificationSettings = settingsResult[0]
}
// 检查用户是否绑定了 MeoW 账号
if (!user?.meowNickname) {
return false
}
// 检查用户是否启用了通知
if (userNotificationSettings && !userNotificationSettings.enabled) {
return false
}
// 检查是否有其他用户绑定了相同的 MeoW ID
const usersWithSameMeowId = await db
.select({
name: users.name
})
.from(users)
.where(and(eq(users.meowNickname, user.meowNickname!), ne(users.id, userId)))
// 获取站点标题
const siteTitle = await getSiteTitle()
// 构建完整的通知标题
const fullTitle = `${notificationTitle} | ${siteTitle}通知推送`
// 如果有多个用户绑定了相同的 MeoW ID,在消息中加上用户名备注
let enhancedMessage = notificationMessage
if (usersWithSameMeowId.length > 0) {
// 检查消息是否以"您"开头,如果是则替换,否则添加前缀
if (notificationMessage.startsWith('您')) {
enhancedMessage = `您(${user.name})${notificationMessage.substring(1)}`
} else {
enhancedMessage = `您(${user.name})${notificationMessage}`
}
}
// 发送 MeoW 通知
return await sendMeowNotification(user.meowNickname, fullTitle, enhancedMessage, url)
} catch (error) {
console.error('发送用户 MeoW 通知失败:', error)
return false
}
}
/**
* 批量发送 MeoW 通知
*/
export async function sendBatchMeowNotifications(
userIds: number[],
notificationTitle: string,
notificationMessage: string,
url?: string
): Promise<{ success: number; failed: number }> {
let success = 0
let failed = 0
// 获取所有绑定了 MeoW 的用户
const usersWithMeow = await db
.select({
id: users.id,
name: users.name,
meowNickname: users.meowNickname
})
.from(users)
.where(and(inArray(users.id, userIds), isNotNull(users.meowNickname)))
// 获取这些用户的通知设置
const userNotificationSettingsMap = new Map()
if (usersWithMeow.length > 0) {
const settingsResults = await db
.select({
userId: notificationSettings.userId,
enabled: notificationSettings.enabled
})
.from(notificationSettings)
.where(
inArray(
notificationSettings.userId,
usersWithMeow.map((u) => u.id)
)
)
settingsResults.forEach((setting) => {
userNotificationSettingsMap.set(setting.userId, setting)
})
}
// 获取站点标题
const siteTitle = await getSiteTitle()
const fullTitle = `${notificationTitle} | ${siteTitle}通知推送`
// 统计每个 MeoW ID 绑定的用户数量
const meowIdCounts = new Map<string, number>()
usersWithMeow.forEach((user) => {
const count = meowIdCounts.get(user.meowNickname!) || 0
meowIdCounts.set(user.meowNickname!, count + 1)
})
// 并发发送通知(限制并发数)
const batchSize = 5
for (let i = 0; i < usersWithMeow.length; i += batchSize) {
const batch = usersWithMeow.slice(i, i + batchSize)
const promises = batch.map(async (user) => {
// 检查用户是否启用了通知
const userSettings = userNotificationSettingsMap.get(user.id)
if (userSettings && !userSettings.enabled) {
return false
}
// 如果该 MeoW ID 绑定了多个用户,在消息中加上用户名备注
let enhancedMessage = notificationMessage
const userCount = meowIdCounts.get(user.meowNickname!)
if (userCount && userCount > 1) {
// 检查消息是否以"您"开头,如果是则替换,否则添加前缀
if (notificationMessage.startsWith('您')) {
enhancedMessage = `您(${user.name})${notificationMessage.substring(1)}`
} else {
enhancedMessage = `您(${user.name})${notificationMessage}`
}
}
return await sendMeowNotification(user.meowNickname!, fullTitle, enhancedMessage, url)
})
const results = await Promise.allSettled(promises)
results.forEach((result) => {
if (result.status === 'fulfilled' && result.value) {
success++
} else {
failed++
}
})
}
return { success, failed }
}