Files
nucleoWhisper/nuxt4/app/composables/useStreams.ts
josedario87 8cc88c3dc4
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m5s
Agregar endpoints proxy para evitar CORS entre subdominios
- /api/streams/list: proxy a streams.nucleoriofrio.com/api/streams
- /api/frigate/event: proxy a camaras.nucleoriofrio.com/api/events
- Actualizar composables para usar los proxies del backend
- Los iframes de streaming siguen usando URLs directas (sesion propia)
2025-12-30 03:14:00 -06:00

168 lines
4.1 KiB
TypeScript

/**
* Composable para gestionar streams de video desde go2rtc
* Usa proxy backend para evitar problemas de CORS/cookies entre subdominios
* API Proxy: /api/streams/list
* Streaming: https://streams.nucleoriofrio.com (iframe con sesion propia)
*/
export type StreamType = 'webrtc' | 'mse' | 'mp4' | 'hls' | 'mjpeg'
export interface StreamTypeOption {
label: string
value: StreamType
description: string
useIframe: boolean
}
export const STREAM_TYPES: StreamTypeOption[] = [
{
label: 'WebRTC',
value: 'webrtc',
description: 'Menor latencia',
useIframe: true
},
{
label: 'MSE',
value: 'mse',
description: 'Media Source Extensions',
useIframe: true
},
{
label: 'MP4',
value: 'mp4',
description: 'Streaming MP4',
useIframe: false
},
{
label: 'HLS',
value: 'hls',
description: 'HTTP Live Streaming',
useIframe: false
},
{
label: 'MJPEG',
value: 'mjpeg',
description: 'Motion JPEG',
useIframe: false
}
]
export const useStreams = () => {
const BASE_URL = 'https://streams.nucleoriofrio.com'
// Estado reactivo
const streams = useState<string[]>('streams_list', () => [])
const selectedStream = useState<string | null>('streams_selected', () => null)
const selectedType = useState<StreamType>('streams_type', () => 'mse')
const isLoading = useState<boolean>('streams_loading', () => false)
const error = useState<string | null>('streams_error', () => null)
/**
* Obtiene la lista de streams disponibles via proxy backend
*/
const fetchStreams = async (): Promise<void> => {
isLoading.value = true
error.value = null
try {
// Usar proxy backend para evitar CORS/cookies issues
const response = await $fetch<Record<string, unknown>>('/api/streams/list')
// Extraer nombres de streams del objeto
streams.value = Object.keys(response).sort()
// Seleccionar el primero si no hay ninguno seleccionado
if (streams.value.length > 0 && !selectedStream.value) {
selectedStream.value = streams.value[0]
}
} catch (err: unknown) {
const errorMessage = (err as Error)?.message || 'Error al cargar streams'
error.value = errorMessage
console.error('[Streams] Error fetching streams:', err)
} finally {
isLoading.value = false
}
}
/**
* Genera la URL del stream segun el tipo seleccionado
*/
const getStreamUrl = computed((): string | null => {
if (!selectedStream.value) return null
const streamName = encodeURIComponent(selectedStream.value)
switch (selectedType.value) {
case 'webrtc':
return `${BASE_URL}/stream.html?src=${streamName}`
case 'mse':
return `${BASE_URL}/stream.html?src=${streamName}&mode=mse`
case 'mp4':
return `${BASE_URL}/api/stream.mp4?src=${streamName}`
case 'hls':
return `${BASE_URL}/api/stream.m3u8?src=${streamName}`
case 'mjpeg':
return `${BASE_URL}/api/stream.mjpeg?src=${streamName}`
default:
return null
}
})
/**
* Determina si se debe usar iframe o video nativo
*/
const useIframe = computed((): boolean => {
const typeConfig = STREAM_TYPES.find(t => t.value === selectedType.value)
return typeConfig?.useIframe ?? true
})
/**
* Obtiene las opciones para el dropdown de tipos
*/
const streamTypeOptions = computed(() => {
return STREAM_TYPES.map(type => ({
label: type.label,
value: type.value
}))
})
/**
* Obtiene las opciones para el dropdown de streams
*/
const streamOptions = computed(() => {
return streams.value.map(name => ({
label: name.replace(/_/g, ' '),
value: name
}))
})
/**
* Limpia el error
*/
const clearError = () => {
error.value = null
}
return {
// Estado
streams: readonly(streams),
selectedStream,
selectedType,
isLoading: readonly(isLoading),
error: readonly(error),
// Computed
getStreamUrl,
useIframe,
streamTypeOptions,
streamOptions,
// Metodos
fetchStreams,
clearError,
// Constantes
STREAM_TYPES
}
}