Releases: sfox38/TikTokTTS
Release list
TikTokTTS v1.2.5
v1.2.5
- Fix: Selecting the
(loading...)placeholder in the device dropdown (shown when no media players are available yet) no longer crashes theselect.select_optionservice call with anIndexError - Fix: Calling
tiktoktts.set_random_voicesafter the last config entry was unloaded (e.g. the entry is disabled) no longer crashes with aKeyError; the pool is still validated and persisted - Refactor: The shared select/text/button entities are now forwarded by a single owning config entry instead of every entry, deleting the per-platform singleton guards and per-entry bookkeeping flags. Re-homing the shared entities to a surviving entry (when the owner is unloaded while another entry remains) now runs as a tracked Home Assistant task that is skipped during shutdown and no-ops when the owner was merely reloaded - replacing a raw
call_soonhook that could race HA shutdown - Refactor: The language and voice dropdowns no longer hold direct references to each other. They coordinate through dispatcher signals plus one
hass.datakey, which removes the startup readiness event, its 10-second timeout, and the entity object previously stashed inhass.datafor the service handler. Behaviour (restore on restart, default-voice preservation, random-voice handling) is unchanged and covered by tests - Perf: Direct API mode now remembers the endpoint that last served a request and tries it first, so when the configured endpoint is down, a multi-chunk message no longer re-probes it (with full retries) for every chunk
- Perf: Direct API mode now has an overall per-message deadline (120 s) so a long message during an outage cannot stall a
tts.speakcall for many minutes while every chunk walks the whole endpoint fallback list - Perf: The device dropdown's media-player discovery now filters state events inside Home Assistant's event dispatch (
event_filter), so routine attribute updates from active players never wake the integration at all - Perf: Static assets (card JS, icon) are now served with cache headers; the card URL already carries a
?v=<version>cache-buster so upgrades still load the new card immediately - Security: The TikTok
session_idfield in the setup and options forms is now a masked password input instead of plain text - Fix: Connection-test responses in the config flow are now properly released via context managers, and unexpected connection-test failures are logged with a traceback instead of being silently reported as "unknown error"
- Meta:
manifest.jsonnow declaresintegration_type: serviceandiot_class: cloud_push(matching core TTS integrations) - Tests: 133 tests (up from 118); new coverage for the two crash fixes above, endpoint memoization, the per-message deadline, device selection and restore-wait behaviour, Speak-button guard paths, the options-save reload cycle, and config-flow unknown-error branches. The frontend tests now read the version from
manifest.jsoninstead of hardcoding it, so version bumps no longer break the suite - CI: Added
ruff checkandruff format --checkto the test workflow; the codebase is now Ruff-formatted
v1.2.4
- Fix: Dashboard card no longer crashes with
the name "tiktoktts-card" has already been used with this registryafter upgrading. Older versions registered the card as a Lovelace dashboard resource; the current version registers it via the frontend module API, so on upgrade both could load the card and define the element twice. The card now guards against double-registration. If you upgraded, you can also remove the leftover/tiktoktts/tiktoktts-card.jsentry under Settings -> Dashboards -> Resources.
v1.2.2
Changelog
v1.2.2
- Fix: Lovelace card resource is now removed only on true integration deletion, not on every reload or options save (was wiping the card resource on every settings change)
- Fix: Language-aware voice fallback - if the configured default voice is not available for the requested language, the integration now correctly falls back to the first voice of that language (matches the documented behaviour)
- Fix: Direct API retry tuning - the configured endpoint gets 3 attempts × 20 s; each automatic fallback endpoint gets 1 attempt × 10 s (was using the same retry count for all endpoints)
- Fix: All failure paths now raise
HomeAssistantErrorso errors surface in the HA UI and automation traces instead of silently returning empty audio - Fix:
aiohttpsessions are now properly closed viaasync withcontext managers (previously leaked connections on errors) - Fix: Options flow now saves sanitized values (trailing slashes stripped from endpoint, whitespace stripped from session_id) instead of raw user input
- Fix:
async_delete_issueis now called after a successful direct-API options save, clearing the expired-session repair issue - Fix: Voice dropdown no longer resets on every random-voice pool save - only resets when the language actually changes
- Fix: Restored voice is now correctly re-applied after restart even when the restored language differs from the startup default
- Fix:
button.tiktoktts_speaknow guards against speaking the literal strings "unavailable" or "unknown" - Fix:
ConfigEntryStateimport moved to module level in button.py - Fix: Redundant
native_valueproperty removed fromMessageTextEntity(base class handles_attr_native_value) - Fix: JS card - Speak button now cancels any pending debounce and flushes the current message to HA before pressing the button, preventing a race where the last typed characters could be missed
- Fix:
services.yaml-languagesfield now uses a proper multi-select selector with all 16 language codes instead of a bareobjectselector - Fix: Dead
"unknown"error key removed fromstrings.jsonandtranslations/en.json - Fix: Lovelace resource URL match tightened to exact path equality (was
startsWith, could match unrelated resources) - Fix:
manifest.jsonversion now read lazily via executor job infrontend/__init__.pyto avoid blocking I/O on the event loop at import time - Docs: README corrected - cache limitation for
voice: randomin automations, chunking behaviour, proxy privacy note, proxy-wins-over-direct note, GitHub capitalisation, image tag attributes
v1.2.1
v1.2.0
v1.2
New Feature: Random Voice
Configure a pool of language groups and the integration picks a different voice on every tts.speak call.
Setup: Press the 🎲 button next to Speak in the dashboard card, tick the language groups you want, press "Save and close". Then select 🎲 Random Voice from the language dropdown.
Automations: Pass voice: random in options:
options:
voice: randomA fresh voice is picked on every call from both the dashboard card and automation callers. The pool persists across restarts and is independent of config entries.
Bug Fixes
Switching connection modes (proxy/direct) now works correctly. Disabling or deleting one connection mode while the other is active no longer destroys the shared dashboard entities (language, voice, device, message, speak button). Those entities now survive and transfer cleanly to the remaining connection entry.
Speak button no longer targets a stale TTS entity. After removing one connection mode, the button was staying locked to the old entity. It now checks loaded config entry states rather than potentially stale hass.states.
Message length. HA's text entity enforces a 255 character limit with a colour-coded live counter.
Language dropdown icon was rendering incorrectly. Replaced with a clean MDI translate glyph.
Random Voice state restore on restart was partially broken - the language dropdown restored correctly but the voice dropdown showed a real voice name instead of "Random Voice". Both now restore correctly.
Dashboard Card Changes
- 🎲 dice button added alongside Speak button to open the Random Voice settings panel.
- Speak button no longer full width.
- Status feedback line removed as it was unnecessary.
- Message textarea capped at 255 characters with a live counter.
Internal
- Random voice pool stored via HA's
Storeclass (.storage/tiktoktts_random_voices.json) - the correct HA-idiomatic approach for user preference data independent of config entries. _RandomVoiceAwareCachedict subclass replaces HA's TTSSpeechManager.mem_cacheto force cache misses forvoice=randomcalls, ensuring a fresh voice is picked every time from any call source.services.yamladded to suppress HA startup log warning about undescribed services.- Shared platforms (select, text, button) now tracked per config entry to prevent the
"already been setup"error when switching between connection modes.
v1.1
New Features
- New Voices: Now has over 100 unique voices, in multiple languages
- Additional endpoints: For Direct API usage
- Custom Dashboard Card: Use this card to easily preview voices or to send impromptu messages around your home.
v1.0
This is a modernized fork of the original philipp-luettecke/tiktoktts integration, updated for current Home Assistant versions with significant new features and bug fixes.
Important
If you are upgrading from the original integration, please read the Upgrading from the Original Integration section in the README before installing. A clean removal of the old integration is required.
Bug Fixes
- Fixed
PLATFORMSdeclaration: was a single value instead of a list, causing the integration to fail silently on modern HA versions - Fixed missing commas in
SUPPORTED_VOICES: several singing/expressive voice entries were being silently concatenated into invalid strings by Python - Fixed default language and voice: changed from German (
de/de_001) to English US (en_us/en_us_001) - Fixed broken GitHub URL in original
en.json(pointed to wrong repository)
New Features
- UI config flow: integration is now configured via Settings -> Devices & Services, no
configuration.yamlediting required - Live connection test: endpoint and session ID are validated before saving, so failures are caught at setup time
- Options flow: change endpoint, voice, or session ID at any time via the gear icon, changes take effect immediately without a restart
- Direct TikTok API mode: optional alternative to the proxy that calls TikTok's internal API directly using a browser session cookie, with automatic fallback across 4 known regional endpoints
- Automatic text chunking: direct mode splits long messages at sentence and word boundaries to respect TikTok's 200-character per-request limit
- Retry logic: both proxy and direct modes retry failed requests up to 2 times with backoff before giving up
- Stable entity ID: always
tts.tiktoktts_proxyortts.tiktoktts_direct, no longer a random UUID
Technical / Internal Changes
- Migrated from legacy
Providerbase class to modernTextToSpeechEntity - Replaced deprecated
async_timeoutlibrary with Python's built-inasyncio.timeout - All hardcoded strings (API paths, field names, status codes, retry config) moved to
const.py - Config stored entirely in
entry.data- single source of truth for both setup and options flows - Full developer documentation added to all files
Credits
| Role | Person / Project |
|---|---|
| Original integration | philipp-luettecke/tiktoktts |
| Community TTS proxy | Weilbyte/tiktok-tts |
| Voice list reference | oscie57/tiktok-voice |
Version 1.1
TikTok TTS: v1.1
✨ New Features
- New Voices: Now has over 100 unique voices, in multiple languages
- Additional endpoints: For Direct API usage
- Custom Dashboard Card: Use this card to easily preview voices or to send impromptu messages around your home.
v1.0.0
This is a modernized fork of the original philipp-luettecke/tiktoktts integration, updated for current Home Assistant versions with significant new features and bug fixes.
Important
If you are upgrading from the original integration, please read the Upgrading from the Original Integration section in the README before installing. A clean removal of the old integration is required.
🐛 Bug Fixes
- Fixed
PLATFORMSdeclaration: was a single value instead of a list, causing the integration to fail silently on modern HA versions - Fixed missing commas in
SUPPORTED_VOICES: several singing/expressive voice entries were being silently concatenated into invalid strings by Python - Fixed default language and voice: changed from German (
de/de_001) to English US (en_us/en_us_001) - Fixed broken GitHub URL in original
en.json(pointed to wrong repository)
✨ New Features
- UI config flow: integration is now configured via Settings -> Devices & Services, no
configuration.yamlediting required - Live connection test: endpoint and session ID are validated before saving, so failures are caught at setup time
- Options flow: change endpoint, voice, or session ID at any time via the gear icon, changes take effect immediately without a restart
- Direct TikTok API mode: optional alternative to the proxy that calls TikTok's internal API directly using a browser session cookie, with automatic fallback across 4 known regional endpoints
- Automatic text chunking: direct mode splits long messages at sentence and word boundaries to respect TikTok's 200-character per-request limit
- Retry logic: both proxy and direct modes retry failed requests up to 2 times with backoff before giving up
- Stable entity ID: always
tts.tiktoktts_proxyortts.tiktoktts_direct, no longer a random UUID
🔧 Technical / Internal Changes
- Migrated from legacy
Providerbase class to modernTextToSpeechEntity - Replaced deprecated
async_timeoutlibrary with Python's built-inasyncio.timeout - All hardcoded strings (API paths, field names, status codes, retry config) moved to
const.py - Config stored entirely in
entry.data- single source of truth for both setup and options flows - Full developer documentation added to all files
Credits
| Role | Person / Project |
|---|---|
| Original integration | philipp-luettecke/tiktoktts |
| Community TTS proxy | Weilbyte/tiktok-tts |
| Voice list reference | oscie57/tiktok-voice |
TikTok TTS v1.0
TikTok TTS: v1.0.0
This is a modernized fork of the original philipp-luettecke/tiktoktts integration, updated for current Home Assistant versions with significant new features and bug fixes.
Important
If you are upgrading from the original integration, please read the Upgrading from the Original Integration section in the README before installing. A clean removal of the old integration is required.
🐛 Bug Fixes
- Fixed
PLATFORMSdeclaration: was a single value instead of a list, causing the integration to fail silently on modern HA versions - Fixed missing commas in
SUPPORTED_VOICES: several singing/expressive voice entries were being silently concatenated into invalid strings by Python - Fixed default language and voice: changed from German (
de/de_001) to English US (en_us/en_us_001) - Fixed broken GitHub URL in original
en.json(pointed to wrong repository)
✨ New Features
- UI config flow: integration is now configured via Settings -> Devices & Services, no
configuration.yamlediting required - Live connection test: endpoint and session ID are validated before saving, so failures are caught at setup time
- Options flow: change endpoint, voice, or session ID at any time via the gear icon, changes take effect immediately without a restart
- Direct TikTok API mode: optional alternative to the proxy that calls TikTok's internal API directly using a browser session cookie, with automatic fallback across 4 known regional endpoints
- Automatic text chunking: direct mode splits long messages at sentence and word boundaries to respect TikTok's 200-character per-request limit
- Retry logic: both proxy and direct modes retry failed requests up to 2 times with backoff before giving up
- Stable entity ID: always
tts.tiktoktts_proxyortts.tiktoktts_direct, no longer a random UUID
🔧 Technical / Internal Changes
- Migrated from legacy
Providerbase class to modernTextToSpeechEntity - Replaced deprecated
async_timeoutlibrary with Python's built-inasyncio.timeout - All hardcoded strings (API paths, field names, status codes, retry config) moved to
const.py - Config stored entirely in
entry.data- single source of truth for both setup and options flows - Full developer documentation added to all files
Credits
| Role | Person / Project |
|---|---|
| Original integration | philipp-luettecke/tiktoktts |
| Community TTS proxy | Weilbyte/tiktok-tts |
| Voice list reference | oscie57/tiktok-voice |

