Pla d'Importació de Balls des de YouTube
Estat: ✅ Implementat (v1)
Data última actualització: 2025-01-28
Prioritat: Alta
Progrés
| Component | Estat |
|---|---|
| Backend DTOs | ✅ Completat |
| YouTubeService | ✅ Completat |
| DanceDescriptionParser | ✅ Completat |
| DanceImportService | ✅ Completat |
| DanceImportController | ✅ Completat |
| Frontend YouTubeImportPage | ✅ Completat |
| Ruta i menú | ✅ Completat |
| Tests unitaris | ✅ Completat |
| Tests d'integració | ⏳ Pendent |
Objectiu
Permetre a un admin importar un ball a partir d'un vídeo de YouTube, extraient automàticament les dades de la descripció i facilitant la creació del ball amb les seves relacions (cançó, coreògrafs, vídeo tutorial).
Flux General
┌─────────────────────────────────────────────────────────────────────┐
│ IMPORTACIÓ BALL DES DE YOUTUBE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. ENTRADA │
│ • URL YouTube │
│ • Títol del vídeo │
│ • Descripció (enganxada manualment / API futur) │
│ │
│ 2. ANÀLISI (backend) │
│ • Parseja descripció → extreu camps │
│ • Cerca duplicats per nom │
│ • Cerca coreògraf existent │
│ │
│ 3. DETECCIÓ DUPLICATS │
│ ├─ Si duplicat ALTA probabilitat: │
│ │ → Mostra ball existent │
│ │ → Opcions: [Afegir vídeo] [Crear nou] [Cancel·lar] │
│ │ │
│ └─ Si no duplicat o baixa probabilitat: │
│ → Mostra draft editable │
│ │
│ 4. DRAFT EDITABLE │
│ • Nom ball (detectat) │
│ • Counts, Walls, Level (manual o detectat) │
│ • Any origen (detectat) │
│ • Coreògraf (find-or-create) │
│ • Cançó (selector iTunes) │
│ • Tipus vídeo (Tutorial/Demo/Música) │
│ • Descripció ball (si detectada) │
│ • Especificació tècnica (Parts, Sequence...) │
│ │
│ 5. CONFIRMACIÓ → Inserts a BD │
│ • Choreographer (si nou) │
│ • Dance │
│ • DanceSong (PRIMARY) │
│ • DanceChoreographer │
│ • Link (YOUTUBE_*) │
│ • LineDanceSpec (amb sourceText) │
│ │
│ 5b. AFEGIR VÍDEO (si ball ja existeix) │
│ • Només Link (YOUTUBE_*) │
│ │
└─────────────────────────────────────────────────────────────────────┘
Control de Duplicats
Lògica de detecció
| Coincidència | Probabilitat Duplicat |
|---|---|
| Nom + Coreògraf + Cançó | 🔴 ALTA (95%) - Gairebé segur duplicat |
| Nom + Coreògraf | 🟠 MITJANA-ALTA (80%) - Probablement duplicat |
| Nom + Cançó | 🟡 MITJANA (60%) - Podria ser versió diferent |
| Només Nom | 🟢 BAIXA (30%) - Podria ser ball diferent |
Controls implementats
| Control | Implementació |
|---|---|
| Duplicat Ball | Cerca per nom similar + comparació coreògraf/cançó |
| Duplicat Cançó | ✅ Ja controlat per iTunes import (trackViewUrl) |
| Duplicat Coreògraf | ✅ Find-or-create per nom normalitzat |
| Duplicat Link | Comprovar si URL YouTube ja existeix |
Mapeig de Camps
| Camp Descripció YouTube | Camp LDP | Entitat | Notes |
|---|---|---|---|
| Títol vídeo | name | Dance | Principal |
| "Choreographed by X" | name | Choreographer | Find-or-create |
| "Cançó - Artista" | cerca iTunes | Song | Selector existent |
| Data (YYYY-MM-DD) | originYear | Dance | Només any |
| Walls | walls | Dance | Manual si no detectat |
| Level | levelCode | Dance | Manual si no detectat |
| Counts | counts | Dance | Manual si no detectat |
| Part A=32c, Sequence... | sourceText | LineDanceSpec | Text complet |
| Descripció del ball | description | Dance | Si detectada |
| URL YouTube | url | Link | YOUTUBE_TEACH/DANCE/MUSIC |
Tipus de Vídeo (LinkKind)
YOUTUBE_TEACH- Tutorial / ClasseYOUTUBE_DANCE- Demo / BallYOUTUBE_MUSIC- Vídeo musical / Cançó oficial
Patrons de Parsing
# Coreògraf
Choreographed by (.+)
# Cançó - Artista
^(.+)\s*-\s*(.+)$ (línia amb format "Títol - Artista")
# Àlbum
Album\s*[-:]\s*(.+?)[-]?(\d{4})?
# Data
\d{4}-\d{2}-\d{2}
# Counts/Walls (si surten)
(\d+)\s*[Cc]ounts?
(\d+)\s*[Ww]alls?
# Level (si surt)
[Ll]evel[:.\s]*(\w+)
# Especificació tècnica
Part [AB]=\d+c.*
Sequence:.*
Components a Implementar
Backend
| Component | Descripció |
|---|---|
DanceImportController | Endpoints /api/admin/dance-import/* |
DanceDescriptionParser | Servei per parsejar descripcions |
DanceImportService | Lògica de negoci (duplicats, find-or-create) |
DTOs
record DanceImportParseRequest(
String youtubeUrl,
String videoTitle,
String description
)
record DanceImportAnalysisDto(
DanceImportDraftDto draft,
List<DuplicateCandidateDto> duplicateCandidates,
DuplicateRisk duplicateRisk
)
record DanceImportConfirmRequest(
String youtubeUrl,
String videoType,
String danceTitle,
Integer counts,
Integer walls,
String levelCode,
Integer originYear,
String description,
String techSpec,
String choreographerName,
String choreographerCountry,
Long existingChoreographerId,
Long songId,
Long existingDanceId // null = crear nou
)
Frontend
| Component | Descripció |
|---|---|
DanceImportPage | Pàgina principal d'importació |
| Integració iTunes | Reutilitza selector de cançons existent |
Què es crea a la BD
| Ordre | Taula | Acció | Dades |
|---|---|---|---|
| 1 | choreographers | INSERT (si nou) | name, country, listingStatus=INFORMATIVE |
| 2 | dances | INSERT | name, counts, walls, level_id, origin_year, description |
| 3 | dance_choreographer | INSERT | dance_id, choreographer_id |
| 4 | dance_song | INSERT | dance_id, song_id, role=PRIMARY |
| 5 | links | INSERT | kind=YOUTUBE_*, url, dance_id |
| 6 | line_dance_specs | INSERT | dance_id, status=DRAFT, sourceText |
API YouTube (Futur)
Quan es tingui API Key:
youtube:
api-key: ${YOUTUBE_API_KEY:}
enabled: ${YOUTUBE_API_ENABLED:false}
Endpoint: GET https://www.googleapis.com/youtube/v3/videos?part=snippet&id={videoId}&key={API_KEY}
Retorna: snippet.title, snippet.description, snippet.channelTitle, snippet.publishedAt
Fases d'Implementació
Fase 1: MVP (sense API YouTube)
- Backend: DTOs i endpoints
- Backend: Parser de descripcions
- Backend: Detecció duplicats
- Backend: Find-or-create coreògrafs
- Frontend: Pàgina d'importació
- Tests
Fase 2: Millores
- API YouTube per fetch automàtic
- Millora del parser (més patrons)
- Historial d'importacions
- Importació en lot