Changeset 3480845
- Timestamp:
- 03/12/2026 06:30:29 AM (3 weeks ago)
- Location:
- natural-text-to-speech/trunk
- Files:
-
- 15 added
- 7 deleted
- 5 edited
-
components/config.php (modified) (1 diff)
-
components/rest/podcast (added)
-
components/rest/podcast-loader.php (added)
-
components/rest/podcast.php (deleted)
-
components/rest/podcast/bootstrap.php (added)
-
components/rest/podcast/explorer.php (added)
-
components/rest/podcast/generation.php (added)
-
components/rest/podcast/index.php (added)
-
components/rest/podcast/queue.php (added)
-
components/rest/podcast/rest.php (added)
-
components/rest/podcast/rss.php (added)
-
components/rest/route.php (modified) (5 diffs)
-
components/rest/utils.php (modified) (3 diffs)
-
natural-text-to-speech.php (modified) (4 diffs)
-
public/js/ntts-admin-v2.6.4-main.js (deleted)
-
public/js/ntts-admin-v2.6.4-vendor.js (deleted)
-
public/js/ntts-admin-v2.6.5-main.js (added)
-
public/js/ntts-admin-v2.6.5-vendor.js (added)
-
public/js/ntts-public-v2.6.4-main.js (deleted)
-
public/js/ntts-public-v2.6.4-vendor.js (deleted)
-
public/js/ntts-public-v2.6.5-main.js (added)
-
public/js/ntts-public-v2.6.5-vendor.js (added)
-
public/js/nttsa-00974f6b.js (added)
-
public/js/nttsa-85278bfb.js (deleted)
-
public/js/nttsa-af17ad66.js (added)
-
public/js/nttsa-e31f66e6.js (deleted)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
natural-text-to-speech/trunk/components/config.php
r3478726 r3480845 252 252 natuteto_set_plugin_config( $new_config ); 253 253 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(); 255 256 natuteto_sync_podcast_schedule( $new_config ); 256 257 } -
natural-text-to-speech/trunk/components/rest/route.php
r3478726 r3480845 23 23 array( 24 24 '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 }, 26 29 'permission_callback' => '__return_true', 27 30 ) … … 210 213 array( 211 214 '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 }, 213 219 'permission_callback' => 'natuteto_rest_only_admin', 214 220 ) … … 220 226 array( 221 227 '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 }, 223 284 'permission_callback' => 'natuteto_rest_only_admin', 224 285 ) … … 230 291 array( 231 292 '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 }, 233 297 'permission_callback' => '__return_true', 234 298 ) … … 240 304 array( 241 305 '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 }, 243 310 'permission_callback' => '__return_true', 244 311 ) -
natural-text-to-speech/trunk/components/rest/utils.php
r3478726 r3480845 513 513 514 514 header( "Content-Type: {$mime}" ); 515 header( 'Content-Length: ' . filesize( $full_path ) );516 515 header( 'Content-Disposition: inline; filename="' . basename( $full_path ) . '"' ); 517 516 … … 519 518 $file_etag = '"' . md5_file( $full_path ) . '"'; 520 519 $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; 521 526 522 527 if ( false !== $file_mtime ) { … … 526 531 header( 'ETag: ' . $file_etag ); 527 532 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 ); 531 593 532 594 // Kill WordPress completely, no HTML wrapper. -
natural-text-to-speech/trunk/natural-text-to-speech.php
r3479631 r3480845 4 4 * Plugin URI: https://wordpress.org/plugins/natural-text-to-speech 5 5 * 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. 46 * Version: 2.6.5 7 7 * Author: Reinvent WP 8 8 * Author URI: https://reinventwp.com … … 20 20 * serious issues with the options, so no if ( ! defined() ).}} 21 21 */ 22 define( 'NATUTETO_VERSION', '2.6. 4' );22 define( 'NATUTETO_VERSION', '2.6.5' ); 23 23 24 24 if ( ! defined( 'NATUTETO_PLUGIN_DIR' ) ) { … … 118 118 require_once plugin_dir_path( __FILE__ ) . 'components/rest/tts.php'; 119 119 120 // Podcast generation and RSS feed.121 require_once plugin_dir_path( __FILE__ ) . 'components/rest/podcast.php';122 123 120 // Providing OpenAI completion API. 124 121 require_once plugin_dir_path( __FILE__ ) . 'components/rest/llm.php'; … … 138 135 // Regiseter Public rest api. 139 136 require_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 */ 143 function 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 */ 159 function 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 */ 178 function natuteto_should_boot_podcast_runtime() { 179 return natuteto_has_enabled_podcast_feeds() || false !== wp_next_scheduled( 'natuteto_podcast_scan' ); 180 } 181 182 add_filter( 183 'cron_schedules', 184 function ( $schedules ) { 185 natuteto_load_podcast_module(); 186 return natuteto_podcast_cron_schedules( $schedules ); 187 } 188 ); 189 190 add_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 204 add_action( 205 'natuteto_podcast_scan', 206 function () { 207 natuteto_load_podcast_module(); 208 natuteto_podcast_scan_event(); 209 } 210 ); 211 212 add_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 222 add_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 ); 140 233 141 234 // API route. -
natural-text-to-speech/trunk/readme.txt
r3479646 r3480845 4 4 Requires at least: 5.0 5 5 Tested up to: 6.9 6 Stable tag: 2.6. 47 Version: 2.6. 46 Stable tag: 2.6.5 7 Version: 2.6.5 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later … … 481 481 == Changelog == 482 482 483 = 2.6.5 = 484 * Add auto checking requirement for apple podcast, spotify 485 483 486 = 2.6.4 = 484 487 * Enhance Podcast setting UI
Note: See TracChangeset
for help on using the changeset viewer.