mirror of
https://github.com/forkless/Piperless.git
synced 2026-08-16 00:46:38 +02:00
20 KiB
20 KiB
Changelog
All notable changes to the Piperless WordPress plugin.
[1.0.0] — 2026-05-09
Added
- Voice model aliases — assign custom display names to voice models from the Piper tab. Aliases appear in admin dropdowns and the Gutenberg sidebar, making technical model names like "en_US-lessac-low" readable as "American Female". Stored in
piperless_settings['voice_aliases']. - Accessibility landmark — player container exposes
role="region"+aria-label="Audio transcript: Post Title". Screen readers announce the player's purpose and allow keyboard navigation as a landmark region. - Configurable player max-width — new "Player Max Width" field in the Styling tab. Set to any pixel value (default 680) or 0 for 100% width. Injected as inline CSS; works across all 6 themes and admin preview.
- "Alias" string translated to all 5 locales (de_DE, fr_FR, es_ES, nl_NL, zh_CN).
Changed
- Voice column in model table shows original lowercase names (
amy,lessac) instead ofucfirst(). - Gutenberg voice dropdown wired to use aliases from the REST API.
- Title moved inside player container —
__titlediv is now a flex child of.piperless-player, usingflex-wrap: wrap+flex: 0 0 100%. Eliminates gap between title and controls. - Translations — all 5 locales at 100/100 strings including "Audio transcript: %s" accessibility label.
[0.8.2] — 2026-05-09
Fixes
- Player
max-width: 680pxrestored after earlier 100% width experiment. - CSS cache bust
[0.8.1] — 2026-05-09
Changed
- Title moved inside player flex container —
__titleis now a child of.piperless-playerwithflex-wrap: wrap. Applies to all 6 themes. - Base player margin reduced from
1.5emto0.5emvertical.
[0.8.0] — 2026-05-09
Fixed
- Title spacing gap —
.piperless-player__titlemargin-bottomset to0, playermarginreduced to close gap between title and player on themed frontends.
[0.7.9] — 2026-05-09
Fixed
- Title margin —
.piperless-player__titleremovedmargin-bottom: 4px. - Removed unused
.piperless-player__title + .piperless-playersibling collapse rule (never matched DOM structure).
[0.7.8] — 2026-05-09
Security
escapeshellcmd→escapeshellargon ffmpeg binary path inCache_Manager::put(). All shell calls now useescapeshellarg— zeroescapeshellcmd()calls remain in the codebase.- Removed
FOLLOW_SYMLINKSfrom model directory scanner to prevent symbolic links from escaping the allowed models directory. - Removed duplicate database query in
Cache_Manager::get_entries()— dead code that re-queried_piperless_cache_keymeta into an unused variable.
[0.7.7] — 2026-05-09
Added
- Player Preview field label — "Player Preview" now appears as a proper left-aligned label in the Styling tab.
- Show Duration preview live — toggling the checkbox instantly shows/hides the duration in the player preview, no save required.
Changed
- Model table layout — removed the Name column. "Available models" now appears as a field label to the left. Columns are shrink-wrapped (
table-layout: auto,max-width: 620px) so the Preview button stays near the data on wide screens. - Model table sorting — Voice and Quality columns are click-to-sort. Voice sorts alphabetically; Quality sorts by tier priority (low → medium → high). Sort arrows initialize on page load.
- Voice names capitalized in model table.
- Minimal player style — removed the bottom border divider for a cleaner look.
[0.7.6] — 2026-05-09
Changed
- Incremental CSS/JS cache-bust bumps.
[0.7.2] — 2026-05-09
Added
- Sortable model table — Voice and Quality columns in the model preview table are now click-to-sort. Voice sorts alphabetically; Quality sorts by tier priority (low → medium → high). Sort arrows show active column and direction on load.
Changed
- Voice names capitalized — model table voice column now displays with the first letter uppercased (e.g., "Amy").
- Per-post overrides — Gutenberg sidebar gained Player Style and Placement dropdowns in a new Display Settings panel, separate from Voice Settings. Per-post meta (
_piperless_style,_piperless_placement) overrides global settings.
[0.7.1] — 2026-05-09
Added
Nothing new — version skipped due to uploader glitch.
[0.7.0] — 2026-05-09
Added
- NewsViews Classic player style — based on the NewsViews theme with
#233452dark navy replacing the burgundy accent. - Above & below content placement option — renders the player both before and after the post content.
- Dropdown separators — visual divider lines in the Player Style and Placement dropdowns, separating preset options from Custom CSS / Manual.
Changed
- Style dropdown reordered — sorted alphabetically (Classic, Minimal, Modern Dark, NewsViews, NewsViews Classic) with Custom CSS remaining last.
- Player width — removed
max-width: 680pxfrom base styles. Players now fill 100% of their container.
Fixed
- Audio player progress bar, seeking, and time display — all three now work on WAV-only setups. The REST proxy gained HTTP
Rangerequest support (206 Partial Content+Content-Range), which browsers require for duration detection and seeking. Removed the hardcodedtype="audio/wav"attribute so the browser auto-detects MIME type from the proxy'sContent-Typeheader. Preload changed frommetadatatoauto. is_path_accessible()fatal crash — whenrealpath()returnedfalseon parent directories outsideopen_basedir, the method fell back to a non-string causingstr_starts_with()TypeError.file_exists('/')warning — parent-directory walker inis_path_accessible()now stops at filesystem root.- ffmpeg
open_basedirwarnings —find_ffmpeg()now suppressesfile_exists()/is_executable()on default and custom paths.
[0.6.3] — 2026-05-09
Fixed
- Audio player progress bar, seeking, and time display — all three now work on WAV-only setups. The REST proxy gained HTTP
Rangerequest support (206 Partial Content+Content-Range), which browsers require for duration detection and seeking. Removed the hardcodedtype="audio/wav"attribute so the browser auto-detects MIME type from the proxy'sContent-Typeheader. Preload changed frommetadatatoautoto ensure the browser reads enough data for duration. is_path_accessible()fatal crash — whenrealpath()returnedfalseon parent directories outsideopen_basedir,$real_pathbecamefalseinstead of a string, crashingstr_starts_with(). Now falls back to the original path string.file_exists('/')warning — the parent-directory walker inis_path_accessible()now stops at filesystem root ('/' !== $parent) and suppresses allfile_exists()/realpath()calls with@.- ffmpeg
open_basedirwarnings —find_ffmpeg()now uses@suppression on allfile_exists()/is_executable()calls for both custom and default paths.
Changed
- Player width — removed
max-width: 680pxfrom player base styles. Players now fill 100% of their container.
[0.6.2] — 2026-05-09
Fixed
file_exists('/')warning onopen_basedir—is_path_accessible()parent-directory walker now stops at filesystem root ('/' !== $parent) and suppressesfile_exists()andrealpath()with@. Prevents the walker from checking/when the configured path doesn't exist on the server.
[0.6.1] — 2026-05-09
Fixed
- Admin panel timeout on
open_basedir—check_binary_status(),scan_models(), andsynthesise()now checkopen_basedirwith a pure string-path comparison before any filesystem call. On hosts wherefile_exists()/is_dir()hang on blocked paths (stale NFS mounts, slow network filesystems), the page now loads instantly. Filesystem calls also use@suppression as a second layer against warning-log delays.
[0.6.0] — 2026-05-09
Added
- Performance tab — configurable Piper process timeout (30–3600s, default 300) and audio endpoint rate limit (1–600 req/min per IP, default 60). Both clamp to safe ranges and pre-fill with existing defaults.
Changed
- Block text extraction rewritten — the Skip Embedded Content path now extracts text directly from the block tree (
innerHTMLrecursion) instead of callingrender_block()+the_content. Fixes a regression where paragraphs and headings were lost, leaving only the post title. - Raw PCM synthesis streams to temp file — Piper's stdout is now streamed in 64KB chunks to a temp file instead of loaded entirely into memory via
stream_get_contents. Avoids 25+ MB peaks on long posts.
Security
- REST endpoints —
rest_status,rest_generate, andrest_remove_audionow verify per-post ownership (current_user_can('edit_post', $post_id)) in addition to theedit_postscapability gate. - Shell escaping — all
escapeshellcmdcalls replaced withescapeshellargfor binary paths across all three synthesis modes andrun_help(). Zeroescapeshellcmdremaining. - Error capture —
error_clear_last()called before every@-suppressed filesystem operation that's followed bylog_last_error(), making error attribution deterministic. - CSS sanitization — custom CSS now strips lines containing
url(),expression(),@import,behavior:, and-moz-bindingin addition to HTML tag removal. - Rate limiting — audio proxy endpoint now rate-limited per IP via transient (configurable in Performance tab).
- Synthesis mutex — only one Piper process per cache key at a time; concurrent requests for the same content receive a "generation already in progress" response.
- Auto-generate deferred —
maybe_auto_generatenow schedules awp_schedule_single_eventcron job instead of running Piper synchronously on publish, preventing browser hangs. - Log file permissions —
chmod 0600applied after every log write, restricting read to the file owner on servers without.htaccessprotection. - REST models endpoint — absolute filesystem paths stripped from the response; only the model basename is exposed.
- Shutdown hooks —
stream_file()now firesdo_action('shutdown')beforedie(), allowing WordPress cron spawners and cleanup callbacks to execute.
[0.5.0] — 2026-05-09
Added
set_time_limit()guard on all Piper synthesis calls — bumps the PHP execution time limit to 300s duringproc_open, then restores it. Preventsmax_execution_timekills on long posts.- Logger error fallback — when the dedicated
piperless.logcan't be written (unwritable uploads directory), log entries fall through to PHP'serror_log(), ensuring diagnostics are never completely lost. log_last_error()helper — captureserror_get_last()after@-suppressed filesystem operations (failedfile_put_contents,mkdir,file_get_contents) and writes the OS-level error to the log. Wired intoCache_ManagerandPipermodel validation.
Changed
scan_models()cached per request — the models directory is now scanned once and the result reused across admin page load (previously 3×), model preview table, and JS localisation.
[0.4.0] — 2026-05-09
Added
- Binary pre-flight check — on every admin page load, the plugin checks whether the Piper binary is configured, exists, and is executable using only filesystem calls (no binary invocation, no timeout risk). A dismissible WordPress admin notice warns the user with a specific message for each state: not configured, not found, or not executable.
[0.3.1] — 2026-05-09
Changed
- Logging Level moved from Content tab to Logs tab — now appears as the first setting above the log viewer, with its own Save button.
[0.3.0] — 2026-05-09
Added
- Skip Embedded Content setting — when enabled and no manual excerpt exists, Gutenberg embed blocks (core/embed, core-embed/*, extensible via
piperless_skip_blocksfilter) are stripped from the body before text extraction. - nl_NL (Dutch) translation — full locale support with 84 translated strings, compiled .po/.mo.
- Translation toolchain —
tools/pot2json.sh,tools/sync-translations.sh,tools/json2po.sh,tools/lock-translations.sh, andMakefiletargets for extracting, syncing, converting, and locking per-locale JSON translation files.
Changed
- Admin panel restructured — the single Configuration tab is now three: Piper (TTS engine settings), Content (auto-generate, skip embeds, logging), and Styling (player appearance/placement). All three share one form.
- Model preview table and player preview moved within their respective tabs.
[1.1.6] — 2026-05-08
Fixed
- Model enumeration regression from 1.1.5: models without a
.onnx.jsoncompanion file are no longer excluded. Only models where the.jsonexists but is broken (LFS pointer, empty, malformed JSON) are filtered out. Missing.jsonis allowed since native Piper reads config from the.onnxfile itself.
[1.1.5] — 2026-05-08
Fixed
scan_models()now validates each model's.onnx.jsoncompanion file before listing it. Detects: missing JSON, empty files, Git LFS pointer files (common on Hugging Face without git-lfs), and malformed JSON. Models with broken configs are excluded from the UI and logged with specific warnings in the Debug Log.
[1.1.4] — 2026-05-08
Fixed
- Quality tier detection expanded to recognize
lite,small,fast,qualityin addition tolow/medium/high. Filterable viapiperless_quality_tiers. scan_models()now warns in the Debug Log when a model's companion.onnx.jsonfile is missing or empty — the leading cause ofJSONDecodeErrorwith the Python Piper wheel.- Default Quality dropdown in admin now includes Lite and Small options.
[1.1.3] — 2026-05-08
Added
- open_basedir detection: all filesystem checks (binary path, models directory) now detect when the path is outside PHP's
open_basedirrestriction and show a clear, actionable error message. The Piper Configuration section header displays the current open_basedir status. - Admin page load now writes an INFO-level log entry, so the Debug Log always shows at least one entry when the page is accessed — proving the logger works.
Changed
scan_models()logs a WARNING when the models directory is outside open_basedir.- Test Connection response now includes
open_basedirinfo.
[1.1.2] — 2026-05-08
Fixed
- Debug Log viewer was non-functional — it called the wrong AJAX endpoint and never displayed log data. Now renders server-side on page load (
tail 50) and refreshes via the newpiperless_log_tailAJAX handler. - Test Connection error for missing binary now includes the exact path that was checked, making misconfiguration immediately visible.
[1.1.1] — 2026-05-08
Fixed
scan_models()now wraps the recursive directory iterator in try-catch and logs the scanned directory path + file count. Permission errors or unreadable subdirectories no longer silently return an empty list — the error appears in the Debug Log.- Switched from
SplFileInfo::getExtension()topathinfo(…, PATHINFO_EXTENSION)for broader PHP compatibility with the recursive iterator. - Added
FOLLOW_SYMLINKSflag so symlinked model directories are followed.
[1.1.0] — 2026-05-08
Added
- Positional wrapper mode — for custom scripts like
/opt/bin/run-piperthat takebinary model_path "text"as positional arguments and writeoutput.wavto CWD. Choose "Positional" in the new Piper Interface Mode setting. piper_interfacesetting (Auto-detect / Standard / Positional) — overrides auto-detection for non-standard wrappers. Test Connection reports the effective mode.
Changed
scan_models()now scans the models directory recursively usingRecursiveDirectoryIterator, so models nested in subdirectories are discovered.- The Default Voice text field is now a dropdown populated from discovered model voice names, with an "— Use first available —" empty option.
- Default
models_directorychanged to/opt/var/piper/voices.
[1.0.4] — 2026-05-08
Fixed
- Test Connection no longer treats a non-zero
--helpexit as a hard failure. Python wheel wrappers that don't implement--helpnow report OK (binary found) with the detected output mode. The--helpinvocation is also cached sodetect_output_mode()andtest()share a single call.
[1.0.3] — 2026-05-08
Added
- Auto-detection of Piper output mode:
Piperclass now probes--helpto determine whether the binary supports--output-raw(native CLI) or--output_file(Python wheel wrappers like/opt/bin/run-piper). Falls back to file mode for unknown wrappers. Test Connection button now shows the detected mode.
Changed
- Default Piper binary path is now empty (force user to configure), with an updated description mentioning Python wheel wrappers.
[1.0.2] — 2026-05-08
Fixed
- Removed invalid module-level
useDispatch()call in gutenberg.js that crashed the script with "Invalid hook call", preventing the Gutenberg sidebar from appearing at all.createNoticewas already correctly obtained inside the component.
[1.0.1] — 2026-05-08
Fixed
- Autoloader now converts underscores to hyphens in class names, fixing "Class 'Piperless\Cache_Manager' not found" fatal error on plugin activation.
[1.0.0] — 2024-01-01
Added
- Piper TTS integration via CLI wrapper (
Piperclass) with proc_open, raw PCM → WAV conversion, length-scale quality control, and voice model scanner. - Audio transcript generation pipeline (
Transcriberclass): excerpt-first text extraction, SHA-256 content caching, WAV duration parsing from RIFF headers. - Hash-based audio cache (
Cache_Manager) inwp-content/uploads/piperless/with orphan detection (cross-referenced post meta), flush, and stats. - PSR-3-style file logger (
Logger) with 8 severity levels, WordPress debug.log integration, and dedicatedpiperless.log. - Admin settings page under Settings → Piperless with three sections:
- Piper Configuration — binary path, models directory, default voice/language/quality, logging level, and Test Connection button.
- Voice Model Previews — discovered models table with per-model audio preview (play/pause, cached per model + quality).
- Audio Player Settings — 3 preset themes (Classic, Modern Dark, Minimal) + Custom CSS, player placement (before/after/manual), duration toggle.
- Player Preview — live theme preview that swaps on dropdown change.
- Cache Management — clear orphaned audio, flush entire cache, live stats.
- Debug Log — log viewer with refresh and clear.
- Gutenberg PluginSidebar with Generate/Regenerate Audio button, per-post voice/language/quality overrides (SelectControls), audio preview player, and remove button.
- Custom HTML5 audio player (zero-dependency JS) with play/pause SVG toggle, click-to-seek progress bar, buffer indicator, duration display (mm:ss), touch support, MutationObserver for dynamic content, error state handling, and multi-instance support.
- REST API endpoints: POST generate, GET status, GET models, DELETE audio.
- Shortcode:
[piperless_player post_id="123"]. the_contentfilter auto-placement (before/after/manual).build.sh— reads version from plugin header, createspiperless-X.Y.Z.zip.uninstall.php— removes all options, post meta, cached files, and scheduled hooks.- Full i18n support with
piperless.pot(100+ strings). - Activation version checks (WP 6.0+, PHP 8.0+) with user-facing error messages.
- Security: ABSPATH guards,
index.phpin all directories,.htaccessdeny in cache dir, nonce verification on all AJAX/REST endpoints, capability checks, input sanitization, output escaping.