Changeset 3437951
- Timestamp:
- 01/12/2026 04:40:05 PM (3 months ago)
- Location:
- post2podcast
- Files:
-
- 10 edited
- 1 copied
-
tags/1.2.11 (copied) (copied from post2podcast/trunk)
-
tags/1.2.11/assets/js/admin.js (modified) (3 diffs)
-
tags/1.2.11/includes/class-post2podcast-admin.php (modified) (1 diff)
-
tags/1.2.11/includes/class-post2podcast-api.php (modified) (4 diffs)
-
tags/1.2.11/post2podcast.php (modified) (2 diffs)
-
tags/1.2.11/readme.txt (modified) (2 diffs)
-
trunk/assets/js/admin.js (modified) (3 diffs)
-
trunk/includes/class-post2podcast-admin.php (modified) (1 diff)
-
trunk/includes/class-post2podcast-api.php (modified) (4 diffs)
-
trunk/post2podcast.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
post2podcast/tags/1.2.11/assets/js/admin.js
r3437893 r3437951 167 167 var voice2 = detection.suggested_voices.voice2; 168 168 169 console.log('Attempting to select voice1:', voice1, 'voice2:', voice2); 170 169 171 // Set the voice selectors to the suggested voices 170 172 var $voice1Select = $('#post2podcast_voice1'); 171 173 var $voice2Select = $('#post2podcast_voice2'); 172 174 175 var voice1Found = false; 176 var voice2Found = false; 177 173 178 // Check if the voices exist in the dropdown and select them 174 179 if ($voice1Select.find('option[value="' + voice1 + '"]').length > 0) { 175 180 $voice1Select.val(voice1); 176 console.log('Selected voice1: ' + voice1); 181 voice1Found = true; 182 console.log('✓ Selected voice1: ' + voice1); 177 183 } else { 178 console.warn(' Voice ' + voice1 + 'not found in dropdown');184 console.warn('✗ Voice1 "' + voice1 + '" not found in dropdown'); 179 185 } 180 186 181 187 if ($voice2Select.find('option[value="' + voice2 + '"]').length > 0) { 182 188 $voice2Select.val(voice2); 183 console.log('Selected voice2: ' + voice2); 189 voice2Found = true; 190 console.log('✓ Selected voice2: ' + voice2); 184 191 } else { 185 console.warn(' Voice ' + voice2 + 'not found in dropdown');192 console.warn('✗ Voice2 "' + voice2 + '" not found in dropdown'); 186 193 } 187 194 195 // Trigger change event to validate selection 196 if (voice1Found || voice2Found) { 197 validateVoiceSelection(); 198 } 199 188 200 // Update the language info to show selected voices 189 languageInfo += '<p class="description" style="color: #28a745; font-weight: 500;">✓ Voices automatically selected: ' + 190 voice1 + ' and ' + voice2 + '</p>'; 201 if (voice1Found && voice2Found) { 202 languageInfo += '<p class="description" style="color: #28a745; font-weight: 500;">✓ Voices automatically selected: ' + 203 voice1 + ' and ' + voice2 + '</p>'; 204 } else { 205 languageInfo += '<p class="description" style="color: #856404; background: #fff3cd; padding: 8px; border-radius: 3px;">⚠ Some suggested voices were not found. Please select voices manually.</p>'; 206 } 191 207 $('#detected-language-info').html(languageInfo); 192 208 } else { 209 console.warn('No suggested_voices in detection result'); 193 210 languageInfo += '<p class="description">Please select appropriate voices for this language.</p>'; 194 211 $('#detected-language-info').html(languageInfo); … … 299 316 lastMessageTime = Date.now(); 300 317 301 // Start timeout monitoring - if no message for 3 minutes, assume something went wrong 318 // Start timeout monitoring - if no message for 25 minutes, assume something went wrong 319 // Long timeout is needed because audio generation for lengthy articles can take 15-20 minutes 302 320 timeoutCheckInterval = setInterval(function() { 303 321 var timeSinceLastMessage = Date.now() - lastMessageTime; 304 var maxIdleTime = 1 80000; // 3 minutes in milliseconds322 var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles) 305 323 306 324 if (timeSinceLastMessage > maxIdleTime && generationInProgress) { 307 addStatusMessage('❌ Server stopped responding . The generation may have failed.', 'error');325 addStatusMessage('❌ Server stopped responding after 25 minutes. The generation may have failed.', 'error'); 308 326 if (progressInterval) clearInterval(progressInterval); 309 327 if (timeoutCheckInterval) clearInterval(timeoutCheckInterval); … … 314 332 resetUI(false); 315 333 } 316 }, 10000); // Check every 10 seconds334 }, 30000); // Check every 30 seconds 317 335 }; 318 336 -
post2podcast/tags/1.2.11/includes/class-post2podcast-admin.php
r3437853 r3437951 1521 1521 1522 1522 $detection_result = json_decode($response_body, true); 1523 1523 1524 1524 if (!$detection_result) { 1525 1525 wp_send_json_error(['message' => 'Invalid response from language detection service.']); 1526 1526 return; 1527 1527 } 1528 1528 1529 // Log the detection result for debugging 1530 error_log('Post2Podcast: Language detection result: ' . wp_json_encode($detection_result)); 1531 1529 1532 // Save detected language to post meta 1530 1533 if ($detection_result['language_code']) { 1531 1534 update_post_meta($post_id, '_post2podcast_detected_language', $detection_result['language_code']); 1532 1535 update_post_meta($post_id, '_post2podcast_detected_language_name', $detection_result['language_name']); 1533 } 1534 1536 1537 // Also save suggested voices if available 1538 if (!empty($detection_result['suggested_voices'])) { 1539 error_log('Post2Podcast: Suggested voices: ' . wp_json_encode($detection_result['suggested_voices'])); 1540 } 1541 } 1542 1535 1543 wp_send_json_success([ 1536 1544 'detection_result' => $detection_result, -
post2podcast/tags/1.2.11/includes/class-post2podcast-api.php
r3437923 r3437951 213 213 @ini_set('output_buffering', 'off'); 214 214 @ini_set('zlib.output_compression', false); 215 @ini_set('implicit_flush', true); 215 216 // @codingStandardsIgnoreEnd 216 217 218 // Disable all output buffering 219 while (ob_get_level()) { 220 ob_end_flush(); 221 } 222 217 223 // SSE Spec requires UTF-8. This is a keep-alive padding, not dynamic user data. 218 224 // To satisfy the plugin checker, we'll escape it. 219 echo esc_html(":" . str_repeat(" ", 2048) . "\n\n"); 220 @ob_flush(); 225 echo esc_html(":" . str_repeat(" ", 2048) . "\n\n"); 226 if (function_exists('ob_flush')) { 227 @ob_flush(); 228 } 221 229 flush(); 222 230 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { … … 362 370 } 363 371 } 364 $job_response = $this->start_sync_generation($formatted_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email_for_api, $wp_site_url_for_api, $text_model, $options); 365 if (is_wp_error($job_response)) { 372 373 $this->log('Processing content and generating audio. This may take several minutes for long articles...'); 374 375 // Use streaming generation to get progress updates and keep SSE connection alive 376 $job_response = $this->start_streaming_generation($formatted_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email_for_api, $wp_site_url_for_api, $text_model, $options); 377 378 if (is_wp_error($job_response)) { 366 379 throw new Exception('Failed to start job on API server: ' . $job_response->get_error_message()); 367 380 } … … 1107 1120 // wp_json_encode handles potential security issues better than raw json_encode. 1108 1121 echo "data: " . wp_json_encode($response) . "\n\n"; 1109 @ob_flush(); 1122 1123 // Aggressive flushing to ensure message is sent immediately 1124 if (function_exists('ob_flush')) { 1125 @ob_flush(); 1126 } 1110 1127 flush(); 1128 1129 // Give the client time to receive the message 1130 usleep(10000); // 10ms delay 1111 1131 } 1112 1132 … … 1239 1259 } 1240 1260 } 1261 1262 /** 1263 * Start streaming generation - connects to backend SSE endpoint and forwards progress messages 1264 */ 1265 private function start_streaming_generation($post_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email, $wp_site_url, $text_model, $options) { 1266 $url = $this->api_base . '/generate-with-progress'; 1267 1268 // Build payload 1269 $payload = array( 1270 'post_content' => $post_content, 1271 'voice1' => $voice1, 1272 'voice2' => $voice2, 1273 'speaker1_instructions' => $speaker1, 1274 'speaker2_instructions' => $speaker2, 1275 'wp_user_email' => $wp_user_email, 1276 'wp_site_url' => $wp_site_url, 1277 'text_model' => $text_model ?: 'qwen3:8b', 1278 ); 1279 1280 // Use cURL for SSE streaming support 1281 $ch = curl_init($url); 1282 curl_setopt($ch, CURLOPT_POST, true); 1283 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); 1284 curl_setopt($ch, CURLOPT_HTTPHEADER, array( 1285 'Content-Type: application/json; charset=utf-8', 1286 'Accept: text/event-stream', 1287 )); 1288 curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); 1289 curl_setopt($ch, CURLOPT_TIMEOUT, 1800); // 30 minutes 1290 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 1291 1292 // Track the final response data 1293 $final_response = null; 1294 1295 // Callback to process streamed data 1296 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use (&$final_response) { 1297 $length = strlen($data); 1298 1299 // Parse SSE data 1300 $lines = explode("\n", $data); 1301 foreach ($lines as $line) { 1302 if (strpos($line, 'data: ') === 0) { 1303 $json_data = substr($line, 6); // Remove 'data: ' prefix 1304 $event_data = json_decode($json_data, true); 1305 1306 if ($event_data && isset($event_data['status'])) { 1307 // Forward the SSE message to the client 1308 $this->send_sse_message( 1309 $event_data['status'], 1310 $event_data['message'] ?? '', 1311 isset($event_data['progress']) ? array('progress' => $event_data['progress']) : array() 1312 ); 1313 1314 // If this is the final success message with audio_content, store it 1315 if ($event_data['status'] === 'success' && isset($event_data['audio_content'])) { 1316 $final_response = $event_data; 1317 } 1318 } 1319 } 1320 } 1321 1322 return $length; 1323 }); 1324 1325 // Execute the request 1326 $exec_result = curl_exec($ch); 1327 1328 if ($exec_result === false) { 1329 $error = curl_error($ch); 1330 curl_close($ch); 1331 error_log("Post2Podcast: cURL error in streaming generation: " . $error); 1332 return new WP_Error('curl_error', 'Streaming generation failed: ' . $error); 1333 } 1334 1335 $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 1336 curl_close($ch); 1337 1338 if ($status_code >= 400) { 1339 error_log("Post2Podcast: Streaming generation failed with status " . $status_code); 1340 return new WP_Error('http_error', 'Server returned error status: ' . $status_code); 1341 } 1342 1343 if (!$final_response || !isset($final_response['audio_content'])) { 1344 error_log("Post2Podcast: No audio content received from streaming endpoint"); 1345 return new WP_Error('no_audio', 'No audio content received from server'); 1346 } 1347 1348 return $final_response; 1349 } 1241 1350 } -
post2podcast/tags/1.2.11/post2podcast.php
r3437923 r3437951 4 4 * Plugin server URI: https://github.com/samukbg/post2podcast-server 5 5 * Description: Convert WordPress posts into podcast episodes with AI voices 6 * Version: 1.2. 86 * Version: 1.2.10 7 7 * Author: Samuel Bezerra 8 8 * Author URI: https://github.com/samukbg … … 20 20 21 21 // Define plugin constants 22 define('POST2PODCAST_VERSION', '1.2. 8');22 define('POST2PODCAST_VERSION', '1.2.10'); 23 23 define('POST2PODCAST_PLUGIN_DIR', plugin_dir_path(__FILE__)); 24 24 define('POST2PODCAST_PLUGIN_URL', plugin_dir_url(__FILE__)); -
post2podcast/tags/1.2.11/readme.txt
r3437923 r3437951 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 1.2. 87 Stable tag: 1.2.10 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 274 274 == Changelog == 275 275 276 = 1.2.10 = 277 * FIXED: Language detection now correctly auto-selects voices from the SAME detected language 278 * FIXED: French language now uses the same voice (ff_siwis) for both speakers since only one French voice is available 279 * IMPROVED: Enhanced voice auto-selection with better logging and user feedback 280 * IMPROVED: Frontend JavaScript now validates voice selection and triggers change event after auto-selection 281 * IMPROVED: Better error messages when suggested voices are not found in dropdowns 282 283 = 1.2.9 = 284 * CRITICAL FIX: SSE connection timeout after 2 minutes during long audio generation - now uses streaming backend endpoint 285 * ADDED: New backend SSE endpoint (/generate-with-progress) that streams real-time progress updates 286 * IMPROVED: WordPress plugin now receives continuous progress updates during generation, preventing connection timeouts 287 * IMPROVED: Frontend timeout extended to 25 minutes to accommodate very long article generation 288 * IMPROVED: Better handling of long-running audio generation (15-20+ minutes for lengthy articles) 289 * TECHNICAL: Switched from blocking HTTP requests to SSE streaming with cURL for continuous progress updates 290 276 291 = 1.2.8 = 277 292 * CRITICAL FIX: Corrupted MP3 files with long articles - audio now generates completely without truncation -
post2podcast/trunk/assets/js/admin.js
r3437893 r3437951 167 167 var voice2 = detection.suggested_voices.voice2; 168 168 169 console.log('Attempting to select voice1:', voice1, 'voice2:', voice2); 170 169 171 // Set the voice selectors to the suggested voices 170 172 var $voice1Select = $('#post2podcast_voice1'); 171 173 var $voice2Select = $('#post2podcast_voice2'); 172 174 175 var voice1Found = false; 176 var voice2Found = false; 177 173 178 // Check if the voices exist in the dropdown and select them 174 179 if ($voice1Select.find('option[value="' + voice1 + '"]').length > 0) { 175 180 $voice1Select.val(voice1); 176 console.log('Selected voice1: ' + voice1); 181 voice1Found = true; 182 console.log('✓ Selected voice1: ' + voice1); 177 183 } else { 178 console.warn(' Voice ' + voice1 + 'not found in dropdown');184 console.warn('✗ Voice1 "' + voice1 + '" not found in dropdown'); 179 185 } 180 186 181 187 if ($voice2Select.find('option[value="' + voice2 + '"]').length > 0) { 182 188 $voice2Select.val(voice2); 183 console.log('Selected voice2: ' + voice2); 189 voice2Found = true; 190 console.log('✓ Selected voice2: ' + voice2); 184 191 } else { 185 console.warn(' Voice ' + voice2 + 'not found in dropdown');192 console.warn('✗ Voice2 "' + voice2 + '" not found in dropdown'); 186 193 } 187 194 195 // Trigger change event to validate selection 196 if (voice1Found || voice2Found) { 197 validateVoiceSelection(); 198 } 199 188 200 // Update the language info to show selected voices 189 languageInfo += '<p class="description" style="color: #28a745; font-weight: 500;">✓ Voices automatically selected: ' + 190 voice1 + ' and ' + voice2 + '</p>'; 201 if (voice1Found && voice2Found) { 202 languageInfo += '<p class="description" style="color: #28a745; font-weight: 500;">✓ Voices automatically selected: ' + 203 voice1 + ' and ' + voice2 + '</p>'; 204 } else { 205 languageInfo += '<p class="description" style="color: #856404; background: #fff3cd; padding: 8px; border-radius: 3px;">⚠ Some suggested voices were not found. Please select voices manually.</p>'; 206 } 191 207 $('#detected-language-info').html(languageInfo); 192 208 } else { 209 console.warn('No suggested_voices in detection result'); 193 210 languageInfo += '<p class="description">Please select appropriate voices for this language.</p>'; 194 211 $('#detected-language-info').html(languageInfo); … … 299 316 lastMessageTime = Date.now(); 300 317 301 // Start timeout monitoring - if no message for 3 minutes, assume something went wrong 318 // Start timeout monitoring - if no message for 25 minutes, assume something went wrong 319 // Long timeout is needed because audio generation for lengthy articles can take 15-20 minutes 302 320 timeoutCheckInterval = setInterval(function() { 303 321 var timeSinceLastMessage = Date.now() - lastMessageTime; 304 var maxIdleTime = 1 80000; // 3 minutes in milliseconds322 var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles) 305 323 306 324 if (timeSinceLastMessage > maxIdleTime && generationInProgress) { 307 addStatusMessage('❌ Server stopped responding . The generation may have failed.', 'error');325 addStatusMessage('❌ Server stopped responding after 25 minutes. The generation may have failed.', 'error'); 308 326 if (progressInterval) clearInterval(progressInterval); 309 327 if (timeoutCheckInterval) clearInterval(timeoutCheckInterval); … … 314 332 resetUI(false); 315 333 } 316 }, 10000); // Check every 10 seconds334 }, 30000); // Check every 30 seconds 317 335 }; 318 336 -
post2podcast/trunk/includes/class-post2podcast-admin.php
r3437853 r3437951 1521 1521 1522 1522 $detection_result = json_decode($response_body, true); 1523 1523 1524 1524 if (!$detection_result) { 1525 1525 wp_send_json_error(['message' => 'Invalid response from language detection service.']); 1526 1526 return; 1527 1527 } 1528 1528 1529 // Log the detection result for debugging 1530 error_log('Post2Podcast: Language detection result: ' . wp_json_encode($detection_result)); 1531 1529 1532 // Save detected language to post meta 1530 1533 if ($detection_result['language_code']) { 1531 1534 update_post_meta($post_id, '_post2podcast_detected_language', $detection_result['language_code']); 1532 1535 update_post_meta($post_id, '_post2podcast_detected_language_name', $detection_result['language_name']); 1533 } 1534 1536 1537 // Also save suggested voices if available 1538 if (!empty($detection_result['suggested_voices'])) { 1539 error_log('Post2Podcast: Suggested voices: ' . wp_json_encode($detection_result['suggested_voices'])); 1540 } 1541 } 1542 1535 1543 wp_send_json_success([ 1536 1544 'detection_result' => $detection_result, -
post2podcast/trunk/includes/class-post2podcast-api.php
r3437923 r3437951 213 213 @ini_set('output_buffering', 'off'); 214 214 @ini_set('zlib.output_compression', false); 215 @ini_set('implicit_flush', true); 215 216 // @codingStandardsIgnoreEnd 216 217 218 // Disable all output buffering 219 while (ob_get_level()) { 220 ob_end_flush(); 221 } 222 217 223 // SSE Spec requires UTF-8. This is a keep-alive padding, not dynamic user data. 218 224 // To satisfy the plugin checker, we'll escape it. 219 echo esc_html(":" . str_repeat(" ", 2048) . "\n\n"); 220 @ob_flush(); 225 echo esc_html(":" . str_repeat(" ", 2048) . "\n\n"); 226 if (function_exists('ob_flush')) { 227 @ob_flush(); 228 } 221 229 flush(); 222 230 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) { … … 362 370 } 363 371 } 364 $job_response = $this->start_sync_generation($formatted_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email_for_api, $wp_site_url_for_api, $text_model, $options); 365 if (is_wp_error($job_response)) { 372 373 $this->log('Processing content and generating audio. This may take several minutes for long articles...'); 374 375 // Use streaming generation to get progress updates and keep SSE connection alive 376 $job_response = $this->start_streaming_generation($formatted_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email_for_api, $wp_site_url_for_api, $text_model, $options); 377 378 if (is_wp_error($job_response)) { 366 379 throw new Exception('Failed to start job on API server: ' . $job_response->get_error_message()); 367 380 } … … 1107 1120 // wp_json_encode handles potential security issues better than raw json_encode. 1108 1121 echo "data: " . wp_json_encode($response) . "\n\n"; 1109 @ob_flush(); 1122 1123 // Aggressive flushing to ensure message is sent immediately 1124 if (function_exists('ob_flush')) { 1125 @ob_flush(); 1126 } 1110 1127 flush(); 1128 1129 // Give the client time to receive the message 1130 usleep(10000); // 10ms delay 1111 1131 } 1112 1132 … … 1239 1259 } 1240 1260 } 1261 1262 /** 1263 * Start streaming generation - connects to backend SSE endpoint and forwards progress messages 1264 */ 1265 private function start_streaming_generation($post_content, $voice1, $voice2, $speaker1, $speaker2, $openai_api_key, $wp_user_email, $wp_site_url, $text_model, $options) { 1266 $url = $this->api_base . '/generate-with-progress'; 1267 1268 // Build payload 1269 $payload = array( 1270 'post_content' => $post_content, 1271 'voice1' => $voice1, 1272 'voice2' => $voice2, 1273 'speaker1_instructions' => $speaker1, 1274 'speaker2_instructions' => $speaker2, 1275 'wp_user_email' => $wp_user_email, 1276 'wp_site_url' => $wp_site_url, 1277 'text_model' => $text_model ?: 'qwen3:8b', 1278 ); 1279 1280 // Use cURL for SSE streaming support 1281 $ch = curl_init($url); 1282 curl_setopt($ch, CURLOPT_POST, true); 1283 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); 1284 curl_setopt($ch, CURLOPT_HTTPHEADER, array( 1285 'Content-Type: application/json; charset=utf-8', 1286 'Accept: text/event-stream', 1287 )); 1288 curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); 1289 curl_setopt($ch, CURLOPT_TIMEOUT, 1800); // 30 minutes 1290 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); 1291 1292 // Track the final response data 1293 $final_response = null; 1294 1295 // Callback to process streamed data 1296 curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) use (&$final_response) { 1297 $length = strlen($data); 1298 1299 // Parse SSE data 1300 $lines = explode("\n", $data); 1301 foreach ($lines as $line) { 1302 if (strpos($line, 'data: ') === 0) { 1303 $json_data = substr($line, 6); // Remove 'data: ' prefix 1304 $event_data = json_decode($json_data, true); 1305 1306 if ($event_data && isset($event_data['status'])) { 1307 // Forward the SSE message to the client 1308 $this->send_sse_message( 1309 $event_data['status'], 1310 $event_data['message'] ?? '', 1311 isset($event_data['progress']) ? array('progress' => $event_data['progress']) : array() 1312 ); 1313 1314 // If this is the final success message with audio_content, store it 1315 if ($event_data['status'] === 'success' && isset($event_data['audio_content'])) { 1316 $final_response = $event_data; 1317 } 1318 } 1319 } 1320 } 1321 1322 return $length; 1323 }); 1324 1325 // Execute the request 1326 $exec_result = curl_exec($ch); 1327 1328 if ($exec_result === false) { 1329 $error = curl_error($ch); 1330 curl_close($ch); 1331 error_log("Post2Podcast: cURL error in streaming generation: " . $error); 1332 return new WP_Error('curl_error', 'Streaming generation failed: ' . $error); 1333 } 1334 1335 $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 1336 curl_close($ch); 1337 1338 if ($status_code >= 400) { 1339 error_log("Post2Podcast: Streaming generation failed with status " . $status_code); 1340 return new WP_Error('http_error', 'Server returned error status: ' . $status_code); 1341 } 1342 1343 if (!$final_response || !isset($final_response['audio_content'])) { 1344 error_log("Post2Podcast: No audio content received from streaming endpoint"); 1345 return new WP_Error('no_audio', 'No audio content received from server'); 1346 } 1347 1348 return $final_response; 1349 } 1241 1350 } -
post2podcast/trunk/post2podcast.php
r3437923 r3437951 4 4 * Plugin server URI: https://github.com/samukbg/post2podcast-server 5 5 * Description: Convert WordPress posts into podcast episodes with AI voices 6 * Version: 1.2. 86 * Version: 1.2.10 7 7 * Author: Samuel Bezerra 8 8 * Author URI: https://github.com/samukbg … … 20 20 21 21 // Define plugin constants 22 define('POST2PODCAST_VERSION', '1.2. 8');22 define('POST2PODCAST_VERSION', '1.2.10'); 23 23 define('POST2PODCAST_PLUGIN_DIR', plugin_dir_path(__FILE__)); 24 24 define('POST2PODCAST_PLUGIN_URL', plugin_dir_url(__FILE__)); -
post2podcast/trunk/readme.txt
r3437923 r3437951 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 1.2. 87 Stable tag: 1.2.10 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 274 274 == Changelog == 275 275 276 = 1.2.10 = 277 * FIXED: Language detection now correctly auto-selects voices from the SAME detected language 278 * FIXED: French language now uses the same voice (ff_siwis) for both speakers since only one French voice is available 279 * IMPROVED: Enhanced voice auto-selection with better logging and user feedback 280 * IMPROVED: Frontend JavaScript now validates voice selection and triggers change event after auto-selection 281 * IMPROVED: Better error messages when suggested voices are not found in dropdowns 282 283 = 1.2.9 = 284 * CRITICAL FIX: SSE connection timeout after 2 minutes during long audio generation - now uses streaming backend endpoint 285 * ADDED: New backend SSE endpoint (/generate-with-progress) that streams real-time progress updates 286 * IMPROVED: WordPress plugin now receives continuous progress updates during generation, preventing connection timeouts 287 * IMPROVED: Frontend timeout extended to 25 minutes to accommodate very long article generation 288 * IMPROVED: Better handling of long-running audio generation (15-20+ minutes for lengthy articles) 289 * TECHNICAL: Switched from blocking HTTP requests to SSE streaming with cURL for continuous progress updates 290 276 291 = 1.2.8 = 277 292 * CRITICAL FIX: Corrupted MP3 files with long articles - audio now generates completely without truncation
Note: See TracChangeset
for help on using the changeset viewer.