diff --git a/descargar-curso/descargas/LIBRO_DE_ESTUDIO.html b/descargar-curso/descargas/LIBRO_DE_ESTUDIO.html
index 247b198..3de739f 100644
--- a/descargar-curso/descargas/LIBRO_DE_ESTUDIO.html
+++ b/descargar-curso/descargas/LIBRO_DE_ESTUDIO.html
@@ -1111,7 +1111,10 @@ body {
VIDEO
4. Análisis del Opuesto
-Video
+Video
+
+
+
5. EVALUACION y ESTADISTICAS en el VOLEIBOL
Estadísticas: (o métodos estadísticos) Su objetivo es brindar instrumentos para poder valorar los sucesos que ocurren en la realidad.
@@ -1130,7 +1133,10 @@ body {
Programa Excel
8. PELOTA "PIPE"
-Analisis video
+Analisis video
+
+
+
9. La estadística aplicada a la evaluación en VOLEIBOL
¿Se utiliza algún método estadístico en el Voleibol? ¿Cuáles son viables? ¿En qué categoría o nivel de juego? ¿Para qué sirve o se utiliza la estadística? ¿Cómo se evalúa? ¿Qué datos se evalúan? ¿Para qué evaluamos? ¿Es el proceso de recolección preciso o el que se necesita? ¿Cómo se interpretan los datos obtenidos? ¿Se utilizarán los datos recolectados?
diff --git a/descargar-curso/generar_dashboard.mjs b/descargar-curso/generar_dashboard.mjs
index 586f460..9fdc6b4 100644
--- a/descargar-curso/generar_dashboard.mjs
+++ b/descargar-curso/generar_dashboard.mjs
@@ -634,14 +634,24 @@ function generarHTML(datos) {
}
} catch { /* sin mapa */ }
+ let faltantesMd = "# Recursos Pendientes de Descarga\n\nLista de todos los materiales que faltan para alcanzar el 100% offline.\n\n";
+
for (const m of datos) {
totalSecciones += m.secciones.length;
for (const s of m.secciones) {
totalTemas += s.temas.length;
for (const t of s.temas) {
+ let isMissing = false;
+ let missingReason = "";
+
if (t.vimeoID) {
totalVideos++;
- if (videosMap[t.vimeoID]) videosDescargados++;
+ if (videosMap[t.vimeoID]) {
+ videosDescargados++;
+ } else {
+ isMissing = true;
+ missingReason = `[Video] ${t.titulo} (Vimeo ID: ${t.vimeoID})`;
+ }
}
if (t.recursoURL) {
totalRecursos++;
@@ -652,21 +662,47 @@ function generarHTML(datos) {
const archivos = fs.readdirSync(secDir).filter(f => f.startsWith(`recurso_${t.recursoID}.`) || f.startsWith(`archivo_${t.recursoID}_`));
if (archivos.length > 0) downloaded = true;
}
- if (downloaded) recursosDescargados++;
+ if (downloaded) {
+ recursosDescargados++;
+ } else {
+ isMissing = true;
+ missingReason = `[Recurso/Enlace] ${t.titulo} (ID: ${t.recursoID}) -> URL: ${t.recursoURL}`;
+ }
}
}
if (t.contenidoHTML) {
totalContenidos++;
contenidosDescargados++;
}
+
+ if (isMissing) {
+ const basePath = `descargar-curso/descargas/secciones/${m.carpeta}/${s.carpeta}/`;
+ if (t.vimeoID) {
+ faltantesMd += `- [ ] **${m.titulo}** > *${s.titulo}*\n`;
+ faltantesMd += ` - **Video:** ${t.titulo}\n`;
+ faltantesMd += ` - **Vimeo ID:** ${t.vimeoID} (Buscar en Vimeo u obtener con yt-dlp)\n`;
+ faltantesMd += ` - **Guardar como:** \`${basePath}${videosMap[t.vimeoID] || 'MX_video_'+t.vimeoID+'.mp4'}\`\n\n`;
+ } else if (t.recursoURL) {
+ const domain = "https://campus.somosvoley.com"; // O el dominio correspondiente al campus
+ faltantesMd += `- [ ] **${m.titulo}** > *${s.titulo}*\n`;
+ faltantesMd += ` - **Documento:** ${t.titulo}\n`;
+ faltantesMd += ` - **Link original:** [Abrir en el campus](${domain}${t.recursoURL})\n`;
+ faltantesMd += ` - **Guardar como:** \`${basePath}recurso_${t.recursoID}.pdf\` *(Si es excel o word, usar .xls o .doc)*\n\n`;
+ }
+ }
}
}
}
+ const docsDir = path.join(__dirname, "../docs");
+ if (!fs.existsSync(docsDir)) fs.mkdirSync(docsDir, { recursive: true });
+ fs.writeFileSync(path.join(docsDir, "FALTAN.md"), faltantesMd, "utf-8");
+
const totalItems = totalVideos + totalRecursos + totalContenidos;
const itemsDescargados = videosDescargados + recursosDescargados + contenidosDescargados;
const globalPct = totalItems > 0 ? Math.round((itemsDescargados / totalItems) * 100) : 0;
+
const css = `
* { margin: 0; padding: 0; box-sizing: border-box; }
@@ -1256,13 +1292,17 @@ body {
⬇ Descargar PDF
+\n`;
+ } else if (recursoLocal && recursoLocal.endsWith(".mp4")) {
+ bodyHTML += `
+
+
\n`;
} else if (recursoLocal) {
- // Otros archivos locales (ZIP, PPT, XLS, MP4, etc)
- const isVideo = recursoLocal.endsWith(".mp4");
- const icono = isVideo ? "🎬" : "📦";
- const etiqueta = isVideo ? "Ver Video" : "Descargar";
- bodyHTML += `\n`;
+ // Otros archivos locales (ZIP, PPT, XLS, etc)
+ const icono = "📦";
+ const etiqueta = "Descargar";
+ bodyHTML += `\n`;
} else {
// Faltante / no descargado
bodyHTML += `