Loading repository data…
Loading repository data…
educollado / repository
EasyPodcast: gestor en PHP + SQLite para publicar un podcast con web pública, páginas de episodio con URL amigable, panel de administración y feed RSS automático. Disponible en 8 idiomas y con API.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Aplicación en PHP + SQLite para publicar un podcast con web pública, feed RSS, SEO y panel de administración. Sin dependencias externas ni composer.
La forma más sencilla de instalar EasyPodcast: un único archivo PHP que descarga la última release desde GitHub, la extrae en el servidor y crea la base de datos SQLite, todo desde el navegador sin acceso SSH.
Requisitos
| Componente | Mínimo |
|---|---|
| PHP | 8.0+ |
| Extensiones PHP | pdo_sqlite, sqlite3, fileinfo, xmlwriter, zip, gd, curl |
| Servidor | Apache con mod_rewrite |
| Directorio de instalación | Escribible por el servidor web |
Pasos
Descarga instalar.php del repositorio EasyPodcast-Installer y súbelo al directorio raíz de tu servidor web (debe estar vacío o ser el único archivo).
Abre el instalador en tu navegador:
https://tu-dominio.com/instalar.php
Sigue los tres pasos del asistente:
Al finalizar serás redirigido al panel de administración (/admin.php).
Seguridad: el instalador intenta borrarse a sí mismo al completarse. Si no pudo eliminarse, borra
instalar.phpmanualmente antes de usar la aplicación.
1. Crear la base de datos
sqlite3 podcast.sqlite < schema.sql
mkdir -p audios images cache
2. Dar permisos de escritura al usuario del servidor web
chown -R www-data:www-data podcast.sqlite feed.xml audios images cache favicon.ico
chmod 775 audios images cache
chmod 664 podcast.sqlite feed.xml favicon.ico
3. Activar mod_rewrite con AllowOverride All en el virtual host.
4. Primer acceso
Abre /admin.php, crea el administrador y configura el canal en Gestión del Podcast.
5. Comprobaciones
/ → Portada pública
/feed.php → Feed RSS dinámico
/feed.xml → Feed generado
/sitemap.xml
/robots.txt
# Descargar el compose y levantar
curl -O https://github.com/educollado/EasyPodcast/releases/latest/download/docker-compose.yml
docker compose up -d
Abre http://localhost:8080/admin.php y crea el primer administrador. La base de datos se inicializa automáticamente.
O con docker run:
docker run -d \
--name easypodcast \
-p 8080:80 \
-v $(pwd)/data/db:/var/www/html/data \
-v $(pwd)/data/audios:/var/www/html/audios \
-v $(pwd)/data/images:/var/www/html/images \
-v $(pwd)/data/cache:/var/www/html/cache \
ghcr.io/educollado/easypodcast:latest
La imagen del proyecto se construye sobre una base PHP/Apache fijada a una versión concreta, no sobre una etiqueta flotante. Así las actualizaciones de seguridad del contenedor pasan a ser cambios explícitos y revisables.
| Página | Descripción |
|---|---|
Portada (index.php) | Episodios publicados con paginación, reproductor inline y buscador |
Episodio (episode.php) | URL amigable /YYYY/MM/slug, reproductor, descripción HTML saneada y descarga |
Búsqueda (search.php) | Búsqueda por título y descripción con paginación |
feed.php genera el RSS en tiempo real; feed.xml se regenera automáticamente tras cada cambio.rss_item_limit: número máximo de episodios en el feed (0 = sin límite).home_items_per_page: episodios por página en portada y búsqueda (mínimo 1, por defecto 20).scheduled antes de su publicación.podcast.link.canonical, meta description, Open Graph y link rel="alternate" al RSS.rel="prev" / rel="next" en paginación; páginas 2+ marcadas como noindex,follow.PodcastSeries en portada, PodcastEpisode en episodio).robots.txt dinámico con URL del sitemap calculada desde podcast.link.sitemap.xml estático regenerado automáticamente.on*.HttpOnly, SameSite y Secure cuando la petición usa HTTPS.| Página | Función |
|---|---|
admin.php | Login/logout y acceso al panel |
podcast_management.php | Metadatos del canal |
episodes_management.php | CRUD de episodios |
add_episode.php | Alta/edición con editor visual HTML (Jodit), grabación y subida de audio/imagen |
import_feed.php | Importación de episodios desde feed RSS externo |
backups.php | Exportar/importar base de datos y ficheros |
cache_management.php | Habilitar/deshabilitar caché y regenerar imágenes |
twofa_management.php | 2FA TOTP con códigos de recuperación |
social_management.php | Gestión de enlaces a redes sociales |
change_password.php | Cambio de contraseña |
stats.php | Estadísticas de episodios, descargas/reproducciones y caché |
pages_management.php / add_page.php | Páginas estáticas con jerarquía padre/hijo |
api_tokens.php | Generación y revocación de tokens para la API REST |
api_docs.php | Documentación interactiva de la API REST |
update.php | Actualizaciones desde GitHub Releases con recordatorio de copia de seguridad |
| Componente | Requisito |
|---|---|
| PHP | 8+ |
| Extensiones | pdo_sqlite, sqlite3, fileinfo, xmlwriter, zip, gd, curl |
| Servidor | Apache con mod_rewrite |
| Permisos de escritura | podcast.sqlite, feed.xml, audios/, images/, cache/, favicon.ico |
| Tabla | Uso |
|---|---|
podcast | Metadatos del canal (una fila) |
episodes | Episodios y estado de publicación |
management | Credenciales y configuración 2FA (TOTP) |
social | Enlaces a redes sociales (una fila) |
pages | Páginas estáticas con jerarquía padre/hijo |
api_tokens | Tokens de API (reservada) |
estadisticas | Datos brutos de descargas/reproducciones (7 días) |
estadisticas_mensuales | Resumen mensual histórico |
estadisticas_anuales | Resumen anual histórico |
El sistema usa PRAGMA user_version de SQLite. lib/migration_runner.php comprueba la versión en cada request y aplica solo las migraciones pendientes. Las instalaciones nuevas parten de user_version actualizado en schema.sql.
Edita lib/migration_runner.php:
// 1. Bloque condicional en runMigrations()
if ($version < 18) {
migration_v18($pdo);
$pdo->exec('PRAGMA user_version = 18');
}
// 2. Función de migración
function migration_v18(PDO $pdo): void
{
$pdo->exec('ALTER TABLE episodes ADD COLUMN nueva_columna TEXT');
}
Y actualiza schema.sql con PRAGMA user_version = 18.
| Versión | Cambios |
|---|---|
| 1 | Añade rss_item_limit, home_items_per_page, write_audio_metadata, cache_enabled a podcast |
| 2 | Crea tabla api_tokens |
| 3 | Hace pub_date nullable en episodes |
| 4 | Añade columnas TOTP a management |
| 5 | Crea tabla social |
| 6 | Crea tabla pages con índice idx_pages_status |
| 7 | Crea índice idx_episodes_link sobre episodes(link) |
| 8 | Añade app_language a podcast (idioma de la interfaz) |
| 9 | Añade name y last_used_at a api_tokens |
| 10 | Añade short_description a episodes |
| 11 | Renombra columna description → content en episodes |
| 12 | Añade admin_theme a podcast (tema visual del sitio) |
| 13 | Reparación idempotente: añade admin_theme si falta pese a user_version = 12 |
| 14 | Añade tablas e índices de estadísticas agregadas |
| 15 | Añade action_type a estadisticas para diferenciar descargas y reproducciones |
| 16 | Migra api_tokens a hash + sufijo visible y añade alcance explícito |
| 17 | Añade public_theme_mode_auto a podcast para guardar el modo público Según sistema como ajuste global |
├── index.php # Portada pública
├── episode.php # Página de episodio
├── search.php # Búsqueda
├── page.php # Página estática
├── feed.php # Feed RSS dinámico
├── feed.xml # Feed RSS generado
├── feed_builder.php # Constructor de feed
├── robots.php # robots.txt dinámico
├── sitemap.xml # Sitemap estático
├── track.php # Seguimiento de descargas
├── admin.php # Login/logout admin
├── canonical_redirect.php # Redirección canónica 301
├── .htaccess # Reglas Apache
├── schema.sql # Esquema de base de datos
├── podcast.sqlite # Base de datos SQLite
├── favicon.ico # Icono del sitio
├── 403.php # Error 403
├── 404.php # Error 404
├── header.php # Cabecera pública compartida
├── footer.php # Pie público compartido
├── admin_nav.php # Navegación del panel admin
├── add_episode.php # Formulario de episodio
├── add_page.php # Formulario de página estática
├── episodes_management.php # Lista de episodios
├── pages_management.php # Lista de páginas estáticas
├── podcast_management.php # Configuración del podcast
├── social_management.php # Gestión de redes sociales
├── backups.php # Exportar/importar datos
├── cache_management.php # Configuración de caché
├── change_password.php # Cambio de contraseña
├── import_feed.php # Importar desde feed externo
├── media_cleanup.php # Limpieza de archivos huérfanos
├── stats.php # Estadísticas
├── twofa_management.php # Configuración 2FA TOTP
├── update.php # Actualizaciones automáticas
├── upload_audio_ajax.php # Subida de audio por AJAX
├── api_docs.php # Documentación API
├── api_tokens.php # Gestión de tokens API
├── api/ # API REST
│ └── index.php
├── lib/
│ ├── migration_runner.php # Sistema de migraciones BD
│ ├── episode_helpers.php # Slugs, fechas, MIME, rutas
│ ├── episode_save_handler.php # Validación y guardado de episodios
│ ├── episode_query.php # Consultas de episodios
│ ├── episode_seo.php # SEO de episodios
│ ├── upload_service.php # Subida de audio/imagen e ID3
│ ├── id3_service.php # Metadatos ID