Plugin Directory

Changeset 3480845


Ignore:
Timestamp:
03/12/2026 06:30:29 AM (3 weeks ago)
Author:
reinventwp
Message:

Deploying version 2.6.5 - update podcast UI

Location:
natural-text-to-speech/trunk
Files:
15 added
7 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • natural-text-to-speech/trunk/components/config.php

    r3478726 r3480845  
    252252    natuteto_set_plugin_config( $new_config );
    253253
    254     if ( function_exists( 'natuteto_sync_podcast_schedule' ) ) {
     254    if ( array_key_exists( 'podcasts', $validated['settings'] ) && function_exists( 'natuteto_load_podcast_module' ) ) {
     255        natuteto_load_podcast_module();
    255256        natuteto_sync_podcast_schedule( $new_config );
    256257    }
  • natural-text-to-speech/trunk/components/rest/route.php

    r3478726 r3480845  
    2323            array(
    2424                'methods'             => 'GET',
    25                 'callback'            => 'natuteto_rest_podcast_rss',
     25                'callback'            => function ( WP_REST_Request $request ) {
     26                    natuteto_load_podcast_module();
     27                    return natuteto_rest_podcast_rss( $request );
     28                },
    2629                'permission_callback' => '__return_true',
    2730            )
     
    210213            array(
    211214                'methods'             => 'POST',
    212                 'callback'            => 'natuteto_rest_generate_podcast_audio',
     215                'callback'            => function ( WP_REST_Request $request ) {
     216                    natuteto_load_podcast_module();
     217                    return natuteto_rest_generate_podcast_audio( $request );
     218                },
    213219                'permission_callback' => 'natuteto_rest_only_admin',
    214220            )
     
    220226            array(
    221227                'methods'             => 'GET',
    222                 'callback'            => 'natuteto_rest_get_podcast_queue_status',
     228                'callback'            => function () {
     229                    natuteto_load_podcast_module();
     230                    return natuteto_rest_get_podcast_queue_status();
     231                },
     232                'permission_callback' => 'natuteto_rest_only_admin',
     233            )
     234        );
     235
     236        register_rest_route(
     237            NATUTETO_REST_API,
     238            '/podcast/cancel',
     239            array(
     240                'methods'             => 'POST',
     241                'callback'            => function ( WP_REST_Request $request ) {
     242                    natuteto_load_podcast_module();
     243                    return natuteto_rest_cancel_podcast_audio( $request );
     244                },
     245                'permission_callback' => 'natuteto_rest_only_admin',
     246            )
     247        );
     248
     249        register_rest_route(
     250            NATUTETO_REST_API,
     251            '/podcast/feed-posts',
     252            array(
     253                'methods'             => 'GET',
     254                'callback'            => function ( WP_REST_Request $request ) {
     255                    natuteto_load_podcast_module();
     256                    return natuteto_rest_get_podcast_feed_posts( $request );
     257                },
     258                'permission_callback' => 'natuteto_rest_only_admin',
     259            )
     260        );
     261
     262        register_rest_route(
     263            NATUTETO_REST_API,
     264            '/podcast/delete-audio',
     265            array(
     266                'methods'             => 'POST',
     267                'callback'            => function ( WP_REST_Request $request ) {
     268                    natuteto_load_podcast_module();
     269                    return natuteto_rest_delete_podcast_audio_assets( $request );
     270                },
     271                'permission_callback' => 'natuteto_rest_only_admin',
     272            )
     273        );
     274
     275        register_rest_route(
     276            NATUTETO_REST_API,
     277            '/podcast/cover-upload',
     278            array(
     279                'methods'             => 'POST',
     280                'callback'            => function ( WP_REST_Request $request ) {
     281                    natuteto_load_podcast_module();
     282                    return natuteto_rest_upload_podcast_cover( $request );
     283                },
    223284                'permission_callback' => 'natuteto_rest_only_admin',
    224285            )
     
    230291            array(
    231292                'methods'             => 'POST',
    232                 'callback'            => 'natuteto_rest_receive_podcast_progress',
     293                'callback'            => function ( WP_REST_Request $request ) {
     294                    natuteto_load_podcast_module();
     295                    return natuteto_rest_receive_podcast_progress( $request );
     296                },
    233297                'permission_callback' => '__return_true',
    234298            )
     
    240304            array(
    241305                'methods'             => 'POST',
    242                 'callback'            => 'natuteto_rest_receive_podcast_audio',
     306                'callback'            => function ( WP_REST_Request $request ) {
     307                    natuteto_load_podcast_module();
     308                    return natuteto_rest_receive_podcast_audio( $request );
     309                },
    243310                'permission_callback' => '__return_true',
    244311            )
  • natural-text-to-speech/trunk/components/rest/utils.php

    r3478726 r3480845  
    513513
    514514    header( "Content-Type: {$mime}" );
    515     header( 'Content-Length: ' . filesize( $full_path ) );
    516515    header( 'Content-Disposition: inline; filename="' . basename( $full_path ) . '"' );
    517516
     
    519518    $file_etag  = '"' . md5_file( $full_path ) . '"';
    520519    $is_audio   = 0 === strpos( $mime, 'audio/' );
     520    $file_size  = filesize( $full_path );
     521    $method     = isset( $_SERVER['REQUEST_METHOD'] ) ? strtoupper( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) : 'GET';
     522    $range      = isset( $_SERVER['HTTP_RANGE'] ) ? trim( sanitize_text_field( wp_unslash( $_SERVER['HTTP_RANGE'] ) ) ) : '';
     523    $start      = 0;
     524    $end        = $file_size > 0 ? $file_size - 1 : 0;
     525    $status     = 200;
    521526
    522527    if ( false !== $file_mtime ) {
     
    526531    header( 'ETag: ' . $file_etag );
    527532    header( $is_audio ? 'Cache-Control: public, max-age=31536000, immutable' : 'Cache-Control: public, max-age=86400' );
    528 
    529     // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile
    530     readfile( $full_path );
     533    header( 'Accept-Ranges: bytes' );
     534
     535    if ( '' !== $range && preg_match( '/bytes=(\d*)-(\d*)/', $range, $matches ) ) {
     536        $range_start = '' !== $matches[1] ? (int) $matches[1] : null;
     537        $range_end   = '' !== $matches[2] ? (int) $matches[2] : null;
     538
     539        if ( null === $range_start && null !== $range_end ) {
     540            $start = max( 0, $file_size - $range_end );
     541        } elseif ( null !== $range_start ) {
     542            $start = $range_start;
     543            if ( null !== $range_end ) {
     544                $end = min( $range_end, $file_size - 1 );
     545            }
     546        }
     547
     548        if ( $start > $end || $start >= $file_size ) {
     549            status_header( 416 );
     550            header( 'Content-Range: bytes */' . $file_size );
     551            exit;
     552        }
     553
     554        $status = 206;
     555        header( 'Content-Range: bytes ' . $start . '-' . $end . '/' . $file_size );
     556    }
     557
     558    $content_length = max( 0, $end - $start + 1 );
     559    header( 'Content-Length: ' . $content_length );
     560    status_header( $status );
     561
     562    if ( 'HEAD' === $method ) {
     563        exit;
     564    }
     565
     566    $handle = fopen( $full_path, 'rb' );
     567    if ( ! $handle ) {
     568        status_header( 500 );
     569        exit;
     570    }
     571
     572    if ( $start > 0 ) {
     573        fseek( $handle, $start );
     574    }
     575
     576    $remaining = $content_length;
     577    while ( $remaining > 0 && ! feof( $handle ) ) {
     578        $chunk = fread( $handle, min( 8192, $remaining ) );
     579        if ( false === $chunk ) {
     580            break;
     581        }
     582
     583        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Streaming raw file bytes to the response.
     584        echo $chunk;
     585        $remaining -= strlen( $chunk );
     586
     587        if ( function_exists( 'fastcgi_finish_request' ) ) {
     588            flush();
     589        }
     590    }
     591
     592    fclose( $handle );
    531593
    532594    // Kill WordPress completely, no HTML wrapper.
  • natural-text-to-speech/trunk/natural-text-to-speech.php

    r3479631 r3480845  
    44 * Plugin URI:  https://wordpress.org/plugins/natural-text-to-speech
    55 * Description: Read aloud your posts using natural, human-like voices and highlights sentences and words as they are spoken. Available in Free and Pro versions! Start now with 20,000 free characters / month.
    6  * Version:     2.6.4
     6 * Version:     2.6.5
    77 * Author:      Reinvent WP
    88 * Author URI:  https://reinventwp.com
     
    2020 * serious issues with the options, so no if ( ! defined() ).}}
    2121 */
    22 define( 'NATUTETO_VERSION', '2.6.4' );
     22define( 'NATUTETO_VERSION', '2.6.5' );
    2323
    2424if ( ! defined( 'NATUTETO_PLUGIN_DIR' ) ) {
     
    118118require_once plugin_dir_path( __FILE__ ) . 'components/rest/tts.php';
    119119
    120 // Podcast generation and RSS feed.
    121 require_once plugin_dir_path( __FILE__ ) . 'components/rest/podcast.php';
    122 
    123120// Providing OpenAI completion API.
    124121require_once plugin_dir_path( __FILE__ ) . 'components/rest/llm.php';
     
    138135// Regiseter Public rest api.
    139136require_once plugin_dir_path( __FILE__ ) . 'components/public.php';
     137
     138/**
     139 * Load the podcast module only for podcast-specific work.
     140 *
     141 * @return void
     142 */
     143function natuteto_load_podcast_module() {
     144    static $loaded = false;
     145
     146    if ( $loaded ) {
     147        return;
     148    }
     149
     150    require_once plugin_dir_path( __FILE__ ) . 'components/rest/podcast-loader.php';
     151    $loaded = true;
     152}
     153
     154/**
     155 * Check whether any saved podcast feed is enabled.
     156 *
     157 * @return bool
     158 */
     159function natuteto_has_enabled_podcast_feeds() {
     160    $config = get_option( NATUTETO_KV_STORAGE, NATUTETO_DEFAULT_CONFIG );
     161    $config = is_array( $config ) ? $config : array();
     162    $feeds  = natuteto_normalize_podcast_settings( $config );
     163
     164    foreach ( $feeds as $feed ) {
     165        if ( ! empty( $feed['enabled'] ) ) {
     166            return true;
     167        }
     168    }
     169
     170    return false;
     171}
     172
     173/**
     174 * Determine whether the podcast runtime should boot on this request.
     175 *
     176 * @return bool
     177 */
     178function natuteto_should_boot_podcast_runtime() {
     179    return natuteto_has_enabled_podcast_feeds() || false !== wp_next_scheduled( 'natuteto_podcast_scan' );
     180}
     181
     182add_filter(
     183    'cron_schedules',
     184    function ( $schedules ) {
     185        natuteto_load_podcast_module();
     186        return natuteto_podcast_cron_schedules( $schedules );
     187    }
     188);
     189
     190add_action(
     191    'transition_post_status',
     192    function ( $new_status, $old_status, $post ) {
     193        if ( ! natuteto_has_enabled_podcast_feeds() ) {
     194            return;
     195        }
     196
     197        natuteto_load_podcast_module();
     198        natuteto_handle_podcast_publish_transition( $new_status, $old_status, $post );
     199    },
     200    10,
     201    3
     202);
     203
     204add_action(
     205    'natuteto_podcast_scan',
     206    function () {
     207        natuteto_load_podcast_module();
     208        natuteto_podcast_scan_event();
     209    }
     210);
     211
     212add_action(
     213    'natuteto_podcast_generate_single',
     214    function ( $post_id ) {
     215        natuteto_load_podcast_module();
     216        natuteto_generate_podcast_episode_event( $post_id );
     217    },
     218    10,
     219    1
     220);
     221
     222add_action(
     223    'init',
     224    function () {
     225        if ( ! natuteto_should_boot_podcast_runtime() ) {
     226            return;
     227        }
     228
     229        natuteto_load_podcast_module();
     230        natuteto_sync_podcast_schedule();
     231    }
     232);
    140233
    141234// API route.
  • natural-text-to-speech/trunk/readme.txt

    r3479646 r3480845  
    44Requires at least: 5.0
    55Tested up to: 6.9
    6 Stable tag: 2.6.4
    7 Version: 2.6.4
     6Stable tag: 2.6.5
     7Version: 2.6.5
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    481481== Changelog ==
    482482
     483= 2.6.5 =
     484* Add auto checking requirement for apple podcast, spotify
     485
    483486= 2.6.4 =
    484487* Enhance Podcast setting UI
Note: See TracChangeset for help on using the changeset viewer.