La pestaña de películas muestra todas las películas disponibles en las bibliotecas de Jellyfin, con una interfaz moderna tipo tarjetas (cards).
internal/handler/movies.goResponsabilidades:
GetLibrary()Endpoints:
GET /movies - Renderiza la página HTMLGET /api/movies - Devuelve JSON con las películasEstructuras de Datos:
type MovieFile struct {
Path string `json:"path"`
Title string `json:"title"`
Year int `json:"year,omitempty"`
Size int64 `json:"size"`
Extension string `json:"extension"`
Directory string `json:"directory"`
PosterURL string `json:"poster_url,omitempty"`
Jellyfin *JellyfinMovieMetadata `json:"jellyfin,omitempty"`
}
type JellyfinMovieMetadata struct {
ID string `json:"id"`
Overview string `json:"overview,omitempty"`
CommunityRating float64 `json:"community_rating,omitempty"`
PlayCount int `json:"play_count"`
LastPlayed string `json:"last_played,omitempty"`
DateAdded string `json:"date_added,omitempty"`
}
internal/service/clients/jellyfin.goFiltrado de Tipos: El cliente de Jellyfin devuelve diferentes tipos de items:
"Movie" → convertido a type “movie” ✅"Series" → convertido a type “series” (filtrado)"Episode" → convertido a type “episode” (filtrado)"Season" → PROBLEMA ACTUAL: se convierte a “movie” por defectoIssue Conocido: Las temporadas (Seasons) de series están siendo devueltas como “movies” porque el código asume que todo lo que no es “Series” ni “Episode” es una película. Esto necesita ser corregido.
Solución Pendiente:
Agregar filtro explícito para item.Type == "Season" en convertToMedia().
web/templates/pages/movies.htmlComponente Alpine.js: moviesPage()
Estado:
{
movies: [], // Array de películas
libraryPaths: [], // Rutas de bibliotecas de Jellyfin
loading: true, // Estado de carga
error: null, // Errores
searchQuery: '', // Búsqueda
sortBy: 'title', // Ordenamiento
selectedMovies: [] // Películas seleccionadas
}
Funcionalidades:
⚠️ IMPORTANTE: Cada película es UNA LÍNEA HORIZONTAL, no una tarjeta vertical.
Especificación (según docs/templates/card.md):
[ ] Título - Año - Tamaño - ICONOS - Carátula
Elementos por fila (izquierda a derecha):
Layout: Lista vertical donde cada película ocupa una fila horizontal completa.
1. Usuario accede a /movies
2. Frontend carga y hace fetch a /api/movies
3. Backend llama a jellyfinClient.GetLibrary()
4. Jellyfin devuelve todos los items (movies, series, episodes, seasons)
5. convertJellyfinToMovies() filtra solo type="movie"
6. Backend devuelve JSON con películas filtradas
7. Frontend renderiza las tarjetas con Alpine.js
Estado: 🔴 PENDIENTE
Descripción: Las temporadas de series están siendo incluidas en el conteo de películas porque convertToMedia() asigna type=”movie” por defecto a todo lo que no sea “Series” o “Episode”.
Ejemplo:
Solución:
Agregar en jellyfin.go:
func (c *JellyfinClient) convertToMedia(item *jellyfinItem) *models.Media {
mediaType := "movie"
if item.Type == "Series" {
mediaType = "series"
} else if item.Type == "Episode" {
mediaType = "episode"
} else if item.Type == "Season" {
mediaType = "season" // Nueva línea
}
// ...
}
Y en movies.go:
if media.Type != "movie" {
// Filtrar todo excepto movies
continue
}
Estado: 📝 TODO
Descripción: Actualmente solo mostramos metadatos básicos (ID, fechas, play_count) porque están en models.Media. Los metadatos enriquecidos (Overview, CommunityRating) requieren llamadas adicionales a la API de Jellyfin.
Solución Futura:
models.Media con más campos de JellyfinEstado: ⚠️ MEJORABLE
Descripción: El año se extrae del título buscando patrón (YYYY). Esto es frágil y puede fallar con títulos no estándar.
Alternativa: Jellyfin tiene campo ProductionYear que sería más confiable.
year a models.Media desde JellyfinRECORDATORIO: Más tarde crearemos la pestaña de Series con arquitectura similar:
SeriesHandler en internal/handler/series.gomedia.Type == "series"La carpeta docs/templates/ contiene las especificaciones de diseño de los elementos de la UI:
Propósito: Mantener especificaciones de diseño separadas del código permite:
docs/templates/card.mdinternal/service/clients/jellyfin.gointernal/models/models.go.github/copilot-instructions.mdÚltima actualización: 2025-11-11
Estado: En desarrollo activo
Prioridad: Alta