Initial commit: Video player with HLS support
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
140
server/api/videos.get.ts
Normal file
140
server/api/videos.get.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
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' }
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user