Plugin Directory

Changeset 3437951


Ignore:
Timestamp:
01/12/2026 04:40:05 PM (3 months ago)
Author:
samukbg
Message:

Tagging version 1.2.11

Location:
post2podcast
Files:
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • post2podcast/tags/1.2.11/assets/js/admin.js

    r3437893 r3437951  
    167167                            var voice2 = detection.suggested_voices.voice2;
    168168
     169                            console.log('Attempting to select voice1:', voice1, 'voice2:', voice2);
     170
    169171                            // Set the voice selectors to the suggested voices
    170172                            var $voice1Select = $('#post2podcast_voice1');
    171173                            var $voice2Select = $('#post2podcast_voice2');
    172174
     175                            var voice1Found = false;
     176                            var voice2Found = false;
     177
    173178                            // Check if the voices exist in the dropdown and select them
    174179                            if ($voice1Select.find('option[value="' + voice1 + '"]').length > 0) {
    175180                                $voice1Select.val(voice1);
    176                                 console.log('Selected voice1: ' + voice1);
     181                                voice1Found = true;
     182                                console.log('✓ Selected voice1: ' + voice1);
    177183                            } else {
    178                                 console.warn('Voice ' + voice1 + ' not found in dropdown');
     184                                console.warn('✗ Voice1 "' + voice1 + '" not found in dropdown');
    179185                            }
    180186
    181187                            if ($voice2Select.find('option[value="' + voice2 + '"]').length > 0) {
    182188                                $voice2Select.val(voice2);
    183                                 console.log('Selected voice2: ' + voice2);
     189                                voice2Found = true;
     190                                console.log('✓ Selected voice2: ' + voice2);
    184191                            } else {
    185                                 console.warn('Voice ' + voice2 + ' not found in dropdown');
     192                                console.warn('✗ Voice2 "' + voice2 + '" not found in dropdown');
    186193                            }
    187194
     195                            // Trigger change event to validate selection
     196                            if (voice1Found || voice2Found) {
     197                                validateVoiceSelection();
     198                            }
     199
    188200                            // 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                            }
    191207                            $('#detected-language-info').html(languageInfo);
    192208                        } else {
     209                            console.warn('No suggested_voices in detection result');
    193210                            languageInfo += '<p class="description">Please select appropriate voices for this language.</p>';
    194211                            $('#detected-language-info').html(languageInfo);
     
    299316                lastMessageTime = Date.now();
    300317
    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
    302320                timeoutCheckInterval = setInterval(function() {
    303321                    var timeSinceLastMessage = Date.now() - lastMessageTime;
    304                     var maxIdleTime = 180000; // 3 minutes in milliseconds
     322                    var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles)
    305323
    306324                    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');
    308326                        if (progressInterval) clearInterval(progressInterval);
    309327                        if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
     
    314332                        resetUI(false);
    315333                    }
    316                 }, 10000); // Check every 10 seconds
     334                }, 30000); // Check every 30 seconds
    317335            };
    318336
  • post2podcast/tags/1.2.11/includes/class-post2podcast-admin.php

    r3437853 r3437951  
    15211521           
    15221522            $detection_result = json_decode($response_body, true);
    1523            
     1523
    15241524            if (!$detection_result) {
    15251525                wp_send_json_error(['message' => 'Invalid response from language detection service.']);
    15261526                return;
    15271527            }
    1528            
     1528
     1529            // Log the detection result for debugging
     1530            error_log('Post2Podcast: Language detection result: ' . wp_json_encode($detection_result));
     1531
    15291532            // Save detected language to post meta
    15301533            if ($detection_result['language_code']) {
    15311534                update_post_meta($post_id, '_post2podcast_detected_language', $detection_result['language_code']);
    15321535                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
    15351543            wp_send_json_success([
    15361544                'detection_result' => $detection_result,
  • post2podcast/tags/1.2.11/includes/class-post2podcast-api.php

    r3437923 r3437951  
    213213            @ini_set('output_buffering', 'off');
    214214            @ini_set('zlib.output_compression', false);
     215            @ini_set('implicit_flush', true);
    215216            // @codingStandardsIgnoreEnd
    216            
     217
     218            // Disable all output buffering
     219            while (ob_get_level()) {
     220                ob_end_flush();
     221            }
     222
    217223            // SSE Spec requires UTF-8. This is a keep-alive padding, not dynamic user data.
    218224            // 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            }
    221229            flush();
    222230            if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
     
    362370                    }
    363371                }
    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)) {
    366379                    throw new Exception('Failed to start job on API server: ' . $job_response->get_error_message());
    367380                }
     
    11071120        // wp_json_encode handles potential security issues better than raw json_encode.
    11081121        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        }
    11101127        flush();
     1128
     1129        // Give the client time to receive the message
     1130        usleep(10000); // 10ms delay
    11111131    }
    11121132
     
    12391259        }
    12401260    }
     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    }
    12411350}
  • post2podcast/tags/1.2.11/post2podcast.php

    r3437923 r3437951  
    44 * Plugin server URI: https://github.com/samukbg/post2podcast-server
    55 * Description: Convert WordPress posts into podcast episodes with AI voices
    6  * Version: 1.2.8
     6 * Version: 1.2.10
    77 * Author: Samuel Bezerra
    88 * Author URI: https://github.com/samukbg
     
    2020
    2121// Define plugin constants
    22 define('POST2PODCAST_VERSION', '1.2.8');
     22define('POST2PODCAST_VERSION', '1.2.10');
    2323define('POST2PODCAST_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2424define('POST2PODCAST_PLUGIN_URL', plugin_dir_url(__FILE__));
  • post2podcast/tags/1.2.11/readme.txt

    r3437923 r3437951  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.2.8
     7Stable tag: 1.2.10
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    274274== Changelog ==
    275275
     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
    276291= 1.2.8 =
    277292* CRITICAL FIX: Corrupted MP3 files with long articles - audio now generates completely without truncation
  • post2podcast/trunk/assets/js/admin.js

    r3437893 r3437951  
    167167                            var voice2 = detection.suggested_voices.voice2;
    168168
     169                            console.log('Attempting to select voice1:', voice1, 'voice2:', voice2);
     170
    169171                            // Set the voice selectors to the suggested voices
    170172                            var $voice1Select = $('#post2podcast_voice1');
    171173                            var $voice2Select = $('#post2podcast_voice2');
    172174
     175                            var voice1Found = false;
     176                            var voice2Found = false;
     177
    173178                            // Check if the voices exist in the dropdown and select them
    174179                            if ($voice1Select.find('option[value="' + voice1 + '"]').length > 0) {
    175180                                $voice1Select.val(voice1);
    176                                 console.log('Selected voice1: ' + voice1);
     181                                voice1Found = true;
     182                                console.log('✓ Selected voice1: ' + voice1);
    177183                            } else {
    178                                 console.warn('Voice ' + voice1 + ' not found in dropdown');
     184                                console.warn('✗ Voice1 "' + voice1 + '" not found in dropdown');
    179185                            }
    180186
    181187                            if ($voice2Select.find('option[value="' + voice2 + '"]').length > 0) {
    182188                                $voice2Select.val(voice2);
    183                                 console.log('Selected voice2: ' + voice2);
     189                                voice2Found = true;
     190                                console.log('✓ Selected voice2: ' + voice2);
    184191                            } else {
    185                                 console.warn('Voice ' + voice2 + ' not found in dropdown');
     192                                console.warn('✗ Voice2 "' + voice2 + '" not found in dropdown');
    186193                            }
    187194
     195                            // Trigger change event to validate selection
     196                            if (voice1Found || voice2Found) {
     197                                validateVoiceSelection();
     198                            }
     199
    188200                            // 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                            }
    191207                            $('#detected-language-info').html(languageInfo);
    192208                        } else {
     209                            console.warn('No suggested_voices in detection result');
    193210                            languageInfo += '<p class="description">Please select appropriate voices for this language.</p>';
    194211                            $('#detected-language-info').html(languageInfo);
     
    299316                lastMessageTime = Date.now();
    300317
    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
    302320                timeoutCheckInterval = setInterval(function() {
    303321                    var timeSinceLastMessage = Date.now() - lastMessageTime;
    304                     var maxIdleTime = 180000; // 3 minutes in milliseconds
     322                    var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles)
    305323
    306324                    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');
    308326                        if (progressInterval) clearInterval(progressInterval);
    309327                        if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
     
    314332                        resetUI(false);
    315333                    }
    316                 }, 10000); // Check every 10 seconds
     334                }, 30000); // Check every 30 seconds
    317335            };
    318336
  • post2podcast/trunk/includes/class-post2podcast-admin.php

    r3437853 r3437951  
    15211521           
    15221522            $detection_result = json_decode($response_body, true);
    1523            
     1523
    15241524            if (!$detection_result) {
    15251525                wp_send_json_error(['message' => 'Invalid response from language detection service.']);
    15261526                return;
    15271527            }
    1528            
     1528
     1529            // Log the detection result for debugging
     1530            error_log('Post2Podcast: Language detection result: ' . wp_json_encode($detection_result));
     1531
    15291532            // Save detected language to post meta
    15301533            if ($detection_result['language_code']) {
    15311534                update_post_meta($post_id, '_post2podcast_detected_language', $detection_result['language_code']);
    15321535                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
    15351543            wp_send_json_success([
    15361544                'detection_result' => $detection_result,
  • post2podcast/trunk/includes/class-post2podcast-api.php

    r3437923 r3437951  
    213213            @ini_set('output_buffering', 'off');
    214214            @ini_set('zlib.output_compression', false);
     215            @ini_set('implicit_flush', true);
    215216            // @codingStandardsIgnoreEnd
    216            
     217
     218            // Disable all output buffering
     219            while (ob_get_level()) {
     220                ob_end_flush();
     221            }
     222
    217223            // SSE Spec requires UTF-8. This is a keep-alive padding, not dynamic user data.
    218224            // 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            }
    221229            flush();
    222230            if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {
     
    362370                    }
    363371                }
    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)) {
    366379                    throw new Exception('Failed to start job on API server: ' . $job_response->get_error_message());
    367380                }
     
    11071120        // wp_json_encode handles potential security issues better than raw json_encode.
    11081121        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        }
    11101127        flush();
     1128
     1129        // Give the client time to receive the message
     1130        usleep(10000); // 10ms delay
    11111131    }
    11121132
     
    12391259        }
    12401260    }
     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    }
    12411350}
  • post2podcast/trunk/post2podcast.php

    r3437923 r3437951  
    44 * Plugin server URI: https://github.com/samukbg/post2podcast-server
    55 * Description: Convert WordPress posts into podcast episodes with AI voices
    6  * Version: 1.2.8
     6 * Version: 1.2.10
    77 * Author: Samuel Bezerra
    88 * Author URI: https://github.com/samukbg
     
    2020
    2121// Define plugin constants
    22 define('POST2PODCAST_VERSION', '1.2.8');
     22define('POST2PODCAST_VERSION', '1.2.10');
    2323define('POST2PODCAST_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2424define('POST2PODCAST_PLUGIN_URL', plugin_dir_url(__FILE__));
  • post2podcast/trunk/readme.txt

    r3437923 r3437951  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.2.8
     7Stable tag: 1.2.10
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    274274== Changelog ==
    275275
     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
    276291= 1.2.8 =
    277292* CRITICAL FIX: Corrupted MP3 files with long articles - audio now generates completely without truncation
Note: See TracChangeset for help on using the changeset viewer.