🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
141 lines
4.3 KiB
TypeScript
141 lines
4.3 KiB
TypeScript
import { promises as fs } from 'fs'
|
|
import { join } from 'path'
|
|
import { stat } from 'fs/promises'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
const videosPath = join(process.cwd(), 'videos')
|
|
|
|
// Verificar si existe la carpeta
|
|
try {
|
|
await fs.access(videosPath)
|
|
} catch {
|
|
return { videos: [] }
|
|
}
|
|
|
|
const files = await fs.readdir(videosPath)
|
|
|
|
// Detectar videos originales (archivos de video sin sufijos de calidad)
|
|
const videoExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv']
|
|
const videoFiles = files.filter(file => {
|
|
const ext = file.toLowerCase().substring(file.lastIndexOf('.'))
|
|
const nameWithoutExt = file.substring(0, file.lastIndexOf('.'))
|
|
const hasQualitySuffix = /_(4k|2k|1080p|720p|480p|360p)$/i.test(nameWithoutExt)
|
|
return videoExtensions.includes(ext) && !hasQualitySuffix
|
|
})
|
|
|
|
const videoMap = new Map<string, any>()
|
|
|
|
// Procesar cada video original
|
|
for (const file of videoFiles) {
|
|
const ext = file.substring(file.lastIndexOf('.'))
|
|
const baseName = file.substring(0, file.lastIndexOf('.'))
|
|
|
|
// Verificar si existe carpeta HLS
|
|
const hlsDir = join(videosPath, `${baseName}_hls`)
|
|
let isHLS = false
|
|
let hlsQualities: any[] = []
|
|
|
|
try {
|
|
const hlsStat = await stat(hlsDir)
|
|
if (hlsStat.isDirectory()) {
|
|
// Buscar archivos .m3u8 para detectar calidades disponibles
|
|
const hlsFiles = await fs.readdir(hlsDir)
|
|
const qualityFiles = hlsFiles.filter(f =>
|
|
f.endsWith('.m3u8') &&
|
|
f !== 'master.m3u8' &&
|
|
!f.includes('_vtt') // Excluir archivos de subtítulos
|
|
)
|
|
|
|
qualityFiles.forEach(qFile => {
|
|
const quality = qFile.replace('.m3u8', '')
|
|
hlsQualities.push({
|
|
quality,
|
|
label: quality.toUpperCase(),
|
|
url: `/videos/${baseName}_hls/${qFile}`,
|
|
file: qFile,
|
|
isHLS: true
|
|
})
|
|
})
|
|
|
|
if (hlsQualities.length > 0) {
|
|
isHLS = true
|
|
}
|
|
}
|
|
} catch {
|
|
// No existe HLS para este video
|
|
}
|
|
|
|
if (isHLS) {
|
|
// Video con HLS
|
|
videoMap.set(baseName, {
|
|
id: baseName,
|
|
name: baseName,
|
|
extension: ext.toLowerCase(),
|
|
isHLS: true,
|
|
qualities: hlsQualities,
|
|
url: `/videos/${baseName}_hls/master.m3u8`
|
|
})
|
|
} else {
|
|
// Video sin HLS, buscar versiones de calidad tradicionales
|
|
const qualities = [
|
|
{
|
|
quality: 'auto',
|
|
label: 'Original',
|
|
url: `/videos/${file}`,
|
|
file,
|
|
isHLS: false
|
|
}
|
|
]
|
|
|
|
// Buscar versiones con sufijos de calidad
|
|
for (const qualitySuffix of ['4k', '2k', '1080p', '720p', '480p', '360p']) {
|
|
const qualityFile = `${baseName}_${qualitySuffix}${ext}`
|
|
if (files.includes(qualityFile)) {
|
|
qualities.push({
|
|
quality: qualitySuffix,
|
|
label: qualitySuffix.toUpperCase(),
|
|
url: `/videos/${qualityFile}`,
|
|
file: qualityFile,
|
|
isHLS: false
|
|
})
|
|
}
|
|
}
|
|
|
|
videoMap.set(baseName, {
|
|
id: baseName,
|
|
name: baseName,
|
|
extension: ext.toLowerCase(),
|
|
isHLS: false,
|
|
qualities,
|
|
url: `/videos/${file}`
|
|
})
|
|
}
|
|
}
|
|
|
|
// Convertir a array y ordenar calidades
|
|
const videos = Array.from(videoMap.values()).map(video => {
|
|
// Ordenar calidades de mayor a menor
|
|
const qualityOrder = { '4k': 0, '2k': 1, '1080p': 2, '720p': 3, '480p': 4, '360p': 5, 'auto': 6 }
|
|
video.qualities.sort((a: any, b: any) => {
|
|
return (qualityOrder[a.quality as keyof typeof qualityOrder] || 999) -
|
|
(qualityOrder[b.quality as keyof typeof qualityOrder] || 999)
|
|
})
|
|
|
|
// Establecer la URL por defecto (la mejor calidad disponible)
|
|
if (video.isHLS) {
|
|
video.url = `/videos/${video.name}_hls/master.m3u8`
|
|
} else {
|
|
video.url = video.qualities[0].url
|
|
}
|
|
|
|
return video
|
|
})
|
|
|
|
return { videos }
|
|
} catch (error) {
|
|
console.error('Error reading videos:', error)
|
|
return { videos: [], error: 'Failed to load videos' }
|
|
}
|
|
})
|