GallaecIA

Media Hacklab

Laboratorio universitario de experimentación e innovación en intelixencia artificial e xornalismo

📄 Sobre este repositorio

Este repositorio contén o código fonte e documentación do proxecto GallaecIA Media Hacklab, un sistema automatizado para a xestión e publicación de traballos académicos de cinco tipos: proxectos web, aplicacións, programación, vídeo e audio. Non só contidos multimedia: as entregas do alumnado inclúen software executable, que require unha presentación propia con demostración e repositorio consultable.

O proxecto está deseñado para servir como plataforma de publicación e arquivo histórico de proxectos académicos, con optimización automática de recursos multimedia e unha interface retro-futurista.

Nota importante: Este repositorio contén unicamente a estrutura base do proxecto e non inclúe datos persoais nin contidos multimedia reais.

Para quen queira replicalo: a peza que máis atención merece é a separación entre o plano privado e o público. As fichas metodolóxicas que enche o alumnado levan nome completo e correo, así que viven só no ordenador do profesorado (metodoloxia_fichas/) e o que se publica é unha copia saneada (contido/fichas/). Tres barreiras independentes sosteñen esa separación —exclusión na subida, bloqueo no servidor e o JavaScript que só le a copia pública— e scripts/preparar_despregue.py compróbaas todas antes de publicar, xunto con que ningunha ficha pública conteña un correo. Explicación completa na memoria técnica.

Ver README Memoria técnica Ir ao sitio principal

✨ Características principais

Xeración automática intelixente

Sistema de creación e actualización automática de galerías multimedia, acordeóns e bloques de contido, sen necesidade de editar HTML manualmente. Inclúe detección automática de cambios por timestamps e preservación de edicións manuais. Permite manter sempre actualizada a web cos últimos proxectos, vídeos e audios.

Framework moderno minimalista

Deseño baseado en HTML5, CSS3 (Grid/Flexbox) e JavaScript vanilla, sen dependencias de frameworks pesados. Interface retro-futurista inspirada en terminais, optimizada para dispositivos móbiles e escritorio con compatibilidade cross-browser e multiplataforma.

Scripts multiplataforma avanzados

Scripts en Python e Bash con compatibilidade multiplataforma (Linux, macOS, Windows, FreeBSD) para optimizar vídeo/audio, xerar miniaturas, controlar o seguimento de arquivos e automatizar a xeración de bloques HTML e metadatos. Detección automática do sistema operativo e procesamento paralelo eficiente. Facilita o mantemento e reduce erros humanos.

Persistencia simple e segura

Almacenamento de metadatos e configuración en arquivos JSON, sen necesidade de bases de datos externas. Inclúe protección con .htaccess para evitar execución de scripts e accesos indebidos.

Xestión de fichas metodolóxicas

Formulario web para documentar a metodoloxía de cada proxecto, con almacenamento estruturado en JSON e panel de xestión para o profesorado.

Privacidade e seguridade

Separación clara entre datos persoais e repositorio open source. Protección de cartafoles sensibles e arquivos xerados automaticamente para evitar filtracións.

Progressive Web App (PWA)

Aplicación web progresiva con Service Worker, cache offline, instalación en dispositivos móbiles e escritorio. Inclúe notificacións e funcionalidade offline avanzada.

Cada peza coa súa URL

Cada traballo ten páxina propia con etiquetas Open Graph, así que ao compartilo nunha rede ou nunha mensaxe amósase a súa tarxeta —título, autoría e miniatura— e non unha ligazón espida. Xérase soa desde os datos do sitio, sen manter unha lista a man.

Espazo de acollida

Sección para obra allea á materia que se hospeda no sitio: traballos que non forman parte da avaliación pero que teñen interese e merecen estar publicados. Convive coa galería do curso sen mesturarse con ela, e ten a súa propia páxina de entrada.

Publicación comprobada

Publicar non é copiar unha carpeta: antes audítase o que se subiría, gárdase unha copia do que hai no servidor, sóbese só o que cambiou —cifrado e sen borrar nada— e despois compróbase contra o sitio publicado que todo responde e que nada privado quedou accesible.

📂 Estrutura do proxecto

O proxecto segue unha organización modular para facilitar o mantemento e a ampliación:

gallaecia_media_hacklab/
├── index.html                      # Páxina principal do sitio web
├── directorio.html                 # Índice navegable do repositorio (este arquivo)
├── viewcode.html                   # Visualizador de código fonte desde o navegador
├── memoria.html                    # Documentación técnica e memoria do proxecto
├── acollida.html                   # Entrada do espazo de acollida
├── sitemap.xml                     # Mapa do sitio para os buscadores
├── robots.txt                      # Que poden indexar os buscadores
├── index_construcion.html          # Páxina temporal por mantemento ou despregamento
├── README.md                       # Documentación básica e guía de uso do proxecto
├── AUTHORS                         # Información de autoría e contribuidores do proxecto
├── LICENSE-CODE                    # Licenza GPL v3.0 para código fonte
├── LICENSE-CONTENT                 # Licenza CC BY-NC-SA 4.0 para contidos educativos
├── .gitignore                      # Configuración para excluír arquivos/cartafoles en Git
├── .htaccess                       # Configuración de seguridade para o servidor Apache
├── .ftpignore                      # Que non se publica (espello das exclusións do panel)
├── htaccess-modelo.txt             # O .htaccess en texto, para poder lelo desde a web
├── dashboard-metodoloxias-modelo.txt  # O visor docente, só como modelo
├── xerar_galeria.py              # Script principal para analizar directorios e xerar bloques HTML
├── bloques_galeria.html            # Bloques HTML xerados para a galería de proxectos actuais
├── bloques_video.html              # Bloques HTML xerados para a galería de vídeos actuais
├── bloques_audio.html              # Bloques HTML xerados para a galería de audios actuais
├── bloques_acordeon.html           # Bloques HTML para acordeóns de proxectos arquivados
├── bloques_acordeon_video.html     # Bloques HTML para acordeóns de vídeos arquivados
├── bloques_acordeon_audio.html     # Bloques HTML para acordeóns de audios arquivados
├── __pycache__/                    # Arquivos temporais xerados automaticamente por Python
├── assets/                         # Recursos estáticos do sitio (CSS, JS, imaxes, miniaturas)
│   ├── css/                        # Follas de estilo CSS
│   │   ├── styles.css              # Estilos principais da web
│   │   └── styles.min.css          # Estilos minificados para produción
│   ├── js/                         # Scripts JavaScript
│   │   ├── bundle.js               # Funcionalidade principal e modais
│   │   ├── bundle.min.js           # Scripts minificados para produción
│   │   ├── pwa-manager.js          # Xestor de PWA e Service Worker
│   │   └── compartir.js            # Menú de compartir e folla do sistema
│   ├── img/                        # Imaxes de interface (iconos, logos, etc.)
│   │   └── licenzas/               # Iconas das licenzas, servidas desde aquí
│   ├── vendor/                     # Copia local de Font Awesome e marked
│   │                               # (o sitio non carga nada de terceiros)
│   └── thumbs/                     # Miniaturas xeradas automaticamente
│       ├── proxectos/              # Miniaturas de proxectos web
│       ├── video/                  # Miniaturas de vídeos
│       └── audio/                  # Miniaturas de audio
├── espazo_de_acollida/             # Obra allea á materia que se hospeda no sitio
│   ├── curso_actual/               # Traballos acollidos do curso vixente
│   └── arquivo/                    # Traballos acollidos de cursos anteriores
├── proxectos/                      # Proxectos web completos de estudantes
│   ├── curso_actual/               # Proxectos do curso vixente
│   │   └── [ano_académico]/        # Organización por ano académico (ex: 2024-25)
│   │       └── [nome_autor]/       # Proxecto individual (cartafol por autor)
│   └── arquivo/                    # Proxectos de cursos anteriores
│       └── [ano_académico]/        # Organización por ano académico
│           └── [nome_autor]/       # Proxecto individual arquivado
├── video/                          # Contido de vídeo (proxectos, reportaxes, etc.)
│   ├── curso_actual/               # Vídeos do curso vixente
│   │   └── [ano_académico]/        # Organización por ano académico
│   │       └── [nome_autor]/       # Vídeo individual
│   └── arquivo/                    # Arquivo histórico de vídeos
│       └── [ano_académico]/        # Organización por ano académico
│           └── [nome_autor]/       # Vídeo individual arquivado
├── audio/                          # Contido de audio (podcasts, entrevistas, etc.)
│   ├── curso_actual/               # Audios do curso vixente
│   │   └── [ano_académico]/        # Organización por ano académico
│   │       └── [nome_autor]/       # Audio individual
│   └── arquivo/                    # Arquivo histórico de audios
│       └── [ano_académico]/        # Organización por ano académico
│           └── [nome_autor]/       # Audio individual arquivado
├── datos/                          # Metadatos persistentes en JSON
│   ├── info_curso.json             # Información xeral do curso actual
│   ├── proyectos_actuales.json     # Metadatos de proxectos actuais
│   ├── video_actual.json           # Metadatos de vídeos do curso actual
│   ├── audio_actual.json           # Metadatos de audios do curso actual
│   ├── cursos_anteriores.json      # Resumo de cursos anteriores
│   └── autores.json                # Normalización e metadatos de autores
├── logs/                           # Arquivos de seguimento para optimización e tracking
│   ├── videos_procesados.json      # Rexistro de vídeos xa optimizados
│   └── audio_procesados.json       # Rexistro de audios xa optimizados
├── metodoloxia/                    # Sistema de fichas metodolóxicas (formulario e dashboard)
│   ├── metodoloxia.html            # Formulario web para crear fichas metodolóxicas
│   └── dashboard_metodoloxias.html # Panel de xestión de fichas metodolóxicas (só profesorado)
├── metodoloxia_fichas/             # Fichas ORIXINAIS (só local: levan nome e correo)
│   ├── metodologia_proxecto_web_[autor].json  # Ficha metodolóxica de proxecto web
│   ├── metodologia_video_[autor].json         # Ficha metodolóxica de vídeo
│   └── metodologia_audio_[autor].json         # Ficha metodolóxica de audio
├── contido/fichas/                 # Copia SANEADA e pública: é a que le a web
│   └── [curso]__[tipo]__[autoría].json        # Sen datos de contacto
├── pezas/                          # Unha páxina por traballo, para compartir
│   └── [curso]/[tipo]/[slug].html             # Con etiquetas Open Graph
├── ferramentas/                    # Utilidades de migración, de uso puntual
├── docs/                           # Notas de traballo do profesorado (non se publican)
├── deploy/                         # Informes de despregue e lista revisada de datos persoais
├── scripts/                        # Scripts de automatización e mantemento
│   ├── actualizar_rutas.sh             # Actualiza a función de visualización de rutas nos scripts de optimización
│   ├── auditar_estado_local.py         # Informe de só lectura sobre cursos, datos públicos, fichas e multimedia
│   ├── baixar_respaldo.py              # Baixa do servidor unha copia do publicado e un inventario completo, para poder volver atrás
│   ├── capturar_miniaturas.py          # Captura as miniaturas dos proxectos web con Chrome en modo headless
│   ├── control_fichas_metodoloxia.py   # Detecta fichas metodolóxicas ausentes ou orfas respecto do material entregado
│   ├── converter_videos_ios.sh         # Converte os perfís H.264 que Safari en iOS non reproduce
│   ├── detectar_enlaces_proxectos.py   # Descobre e verifica o repositorio e a aplicación en liña de cada entrega, sen listas escritas a man
│   ├── escanear_pii.py                 # Porta de privacidade: busca correos, teléfonos, DNI e credenciais no material publicable e detén a publicación se atopa algo sen revisar
│   ├── ftp_comun.py                    # Conexión FTP cifrada e percorrido do servidor, compartido polas ferramentas de respaldo, limpeza e publicación
│   ├── inxectar_volver_galeria.py      # Inxecta un botón flotante «Volver á galería» nas entregas que non teñen navegación de retorno propia
│   ├── limpar_duplicados.sh            # Detecta e retira ficheiros multimedia duplicados
│   ├── limpar_remoto.py                # Retira do servidor o material que non debe estar publicado, gardando antes unha copia
│   ├── marcar_ficheiros_procesados.sh  # Sistema de seguimento que evita reprocesar o material xa optimizado, comprobando que cumpre antes de marcalo
│   ├── minificar.sh                    # Xera styles.min.css e bundle.min.js para produción
│   ├── normalizar_contedores.py        # Deixa todo o multimedia en .mp4 e .mp3: remuxea sen recodificar cando o contido xa é válido
│   ├── normalizar_nomes.py             # Deixa os nomes de ficheiro e carpeta en NFC e sen espazos sobrantes, para que as rutas funcionen fóra de macOS
│   ├── normalizar_proxectos.py         # Normaliza cada entrega á estrutura estándar: entrada pública na raíz e material non publicable en _fonte/, _local/, _meta/ e _metodoloxia/
│   ├── optimizar_audio.sh              # Converte o audio a MP3 a 192 kbps, iguala o volume a -16 LUFS e mantén o rexistro do xa procesado
│   ├── optimizar_imaxes.py             # Redimensiona e recomprime as imaxes conservando o nome do ficheiro, para non romper as referencias do código do alumnado
│   ├── optimizar_videos.sh             # Comprime os vídeos con ffmpeg (H.264, lado maior 1280, AAC 192k), iguala o volume a -16 LUFS e evita reprocesar o xa optimizado
│   ├── optimizar_videos_paralelo.sh    # Versión paralela do optimizador de vídeo: reparte o traballo entre os núcleos dispoñibles con GNU parallel
│   ├── preparar_despregue.py           # Comprobacións antes de publicar: datos persoais, fichas saneadas, .htaccess, nomes portables, rutas que resolvan, documentación ao día e minificados
│   ├── publicar_ftp.py                 # Sobe ao servidor só o que é novo ou cambiou, comparando contra un respaldo previo
│   ├── sanear_fichas.py                # Xera a copia pública saneada de cada ficha metodolóxica (contido/fichas/) a partir do orixinal privado, sen correos e coas imaxes extraídas a ficheiros
│   ├── transcribir_aperturas.py        # Transcribe en local a apertura dunha peza para poder titulala cando o título entregado non a nomea
│   ├── verificar_publicado.py          # Comproba contra o servidor real que o publicado funciona e que nada privado responde
│   ├── xerar_espazos_apps.py           # Constrúe o portal público de cada aplicación, da materia ou acollida no sitio: demostración, árbore de ficheiros do repositorio (Markdown formatado), ZIP, ficha metodolóxica ou referencia citable
│   ├── xerar_pezas.py                  # Dálle a cada traballo unha URL propia con etiquetas Open Graph, para que ao compartilo se vexa a súa tarxeta e non unha ligazón espida
│   └── xerar_sitemap.py                # Constrúe o sitemap.xml a partir do contido real publicado
├── backup/                         # Copias de seguridade automáticas con timestamps (uso local)
│   └── auto_[YYYYMMDD_HHMMSS]/     # Backup automático antes de cada execución de xerar_galeria.py
│       ├── index.html              # Copia da páxina principal
│       ├── bloques_*.html          # Bloques HTML xerados
│       └── datos/                  # Todos os arquivos JSON de metadatos
├── service-worker.js               # Service Worker para funcionalidade PWA
├── manifest.json                   # Manifesto de aplicación web progresiva
└── requirements.txt                # Dependencias Python do proxecto

Arquivos clave

Listado xerado automaticamente desde o código do proxecto (42 ficheiros). As descricións saen da cabeceira de cada arquivo.

ArquivoDescriciónAccións
README.md Manual do proxecto: instalación, fluxo de traballo, pipeline multimedia e resolución de problemas
Markdown · 580 liñas · 27 KB
Ver código Descargar
dashboard-metodoloxias-modelo.txt Copia descargable do visor docente de fichas: úsase en local e non se despregа no servidor
TXT · 1681 liñas · 66 KB
Ver código Descargar
htaccess-modelo.txt Modelo comentado de .htaccess para protexer os datos persoais do alumnado ao replicar o proxecto
TXT · 114 liñas · 4 KB
Ver código Descargar
manifest.json Manifesto da aplicación web progresiva: nome, iconas e comportamento ao instalala nun dispositivo
JSON · 92 liñas · 2 KB
Ver código Descargar
requirements.txt Dependencias de Python necesarias para executar o proxecto
TXT · 53 liñas · 2 KB
Ver código Descargar
robots.txt Indica aos buscadores que poden indexar e que non
TXT · 55 liñas · 1 KB
Ver código Descargar
service-worker.js Service worker da PWA: caché de recursos estáticos, funcionamento sen conexión e control de versións da caché
JavaScript · 354 liñas · 11 KB
Ver código Descargar
xerar_galeria.py Xerador principal: le o sistema de ficheiros, extrae metadatos de audio, vídeo e proxectos, resolve as fichas metodolóxicas e reescribe index.html
Python · 3515 liñas · 154 KB
Ver código Descargar
metodoloxia.html Formulario que o alumnado enche para xerar a súa ficha metodolóxica
HTML · 3320 liñas · 151 KB
Ver código Descargar
actualizar_rutas.sh Actualiza a función de visualización de rutas nos scripts de optimización
Bash · 133 liñas · 5 KB
Ver código Descargar
auditar_estado_local.py Informe de só lectura sobre cursos, datos públicos, fichas e multimedia
Python · 441 liñas · 15 KB
Ver código Descargar
baixar_respaldo.py Baixa do servidor unha copia do publicado e un inventario completo, para poder volver atrás
Python · 193 liñas · 7 KB
Ver código Descargar
capturar_miniaturas.py Captura as miniaturas dos proxectos web con Chrome en modo headless
Python · 99 liñas · 3 KB
Ver código Descargar
control_fichas_metodoloxia.py Detecta fichas metodolóxicas ausentes ou orfas respecto do material entregado
Python · 79 liñas · 2 KB
Ver código Descargar
converter_videos_ios.sh Converte os perfís H.264 que Safari en iOS non reproduce
Bash · 139 liñas · 4 KB
Ver código Descargar
detectar_enlaces_proxectos.py Descobre e verifica o repositorio e a aplicación en liña de cada entrega, sen listas escritas a man
Python · 319 liñas · 12 KB
Ver código Descargar
escanear_pii.py Porta de privacidade: busca correos, teléfonos, DNI e credenciais no material publicable e detén a publicación se atopa algo sen revisar
Python · 290 liñas · 11 KB
Ver código Descargar
ftp_comun.py Conexión FTP cifrada e percorrido do servidor, compartido polas ferramentas de respaldo, limpeza e publicación
Python · 522 liñas · 19 KB
Ver código Descargar
inxectar_volver_galeria.py Inxecta un botón flotante «Volver á galería» nas entregas que non teñen navegación de retorno propia
Python · 92 liñas · 3 KB
Ver código Descargar
limpar_duplicados.sh Detecta e retira ficheiros multimedia duplicados
Bash · 79 liñas · 2 KB
Ver código Descargar
limpar_remoto.py Retira do servidor o material que non debe estar publicado, gardando antes unha copia
Python · 312 liñas · 11 KB
Ver código Descargar
marcar_ficheiros_procesados.sh Sistema de seguimento que evita reprocesar o material xa optimizado, comprobando que cumpre antes de marcalo
Bash · 385 liñas · 13 KB
Ver código Descargar
minificar.sh Xera styles.min.css e bundle.min.js para produción
Bash · 190 liñas · 6 KB
Ver código Descargar
normalizar_contedores.py Deixa todo o multimedia en .mp4 e .mp3: remuxea sen recodificar cando o contido xa é válido
Python · 243 liñas · 8 KB
Ver código Descargar
normalizar_nomes.py Deixa os nomes de ficheiro e carpeta en NFC e sen espazos sobrantes, para que as rutas funcionen fóra de macOS
Python · 199 liñas · 7 KB
Ver código Descargar
normalizar_proxectos.py Normaliza cada entrega á estrutura estándar: entrada pública na raíz e material non publicable en _fonte/, _local/, _meta/ e _metodoloxia/
Python · 457 liñas · 19 KB
Ver código Descargar
optimizar_audio.sh Converte o audio a MP3 a 192 kbps, iguala o volume a -16 LUFS e mantén o rexistro do xa procesado
Bash · 503 liñas · 17 KB
Ver código Descargar
optimizar_imaxes.py Redimensiona e recomprime as imaxes conservando o nome do ficheiro, para non romper as referencias do código do alumnado
Python · 284 liñas · 10 KB
Ver código Descargar
optimizar_videos.sh Comprime os vídeos con ffmpeg (H.264, lado maior 1280, AAC 192k), iguala o volume a -16 LUFS e evita reprocesar o xa optimizado
Bash · 1224 liñas · 42 KB
Ver código Descargar
optimizar_videos_paralelo.sh Versión paralela do optimizador de vídeo: reparte o traballo entre os núcleos dispoñibles con GNU parallel
Bash · 997 liñas · 35 KB
Ver código Descargar
preparar_despregue.py Comprobacións antes de publicar: datos persoais, fichas saneadas, .htaccess, nomes portables, rutas que resolvan, documentación ao día e minificados
Python · 1382 liñas · 58 KB
Ver código Descargar
publicar_ftp.py Sobe ao servidor só o que é novo ou cambiou, comparando contra un respaldo previo
Python · 415 liñas · 16 KB
Ver código Descargar
sanear_fichas.py Xera a copia pública saneada de cada ficha metodolóxica (contido/fichas/) a partir do orixinal privado, sen correos e coas imaxes extraídas a ficheiros
Python · 366 liñas · 14 KB
Ver código Descargar
transcribir_aperturas.py Transcribe en local a apertura dunha peza para poder titulala cando o título entregado non a nomea
Python · 124 liñas · 4 KB
Ver código Descargar
verificar_publicado.py Comproba contra o servidor real que o publicado funciona e que nada privado responde
Python · 376 liñas · 15 KB
Ver código Descargar
xerar_espazos_apps.py Constrúe o portal público de cada aplicación, da materia ou acollida no sitio: demostración, árbore de ficheiros do repositorio (Markdown formatado), ZIP, ficha metodolóxica ou referencia citable
Python · 1592 liñas · 74 KB
Ver código Descargar
xerar_pezas.py Dálle a cada traballo unha URL propia con etiquetas Open Graph, para que ao compartilo se vexa a súa tarxeta e non unha ligazón espida
Python · 418 liñas · 16 KB
Ver código Descargar
xerar_sitemap.py Constrúe o sitemap.xml a partir do contido real publicado
Python · 152 liñas · 5 KB
Ver código Descargar
styles.css Folla de estilos: interface retro-terminal, galerías, acordeóns e adaptación a móbil
CSS · 2125 liñas · 51 KB
Ver código Descargar
bundle.js JavaScript do sitio: galería, filtros por tipo, modais multimedia e carga das fichas metodolóxicas
JavaScript · 1499 liñas · 66 KB
Ver código Descargar
compartir.js Compartir cada peza: folla nativa do sistema no móbil e menú con WhatsApp, Telegram, correo, LinkedIn, Bluesky, X e copiar ligazón no escritorio
JavaScript · 323 liñas · 13 KB
Ver código Descargar
pwa-manager.js Xestión da PWA: instalación no dispositivo, actualizacións e aviso de funcionamento sen conexión
JavaScript · 1092 liñas · 37 KB
Ver código Descargar

🚀 Instrucións de uso

Requisitos

Fluxo de traballo típico

  1. Coloca os arquivos de contidos (proxectos, vídeos, audios) nas carpetas correspondentes:
    proxectos/curso_actual/[ano_académico]/[nome_autor]/ — Proxectos do curso actual
    proxectos/arquivo/[ano_académico]/[nome_autor]/ — Proxectos de cursos anteriores
    video/curso_actual/[ano_académico]/[nome_autor]/ — Vídeos do curso actual
    video/arquivo/[ano_académico]/[nome_autor]/ — Vídeos de cursos anteriores
    audio/curso_actual/[ano_académico]/[nome_autor]/ — Audios do curso actual
    audio/arquivo/[ano_académico]/[nome_autor]/ — Audios de cursos anteriores
  2. Xera e recopila fichas metodolóxicas para cada proxecto/audio/vídeo:
    • Os estudantes crean a súa ficha con metodoloxia/metodoloxia.html e envíanlla ao profesor.
    • O profesor recopila os arquivos JSON en metodoloxia_fichas/.
  3. Executa o script de marcado para identificar arquivos novos ou modificados:
    Unix/Linux/macOS:
    bash scripts/marcar_ficheiros_procesados.sh
    Windows (CMD):
    bash scripts/marcar_ficheiros_procesados.sh
    Windows (PowerShell):
    bash scripts/marcar_ficheiros_procesados.sh
    Nota: Require Git Bash, WSL ou instalación de Bash en Windows
  4. Executa os scripts de optimización para os novos arquivos:
    Unix/Linux/macOS:
    bash scripts/optimizar_videos.sh
    bash scripts/optimizar_audio.sh
    Windows:
    bash scripts/optimizar_videos.sh
    bash scripts/optimizar_audio.sh
    Nota: Os scripts detectan automaticamente o sistema operativo
  5. Converte vídeos para compatibilidade con iOS Safari (se é necesario):
    Unix/Linux/macOS:
    bash scripts/converter_videos_ios.sh
    Windows:
    bash scripts/converter_videos_ios.sh
    Nota: Só procesa vídeos con perfiles H.264 incompatibles
  6. Xera a galería e os bloques HTML/JSON:
    Unix/Linux/macOS:
    python3 xerar_galeria.py
    Windows:
    python xerar_galeria.py
  7. Comproba a sincronización de fichas metodolóxicas:
    Unix/Linux/macOS:
    python3 scripts/control_fichas_metodoloxia.py
    Windows:
    python scripts/control_fichas_metodoloxia.py
    (Opcional, só profesorado: amosa fichas faltantes ou sobrantes respecto aos contidos reais)
  8. Opcionalmente, minifica CSS e JS para produción:
    # Opción A - Script automatizado (recomendado):
    bash scripts/minificar.sh
    
    # Opción B - Comandos manuais:
    npx clean-css-cli -o assets/css/styles.min.css assets/css/styles.css
    npx terser assets/js/bundle.js -o assets/js/bundle.min.js --compress --mangle
  9. Limpa arquivos temporais e ocultos antes de subir a produción:
    Unix/Linux/macOS:
    find . \( -name ".DS_Store" -o -name "Thumbs.db" -o -name "*.swp" -o -name "*.swo" -o -name "*.tmp" -o -name "*.bak" \) -delete
    Windows (PowerShell):
    Get-ChildItem -Path . -Recurse -Force | Where-Object { $_.Name -match '\.(DS_Store|swp|swo|tmp|bak)$|^Thumbs\.db$' } | Remove-Item -Force
    Windows (CMD):
    for /r . %i in (.DS_Store Thumbs.db *.swp *.swo *.tmp *.bak) do @if exist "%i" del /f /q "%i"

Publicar no servidor

A xeración deixa o sitio listo en local. Publicalo é un paso á parte, con catro ordes que se executan sempre nesta orde. Ningunha delas sobe nada ata a terceira, e a terceira só sobe o que cambiou.

  1. Comprobar antes de nada. Non sobe nada: percorre o que se subiría e audítao. Se algunha comprobación falla, dío e detense; non hai que publicar ata resolvela.
    python3 scripts/preparar_despregue.py
  2. Gardar o que hai publicado. Trae do servidor un inventario completo e unha copia real dos ficheiros lixeiros, que son os que poden romper a web. Serve de punto de retorno e, ademais, de termo de comparación para o paso seguinte.
    python3 scripts/baixar_respaldo.py
  3. Publicar. Sen argumentos fai un simulacro: di canto subiría e que ficheiros, sen tocar o servidor. Con --aplicar sobe só o que é novo ou cambiou, comparando contra o respaldo. A conexión vai cifrada e non borra nada.
    python3 scripts/publicar_ftp.py
    python3 scripts/publicar_ftp.py --aplicar
  4. Verificar contra o servidor. Pregúntalle ao sitio publicado, non ao disco: comproba que as páxinas responden, que coinciden coas locais e que nada privado é accesible.
    python3 scripts/verificar_publicado.py

🔧 Personalización

O sistema está deseñado para ser facilmente personalizable e ampliable:

Estrutura de carpetas

Para engadir novos contidos, utiliza a seguinte estrutura obrigatoria (nomes normalizados, sen espazos nin tildes):

As autorías compartidas únense con _&_. Os nomes van en minúsculas, con guións baixos e sen tiles.

Dentro de cada proxecto, a entrega non se deixa tal cal chega: unha entrega trae tamén código fonte, dependencias e apuntamentos, e todo iso acabaría no servidor. scripts/normalizar_proxectos.py déixaa nesta forma, que separa o publicable do que non o é:

[nome_autor]/
├── index.html          # A entrada pública: isto é o que ve quen visita
├── media/              # Vídeo de demostración e material público
├── _fonte/             # Código fonte e material de traballo
├── _local/             # node_modules, .venv, .git — nunca se publica
├── _meta/              # proxecto.json: tipo, entrada pública e ficha
└── _metodoloxia/       # Copia interna da ficha da autoría
      

As carpetas que empezan por guión baixo non se soben nunca. O tipo de cada entrega declárase en _meta/proxecto.json (proxecto_web, aplicacion, programacion); se ese ficheiro non existe, dedúcese da estrutura de carpetas. normalizar_proxectos.py só simula por defecto: move ficheiros do alumnado, así que esixe --apply expresamente.

Os documentos de traballo quedan fóra do proxecto. Na carpeta de cada entrega vai o que forma parte da peza e o código necesario para reproducila. O texto en Word, o guión en PDF ou a folla de cálculo cos datos gárdanse aparte: ademais de non seren contido web, levan nos seus metadatos internos o nome legal completo de quen escribiu o ficheiro, comprimido onde ningún escáner de texto o ve. A comprobación previa ao despregue mira o árbore enteiro e tamén dentro dos ZIP.

Ao rematar o curso, o contido de curso_actual/ pasa a arquivo/, os datos dese curso gárdanse como datos/<sección>_<curso>.json, os JSON do curso novo comezan baleiros e datos/info_curso.json recolle o cambio. A partir de aí os scripts tratan ese material como histórico.

Configuración

Os parámetros principais do sistema (nomes de curso, autores, etc.) pódense modificar nos arquivos JSON da carpeta datos/.
Os bloques_*.html rexéranse enteiros en cada execución: editalos non serve de nada. Os datos/*.json funcionan doutro xeito, e a diferenza importa: o xerador compara a data de cada entrada coa do ficheiro de orixe e conserva o que se editou á man mentres o orixinal non cambie. Corrixir alí un título ou unha autoría é, polo tanto, un uso previsto. O que si os sobrescribe é --force-regenerate; por iso cada execución garda antes unha copia en backup/.

Personalización visual

Personalización de scripts

🔄 Scripts e automatización

Case todo o que se repite cada curso está automatizado, e non só o multimedia: constrúense as páxinas de cada peza e os portais das aplicacións, ordénanse as entregas separando o publicable do que non o é, revísase que non escapen datos persoais, publícase no servidor e compróbase despois o publicado. Son 30 ferramentas, agrupadas polo que fan; as de uso máis frecuente detállanse a continuación con exemplos de saída.

Xeración do sitio

inxectar_volver_galeria.py

Inxecta un botón flotante «Volver á galería» nas entregas que non teñen navegación de retorno propia

Funcionalidades detalladas
  • Idempotente: marca o fragmento con comentarios `gmh-back-home` e substitúeo en reexecucións.
  • Non invasivo: posiciónase fixo (top-left), con z-index alto e estilos propios encapsulados.
  • Sáltanse os portais de aplicacións (xa teñen unha barra superior con "Volver á galería").
  • Enlace relativo (../../../../index.html#proxectos) que funciona en local e en produción.

Exemplo de saída:

[limpado  ] proxectos/curso_actual/2025-26/almudena_villanueva_castro_&_alejandra_romani_lema/index.html
  [limpado  ] proxectos/curso_actual/2025-26/ana_iglesias_cabarcos/index.html
  [saltado  ] proxectos/curso_actual/2025-26/artai_bringas_gomez_&_javier_rodriguez_gonzalez/index.html
  [limpado  ] proxectos/curso_actual/2025-26/brais_perez_gomez/index.html
  [limpado  ] proxectos/curso_actual/2025-26/claudia_mascitti_nogueiras_&_emma_incera_viadero_&_alexandra_rey_lopez/index.html
  [saltado  ] proxectos/curso_actual/2025-26/ian_vilarino_vicente/index.html
  [limpado  ] proxectos/curso_actual/2025-26/ione_lopez_abalde/index.html
  [limpado  ] proxectos/curso_actual/2025-26/jorge_maril_carregal_&_laura_allegue_villares/index.html
  [limpado  ] proxectos/curso_actual/2025-26/lucia_del_rio_fraguela_&_alba_dosantos_rubio_&_carmen_castro_prieto/index.html
  [limpado  ] proxectos/curso_actual/2025-26/lucia_regueiro_martinez_&_alex_redruello_puga/index.html
  [saltado  ] proxectos/curso_actual/2025-26/miguel_fernandez_santos/index.html
  [saltado  ] proxectos/curso_actual/2025-26/pablo_rivera_carnota_&_jorge_vilarino_fieira/index.html
  [limpado  ] proxectos/curso_actual/2025-26/paula_bouza_lorenzo_&_adrian_abelenda_tobares_&_lucia_bello_perez/index.html
  [saltado  ] proxectos/curso_actual/2025-26/uxia_rodriguez_mendez_&_lucia_seoane_manteiga/index.html
  [saltado  ] proxectos/curso_actual/2025-26/zenaida_pontes_jorda_&_lena_costas_moldes/index.html
  [limpado  ] proxectos/arquivo/2024-25/adrian_sobrino_&_iker-coton/index.html

Python · 92 liñas · ver código · descargar

xerar_espazos_apps.py

Constrúe o portal público de cada aplicación, da materia ou acollida no sitio: demostración, árbore de ficheiros do repositorio (Markdown formatado), ZIP, ficha metodolóxica ou referencia citable

Funcionalidades detalladas
  • Amosa o vídeo de demostración, se a entrega o trae.
  • Deixa executala no navegador cando é posible.
  • Constrúe unha árbore navegable do repositorio, e permite ler cada ficheiro sen saír da páxina.
  • Empaqueta nun ZIP todo o código publicable.
  • Renderiza a ficha metodolóxica da autoría na propia páxina.
  • Exclúe dependencias, material interno e calquera ficheiro que pareza unha base de datos de usuarios.

Como se usa:

python3 scripts/xerar_espazos_apps.py                  # todas as aplicacións
python3 scripts/xerar_espazos_apps.py <carpeta> [...]  # só esas carpetas

Python · 1592 liñas · ver código · descargar

xerar_pezas.py

Dálle a cada traballo unha URL propia con etiquetas Open Graph, para que ao compartilo se vexa a súa tarxeta e non unha ligazón espida

Funcionalidades detalladas
  • Xera unha páxina por peza con `og:title`, `og:description`, `og:image` e `og:url`, para que ao compartila se vexa a súa tarxeta.
  • Usa a miniatura da propia peza, en URL absoluta: as redes non resolven rutas relativas.
  • Escribe páxina real e non un parámetro na URL, porque as redes e a mensaxería non executan JavaScript.
  • Redirixe á galería, co que quen abra a ligazón acaba no sitio.

Exemplo de saída:

Pezas compartibles
  pezas atopadas:      136
  páxinas creadas:     0
  páxinas actualizadas:0
  sen cambios:         136
  etiquetas inxectadas:0
  URL base: https://ia.xornalismo.gal
  Lembra rexerar o sitemap: python3 scripts/xerar_sitemap.py

Python · 418 liñas · ver código · descargar

xerar_sitemap.py

Constrúe o sitemap.xml a partir do contido real publicado

Funcionalidades detalladas
  • O sitemap anterior listaba catro URLs escritas a man e sen data de modificación, mentres o sitio publica unha cincuentena de páxinas de proxectos. Un buscador non ten como descubrir o traballo do alumnado se non está listado: cada proxecto é unha páxina á parte enlazada só desde a galería.
  • Toma as entradas de datos/*.json e as páxinas soltas da raíz, e respecta as mesmas exclusións que .htaccess: nada de _fonte, _local, _meta, ferramenta interna nin o visor docente.

Exemplo de saída:

URLs: 143
     1.0  2026-08-14  index.html
     0.8  2026-08-14  proxectos/arquivo/2024-25/adrian_sobrino_&_iker-coton/index.html
     0.8  2026-08-14  proxectos/arquivo/2024-25/carlos_paz_esperon_&_ruben_jesus_garci
     0.8  2026-08-14  proxectos/arquivo/2024-25/david_aljan_lusquinos_&_eva_cid_rivas/
     0.8  2026-08-14  proxectos/arquivo/2024-25/ines_pouparina_naseiro_&_rocio_maquiei
     0.8  2026-08-14  proxectos/arquivo/2024-25/josefina_torres_pereiro_&_chelsea_sidn
     … e 137 máis
Nada escrito.

Python · 152 liñas · ver código · descargar

Multimedia

capturar_miniaturas.py

Captura as miniaturas dos proxectos web con Chrome en modo headless

Funcionalidades detalladas
  • Servidor local activo: python3 -m http.server 8000
  • Google Chrome instalado.
  • macOS (usa ``sips`` para converter PNG -> JPG).

Como se usa:

python3 scripts/capturar_miniaturas.py

Python · 99 liñas · ver código · descargar

normalizar_contedores.py

Deixa todo o multimedia en .mp4 e .mp3: remuxea sen recodificar cando o contido xa é válido

Funcionalidades detalladas
  • Os optimizadores existentes miran resolución, bitrate e códec, pero non o CONTEDOR, así que un .mov ou un .mpeg pasaban o filtro. E o contedor importa: QuickTime non está garantido en todos os navegadores, e un audio chamado .mpeg pode servirse cun tipo MIME que o navegador non asocia a audio.
  • Atopado no material: tres audios MP3 con extensión .mpeg —un chámase audio.mp3.mpeg, claramente un renomeado accidental— e un vídeo .MOV con H.264 e AAC dentro.
  • Como o contido xa é o correcto, só se cambia o envoltorio con `-c copy`: non se recodifica nada e non se perde calidade. Se algún día aparece un contedor con códecs que non correspondan, este script avisa e non o toca: para iso están os optimizadores.
  • Actualízanse tamén as referencias en HTML, CSS, JS e datos/.

Exemplo de saída:

Modo: SIMULACIÓN
  Todo o multimedia xa está en .mp4 e .mp3.

Python · 243 liñas · ver código · descargar

optimizar_imaxes.py

Redimensiona e recomprime as imaxes conservando o nome do ficheiro, para non romper as referencias do código do alumnado

Funcionalidades detalladas
  • JPEG → JPEG co mesmo nome. 88 % de aforro e cero cambios no seu código.
  • PNG referenciado nun HTML → PNG cuantizado, que tamén conserva o nome.
  • PNG NON referenciado (maquetas soltas) → WebP, que aí si podemos.

Exemplo de saída:

Modo: SIMULACIÓN · mínimo 150 KB
Indexando referencias nos HTML/CSS/JS…
  imaxes citadas no código: 984
  imaxes optimizadas: 0  ·  omitidas por non compensar: 201  ·  erros: 0
Nada escrito. Repite sen --dry-run para aplicar.

Python · 284 liñas · ver código · descargar

optimizar_videos_paralelo.sh

Versión paralela do optimizador de vídeo: reparte o traballo entre os núcleos dispoñibles con GNU parallel

Funcionalidades detalladas
  • Linux: Usa flock nativo para bloqueo, nproc para núcleos, stat con formato GNU
  • macOS: Usa mkdir atómico para bloqueo, sysctl para núcleos, stat con formato BSD
  • FreeBSD/OpenBSD/NetBSD: stat formato BSD, sysctl para núcleos
  • Windows (Cygwin/MSYS2/Git Bash): stat formato GNU, variable NUMBER_OF_PROCESSORS
  • Solaris: psrinfo para núcleos
  • Otros Unix: Fallback con getconf y /proc/cpuinfo

Como se usa:

bash scripts/optimizar_videos_paralelo.sh

Bash · 997 liñas · ver código · descargar

transcribir_aperturas.py

Transcribe en local a apertura dunha peza para poder titulala cando o título entregado non a nomea

Funcionalidades detalladas
  • Varias pezas están publicadas cun título que describe o formato («Crítica musical») ou que arrastra o enunciado da práctica («Segunda Prueba Audio»). A ficha metodolóxica non sempre nomea o tema, pero a propia peza si: nos primeiros segundos preséntase o programa e anúnciase o contido.
  • Isto NON escribe títulos: só extrae material verificable para decidilos. A transcrición gárdase para poder citar de onde sae cada proposta.

Como se usa:

python3 scripts/transcribir_aperturas.py ruta1.mp3 ruta2.mp4 ...
python3 scripts/transcribir_aperturas.py --segundos 90 ruta.mp3

Python · 124 liñas · ver código · descargar

Entregas do alumnado

detectar_enlaces_proxectos.py

Descobre e verifica o repositorio e a aplicación en liña de cada entrega, sen listas escritas a man

Funcionalidades detalladas
  • POR QUE EXISTE O xerador de portais tiña un dicionario APP_LINKS coas URL escritas unha a unha. Iso resolve o curso actual e non serve para o seguinte: cada ano habería que editar o script. Ademais unha URL escrita a man non se comproba soa, e xa apareceu un caso no que o repositorio declarado non contén o mesmo código que se publica.
  • COMO DECIDE Por orde de autoridade, e sen adiviñar:
  • Despois verifica que cada candidata responda, e compara —cando é GitHub— o código publicado co do repositorio, para saber se se está enlazando a algo distinto do que se amosa.
  • Non inventa nada: escribe as confirmadas en `_meta/proxecto.json`, que é de onde as le o xerador, e informa dos conflitos en vez de escoller só.

Exemplo de saída:

── ian_vilarino_vicente
   _meta (curado)       https://github.com/ianvilarino-create/muckrakai-app
   remoto do .git       https://github.com/AlbertoQuian/muckrakai
   ⚠ CONFLITO: hai máis dun repositorio vivo. Decide cal e ponno en _meta/proxecto.json; este script respéctao.
── zenaida_pontes_jorda_&_lena_costas_moldes
   _meta (curado)       https://github.com/zzzenaida/Asistente-periodistico-ai
   app en liña          https://asistente-periodistico-ai-ttfaomg8rwgeyt9vqeakfz.streamlit.app/
  conflitos: 1
  (informe; engade --escribir para gravar en _meta/proxecto.json)

Python · 319 liñas · ver código · descargar

limpar_duplicados.sh

Detecta e retira ficheiros multimedia duplicados

Funcionalidades detalladas
  • Bash · 79 liñas · 2 KB

Exemplo de saída:

🧹 Limpiando archivos duplicados con sufijo '_optimizado'
✅ No se encontraron archivos duplicados

Bash · 79 liñas · ver código · descargar

normalizar_nomes.py

Deixa os nomes de ficheiro e carpeta en NFC e sen espazos sobrantes, para que as rutas funcionen fóra de macOS

Funcionalidades detalladas
  • **O renomeado vai en dous pasos.** Para macOS «imágenes» en NFD e en NFC son o mesmo nome, así que un `rename()` directo é unha operación baleira e o nome queda como estaba. Pasando por un nome temporal, si cambia.
  • **As referencias só se reescriben cando cambia algo visible**, é dicir, cando se quita un espazo. Un cambio de NFD a NFC non require tocar ningún texto —o HTML xa está en NFC— e reescribilo é perigoso: «vídeos » é o nome dunha carpeta, pero tamén é a palabra «vídeos» seguida dun espazo, e substituír a cegas mete o texto seguinte pegado («97 vídeoscon selo»). Por iso só se substitúe cando o nome vai seguido dunha barra, é dicir, cando de verdade é unha ruta.

Exemplo de saída:

  Todos os nomes son portables. Nada que facer.

Python · 199 liñas · ver código · descargar

normalizar_proxectos.py

Normaliza cada entrega á estrutura estándar: entrada pública na raíz e material non publicable en _fonte/, _local/, _meta/ e _metodoloxia/

Funcionalidades detalladas
  • O script separa entrada publica, fonte local, metadatos e materiais auxiliares sen perder a trazabilidade da entrega orixinal. Por defecto executase en modo dry-run; usar --apply para aplicar os movementos.

Exemplo de saída:

{
  "aplicado": false,
  "fecha": "2026-08-14 15:30:40",
  "acciones": [
    {
      "action": "move",
      "src": "proxectos/curso_actual/2025-26/ian_vilarino_vicente/_fonte/aplicacion_buscador_contratos.BACKUP_20260709_113423/__pycache__",
      "dst": "proxectos/curso_actual/2025-26/ian_vilarino_vicente/_local/dependencias/_fonte__aplicacion_buscador_contratos.BACKUP_20260709_113423____pycache__",
      "detail": "dependency/local cache"
    },
    {
      "action": "move",
      "src": "proxectos/curso_actual/2025-26/ian_vilarino_vicente/_fonte/aplicacion_buscador_contratos/__pycache__",
      "dst": "proxectos/curso_actual/2025-26/ian_vilarino_vicente/_local/dependencias/_fonte__aplicacion_buscador_contratos____pycache__",
      "detail": "dependency/local cache"
    },

Python · 457 liñas · ver código · descargar

Privacidade e revisión

auditar_estado_local.py

Informe de só lectura sobre cursos, datos públicos, fichas e multimedia

Funcionalidades detalladas
  • Genera un informe de solo lectura sobre cursos, datos publicos, fichas, formatos multimedia, duplicados de optimizacion y dependencias pesadas.

Exemplo de saída:

# Auditoria de estado local GallaecIA
Fecha: 2026-08-14 15:20:47
Directorio base: `…/gallaecia_media_hacklab`
## Curso declarado
- Archivo: `datos/info_curso.json`
- Existe: True
- Curso actual declarado: `2025-26`
- Fecha de actualizacion: `2026-06-02 17:35:00`
…
- `.svg`: 1 arquivos, 1.2 KB
- Formatos no deseados detectados: 0
- Archivos con sufijo `_optimizado`: 0
## Dependencias pesadas en contenidos 2025-26
- No se detectaron `node_modules`, `.venv` o `venv` en contenidos 2025-26.
## Conclusiones inmediatas
- No se detectan bloqueos inmediatos en los apartados auditados.

Python · 441 liñas · ver código · descargar

escanear_pii.py

Porta de privacidade: busca correos, teléfonos, DNI e credenciais no material publicable e detén a publicación se atopa algo sen revisar

Funcionalidades detalladas
  • Non se borra nada nin se adiviña. Cada achado hai que revisalo unha vez e decidir: ou se retira do publicable, ou se anota en deploy/pii_permitidos.toml co seu motivo. As anotacións gárdanse co hash da liña que as contén, así que se o arquivo cambia a excepción caduca e volve a revisión. Iso é o que impide que a lista se pudra.
  • Códigos de saída: 0 ningún achado sen revisar 1 hai achados novos (o build ou o despregue deben parar) 2 erro de uso

Exemplo de saída:

Escaneado: …/gallaecia_media_hacklab
Achados totais: 46  ·  xa revisados: 46  ·  NOVOS: 0
✅ Ningún dato persoal sen revisar.

Python · 290 liñas · ver código · descargar

Publicación

baixar_respaldo.py

Baixa do servidor unha copia do publicado e un inventario completo, para poder volver atrás

Funcionalidades detalladas
  • `manifesto_remoto.json` — todo o que hai no servidor, con ruta, tamaño e data. É o «antes» co que comparar, e o que fai posible que a publicación suba só o que cambiou en vez do 1,6 GB enteiro.
  • `sitio/` — copia real dos ficheiros que poden romper a web: HTML, CSS, JS, JSON, XML, texto. Pesan pouco e son o que de verdade hai que poder restaurar. O multimedia queda fóra: son gigabytes, non se sobrescriben ao publicar, e o manifesto abonda para sabelos.

Como se usa:

python3 scripts/baixar_respaldo.py
python3 scripts/baixar_respaldo.py --so-inventario   # sen descargar nada
python3 scripts/baixar_respaldo.py --destino RUTA

Python · 193 liñas · ver código · descargar

ftp_comun.py

Conexión FTP cifrada e percorrido do servidor, compartido polas ferramentas de respaldo, limpeza e publicación

Funcionalidades detalladas
  • Moitos servidores esixen que a canle de datos continúe a mesma sesión TLS que a de control. Python non o fai por defecto e a transferencia córtase cun erro de handshake; `_FTPTLSReutilizando` resólveo.
  • En aloxamento compartido o certificado adoita estar emitido para o dominio do provedor, non para o do sitio, así que a verificación estrita falla. Inténtase primeiro verificando e despois sen verificar: segue cifrando o tránsito, que é o que protexe a credencial.

Exemplo de saída:

Base común das ferramentas que falan co servidor de publicación.
Biblioteca: non se executa soa. Reúne nun só sitio a conexión e o percorrido
remoto, para que as ferramentas de respaldo, publicación e limpeza fagan as
dúas cousas igual.
**Conexión cifrada por defecto.** Úsase `ftplib.FTP_TLS`, que negocia TLS
sobre a mesma conexión FTP: o mesmo servidor, o mesmo porto e as mesmas
credenciais, pero o contrasinal non viaxa lexible. A maioría dos aloxamentos
compartidos admíteno aínda que non o anuncien na súa documentación; pódese
comprobar mirando se a resposta ao comando `FEAT` inclúe `AUTH TLS`. Se non
está dispoñible, este módulo négase a conectar mentres non se autorice
expresamente con `permitir_claro`.
Dous detalles de implementación que adoitan dar problemas con FTPS:
  · Moitos servidores esixen que a canle de datos continúe a mesma sesión TLS
    que a de control. Python non o fai por defecto e a transferencia córtase
    cun erro de handshake; `_FTPTLSReutilizando` resólveo.
  · En aloxamento compartido o certificado adoita estar emitido para o

Python · 522 liñas · ver código · descargar

limpar_remoto.py

Retira do servidor o material que non debe estar publicado, gardando antes unha copia

Funcionalidades detalladas
  • Un fluxo de publicación que só sabe subir deixa no servidor todo o que algunha vez chegou alí, aínda que xa non forme parte do sitio. Para material que non debe ser público iso non abonda.
  • Bloquear o acceso cunha regra de servidor é unha barreira útil, pero é a segunda: unha regra pódese perder ao editar a configuración. A primeira é que o ficheiro non estea.
  • 1. Percorre o que hai que retirar e ensina o reconto. Aquí para. 2. Con `--aplicar`, **primeiro descarga todo** a GALLAECIA_MEDIA_HACKLAB_BACKUPS/, e comproba tamaño a tamaño que a copia está completa. Se falla un só ficheiro, non borra nada. 3. Só entón borra, e comproba por HTTPS que deixou de responder.
  • O paso 2 non é adorno: sen el, un borrado é irreversible. Con el, é unha copia local máis unha retirada.

Exemplo de saída:

==========================================================================
RETIRADA DE MATERIAL PRIVADO DO SERVIDOR
==========================================================================
  Conexión: FTPS, certificado non verificado · ftp.xornalismo.gal:21 · usuario_ftp
  Raíz remota: /
--------------------------------------------------------------------------
  metodoloxia_fichas
    Fichas orixinais do alumnado: levan nome completo e correo electrónico. O que a web le é contido/fichas/, a copia saneada.
…
    → non está no servidor. Nada que facer.
--------------------------------------------------------------------------
  Comprobando exposición real por HTTPS (mostra de 8)…
    0 de 1 responden 200 e entregan o seu contido.
  TOTAL A RETIRAR: 1 ficheiros, 1.3 KB
  SIMULACRO. Non se tocou nada.
  Para copiar e borrar de verdade:  --aplicar

Python · 312 liñas · ver código · descargar

preparar_despregue.py

Comprobacións antes de publicar: datos persoais, fichas saneadas, .htaccess, nomes portables, rutas que resolvan, documentación ao día e minificados

Funcionalidades detalladas
  • datos persoais sen revisar no material publicable
  • as fichas orixinais, coas súas datos de contacto, subindo no canto das saneadas
  • as regras de bloqueo do servidor quedando só en local
  • referencias rotas na páxina principal
  • material fóra de formato que non todos os navegadores len
  • nomes de ficheiro que só funcionan no sistema onde se traballa

Exemplo de saída:

Preparación do despregue — non se sube nada
  ficheiros a subir: 4561
  peso total:        1593 MB
  ✅ Datos persoais         sen datos persoais fóra da lista revisada
  ✅ Nada privado na subida nada privado no inventario de subida
  ✅ Fichas metodolóxicas   137 fichas públicas, 0 orixinais
  ✅ Fichas sen correo      ningunha ficha pública leva correo electrónico
  ✅ Fichas no navegador    o navegador non pide fichas privadas
…
          1.0 MB  contido
          0.8 MB  (raíz)
          0.4 MB  pezas
          0.4 MB  scripts
          0.1 MB  metodoloxia
  informe: deploy/despregue_20260814_152029.json
  ❌ 1 comprobación(s) sen pasar. NON publiques ata resolvelas.

Python · 1382 liñas · ver código · descargar

publicar_ftp.py

Sobe ao servidor só o que é novo ou cambiou, comparando contra un respaldo previo

Funcionalidades detalladas
  • Capa lixeira (HTML, CSS, JS, JSON, XML…). É o que pode romper a web. Compárase **byte a byte** contra a copia que baixou `baixar_respaldo.py`. Certeza total, e sae de balde porque esa copia xa existe.
  • Multimedia. Compárase por **existencia e tamaño exacto** contra o manifesto. Baixar 1,1 GB para verificalo non ten sentido, e para .mp4, .mp3, .webp ou .jpg o tamaño é un criterio sólido: unha recompresión ou unha imaxe distinta sempre o cambia.

Exemplo de saída:

==========================================================================
PUBLICACIÓN DIFERENCIAL
==========================================================================

Python · 415 liñas · ver código · descargar

verificar_publicado.py

Comproba contra o servidor real que o publicado funciona e que nada privado responde

Funcionalidades detalladas
  • `preparar_despregue.py` mira o disco: di se o que hai en local está ben. Isto pregúntallo ao servidor: di se o que está **publicado** está ben.
  • Non son a mesma pregunta. Un ficheiro pode estar correcto en local e non chegar a subirse; unha regra de bloqueo pode estar escrita e non aplicarse; unha caché pode seguir servindo a versión anterior. Só se comproba pedindo as páxinas como as pide calquera visitante.

Exemplo de saída:

==========================================================================
VERIFICACIÓN DE https://ia.xornalismo.gal
==========================================================================
  ✅ Fichas privadas        as 136 rutas bloqueadas ou inexistentes
  ✅ Visor docente          visor docente non accesible (403)
  ✅ Nada privado aberto    as 10 rutas internas están pechadas
  ✅ Páxinas principais     as 10 páxinas principais responden
  ✅ Curso publicado        curso 2025-26, 200117 bytes, coincide coa local
  ✅ Páxinas ao día         as 5 páxinas coinciden co local e revalidan caché
  ❌ Código publicado       1 de 42 desfasados: xerar_galeria.py
  ✅ Fichas públicas        12 fichas públicas servidas, sen correos
  ✅ Páxinas por peza       10 pezas servidas, con Open Graph completo · 136 en total
  ✅ MIME de WebAssembly    1 ficheiro(s) .wasm, MIME correcto
  ✅ Referencias en index   omitida (--rapido)
==========================================================================
  1 de 11 comprobacións en vermello:

Python · 376 liñas · ver código · descargar

Panel e mantemento

actualizar_rutas.sh

Actualiza a función de visualización de rutas nos scripts de optimización

Funcionalidades detalladas
  • Script auxiliar para actualizar la función truncate_path_for_display() en optimizar_videos.sh. Mejora la visualización de rutas largas en terminal manteniendo contexto del proyecto. Función para crear la nueva función mejorada

Como se usa:

bash scripts/actualizar_rutas.sh

Bash · 133 liñas · ver código · descargar

Outros

sanear_fichas.py

Xera a copia pública saneada de cada ficha metodolóxica (contido/fichas/) a partir do orixinal privado, sen correos e coas imaxes extraídas a ficheiros

Funcionalidades detalladas
  • `metodoloxia_fichas/` — orixinais privados, con nome completo e correo. Nunca se publican.
  • `contido/fichas/` — copias públicas saneadas, o único que pide o navegador.

Como se usa:

python3 scripts/sanear_fichas.py                     # simulacro: que cambiaría
python3 scripts/sanear_fichas.py --aplicar           # escribe as copias públicas
python3 scripts/sanear_fichas.py --aplicar <ficha>   # só unha ficha privada

Python · 366 liñas · ver código · descargar

xerar_galeria.py

Script principal que automatiza a xeración e actualización de galerías.

Funcionalidades detalladas
  • Analiza a estrutura de directorios e arquivos
  • Extrae metadatos de proxectos, vídeos e audios
  • Xera bloques HTML para cada tipo de contido
  • Crea e optimiza miniaturas para proxectos (usando PIL/Pillow)
  • Detecta o que cambiou comparando datas, e conserva as edicións feitas a man nos JSON
  • Crea unha páxina por peza con etiquetas Open Graph, para que ao compartila se vexa a súa tarxeta
  • Mantén ao día o índice de código, a árbore de scripts e as cifras de directorio.html e memoria.html
  • Preserva edicións manuais cando os arquivos fonte non cambiaron
  • Actualiza automaticamente os arquivos HTML
  • Xestiona o sistema de acordeón para contido arquivado
  • Crea respaldos automáticos antes de cada execución

Exemplo de saída:

🚀 Executando con detección automática por timestamps...
🚀 Iniciando xeración de galería...
⚡ Modo: Detección automática por timestamps
✅ Respaldo creado en backup/auto_20250611_200951
🔄 Iniciando procesamento de contidos...
Procesando curso actual...
✅ Preservando edición manual de: index.html
Procesando arquivos de audio do curso actual...
✅ Preservando edición manual de: audio1.mp3
Procesando arquivos de video do curso actual...
✅ Preservando edición manual de: video1.mp4
Actualizando index.html...
✓ Sección proxectos actualizada
✓ Sección video actualizada  
✓ Sección audio actualizada
✅ Index.html actualizado automaticamente con éxito!
🎉 ¡PROCESO FINALIZADO CON ÉXITO!

Python · 3291 liñas · ver código · descargar

marcar_ficheiros_procesados.sh

Sistema de tracking que evita reprocesar arquivos xa optimizados e mantén limpos os rexistros.

Funcionalidades detalladas
  • Escanea directorios de vídeo e audio
  • Anota a data de modificación e o tamaño de cada arquivo
  • Compara contra rexistros previos
  • Actualiza os arquivos JSON de seguimento en logs/
  • Limpa automaticamente entradas orfas (arquivos que xa non existen) nos logs
  • Indica que arquivos requiren procesamento

Exemplo de saída:

=== Marcando arquivos de vídeo como procesados ===
Procesando directorio: video/curso_actual
✓ Marcado: video/curso_actual/2024-25/estudante1/video1.mp4
✓ Marcado: video/curso_actual/2024-25/estudante2/video2.mp4
=== Resumen de marcado ===
Arquivos de vídeo marcados como procesados: 62
Arquivos de vídeo excluídos: 0
Arquivos de audio marcados como procesados: 55
Arquivos de audio excluídos: 0
Limpeza completada.

Bash · 385 liñas · ver código · descargar

control_fichas_metodoloxia.py

Comproba a sincronización entre as fichas metodolóxicas (metodoloxia_fichas/) e os contidos reais (proxectos, vídeos, audios).

Funcionalidades detalladas
  • Escanea metodoloxia_fichas/ e compara cos contidos actuais
  • Detecta fichas faltantes ou sobrantes
  • Xera un informe para o profesorado

Exemplo de saída:

Fichas metodolóxicas FALTANTES:
  - metodologia_audio_estudante1.json
  - metodologia_video_estudante2.json
  - metodologia_proxecto_web_estudante3.json

Fichas metodolóxicas SOBRANTES:
  - metodologia_proxecto_web_estudante_antigo.json

✓ Proxectos: 12 fichas, 12 contidos (sincronizado)
⚠ Vídeos: 8 fichas, 10 contidos (faltan 2 fichas)
⚠ Audio: 5 fichas, 8 contidos (faltan 3 fichas)

Python · 79 liñas · ver código · descargar

optimizar_videos.sh

Procesa e optimiza vídeos para mellorar a carga web e reducir o espazo de almacenamento.

Funcionalidades detalladas
  • Procesa os arquivos de vídeo novos ou modificados
  • Converte formatos diversos (MOV, AVI, MKV, etc.) a MP4
  • Limita o lado maior a 1280 px cando é necesario, así que os vídeos verticais tamén se reducen
  • Fixa o audio en 192 kbps e iguala o volume a -16 LUFS, para que ningunha peza soe máis alta ca outra
  • Escribe un selo nos metadatos do arquivo para non recomprimilo nunca dúas veces
  • Sistema de tracking para evitar reprocesamento
  • Só procesa arquivos con reducción >15% de tamaño
  • Preserva e establece metadatos básicos

Exemplo de saída:

📂 Escaneando directorios...
📹 Encontrados 25 arquivos de video
📝 Procesando arquivos...
Procesando: [██████████████████████████████] 100%
✅ Procesamento completado
Arquivos procesados: 12
Arquivos convertidos: 8
Arquivos optimizados: 4
Arquivos renombrados: 3
Miniaturas xeradas: 12

Bash · 1224 liñas · ver código · descargar

converter_videos_ios.sh

Detecta e converte vídeos con perfiles H.264 incompatibles a formato compatible con iOS Safari.

Funcionalidades detalladas
  • Detecta automaticamente perfís H.264 incompatibles (High 4:2:2, High 10)
  • Converte a perfil Main compatible con iOS Safari
  • Mantén a calidade orixinal durante a conversión
  • Crea backups automáticos con sufixo _original
  • Optimización con faststart para reprodución inmediata
  • Procesa só os vídeos que realmente necesitan conversión
  • Rexistro detallado do proceso e estatísticas finais

Exemplo de saída:

🔧 SCRIPT DE CONVERSIÓN DE VÍDEOS PARA COMPATIBILIDAD iOS
==========================================================

🔄 Procesando: video/curso_actual/2024-25/pablo_gonzalez_garcia/video2.mp4
   📊 Codec actual: h264xHigh 4:2:2
   🔧 Convirtiendo a formato compatible con iOS...
   ✅ Conversión exitosa. Original guardado como: video2_original.mp4

========================================================== 
📊 RESUMEN:
   • Total de vídeos procesados: 4
   • Conversiones exitosas: 4
   • Errores: 0

Bash · 139 liñas · ver código · descargar

optimizar_audio.sh

Converte o audio a MP3, iguala o volume de todas as pezas e leva o rexistro do que xa está procesado.

Funcionalidades detalladas
  • Procesa os arquivos de audio novos ou modificados
  • Converte formatos diversos (WAV, AAC, OGG, FLAC, M4A) a MP3
  • Fixa o bitrate en 192 kbps e iguala o volume a -16 LUFS, para que ningunha peza soe máis alta ca outra
  • Normaliza os nomes de arquivo para que funcionen en calquera sistema
  • Sistema de tracking para evitar reprocesamento
  • Só procesa arquivos con reducción >15% de tamaño
  • Mantiene metadatos básicos (título, autor)

Exemplo de saída:

=== Optimizador de Audio - Só Arquivos Novos ===
Arquivos previamente procesados: 45
Procesando directorio: audio/curso_actual/2024-25/
✓ Convertido: podcast_episodio1.wav → podcast_episodio1.mp3
  Tamaño: 25.8MB → 3.2MB (87% redución)
✓ Optimizado: entrevista.mp3 (128kbps → 192kbps)
=== Estadísticas ===
Arquivos de audio encontrados: 12
Arquivos procesados: 3
Arquivos convertidos a MP3: 2
Arquivos MP3 optimizados: 1
Tamaño actual da carpeta audio: 45.2MB

Bash · 503 liñas · ver código · descargar

Edición manual de autores

Permite editar os nomes dos autores nos metadatos para mostrar tildes, ñ, etc. correctamente na web.

Como se usa?

Opción A - Editor interactivo (recomendado):

  • Executa: python3 xerar_galeria.py --editar-autores
  • Móstrase unha lista de todos os autores actuais
  • Introduce o nome da carpeta que queres editar
  • Introduce o novo nome (con acentos, ñ, etc.)
  • Repite para outros autores ou escribe 'salir' para terminar
  • Os cambios gárdanse automaticamente en datos/autores.json

Opción B - Edición manual de arquivos:

  • Edita directamente datos/autores.json cun editor de código ou texto plano
  • Editores recomendados: VS Code, Sublime Text, Atom, Notepad++, TextEdit (modo texto), nano, vim, emacs, Kate, gedit, etc.
  • NON usar: Word, LibreOffice Writer, Google Docs (corrompen o formato JSON)
  • Formato: "nome_carpeta": "Nome Con Acentos"
  • Garda o arquivo e executa python3 xerar_galeria.py

Exemplo:

Introduce o nome da carpeta que queres editar: josefina_torres_pereiro
Nome actual: Josefina Torres Pereiro
Introduce o novo nome: Josefina Torres Pereiro ✓
Nome actualizado: josefina_torres_pereiro → Josefina Torres Pereiro ✓

minificar.sh

Minifica automaticamente os arquivos CSS e JavaScript para optimizar a carga en produción.

Funcionalidades detalladas
  • Minifica automaticamente assets/css/styles.css → assets/css/styles.min.css
  • Minifica automaticamente assets/js/bundle.js → assets/js/bundle.min.js
  • Detecta automaticamente o sistema operativo e as dependencias
  • Instala automaticamente terser e clean-css-cli se é necesario
  • Mostra estatísticas de compresión por arquivo
  • Compatibilidade total con Linux, macOS, Windows e FreeBSD

Exemplo de saída:

🚀 GallaecIA Media Hacklab - Minificador de Assets
============================================
🔍 Verificando paquetes npm requiridos...
📦 Minificando bundle.js...
🎨 Minificando styles.css...
✅ Minificación completada. Arquivos actualizados:
   - assets/js/bundle.min.js
   - assets/css/styles.min.css
📊 Estadísticas de compresión:
   JS: 45230 → 23145 bytes (-49%)
   CSS: 18420 → 12890 bytes (-30%)

Bash · 190 liñas · ver código · descargar

Compatibilidade multiplataforma

Todos os scripts están probados e funcionan en:

Os scripts detectan automaticamente o sistema operativo e adaptan os comandos.

Fluxo completo de automatización

O sistema está deseñado para funcionar como unha cadea de procesamento automatizada e segura:

1. ENTREGA DO ALUMNADO
   ├── Deposítase na carpeta que lle corresponde:
   │   proxectos|video|audio/curso_actual/[curso]/[autoría]/
   │   espazo_de_acollida/curso_actual/[curso]/[autoría]/   # obra allea á materia
   └── metodoloxia/metodoloxia.html
       └── Cada peza leva a súa ficha metodolóxica, que a autoría enche

2. ORDE DA ENTREGA
   ├── scripts/normalizar_proxectos.py --apply
   │   └── Separa o publicable do que non o é: entrada pública na raíz,
   │       e _fonte/ _local/ _meta/ _metodoloxia/ para o resto
   ├── scripts/normalizar_nomes.py --aplicar
   │   └── Deixa os nomes en NFC e sen espazos sobrantes, para que as
   │       rutas funcionen tamén fóra de macOS
   └── O material de traballo queda fóra do árbore
       └── Na carpeta vai a peza e o código que fai falta para
           reproducila. O texto en Word, o guión en PDF ou a folla de
           cálculo gárdanse aparte: levan nos seus metadatos internos o
           nome legal de quen os escribiu

3. MARCADO PREVIO
   └── scripts/marcar_ficheiros_procesados.sh
       └── Anota o que xa está procesado, para non repetir traballo

4. MULTIMEDIA
   ├── scripts/optimizar_videos.sh
   │   └── H.264, lado maior 1280 px, volume a -16 LUFS, selo anti-recompresión
   ├── scripts/optimizar_audio.sh
   │   └── MP3 a 192 kbps e volume a -16 LUFS
   └── scripts/optimizar_imaxes.py
       └── Redimensiona conservando o nome, para non romper referencias

5. XERACIÓN
   └── python3 xerar_galeria.py [--force-regenerate]
       ├── Modo normal: conserva as edicións feitas a man nos JSON
       ├── --force-regenerate: reescribe todo desde os ficheiros fonte
       ├── Garda antes unha copia en backup/auto_AAAAMMDD_HHMMSS/
       ├── Escribe datos/*.json e os bloques, e reescribe index.html
       ├── Xera as miniaturas e as páxinas por peza con Open Graph
       └── Mantén ao día o índice de código e as cifras das páxinas
   └── scripts/xerar_espazos_apps.py
       └── Portal de cada aplicación: demostración, código e ZIP
   └── scripts/xerar_sitemap.py

6. REVISIÓN
   ├── scripts/control_fichas_metodoloxia.py
   │   └── Fichas ausentes ou orfas respecto do material entregado
   ├── scripts/escanear_pii.py
   │   └── Correos, teléfonos, DNI e credenciais no material publicable.
   │       Mira tamén dentro dos PDF, que gardan o texto comprimido
   └── python3 -m http.server 8000
       └── Revisión visual en http://127.0.0.1:8000/

7. MINIFICACIÓN
   └── scripts/minificar.sh
       ├── styles.min.css e bundle.min.js
       └── Se se executa DESPOIS do xerador, hai que volver executalo:
           o ?v= que rompe a caché escríbeo xerar_galeria.py co
           contido do asset nese momento, e ao minificar de novo queda
           apuntando ao anterior. A comprobación previa detecta o desfase

8. PUBLICACIÓN
   ├── scripts/preparar_despregue.py
   │   └── Audita o que se subiría. Non sobe nada; detense se algo falla
   ├── scripts/baixar_respaldo.py
   │   └── Garda o que hai publicado: inventario e copia dos ficheiros lixeiros
   ├── scripts/publicar_ftp.py [--aplicar]
   │   └── Sen argumentos, simulacro. Sobe cifrado só o novo ou cambiado,
   │       compara contra o respaldo, retómase se se corta e non borra nada
   └── scripts/verificar_publicado.py
       └── Comproba contra o sitio publicado: páxinas, código, fichas
           públicas e que nada privado responda

   Para retirar algo do servidor: scripts/limpar_remoto.py, que descarga
   unha copia e verifícaa antes de borrar.

Os pasos 1 a 7 poden automatizarse: non tocan o servidor e son idempotentes, así que repetilos non fai dano. O paso 8 non. Non hai —nin debe haber— unha tarefa programada que publique soa: a comprobación previa está feita para deterse e que unha persoa decida, e a publicación necesita a credencial do servidor, que non debe quedar dispoñible para un proceso desatendido. Publicar é unha decisión, non un automatismo.

📝 Licenzas

Este proxecto utiliza un sistema de licenzas duais para distinguir entre código e contido:

GPL v3 - Código fonte

Aplicable a scripts, HTML, CSS, JavaScript

Licenciado baixo GNU General Public License v3.0

  • Liberdade total para usar, estudar, modificar e distribuír
  • Copyleft forte — As melloras deben compartirse baixo a mesma licenza
  • Permite uso comercial se se mantén o código aberto
  • Ideal para colaboración entre universidades e desenvolvedores

Inclúe:

  • Scripts Python e Bash (xerar_galeria.py, scripts/)
  • Código HTML, CSS e JavaScript (assets/, arquivos .html)
  • Configuracións de scripts e arquivos de automatización
  • Arquivos de configuración do proxecto (.gitignore, etc.)
  • As entregas do alumnado que son software: aplicacións e programación

CC BY-NC-SA 4.0 - Contido educativo

Aplicable a documentación, metodoloxía e recursos

Licenciado baixo Creative Commons BY-NC-SA 4.0

  • Compartir — copiar e redistribuír en calquera medio
  • Adaptar — remesclar e transformar para contextos educativos
  • Atribución obrigatoria — Citar fonte orixinal
  • Non comercial — Protexe da explotación comercial
  • Compartir igual — Derivados baixo a mesma licenza

Inclúe:

  • Documentación técnica (README.md, memoria.html)
  • Obra do alumnado que non é software: reportaxes web, vídeo e audio
  • Metodoloxía educativa (metodoloxia/)
  • Recursos educativos e exemplos

Como se asigna a cada entrega. Non se decide peza a peza: dedúcese do seu tipo. As aplicacións e a programación van baixo GPL v3, porque son software; as reportaxes web, os vídeos e os audios van baixo CC BY-NC-SA 4.0. A regra está no formulario da ficha metodolóxica, que enche o campo só e non deixa cambialo, e cada ficha publica a licenza que lle corresponde. Unha licenza Creative Commons non serve para código —a propia Creative Commons desaconséllao—, e unha GPL non lle serve a unha peza sonora.

🤝 Por que esta combinación?

  • GPL v3 para código: Garantiza que as melloras técnicas volvan á comunidade
  • CC BY-NC-SA para contido: Protexe o material educativo da explotación comercial
  • Máxima colaboración académica: Permite reutilización en contextos universitarios
  • Claridade legal: Separación limpa entre infraestructura técnica e contido académico
  • Estándar profesional: Ambas as licenzas son amplamente recoñecidas

📞 Contacto para usos comerciais

Para consultas sobre licenciamento comercial do contido educativo:

Alberto Quian - alberto.quian@usc.es
Universidade de Santiago de Compostela
Departamento de Ciencias da Comunicación

Avaliamos cada caso considerando o beneficio para a comunidade educativa e a sustentabilidade do proxecto.

👨‍💻 Autoría do proxecto

Alberto Quian

Doutor en Investigación en Medios de Comunicación
Facultade de Ciencias da Comunicación
Universidade de Santiago de Compostela

🌐 albertoquian.github.io · 📧 alberto.quian@usc.es

📄 Ver información completa de autoría

Como citar este proxecto:

Quian, Alberto (2025). GallaecIA Media Hacklab. Universidade de Santiago de Compostela. Dispoñible en: https://ia.xornalismo.gal