Plugin Directory

Changeset 3438184


Ignore:
Timestamp:
01/12/2026 09:57:32 PM (3 months ago)
Author:
samukbg
Message:

Tagging version 1.3.5

Location:
post2podcast
Files:
6 edited
1 copied

Legend:

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

    r3437951 r3438184  
    303303            }
    304304
    305             var url = ajaxurl + '?action=post2podcast_generate_podcast_audio' +
    306                      '&post_id=' + encodeURIComponent(postId) +
    307                      '&nonce=' + encodeURIComponent(nonce) +
    308                      '&stream=true' +
    309                      '&wordpress_site_url=' + encodeURIComponent(wpSiteUrl) +
    310                      '&application_password=' + encodeURIComponent(appPassword);
    311            
    312             eventSource = new EventSource(url);
    313 
    314             eventSource.onopen = function() {
    315                 addStatusMessage('Connected to generation service', 'info');
    316                 lastMessageTime = Date.now();
    317 
    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
    320                 timeoutCheckInterval = setInterval(function() {
    321                     var timeSinceLastMessage = Date.now() - lastMessageTime;
    322                     var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles)
    323 
    324                     if (timeSinceLastMessage > maxIdleTime && generationInProgress) {
    325                         addStatusMessage('❌ Server stopped responding after 25 minutes. The generation may have failed.', 'error');
    326                         if (progressInterval) clearInterval(progressInterval);
    327                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    328                         if (eventSource) {
    329                             eventSource.close();
    330                             eventSource = null;
    331                         }
     305            // Use AJAX polling instead of SSE for better reliability with long-running jobs
     306            $.ajax({
     307                url: ajaxurl,
     308                type: 'POST',
     309                data: {
     310                    action: 'post2podcast_generate_podcast_audio',
     311                    post_id: postId,
     312                    nonce: nonce,
     313                    stream: 'false',  // Disable SSE, use polling instead
     314                    wordpress_site_url: wpSiteUrl,
     315                    application_password: appPassword
     316                },
     317                timeout: 0,  // No timeout - polling will handle progress
     318                success: function(response) {
     319                    if (progressInterval) clearInterval(progressInterval);
     320                    $progressBar.css('width', '100%').text('100%');
     321
     322                    if (response.success && response.data && response.data.audio_url) {
     323                        addStatusMessage('✓ Audio generated successfully!', 'success');
     324                        showAudioPreview(response.data.audio_url);
     325                        updateCreditDisplay();
     326
     327                        // Update button visibility
     328                        generationInProgress = false;
     329                        $spinner.removeClass('is-active');
     330                        $('#generate_audio').hide();
     331                        $('#regenerate_audio').show().prop('disabled', false);
     332                        $('#delete_podcast').show().prop('disabled', false);
     333                    } else {
     334                        var errorMsg = response.data && response.data.message ? response.data.message : 'Unknown error occurred';
     335                        addStatusMessage('❌ Error: ' + errorMsg, 'error');
    332336                        resetUI(false);
    333337                    }
    334                 }, 30000); // Check every 30 seconds
    335             };
    336 
    337             eventSource.onmessage = function(event) {
    338                 lastMessageTime = Date.now(); // Update last message time
    339                 try {
    340                     var data = JSON.parse(event.data);
    341                    
    342                     if (data.status === 'generating') {
    343                         addStatusMessage(data.message, 'info');
    344                         // We ignore data.progress for the bar itself now, using simulated progress
    345                     } else if (data.status === 'success') {
    346                         if (progressInterval) clearInterval(progressInterval);
    347                         $progressBar.css('width', '100%').text('100%');
    348                         addStatusMessage('✓ ' + data.message, 'success');
    349 
    350                         // Show the audio preview instead of reloading
    351                         if (data.audio_url) {
    352                             showAudioPreview(data.audio_url);
    353                             addStatusMessage('Audio preview is ready!', 'success');
    354                         }
    355 
    356                         // Update credit display after successful generation
    357                         updateCreditDisplay();
    358 
    359                         // Instead of full resetUI, specifically manage button visibility
    360                         generationInProgress = false; // Allow new actions
    361                         $spinner.removeClass('is-active');
    362                         // $generateBtn.prop('disabled', false); // Don't re-enable all $generateBtn yet
    363 
    364                         // Hide "Generate Audio", show "Regenerate Audio" and "Delete Podcast"
    365                         $('#generate_audio').hide(); // Hide the main one
    366                         $('#regenerate_audio').show().prop('disabled', false); // Show and enable regenerate
    367                         $('#delete_podcast').show().prop('disabled', false);   // Show and enable delete
    368 
    369                         // Explicitly close the connection on success from client-side
    370                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    371                         if (eventSource) {
    372                             addStatusMessage('Closing SSE connection from client after success.', 'info');
    373                             eventSource.close();
    374                             eventSource = null; // Prevent resetUI or onerror from trying to close it again
    375                         }
    376 
    377                     } else if (data.status === 'error') {
    378                         // Stop the simulated progress immediately on error
    379                         if (progressInterval) clearInterval(progressInterval);
    380                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    381                         // Do NOT set progress to 100% on error
    382                         addStatusMessage('❌ Error: ' + data.message, 'error');
    383                         resetUI(false); // Pass false to indicate error - this will hide progress bar and reset UI
    384                     }
    385                    
    386                     // Auto-scroll to bottom of log
    387                     $statusLog.scrollTop($statusLog[0].scrollHeight);
    388                 } catch (e) {
    389                     console.error('Error parsing SSE data:', e);
    390                     addStatusMessage('Error processing server response', 'error');
     338                },
     339                error: function(jqXHR, textStatus, errorThrown) {
     340                    if (progressInterval) clearInterval(progressInterval);
     341                    addStatusMessage('❌ Connection error: ' + errorThrown, 'error');
     342                    resetUI(false);
    391343                }
    392             };
    393            
    394             eventSource.onerror = function(error) {
    395                 console.error('SSE Error:', error);
    396                 // Stop the simulated progress immediately
    397                 if (progressInterval) clearInterval(progressInterval);
    398                 if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    399 
    400                 if (eventSource.readyState === EventSource.CLOSED) {
    401                     addStatusMessage('❌ Connection to server was closed. The server may have encountered an error.', 'error');
    402                 } else if (eventSource.readyState === EventSource.CONNECTING) {
    403                     addStatusMessage('❌ Connection error while attempting to reconnect. Please try again.', 'error');
    404                 } else {
    405                     addStatusMessage('❌ Connection error. Please check your internet connection and try again.', 'error');
    406                 }
    407 
    408                 resetUI(false); // Pass false to indicate error/connection close
    409             };
    410            
    411             // Heartbeat is less critical if progress is simulated, but can keep for connection loss detection
    412             var heartbeatInterval = setInterval(function() {
    413                 if (eventSource && eventSource.readyState === EventSource.CLOSED) {
    414                     clearInterval(heartbeatInterval);
    415                     if (progressInterval) clearInterval(progressInterval);
    416                     if (generationInProgress) { // Check if it wasn't a success that closed it
    417                         addStatusMessage('Connection lost. Please try again.', 'error');
    418                         resetUI(false);
    419                     }
    420                 }
    421             }, 5000);
    422            
    423         } catch (e) {
    424             console.error('Error creating EventSource:', e);
    425             if (progressInterval) clearInterval(progressInterval);
    426             addStatusMessage('Error initializing audio generation: ' + e.message, 'error');
     344            });
     345
     346            // Note: The PHP backend handles the job with polling mechanism for better reliability
     347            // SSE code removed - polling is much more reliable for long-running jobs
     348        } catch (error) {
     349            console.error('Error initiating audio generation:', error);
     350            addStatusMessage('❌ Error: ' + error.message, 'error');
    427351            resetUI(false);
    428352        }
    429353    });
     354
     355    // Voice validation logic
     356    var $voice1Select = $('#post2podcast_voice1');
     357    var $voice2Select = $('#post2podcast_voice2');
     358    var $validationMessage = $('#voice-validation-message');
     359
     360    function validateVoiceSelection() {
     361        var voice1 = $voice1Select.val();
     362        var voice2 = $voice2Select.val();
     363
     364        if (voice1 && voice2 && voice1 === voice2) {
     365            $validationMessage.text('The two voices selected are the same. Please select two different voices for better results.').show();
     366        } else {
     367            $validationMessage.hide();
     368        }
     369    }
     370
     371    $voice1Select.on('change', validateVoiceSelection);
     372    $voice2Select.on('change', validateVoiceSelection);
     373
     374    // Initial validation check on page load
     375    validateVoiceSelection();
    430376   
    431377    function addStatusMessage(message, type) {
  • post2podcast/tags/1.3.5/post2podcast.php

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

    r3438162 r3438184  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.3.4
     7Stable tag: 1.3.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    263263== Changelog ==
    264264
     265= 1.3.5 =
     266* FIXED: Removed unused and dead code from admin.js for better performance and maintainability.
     267
    265268= 1.3.4 =
    266 * FIXED: Resolved SSE connection timeout issues during long audio generation by implementing reliable polling-based progress updates.
     269* FIXED: Resolved timeout issues for very long articles by implementing intelligent adaptive summarization.
     270* IMPROVED: Articles over 5,000 words now use more aggressive summarization to prevent generation timeouts.
     271* IMPROVED: Very long articles (10,000+ words) are automatically optimized for faster processing without losing key content.
    267272* ADDED: New job status endpoint for better progress tracking without connection timeouts.
    268 * IMPROVED: Enhanced connection stability for audio generation processes exceeding 5+ minutes.
     273* IMPROVED: Enhanced connection stability and reduced generation time for long-form content.
    269274
    270275= 1.3.3 =
  • post2podcast/trunk/assets/js/admin.js

    r3437951 r3438184  
    303303            }
    304304
    305             var url = ajaxurl + '?action=post2podcast_generate_podcast_audio' +
    306                      '&post_id=' + encodeURIComponent(postId) +
    307                      '&nonce=' + encodeURIComponent(nonce) +
    308                      '&stream=true' +
    309                      '&wordpress_site_url=' + encodeURIComponent(wpSiteUrl) +
    310                      '&application_password=' + encodeURIComponent(appPassword);
    311            
    312             eventSource = new EventSource(url);
    313 
    314             eventSource.onopen = function() {
    315                 addStatusMessage('Connected to generation service', 'info');
    316                 lastMessageTime = Date.now();
    317 
    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
    320                 timeoutCheckInterval = setInterval(function() {
    321                     var timeSinceLastMessage = Date.now() - lastMessageTime;
    322                     var maxIdleTime = 1500000; // 25 minutes in milliseconds (allows for very long articles)
    323 
    324                     if (timeSinceLastMessage > maxIdleTime && generationInProgress) {
    325                         addStatusMessage('❌ Server stopped responding after 25 minutes. The generation may have failed.', 'error');
    326                         if (progressInterval) clearInterval(progressInterval);
    327                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    328                         if (eventSource) {
    329                             eventSource.close();
    330                             eventSource = null;
    331                         }
     305            // Use AJAX polling instead of SSE for better reliability with long-running jobs
     306            $.ajax({
     307                url: ajaxurl,
     308                type: 'POST',
     309                data: {
     310                    action: 'post2podcast_generate_podcast_audio',
     311                    post_id: postId,
     312                    nonce: nonce,
     313                    stream: 'false',  // Disable SSE, use polling instead
     314                    wordpress_site_url: wpSiteUrl,
     315                    application_password: appPassword
     316                },
     317                timeout: 0,  // No timeout - polling will handle progress
     318                success: function(response) {
     319                    if (progressInterval) clearInterval(progressInterval);
     320                    $progressBar.css('width', '100%').text('100%');
     321
     322                    if (response.success && response.data && response.data.audio_url) {
     323                        addStatusMessage('✓ Audio generated successfully!', 'success');
     324                        showAudioPreview(response.data.audio_url);
     325                        updateCreditDisplay();
     326
     327                        // Update button visibility
     328                        generationInProgress = false;
     329                        $spinner.removeClass('is-active');
     330                        $('#generate_audio').hide();
     331                        $('#regenerate_audio').show().prop('disabled', false);
     332                        $('#delete_podcast').show().prop('disabled', false);
     333                    } else {
     334                        var errorMsg = response.data && response.data.message ? response.data.message : 'Unknown error occurred';
     335                        addStatusMessage('❌ Error: ' + errorMsg, 'error');
    332336                        resetUI(false);
    333337                    }
    334                 }, 30000); // Check every 30 seconds
    335             };
    336 
    337             eventSource.onmessage = function(event) {
    338                 lastMessageTime = Date.now(); // Update last message time
    339                 try {
    340                     var data = JSON.parse(event.data);
    341                    
    342                     if (data.status === 'generating') {
    343                         addStatusMessage(data.message, 'info');
    344                         // We ignore data.progress for the bar itself now, using simulated progress
    345                     } else if (data.status === 'success') {
    346                         if (progressInterval) clearInterval(progressInterval);
    347                         $progressBar.css('width', '100%').text('100%');
    348                         addStatusMessage('✓ ' + data.message, 'success');
    349 
    350                         // Show the audio preview instead of reloading
    351                         if (data.audio_url) {
    352                             showAudioPreview(data.audio_url);
    353                             addStatusMessage('Audio preview is ready!', 'success');
    354                         }
    355 
    356                         // Update credit display after successful generation
    357                         updateCreditDisplay();
    358 
    359                         // Instead of full resetUI, specifically manage button visibility
    360                         generationInProgress = false; // Allow new actions
    361                         $spinner.removeClass('is-active');
    362                         // $generateBtn.prop('disabled', false); // Don't re-enable all $generateBtn yet
    363 
    364                         // Hide "Generate Audio", show "Regenerate Audio" and "Delete Podcast"
    365                         $('#generate_audio').hide(); // Hide the main one
    366                         $('#regenerate_audio').show().prop('disabled', false); // Show and enable regenerate
    367                         $('#delete_podcast').show().prop('disabled', false);   // Show and enable delete
    368 
    369                         // Explicitly close the connection on success from client-side
    370                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    371                         if (eventSource) {
    372                             addStatusMessage('Closing SSE connection from client after success.', 'info');
    373                             eventSource.close();
    374                             eventSource = null; // Prevent resetUI or onerror from trying to close it again
    375                         }
    376 
    377                     } else if (data.status === 'error') {
    378                         // Stop the simulated progress immediately on error
    379                         if (progressInterval) clearInterval(progressInterval);
    380                         if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    381                         // Do NOT set progress to 100% on error
    382                         addStatusMessage('❌ Error: ' + data.message, 'error');
    383                         resetUI(false); // Pass false to indicate error - this will hide progress bar and reset UI
    384                     }
    385                    
    386                     // Auto-scroll to bottom of log
    387                     $statusLog.scrollTop($statusLog[0].scrollHeight);
    388                 } catch (e) {
    389                     console.error('Error parsing SSE data:', e);
    390                     addStatusMessage('Error processing server response', 'error');
     338                },
     339                error: function(jqXHR, textStatus, errorThrown) {
     340                    if (progressInterval) clearInterval(progressInterval);
     341                    addStatusMessage('❌ Connection error: ' + errorThrown, 'error');
     342                    resetUI(false);
    391343                }
    392             };
    393            
    394             eventSource.onerror = function(error) {
    395                 console.error('SSE Error:', error);
    396                 // Stop the simulated progress immediately
    397                 if (progressInterval) clearInterval(progressInterval);
    398                 if (timeoutCheckInterval) clearInterval(timeoutCheckInterval);
    399 
    400                 if (eventSource.readyState === EventSource.CLOSED) {
    401                     addStatusMessage('❌ Connection to server was closed. The server may have encountered an error.', 'error');
    402                 } else if (eventSource.readyState === EventSource.CONNECTING) {
    403                     addStatusMessage('❌ Connection error while attempting to reconnect. Please try again.', 'error');
    404                 } else {
    405                     addStatusMessage('❌ Connection error. Please check your internet connection and try again.', 'error');
    406                 }
    407 
    408                 resetUI(false); // Pass false to indicate error/connection close
    409             };
    410            
    411             // Heartbeat is less critical if progress is simulated, but can keep for connection loss detection
    412             var heartbeatInterval = setInterval(function() {
    413                 if (eventSource && eventSource.readyState === EventSource.CLOSED) {
    414                     clearInterval(heartbeatInterval);
    415                     if (progressInterval) clearInterval(progressInterval);
    416                     if (generationInProgress) { // Check if it wasn't a success that closed it
    417                         addStatusMessage('Connection lost. Please try again.', 'error');
    418                         resetUI(false);
    419                     }
    420                 }
    421             }, 5000);
    422            
    423         } catch (e) {
    424             console.error('Error creating EventSource:', e);
    425             if (progressInterval) clearInterval(progressInterval);
    426             addStatusMessage('Error initializing audio generation: ' + e.message, 'error');
     344            });
     345
     346            // Note: The PHP backend handles the job with polling mechanism for better reliability
     347            // SSE code removed - polling is much more reliable for long-running jobs
     348        } catch (error) {
     349            console.error('Error initiating audio generation:', error);
     350            addStatusMessage('❌ Error: ' + error.message, 'error');
    427351            resetUI(false);
    428352        }
    429353    });
     354
     355    // Voice validation logic
     356    var $voice1Select = $('#post2podcast_voice1');
     357    var $voice2Select = $('#post2podcast_voice2');
     358    var $validationMessage = $('#voice-validation-message');
     359
     360    function validateVoiceSelection() {
     361        var voice1 = $voice1Select.val();
     362        var voice2 = $voice2Select.val();
     363
     364        if (voice1 && voice2 && voice1 === voice2) {
     365            $validationMessage.text('The two voices selected are the same. Please select two different voices for better results.').show();
     366        } else {
     367            $validationMessage.hide();
     368        }
     369    }
     370
     371    $voice1Select.on('change', validateVoiceSelection);
     372    $voice2Select.on('change', validateVoiceSelection);
     373
     374    // Initial validation check on page load
     375    validateVoiceSelection();
    430376   
    431377    function addStatusMessage(message, type) {
  • post2podcast/trunk/post2podcast.php

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

    r3438162 r3438184  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.3.4
     7Stable tag: 1.3.5
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    263263== Changelog ==
    264264
     265= 1.3.5 =
     266* FIXED: Removed unused and dead code from admin.js for better performance and maintainability.
     267
    265268= 1.3.4 =
    266 * FIXED: Resolved SSE connection timeout issues during long audio generation by implementing reliable polling-based progress updates.
     269* FIXED: Resolved timeout issues for very long articles by implementing intelligent adaptive summarization.
     270* IMPROVED: Articles over 5,000 words now use more aggressive summarization to prevent generation timeouts.
     271* IMPROVED: Very long articles (10,000+ words) are automatically optimized for faster processing without losing key content.
    267272* ADDED: New job status endpoint for better progress tracking without connection timeouts.
    268 * IMPROVED: Enhanced connection stability for audio generation processes exceeding 5+ minutes.
     273* IMPROVED: Enhanced connection stability and reduced generation time for long-form content.
    269274
    270275= 1.3.3 =
Note: See TracChangeset for help on using the changeset viewer.