feat(wordpress): novas skills seriously-simple-podcasting + mcp-seriously-simple-podcasting
Documenta as 14 tools do MCP dedicado (mcp-seriously-simple-podcasting, porta 3203) para episódios/shows/definições de show em emanuelalmeida.pt, complementado pela skill de conhecimento seriously-simple-podcasting (achado central: REST nativo do plugin é escrita-capaz para episódios mas read-only para definições de show).
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
---
|
||||
name: seriously-simple-podcasting
|
||||
description: Conhecimento profundo do Seriously Simple Podcasting (Castos, plugin `seriously-simple-podcasting`) — arquitectura, CPT `podcast` (episódios) e taxonomia `series` (shows), meta fields custom, REST API nativo (o que é escrita-capaz vs read-only), wp_options de definições de show (`ss_podcasting_*`), categorias iTunes/Apple Podcasts, feed RSS, e o estado real em emanuelalmeida.pt (39 episódios, 8 shows, sem addon Castos/Pro). Usar quando "seriously simple podcasting", "podcast wordpress", "episódio podcast", "show podcast", "feed rss podcast", "categorias itunes", "apple podcasts categoria", "castos", "ss_podcasting", "cpt podcast", ou qualquer trabalho de configuração/estratégia de podcast que não seja apenas chamar o MCP. Para execução directa (CRUD de episódios/shows), usar a tool MCP `mcp-seriously-simple-podcasting`.
|
||||
layer: wiki
|
||||
---
|
||||
|
||||
# /seriously-simple-podcasting — Seriously Simple Podcasting (Castos) — conhecimento de plugin
|
||||
|
||||
Plugin `seriously-simple-podcasting` (Free, `SSP_VERSION` 3.17.0), instalado e activo em
|
||||
**emanuelalmeida.pt**. **Sem addon Castos/Pro** — não há `fluentcampaign-pro`-equivalente neste
|
||||
site (confirmado: pasta `php/` do plugin não tem addon Pro, `ssp_is_connected_to_castos()` devolve
|
||||
falso, sem hospedagem/sincronização externa de ficheiros). Mapeamento feito por leitura completa
|
||||
do código-fonte (`wp-content/plugins/seriously-simple-podcasting/php/`) via SSH, 19-08-2026, antes
|
||||
de construir o MCP `mcp-seriously-simple-podcasting`.
|
||||
|
||||
---
|
||||
|
||||
## 0. Free vs addon Castos (não instalado aqui)
|
||||
|
||||
| | Free (activo) | Addon Castos/Pro (ausente) |
|
||||
|---|---|---|
|
||||
| Episódios (CPT `podcast`), shows (taxonomia `series`), feed RSS | ✅ core | — |
|
||||
| Upload/hosting de ficheiros de áudio | ❌ (URL externo só) | ✅ hosting Castos + analytics avançado |
|
||||
| Sincronização automática (`podmotor_*` meta) | campos existem mas vazios (nunca usados) | ✅ |
|
||||
| Transcrições, capítulos | não encontrado no código lido (sem módulo dedicado nesta versão) | — |
|
||||
|
||||
Todos os 39 episódios reais têm `audio_file` a apontar para `episodes.castos.com` (CDN legado de
|
||||
uma ligação Castos anterior, hoje desligada) — os ficheiros continuam a servir de lá, mas o plugin
|
||||
já não está autenticado/sincronizado com a conta.
|
||||
|
||||
---
|
||||
|
||||
## 1. Onde vivem os dados
|
||||
|
||||
### 1.1 Episódios — CPT `podcast` (constante `SSP_CPT_PODCAST`)
|
||||
|
||||
Post standard (`show_in_rest => true`), **sem tabela própria** — tudo em `wp_posts`/`wp_postmeta`.
|
||||
Meta fields registados via `register_meta()` (todos `show_in_rest => true`, confirmado em
|
||||
`CPT_Podcast_Handler::register_meta()`):
|
||||
|
||||
| Meta key | Tipo | Nota |
|
||||
|---|---|---|
|
||||
| `episode_type` | `audio`\|`video` | |
|
||||
| `audio_file` | URL | ficheiro (ou stream) do episódio |
|
||||
| `cover_image` / `cover_image_id` | URL / attachment ID | imagem quadrada, `cover_image_id` é interno (não escrever directamente) |
|
||||
| `duration` | texto | ex. `00:32:14`, calculado automaticamente se possível, mas aceita override manual |
|
||||
| `filesize` / `filesize_raw` | texto / bytes | `filesize_raw` é interno/calculado, usado no RSS — não escrever directamente |
|
||||
| `date_recorded` | `Y-m-d` | distinto de `post_date` (data de publicação) |
|
||||
| `explicit` / `block` | checkbox (`'on'`\|`''`) | `block` esconde de directórios iTunes/Google |
|
||||
| `itunes_episode_number` / `itunes_season_number` | número | tags iTunes WWDC 2017 |
|
||||
| `itunes_title` | texto | título específico para o feed iTunes (sem número de episódio/show) |
|
||||
| `itunes_episode_type` | `full`\|`trailer`\|`bonus` | |
|
||||
| `podmotor_file_id` / `podmotor_episode_id` / `castos_file_data` / `sync_status` | — | só-Castos, sempre vazios neste site |
|
||||
|
||||
### 1.2 Shows — taxonomia `series` (função `ssp_series_taxonomy()`, devolve `'series'`)
|
||||
|
||||
Termo hierárquico, `show_in_rest => true`, `rest_base => 'series'`. Um episódio pode pertencer a
|
||||
0-N shows (`wp_set_post_terms`). Tags normais (`post_tag`) também estão ligadas ao CPT por
|
||||
omissão (filtro `ssp_use_post_tags`, `true` neste site) — existe também uma taxonomia alternativa
|
||||
`podcast_tags`, mas só é registada se `ssp_use_post_tags` for desligado (não é o caso aqui).
|
||||
|
||||
### 1.3 Definições de show — `wp_options`, NUNCA numa tabela/post
|
||||
|
||||
Cada show tem um bloco de opções `ss_podcasting_data_{campo}_{series_id}` (título, subtítulo,
|
||||
descrição, autor, imagem, owner_name/email, idioma, copyright, category/subcategory 1-3) **mais**
|
||||
duas excepções sem o infixo `data_`: `ss_podcasting_explicit_{series_id}` e
|
||||
`ss_podcasting_complete_{series_id}` (gotcha — ver §6). Confirmado por SQL directo em
|
||||
`emanuelalmeida.pt`: 18 opções distintas escritas para o show "Afirmações" (id 120).
|
||||
|
||||
Existe também um conjunto **sem sufixo `_{series_id}`** — os defaults globais do site (usados
|
||||
quando um show não tem override próprio), lidos em
|
||||
`Rest_Api_Controller::get_default_podcast_settings()`.
|
||||
|
||||
---
|
||||
|
||||
## 2. REST API — o que é escrita-capaz vs read-only (achado central)
|
||||
|
||||
| Endpoint | Leitura | Escrita |
|
||||
|---|---|---|
|
||||
| `GET/POST/PUT /wp/v2/podcast` | ✅ episódios completos + todos os meta fields do §1.1 | ✅ (CPT standard, `show_in_rest`, capacidades `edit_podcasts` mapeadas para editor/administrator) |
|
||||
| `GET/POST/PUT /wp/v2/series` | ✅ termos + **campos extra injectados** (title/subtitle/author/owner_name/owner_email/language/copyright/image/category1-3/explicit_option/complete_option) | ❌ os campos extra são só-leitura — `register_rest_field()` em `Rest_Api_Controller::create_api_series_fields()` só regista `get_callback`, **sem `update_callback`**. Confirmado lendo o código-fonte; um `PUT` no termo não altera nenhuma destas definições. |
|
||||
| `GET /ssp/v1/episodes` | ✅ query cross-post-type (namespace próprio) | endpoint dedicado só para `podmotor_episode_id`/`audio_file` (uso interno Castos) |
|
||||
|
||||
**Implicação prática:** episódios podem ser geridos 100% via REST nativo (Application Password),
|
||||
mas **definições de show só podem ser escritas via `wp_options` directamente** (WP-CLI `wp option
|
||||
update` ou, como o MCP faz, `update_option()` dentro de um `wp eval`). É por isto que
|
||||
`mcp-seriously-simple-podcasting` usa o bootstrap WordPress completo (`wp eval`) para tudo, em vez
|
||||
de misturar REST para episódios e SQL para shows — um único mecanismo, sempre consistente.
|
||||
|
||||
---
|
||||
|
||||
## 3. wp-admin — páginas principais
|
||||
|
||||
| Página | Conteúdo |
|
||||
|---|---|
|
||||
| **Podcasting → All Episodes** | lista de episódios (CPT `podcast`), com metabox de todos os campos do §1.1 |
|
||||
| **Podcasting → Add New Episode** | criação, campo de show (taxonomia `series`) na sidebar |
|
||||
| **Podcasting → Settings → General** | defaults globais do site |
|
||||
| **Podcasting → Settings → Feed Details** | por show (selector "feed-series" no topo) — título/subtítulo/owner/categorias/idioma/copyright/imagem — é aqui que se editam manualmente as opções do §1.3 |
|
||||
| **Podcasting → Settings → Hosting** | ligação Castos (desligada neste site) |
|
||||
| **Podcasting → Settings → Import** | importar de outro feed RSS |
|
||||
|
||||
---
|
||||
|
||||
## 4. Categorias iTunes/Apple Podcasts
|
||||
|
||||
19 categorias de topo (`Arts`, `Business`, `Comedy`, `Education`, `Fiction`, `Government`,
|
||||
`History`, `Health & Fitness`, `Kids & Family`, `Leisure`, `Music`, `News`,
|
||||
`Religion & Spirituality`, `Science`, `Society & Culture`, `Sports`, `Technology`, `True Crime`,
|
||||
`TV & Film`), a maioria com subcategorias próprias (`Government`/`History`/`Technology`/
|
||||
`True Crime` não têm) — é a taxonomia oficial Apple Podcasts, lida de
|
||||
`php/config/settings/feed-categories.php` e `feed-subcategories.php`. Cada show suporta até 3
|
||||
pares categoria/subcategoria (`category`/`subcategory`, `category2`/`subcategory2`,
|
||||
`category3`/`subcategory3`). Lista completa disponível na tool `ssp_get_itunes_categories` do MCP
|
||||
(sem chamada SSH — é referência estática).
|
||||
|
||||
---
|
||||
|
||||
## 5. Feed RSS
|
||||
|
||||
URL construído a partir de `home_url()` + `feed/podcast` (ou `?feed=podcast` sem permalinks
|
||||
bonitos) + `/{slug-do-show}` para o feed de um show específico. Cada show tem o seu próprio feed
|
||||
filtrado (`Episode_Repository::get_feed_url()`); o feed "geral" (sem `series_id`) inclui episódios
|
||||
de todos os shows.
|
||||
|
||||
---
|
||||
|
||||
## 6. Estado real em emanuelalmeida.pt (verificado 19-08-2026)
|
||||
|
||||
- **39 episódios**, todos `publish`, distribuídos por **8 shows**: Meditação (11), DDE Desafio
|
||||
Detox Emocional (10), Afirmações (8), Reprogramação mental (6), Motivacionais (3), + 3 shows
|
||||
menores/vazios (incl. "Emanuel Almeida", 0 episódios).
|
||||
`audio_file` sempre aponta para o CDN legado `episodes.castos.com` (ligação Castos desligada,
|
||||
ficheiros continuam a servir de lá).
|
||||
- **Nenhum episódio marcado `explicit`** (único valor visto na coluna: `''`).
|
||||
- Plugins activos relevantes no mesmo site: Rank Math SEO PRO, Wordfence, WP Meteor, WP Fastest
|
||||
Cache, `seguranca-descomplicar` — nenhum interfere com REST/feeds do SSP nesta verificação
|
||||
(`curl` a `/wp-json/wp/v2/podcast` e `/feed/podcast/...` devolveram 200 sem bloqueio).
|
||||
|
||||
---
|
||||
|
||||
## 7. Gotchas
|
||||
|
||||
| Sintoma | Causa | Nota |
|
||||
|---|---|---|
|
||||
| `wp/v2/series` devolve `explicit_option`/`complete_option` sempre vazios ou iguais ao default global, mesmo com override por show definido | Bug do próprio plugin: `series_get_field_value()` faz fallback genérico para `ss_podcasting_data_{campo}_{series_id}`, mas `explicit`/`complete` são gravados em `ss_podcasting_{campo}_{series_id}` (sem `data_`) — o REST nunca encontra o override | Ler via `ssp_get_series_settings` do MCP (lê directamente com o prefixo correcto) em vez de confiar no REST nativo para estes dois campos |
|
||||
| `PUT /wp/v2/series/{id}` com `title`/`owner_email`/etc no payload não faz nada | Campos são `get_callback`-only (§2) | Escrever via `ssp_update_series_settings` do MCP (`update_option`) |
|
||||
| `ssp_delete_series`/qualquer verificação de "show tem episódios" baseada em `term->count` dá 0 mesmo com episódios associados | `term_taxonomy.count` do WordPress só conta posts **publicados** — episódios em `draft`/`pending`/`future` não entram na contagem | Não assumir "count=0 → seguro apagar"; confirmar sempre com `ssp_list_episodes` incluindo `status=any` antes de remover um show |
|
||||
| Nenhum registo de transcrições/capítulos encontrado no código | Este site usa a versão Free sem addon; não há módulo de transcrição na árvore lida (`grep -i transcript` só encontra uma referência de string solta num metabox, sem implementação funcional associada) | Não assumir suporte — verificar de novo se o plugin for actualizado/o addon Castos for religado |
|
||||
|
||||
---
|
||||
|
||||
## Fonte
|
||||
|
||||
Leitura completa do código-fonte `seriously-simple-podcasting` 3.17.0 via SSH em
|
||||
emanuelalmeida.pt (`php/classes/handlers/class-cpt-podcast-handler.php`,
|
||||
`class-series-handler.php`, `php/classes/repositories/class-episode-repository.php`,
|
||||
`php/classes/rest/class-rest-api-controller.php`, `class-episodes-rest-controller.php`,
|
||||
`php/classes/controllers/class-settings-controller.php`, `php/config/settings/*.php`,
|
||||
`php/includes/ssp-functions.php`), cruzada com `SHOW TABLES`/`DESCRIBE`/agregações reais via SQL e
|
||||
chamadas REST reais (`curl`), 19-08-2026 — sessão de construção do MCP
|
||||
`mcp-seriously-simple-podcasting`. Ver essa skill para a lista completa de 14 tools programáticas.
|
||||
Reference in New Issue
Block a user