80 lines
2.2 KiB
TypeScript
80 lines
2.2 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import { slskdFetch } from '@/lib/slskd'
|
|
import { extractBestFiles, type SlskdRawResponse } from '@/lib/slskd-dedup'
|
|
|
|
function sleep(ms: number) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
}
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const { artist, title } = await request.json()
|
|
if (!artist || !title) {
|
|
return NextResponse.json({ error: 'artist and title required' }, { status: 400 })
|
|
}
|
|
|
|
const query = `${artist} ${title}`
|
|
|
|
// Start slskd search
|
|
const searchRes = await slskdFetch('/searches', {
|
|
method: 'POST',
|
|
body: JSON.stringify({ searchText: query }),
|
|
})
|
|
|
|
if (!searchRes.ok) {
|
|
throw new Error(`slskd search returned ${searchRes.status}`)
|
|
}
|
|
|
|
const { id: searchId } = await searchRes.json()
|
|
|
|
// Poll up to 15s (5 polls x 3s)
|
|
let bestFile = null
|
|
for (let i = 0; i < 5; i++) {
|
|
await sleep(3000)
|
|
|
|
const res = await slskdFetch(`/searches/${searchId}`)
|
|
if (!res.ok) continue
|
|
|
|
const data = await res.json()
|
|
const responses: SlskdRawResponse[] = (data.responses || [])
|
|
.filter((r: SlskdRawResponse) => r.files?.length > 0)
|
|
|
|
const files = extractBestFiles(responses, 1)
|
|
if (files.length > 0) {
|
|
bestFile = files[0]
|
|
if (data.state === 'Completed' || data.state === 'TimedOut') break
|
|
}
|
|
}
|
|
|
|
if (!bestFile) {
|
|
return NextResponse.json({ success: false, searchId, error: 'No results found' })
|
|
}
|
|
|
|
// Trigger download
|
|
const dlRes = await slskdFetch(
|
|
`/transfers/downloads/${encodeURIComponent(bestFile.bestPeer.username)}`,
|
|
{
|
|
method: 'POST',
|
|
body: JSON.stringify([{
|
|
filename: bestFile.filename,
|
|
size: bestFile.size,
|
|
}]),
|
|
}
|
|
)
|
|
|
|
if (!dlRes.ok) {
|
|
throw new Error(`slskd download returned ${dlRes.status}`)
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
searchId,
|
|
filename: bestFile.displayName,
|
|
peer: bestFile.bestPeer.username,
|
|
})
|
|
} catch (error) {
|
|
console.error('Auto-download error:', error)
|
|
return NextResponse.json({ error: 'Auto-download failed' }, { status: 502 })
|
|
}
|
|
}
|