Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 754915b91f | |||
| 5cf588ffe3 | |||
| a734ffc933 | |||
| b3a2ae682b | |||
| 825434a0b7 | |||
| 908188ddf2 |
@@ -407,5 +407,14 @@ traducción inmediata, avisar a Rafa directamente además de pedírselo a Hermes
|
||||
| Asignar `_carta_id` a un artículo | `POST /wp-json/fea/v1/carta-id/{id}` con body `{"carta_id": N}` |
|
||||
| Borrar `_carta_id` de un artículo | `DELETE /wp-json/fea/v1/carta-id/{id}` |
|
||||
|
||||
## Regla para la sección Evangelio y comentarios al Evangelio
|
||||
|
||||
La sección empieza siempre con el enlace al post del evangelio de esa semana (por
|
||||
ejemplo, `MATEO 14, 22-33`) y después van los comentarios. Si ese post no existe,
|
||||
avisad antes de publicar la carta: no empecéis la sección por un comentario.
|
||||
|
||||
No hay que completar ningún campo nuevo. A partir de ese enlace, el sitio asigna la
|
||||
cita bíblica automáticamente a los comentarios nuevos.
|
||||
|
||||
Campos útiles del post: `title`, `content` (HTML), `status` (`draft`/`publish`/`future`),
|
||||
`date` (ISO 8601 para programar), `categories` (array de IDs), `featured_media` (ID de adjunto).
|
||||
|
||||
@@ -98,6 +98,13 @@ add_action('wp_head', function () {
|
||||
background-color: #0d0d0d !important;
|
||||
color: #ececec !important;
|
||||
}
|
||||
/* En artículos, fea-ui.php fija --wp--preset--color--base en el body
|
||||
para el modo claro. El contenedor desplegable del menú hereda esa
|
||||
variable, así que hay que restaurarla aquí en oscuro. */
|
||||
html[data-fea-theme="dark"] body.single-post {
|
||||
--wp--preset--color--base: #0d0d0d;
|
||||
--wp--preset--color--contrast: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] a { color: <?php echo esc_html($accent_dark); ?>; }
|
||||
html[data-fea-theme="dark"] a:focus-visible,
|
||||
html[data-fea-theme="dark"] button:focus-visible {
|
||||
@@ -161,6 +168,22 @@ add_action('wp_head', function () {
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-card-title a { color: #ececec; }
|
||||
|
||||
/* Archivos (categoría, búsqueda y autor) — fea-homepage.php fija aquí
|
||||
fondos y texto claros que no heredan del tema. */
|
||||
html[data-fea-theme="dark"] .wp-block-query-title {
|
||||
color: #ececec !important;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-archive-card {
|
||||
background: #161311;
|
||||
border-color: #2a2320;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-archive-title a {
|
||||
color: #ececec;
|
||||
}
|
||||
html[data-fea-theme="dark"] .fea-archive-excerpt {
|
||||
color: #b8afa8;
|
||||
}
|
||||
|
||||
/* Selector de idioma (fea-homepage.php) */
|
||||
html[data-fea-theme="dark"] #fea-lang-btn { border-color: rgba(255,255,255,0.3); }
|
||||
html[data-fea-theme="dark"] #fea-lang-btn:hover,
|
||||
|
||||
@@ -13,23 +13,11 @@ function fea_audio_player_html(): string {
|
||||
$url = get_post_meta($id, 'fea_audio_url', true);
|
||||
if (!$url) return '';
|
||||
$voice = get_post_meta($id, 'fea_audio_voice', true) ?: 'NicoFeadulta2026';
|
||||
$sha256 = get_post_meta($id, 'fea_audio_sha256', true);
|
||||
$label = '<span class="fea-audio-label">'
|
||||
return '<div class="fea-audio">'
|
||||
. '<span class="fea-audio-label">'
|
||||
. '<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" focusable="false">'
|
||||
. '<path fill="currentColor" d="M3 10v4h4l5 5V5L7 10H3zm13.5 2a4.5 4.5 0 0 0-2.5-4.03v8.06A4.5 4.5 0 0 0 16.5 12zM14 3.23v2.06a7 7 0 0 1 0 13.42v2.06a9 9 0 0 0 0-17.54z"/>'
|
||||
. '</svg> Escucha</span>';
|
||||
// Para un asset con hash registrado, descarga y verifica el fichero completo
|
||||
// antes de delegar playback al navegador. Evita que un stream Range mezclado
|
||||
// por una caché reproduzca fragmentos de otro MP3.
|
||||
if (preg_match('/^[a-f0-9]{64}$/i', $sha256)) {
|
||||
return '<div class="fea-audio">' . $label
|
||||
. '<button type="button" class="fea-audio-verified-play" data-fea-audio-verified-play'
|
||||
. ' data-src="' . esc_url($url) . '" data-sha256="' . esc_attr(strtolower($sha256)) . '"'
|
||||
. ' data-post-id="' . esc_attr($id) . '" data-voice="' . esc_attr($voice) . '">Reproducir audio</button>'
|
||||
. '<audio controls preload="none" hidden data-fea-audio-track data-post-id="' . esc_attr($id) . '" data-voice="' . esc_attr($voice) . '"></audio>'
|
||||
. '<span class="fea-audio-status" role="status" aria-live="polite"></span></div>';
|
||||
}
|
||||
return '<div class="fea-audio">' . $label
|
||||
. '</svg> Escucha</span>'
|
||||
. '<audio controls preload="none" src="' . esc_url($url) . '"'
|
||||
. ' data-fea-audio-track data-post-id="' . esc_attr($id) . '" data-voice="' . esc_attr($voice) . '"></audio>'
|
||||
. '</div>';
|
||||
@@ -68,9 +56,6 @@ add_action('wp_head', function () {
|
||||
.fea-audio-label{display:inline-flex;align-items:center;gap:.35rem;font-size:.78rem;
|
||||
font-weight:600;color:#8b1a2e;white-space:nowrap;line-height:1}
|
||||
.fea-audio audio{height:32px;width:230px;max-width:44vw}
|
||||
.fea-audio-verified-play{border:1px solid #8b1a2e;border-radius:6px;background:#fff;color:#8b1a2e;padding:.35rem .6rem;font:inherit;font-size:.82rem;font-weight:600;cursor:pointer}
|
||||
.fea-audio-verified-play:disabled{opacity:.65;cursor:wait}
|
||||
.fea-audio-status{font-size:.76rem;color:#6b5c60}
|
||||
@media(max-width:600px){
|
||||
.fea-audio{margin-left:0;width:100%;margin-top:.5rem}
|
||||
.fea-audio audio{flex:1 1 auto;width:auto;max-width:none}
|
||||
@@ -88,52 +73,17 @@ add_action('wp_footer', function () {
|
||||
if (!get_post_meta(get_queried_object_id(), 'fea_audio_url', true)) return;
|
||||
?>
|
||||
<script>
|
||||
(function () {
|
||||
function hex(buffer) {
|
||||
return Array.from(new Uint8Array(buffer)).map(function (n) {
|
||||
return n.toString(16).padStart(2, '0');
|
||||
}).join('');
|
||||
}
|
||||
document.querySelectorAll('[data-fea-audio-verified-play]').forEach(function (button) {
|
||||
button.addEventListener('click', async function () {
|
||||
var wrap = button.closest('.fea-audio');
|
||||
var audio = wrap.querySelector('audio[data-fea-audio-track]');
|
||||
var status = wrap.querySelector('.fea-audio-status');
|
||||
button.disabled = true;
|
||||
status.textContent = 'Verificando audio…';
|
||||
try {
|
||||
// Se descarga el objeto entero una vez y se valida su hash. Sólo
|
||||
// entonces se crea un blob local: el <audio> no hará Range contra
|
||||
// CDN y jamás podrá mezclar fragmentos de otro MP3.
|
||||
var response = await fetch(button.dataset.src, {cache: 'no-store'});
|
||||
if (!response.ok) throw new Error('HTTP ' + response.status);
|
||||
var bytes = await response.arrayBuffer();
|
||||
var digest = hex(await crypto.subtle.digest('SHA-256', bytes));
|
||||
if (digest !== button.dataset.sha256) throw new Error('La copia recibida no coincide con el audio verificado');
|
||||
audio.src = URL.createObjectURL(new Blob([bytes], {type: 'audio/mpeg'}));
|
||||
audio.hidden = false;
|
||||
button.hidden = true;
|
||||
status.textContent = '';
|
||||
await audio.play();
|
||||
} catch (error) {
|
||||
status.textContent = 'No se pudo verificar el audio. Inténtalo de nuevo.';
|
||||
button.disabled = false;
|
||||
console.error('Fe Adulta audio verification failed:', error);
|
||||
}
|
||||
document.querySelectorAll('audio[data-fea-audio-track]').forEach(function (audio) {
|
||||
var fired = false;
|
||||
audio.addEventListener('play', function () {
|
||||
if (fired || typeof gtag !== 'function') return;
|
||||
fired = true;
|
||||
gtag('event', 'audio_play', {
|
||||
post_id: audio.dataset.postId,
|
||||
voice: audio.dataset.voice
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('audio[data-fea-audio-track]').forEach(function (audio) {
|
||||
var fired = false;
|
||||
audio.addEventListener('play', function () {
|
||||
if (fired || typeof gtag !== 'function') return;
|
||||
fired = true;
|
||||
gtag('event', 'audio_play', {
|
||||
post_id: audio.dataset.postId,
|
||||
voice: audio.dataset.voice
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
});
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Fe Adulta — Evangelio en comentarios
|
||||
* Description: Deriva la cita de la carta semanal y muestra la lectura en los comentarios al evangelio.
|
||||
* Version: 1.0
|
||||
*/
|
||||
|
||||
function fea_evangelio_category($es_id) {
|
||||
return function_exists('fea_cat') ? (int) fea_cat($es_id) : (int) $es_id;
|
||||
}
|
||||
|
||||
function fea_evangelio_comment_categories() {
|
||||
return array_map('fea_evangelio_category', [1647, 1646]);
|
||||
}
|
||||
|
||||
function fea_evangelio_is_comment($post_id) {
|
||||
return has_category(fea_evangelio_comment_categories(), $post_id);
|
||||
}
|
||||
|
||||
/** Lee el meta del comentario; las traducciones heredan el dato editorial del original ES. */
|
||||
function fea_evangelio_comment_meta($post_id, $key) {
|
||||
$value = get_post_meta($post_id, $key, true);
|
||||
if ($value !== '' && $value !== null) return $value;
|
||||
if (!function_exists('pll_get_post')) return $value;
|
||||
|
||||
$source_id = (int) pll_get_post((int) $post_id, 'es');
|
||||
return $source_id && $source_id !== (int) $post_id
|
||||
? get_post_meta($source_id, $key, true)
|
||||
: $value;
|
||||
}
|
||||
|
||||
function fea_evangelio_reading_title($cita) {
|
||||
$cita = trim(wp_strip_all_tags((string) $cita));
|
||||
if (!preg_match('/^(Mt|Mc|Lc|Jn)\s+(.+)$/u', $cita, $m)) return '';
|
||||
$books = ['Mt' => 'MATEO', 'Mc' => 'MARCOS', 'Lc' => 'LUCAS', 'Jn' => 'JUAN'];
|
||||
return $books[$m[1]] . ' ' . preg_replace('/\s+/u', ' ', trim($m[2]));
|
||||
}
|
||||
|
||||
/** Localiza la lectura española, sin depender del slug (que puede llevar sufijos). */
|
||||
function fea_evangelio_reading_id($cita) {
|
||||
global $wpdb;
|
||||
static $cache = [];
|
||||
$title = fea_evangelio_reading_title($cita);
|
||||
if ($title === '') return 0;
|
||||
if (isset($cache[$title])) return $cache[$title];
|
||||
// La coincidencia se hace siempre contra la lectura original en español; después
|
||||
// Polylang la sustituye por la traducción del comentario cuando exista.
|
||||
$cat = 1645;
|
||||
$sql = $wpdb->prepare(
|
||||
"SELECT p.ID FROM {$wpdb->posts} p
|
||||
INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id = p.ID
|
||||
INNER JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE p.post_type = 'post' AND p.post_status = 'publish' AND p.post_title = %s
|
||||
AND tt.taxonomy = 'category' AND tt.term_id = %d
|
||||
ORDER BY p.post_date DESC LIMIT 1",
|
||||
$title, $cat
|
||||
);
|
||||
return $cache[$title] = (int) $wpdb->get_var($sql);
|
||||
}
|
||||
|
||||
/** Devuelve los evangelios enlazados en la sección pertinente de una carta. */
|
||||
function fea_evangelio_from_carta($carta_id) {
|
||||
if (!function_exists('fea_parse_carta_sections')) return [];
|
||||
if (function_exists('pll_get_post')) $carta_id = (int) (pll_get_post((int) $carta_id, 'es') ?: $carta_id);
|
||||
$links = fea_parse_carta_sections((int) $carta_id)['evangelio'] ?? [];
|
||||
$result = [];
|
||||
foreach ($links as $id) {
|
||||
$post = get_post($id);
|
||||
if (!$post) continue;
|
||||
$cita = get_post_meta($id, '* Cita biblica', true);
|
||||
if (!$cita && preg_match('/^(MATEO|MARCOS|LUCAS|JUAN)\s+(.+)$/u', trim($post->post_title), $m)) {
|
||||
$abbr = ['MATEO' => 'Mt', 'MARCOS' => 'Mc', 'LUCAS' => 'Lc', 'JUAN' => 'Jn'][$m[1]];
|
||||
$cita = $abbr . ' ' . $m[2];
|
||||
}
|
||||
if (fea_evangelio_reading_title($cita)) $result[(string) $id] = trim($cita);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/** Busca una carta en las tres categorías históricas, dentro de cuatro días. */
|
||||
function fea_evangelio_nearest_carta_id(WP_Post $post) {
|
||||
$date = mysql2date('Y-m-d', $post->post_date, false);
|
||||
$cartas = get_posts([
|
||||
'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => 10,
|
||||
'category__in' => array_map('fea_evangelio_category', [6, 21, 22]),
|
||||
'date_query' => [[
|
||||
'after' => date('Y-m-d', strtotime($date . ' -4 days')),
|
||||
'before' => date('Y-m-d', strtotime($date . ' +4 days')), 'inclusive' => true,
|
||||
]],
|
||||
'orderby' => 'date', 'order' => 'DESC',
|
||||
]);
|
||||
if (!$cartas) return 0;
|
||||
usort($cartas, function($a, $b) use ($post) {
|
||||
return abs(strtotime($a->post_date) - strtotime($post->post_date)) <=> abs(strtotime($b->post_date) - strtotime($post->post_date));
|
||||
});
|
||||
return (int) $cartas[0]->ID;
|
||||
}
|
||||
|
||||
/** Escribe solo metadatos ausentes cuando la carta identifica un único evangelio. */
|
||||
function fea_evangelio_capture_meta($post_id) {
|
||||
$post = get_post($post_id);
|
||||
if (!$post || $post->post_type !== 'post' || $post->post_status !== 'publish' || !fea_evangelio_is_comment($post_id)) return false;
|
||||
if (get_post_meta($post_id, '_cita_evangelio', true)) return false;
|
||||
$carta_id = (int) get_post_meta($post_id, '_carta_id', true);
|
||||
if (!$carta_id) $carta_id = fea_evangelio_nearest_carta_id($post);
|
||||
if (!$carta_id) return false;
|
||||
$evangelios = fea_evangelio_from_carta($carta_id);
|
||||
if (count($evangelios) !== 1) {
|
||||
error_log(sprintf('Fe Adulta: comentario %d sin cita; carta %d tiene %d evangelios.', $post_id, $carta_id, count($evangelios)));
|
||||
return false;
|
||||
}
|
||||
update_post_meta($post_id, '_cita_evangelio', reset($evangelios));
|
||||
if (!get_post_meta($post_id, '_carta_id', true)) update_post_meta($post_id, '_carta_id', $carta_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function fea_evangelio_summary_label($lang) {
|
||||
$labels = [
|
||||
'es' => 'Leer el evangelio', 'en' => 'Read the Gospel', 'fr' => 'Lire l’Évangile',
|
||||
'it' => 'Leggi il Vangelo', 'pt' => 'Ler o Evangelho',
|
||||
];
|
||||
return $labels[$lang] ?? $labels['es'];
|
||||
}
|
||||
|
||||
add_action('transition_post_status', function($new_status, $old_status, $post) {
|
||||
if ($new_status === 'publish' && $old_status !== 'publish') fea_evangelio_capture_meta($post->ID);
|
||||
}, 20, 3);
|
||||
|
||||
/** Añade referencia y texto plegado, cerrado por defecto, antes del comentario. */
|
||||
add_filter('the_content', function($content) {
|
||||
if (!is_single() || is_admin()) return $content;
|
||||
global $post;
|
||||
if (!$post || !fea_evangelio_is_comment($post->ID)) return $content;
|
||||
$cita = trim((string) fea_evangelio_comment_meta($post->ID, '_cita_evangelio'));
|
||||
if (!$cita) return $content;
|
||||
$reading_id = fea_evangelio_reading_id($cita);
|
||||
$lang = function_exists('pll_current_language') ? pll_current_language() : 'es';
|
||||
if ($reading_id && $lang && $lang !== 'es' && function_exists('pll_get_post')) $reading_id = (int) (pll_get_post($reading_id, $lang) ?: $reading_id);
|
||||
$reading = $reading_id ? get_post($reading_id) : null;
|
||||
$starts_with_cita = preg_match('/^\s*' . preg_quote($cita, '/') . '(?:[\s\.,:;\-–—]|$)/iu', wp_strip_all_tags($content));
|
||||
$html = '<section class="fea-com-evangelio" aria-label="' . esc_attr(fea_evangelio_summary_label($lang)) . '">';
|
||||
if (!$starts_with_cita) $html .= '<p class="fea-com-evangelio-cita">' . esc_html($cita) . '</p>';
|
||||
if ($reading && trim(wp_strip_all_tags($reading->post_content)) !== '') {
|
||||
$html .= '<details class="fea-com-evangelio-details"><summary>' . esc_html(fea_evangelio_summary_label($lang)) . '</summary>'
|
||||
. wpautop(do_shortcode($reading->post_content)) . '</details>';
|
||||
}
|
||||
return $html . '</section>' . $content;
|
||||
}, 8);
|
||||
|
||||
add_action('wp_head', function() {
|
||||
if (!is_single()) return;
|
||||
global $post;
|
||||
if (!$post || !fea_evangelio_is_comment($post->ID)) return;
|
||||
?>
|
||||
<style>
|
||||
.fea-com-evangelio { margin: 0 0 1.75rem; padding: 1rem 1.15rem; background: #f7f4ed; border-left: 4px solid #a77b2d; }
|
||||
.fea-com-evangelio-cita { margin: 0 0 .65rem; font-weight: 700; }
|
||||
.fea-com-evangelio-details summary { cursor: pointer; font-weight: 700; color: #51401e; }
|
||||
.fea-com-evangelio-details > :last-child { margin-bottom: 0; }
|
||||
.fea-com-evangelio-details[open] summary { margin-bottom: .85rem; }
|
||||
</style>
|
||||
<?php
|
||||
});
|
||||
@@ -2044,8 +2044,12 @@ add_filter('the_content', function($content) {
|
||||
global $post;
|
||||
if (!in_category('comentarios-al-evangelio', $post)) return $content;
|
||||
|
||||
$carta_id = get_post_meta($post->ID, '_carta_id', true);
|
||||
$cita = get_post_meta($post->ID, '_cita_evangelio', true);
|
||||
$carta_id = function_exists('fea_evangelio_comment_meta')
|
||||
? fea_evangelio_comment_meta($post->ID, '_carta_id')
|
||||
: get_post_meta($post->ID, '_carta_id', true);
|
||||
$cita = function_exists('fea_evangelio_comment_meta')
|
||||
? fea_evangelio_comment_meta($post->ID, '_cita_evangelio')
|
||||
: get_post_meta($post->ID, '_cita_evangelio', true);
|
||||
|
||||
if (!$carta_id && !$cita) return $content;
|
||||
|
||||
@@ -2066,23 +2070,6 @@ add_filter('the_content', function($content) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Cita del evangelio — link directo al anchor en el índice ---
|
||||
if ($cita) {
|
||||
$book_post_id = ['Mt' => 43908, 'Mc' => 43909, 'Lc' => 43907, 'Jn' => 43906];
|
||||
$abbr = substr($cita, 0, 2);
|
||||
$anchor = fea_cita_to_anchor($cita);
|
||||
$index_url = isset($book_post_id[$abbr])
|
||||
? esc_url(get_permalink($book_post_id[$abbr]) . '#' . $anchor)
|
||||
: '';
|
||||
|
||||
$html .= '<div class="fea-com-row fea-com-cita">'
|
||||
. '<span class="fea-com-label">Evangelio</span>'
|
||||
. ($index_url
|
||||
? '<a href="' . $index_url . '">' . esc_html($cita) . '</a>'
|
||||
: '<span>' . esc_html($cita) . '</span>')
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
// --- Otros comentarios de esta misma cita ---
|
||||
if ($cita) {
|
||||
$others = get_posts([
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/** Propuesta/aplicación segura del backfill de _cita_evangelio. */
|
||||
/** Uso: wp eval-file scripts/backfill_evangelio_meta.php [--apply] --path=/var/www/html */
|
||||
|
||||
$apply = in_array('--apply', $_SERVER['argv'] ?? [], true);
|
||||
$posts = get_posts([
|
||||
'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => -1,
|
||||
'category__in' => fea_evangelio_comment_categories(),
|
||||
'meta_query' => [['key' => '_cita_evangelio', 'compare' => 'NOT EXISTS']],
|
||||
'orderby' => 'date', 'order' => 'ASC',
|
||||
]);
|
||||
$out = fopen('php://output', 'w');
|
||||
fputcsv($out, ['post_id', 'fecha', 'carta_id', 'cita_propuesta', 'resultado']);
|
||||
foreach ($posts as $post) {
|
||||
$before_carta = (int) get_post_meta($post->ID, '_carta_id', true);
|
||||
// Las cartas deducidas solo se proponen: la cola histórica requiere revisión humana.
|
||||
$carta_id = $before_carta ?: fea_evangelio_nearest_carta_id($post);
|
||||
$evangelios = $carta_id ? fea_evangelio_from_carta($carta_id) : [];
|
||||
$cita = $before_carta && count($evangelios) === 1 ? reset($evangelios) : '';
|
||||
$result = $cita ? ($apply ? 'aplicado' : 'propuesta') : (!$before_carta ? 'revision_manual_carta_por_fecha' : (count($evangelios) > 1 ? 'revision_manual_multi_evangelio' : 'sin_evangelio'));
|
||||
if ($apply && $cita) {
|
||||
update_post_meta($post->ID, '_cita_evangelio', $cita);
|
||||
if (!$before_carta) update_post_meta($post->ID, '_carta_id', $carta_id);
|
||||
}
|
||||
fputcsv($out, [$post->ID, $post->post_date, $carta_id ?: '', $cita, $result]);
|
||||
}
|
||||
@@ -19,7 +19,6 @@ Rollback (despublica en prod lo que este script publicó):
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
@@ -145,21 +144,16 @@ def prod_helper(subcmd: str, *args: str) -> str:
|
||||
return _ssh_text(_remote_wrap(inner), timeout=60)
|
||||
|
||||
|
||||
def prod_upload_mp3(post_id: int) -> str:
|
||||
def prod_upload_mp3(post_id: int) -> None:
|
||||
src = LOCAL_TTS_DIR / f"{post_id}.mp3"
|
||||
data = src.read_bytes()
|
||||
local_sha256 = hashlib.sha256(data).hexdigest()
|
||||
remote_path = f"{PROD_UPLOADS_TTS}/{post_id}.mp3"
|
||||
_ssh_upload_bytes(data, remote_path)
|
||||
# Verificación de tamaño+contenido: un rc=0 de ssh no acredita que el asset
|
||||
# sea el mismo. El hash se persiste como meta y permite playback verificado.
|
||||
# Verificación de tamaño: no fiarse ciegamente del rc=0 de ssh. `wc -c` debe
|
||||
# correr (y resolver la redirección) DENTRO del contenedor — ver _remote_wrap.
|
||||
remote_size = int(_ssh_text(_remote_wrap(f"wc -c < {remote_path}")).strip())
|
||||
if remote_size != len(data):
|
||||
raise RuntimeError(f"tamaño no coincide tras subir #{post_id}: local={len(data)} remoto={remote_size}")
|
||||
remote_sha256 = _ssh_text(_remote_wrap(f"sha256sum {remote_path} | cut -d' ' -f1")).strip()
|
||||
if remote_sha256 != local_sha256:
|
||||
raise RuntimeError(f"SHA-256 no coincide tras subir #{post_id}: local={local_sha256} remoto={remote_sha256}")
|
||||
return local_sha256
|
||||
|
||||
|
||||
def prod_remove_mp3(post_id: int) -> None:
|
||||
@@ -191,9 +185,8 @@ def sync_one(post_id: int, state: dict, *, dry_run: bool) -> str:
|
||||
return "PLAN: subiría mp3 + setaudio"
|
||||
|
||||
voice = local_meta(post_id, "fea_audio_voice") or "NicoFeadulta2026"
|
||||
sha256 = prod_upload_mp3(post_id)
|
||||
prod_upload_mp3(post_id)
|
||||
prod_helper("setaudio", str(post_id), f"/wp-content/uploads/tts/{post_id}.mp3", voice)
|
||||
prod_helper("setflag", str(post_id), "fea_audio_sha256", sha256)
|
||||
if post_id not in state["synced"]:
|
||||
state["synced"].append(post_id)
|
||||
save_state(state)
|
||||
|
||||
Reference in New Issue
Block a user