jefflix-website/app/api/request-channel/route.ts

119 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import nodemailer from 'nodemailer'
interface ChannelSelection {
id: string
name: string
country: string
categories: string[]
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
const { email, channels } = body as { email: string; channels: ChannelSelection[] }
// Validate email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
if (!email || !emailRegex.test(email)) {
return NextResponse.json(
{ error: 'A valid email is required' },
{ status: 400 }
)
}
// Validate channels
if (!Array.isArray(channels) || channels.length === 0 || channels.length > 20) {
return NextResponse.json(
{ error: 'Select between 1 and 20 channels' },
{ status: 400 }
)
}
for (const ch of channels) {
if (!ch.id || !ch.name) {
return NextResponse.json(
{ error: 'Invalid channel data' },
{ status: 400 }
)
}
}
const smtpHost = process.env.SMTP_HOST
const smtpUser = process.env.SMTP_USER
const smtpPass = process.env.SMTP_PASS
if (!smtpHost || !smtpUser || !smtpPass) {
console.error('SMTP credentials not configured')
return NextResponse.json(
{ error: 'Email service not configured' },
{ status: 500 }
)
}
const adminEmail = process.env.ADMIN_EMAIL || 'jeff@jeffemmett.com'
const transporter = nodemailer.createTransport({
host: smtpHost,
port: Number(process.env.SMTP_PORT) || 587,
secure: false,
auth: { user: smtpUser, pass: smtpPass },
tls: { rejectUnauthorized: false },
})
const channelListHtml = channels
.map(
(ch) =>
`<li><strong>${escapeHtml(ch.name)}</strong> — <code>${escapeHtml(ch.id)}</code>` +
(ch.country ? ` (${escapeHtml(ch.country)})` : '') +
(ch.categories.length > 0 ? ` [${ch.categories.map(escapeHtml).join(', ')}]` : '') +
`</li>`
)
.join('\n')
const subject =
channels.length === 1
? `[Jefflix] Channel Request: ${escapeHtml(channels[0].name)}`
: `[Jefflix] Channel Request: ${channels.length} channels`
await transporter.sendMail({
from: `Jefflix <${smtpUser}>`,
to: adminEmail,
subject,
html: `
<h2>New Channel Request</h2>
<p><strong>${escapeHtml(email)}</strong> requested ${channels.length} channel${channels.length > 1 ? 's' : ''}:</p>
<ul style="line-height: 1.8;">
${channelListHtml}
</ul>
<p><strong>To add these channels:</strong></p>
<ol>
<li>Search each channel ID in Threadfin / iptv-org</li>
<li>Map the streams in Threadfin</li>
<li>Reply to <a href="mailto:${escapeHtml(email)}">${escapeHtml(email)}</a> to confirm</li>
</ol>
<hr style="margin: 20px 0; border: none; border-top: 1px solid #ddd;" />
<p style="color: #666; font-size: 12px;">Automated message from Jefflix · ${new Date().toLocaleString()}</p>
`,
})
return NextResponse.json({ success: true })
} catch (error) {
console.error('Channel request error:', error)
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
)
}
}
function escapeHtml(text: string): string {
const map: Record<string, string> = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;',
}
return text.replace(/[&<>"']/g, (char) => map[char])
}