project-standalo-sonic-cloud/lib/player.ts

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
)
}