253 lines
5.6 KiB
TypeScript
253 lines
5.6 KiB
TypeScript
import { prisma } from './prisma'
|
|
import { requireAuth } from './auth'
|
|
|
|
export async function getUserQueue(userId: string): Promise<any> {
|
|
const queue = await prisma.queue.findUnique({
|
|
where: { userId },
|
|
})
|
|
|
|
if (!queue) {
|
|
// Create a new queue for the user
|
|
return prisma.queue.create({
|
|
data: {
|
|
userId,
|
|
songIds: JSON.stringify([]),
|
|
},
|
|
})
|
|
}
|
|
|
|
return {
|
|
...queue,
|
|
songIds: JSON.parse(queue.songIds),
|
|
}
|
|
}
|
|
|
|
export async function updateUserQueue(
|
|
userId: string,
|
|
songIds: string[],
|
|
currentIndex?: number,
|
|
isShuffled?: boolean,
|
|
repeatMode?: string
|
|
): Promise<any> {
|
|
const queue = await prisma.queue.upsert({
|
|
where: { userId },
|
|
update: {
|
|
songIds: JSON.stringify(songIds),
|
|
currentIndex,
|
|
isShuffled,
|
|
repeatMode,
|
|
updatedAt: new Date(),
|
|
},
|
|
create: {
|
|
userId,
|
|
songIds: JSON.stringify(songIds),
|
|
currentIndex,
|
|
isShuffled,
|
|
repeatMode,
|
|
},
|
|
})
|
|
|
|
return {
|
|
...queue,
|
|
songIds: JSON.parse(queue.songIds),
|
|
}
|
|
}
|
|
|
|
export async function addToQueue(userId: string, songIds: string[]): Promise<any> {
|
|
const queue = await getUserQueue(userId)
|
|
const currentSongIds = queue.songIds as string[] || []
|
|
const newSongIds = [...currentSongIds, ...songIds]
|
|
|
|
return updateUserQueue(userId, newSongIds, queue.currentIndex, queue.isShuffled, queue.repeatMode)
|
|
}
|
|
|
|
export async function removeFromQueue(userId: string, index: number): Promise<any> {
|
|
const queue = await getUserQueue(userId)
|
|
const songIds = queue.songIds as string[] || []
|
|
|
|
if (index < 0 || index >= songIds.length) {
|
|
throw new Error('Invalid index')
|
|
}
|
|
|
|
songIds.splice(index, 1)
|
|
let newCurrentIndex = queue.currentIndex || 0
|
|
|
|
// Adjust current index if necessary
|
|
if (index < newCurrentIndex) {
|
|
newCurrentIndex--
|
|
} else if (newCurrentIndex >= songIds.length) {
|
|
newCurrentIndex = Math.max(0, songIds.length - 1)
|
|
}
|
|
|
|
return updateUserQueue(userId, songIds, newCurrentIndex, queue.isShuffled, queue.repeatMode)
|
|
}
|
|
|
|
export async function playSong(userId: string, songId: string, source?: string): Promise<void> {
|
|
// Add to play history
|
|
await prisma.playHistory.create({
|
|
data: {
|
|
userId,
|
|
songId,
|
|
source,
|
|
},
|
|
})
|
|
|
|
// Update song play count
|
|
await prisma.song.update({
|
|
where: { id: songId },
|
|
data: {
|
|
playCount: {
|
|
increment: 1,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
export async function getPlayHistory(
|
|
userId: string,
|
|
limit: number = 50,
|
|
offset: number = 0
|
|
): Promise<any[]> {
|
|
return prisma.playHistory.findMany({
|
|
where: { userId },
|
|
include: {
|
|
song: {
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
slug: true,
|
|
duration: true,
|
|
artist: {
|
|
select: {
|
|
id: true,
|
|
name: true,
|
|
slug: true,
|
|
},
|
|
},
|
|
album: {
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
slug: true,
|
|
coverUrl: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
orderBy: { playedAt: 'desc' },
|
|
take: limit,
|
|
skip: offset,
|
|
})
|
|
}
|
|
|
|
export async function updatePlayHistoryItem(
|
|
userId: string,
|
|
songId: string,
|
|
playedDuration: number,
|
|
completed: boolean
|
|
): Promise<void> {
|
|
await prisma.playHistory.updateMany({
|
|
where: {
|
|
userId,
|
|
songId,
|
|
completed: false,
|
|
},
|
|
data: {
|
|
playedDuration,
|
|
completed,
|
|
},
|
|
})
|
|
}
|
|
|
|
export async function getNextInQueue(userId: string): Promise<string | null> {
|
|
const queue = await getUserQueue(userId)
|
|
const songIds = queue.songIds as string[] || []
|
|
let currentIndex = queue.currentIndex || 0
|
|
const repeatMode = queue.repeatMode || 'none'
|
|
|
|
if (songIds.length === 0) {
|
|
return null
|
|
}
|
|
|
|
// Handle repeat modes
|
|
if (repeatMode === 'one') {
|
|
return songIds[currentIndex]
|
|
}
|
|
|
|
// Move to next
|
|
currentIndex++
|
|
|
|
// Handle wrap around for repeat all
|
|
if (currentIndex >= songIds.length) {
|
|
if (repeatMode === 'all') {
|
|
currentIndex = 0
|
|
} else {
|
|
return null // End of queue
|
|
}
|
|
}
|
|
|
|
// Update queue with new index
|
|
await updateUserQueue(userId, songIds, currentIndex, queue.isShuffled, repeatMode)
|
|
|
|
return songIds[currentIndex]
|
|
}
|
|
|
|
export async function getPreviousInQueue(userId: string): Promise<string | null> {
|
|
const queue = await getUserQueue(userId)
|
|
const songIds = queue.songIds as string[] || []
|
|
let currentIndex = queue.currentIndex || 0
|
|
|
|
if (songIds.length === 0 || currentIndex <= 0) {
|
|
return null
|
|
}
|
|
|
|
// Move to previous
|
|
currentIndex--
|
|
|
|
// Update queue with new index
|
|
await updateUserQueue(userId, songIds, currentIndex, queue.isShuffled, queue.repeatMode)
|
|
|
|
return songIds[currentIndex]
|
|
}
|
|
|
|
export async function shuffleQueue(userId: string): Promise<any> {
|
|
const queue = await getUserQueue(userId)
|
|
const songIds = queue.songIds as string[] || []
|
|
|
|
if (songIds.length === 0) {
|
|
return queue
|
|
}
|
|
|
|
// Shuffle the array
|
|
const shuffledIds = [...songIds]
|
|
for (let i = shuffledIds.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[shuffledIds[i], shuffledIds[j]] = [shuffledIds[j], shuffledIds[i]]
|
|
}
|
|
|
|
// Find current song in shuffled array
|
|
const currentSongId = songIds[queue.currentIndex || 0]
|
|
const newCurrentIndex = shuffledIds.indexOf(currentSongId)
|
|
|
|
return updateUserQueue(
|
|
userId,
|
|
shuffledIds,
|
|
newCurrentIndex,
|
|
true,
|
|
queue.repeatMode
|
|
)
|
|
}
|
|
|
|
export async function unshuffleQueue(userId: string): Promise<any> {
|
|
const queue = await getUserQueue(userId)
|
|
const songIds = queue.songIds as string[] || []
|
|
|
|
return updateUserQueue(
|
|
userId,
|
|
songIds,
|
|
queue.currentIndex,
|
|
false,
|
|
queue.repeatMode
|
|
)
|
|
} |