@@ -12307,7 +12307,7 @@ class FastSearchCard extends HTMLElement {
1230712307 }
1230812308
1230912309 async speakTTS(text, entityId) {
12310- // 🛡️ Race Condition Protection
12310+ // 🛡️ Race Condition Protection (bleibt unverändert)
1231112311 if (this.isTTSActive) {
1231212312 console.log('⚠️ TTS bereits aktiv, ignoriere neuen Aufruf');
1231312313 return false;
@@ -12323,54 +12323,70 @@ class FastSearchCard extends HTMLElement {
1232312323
1232412324 try {
1232512325 console.log(`🗣️ Speaking: "${text}" on ${entityId}`);
12326-
12327- // 🔍 Erweiterte Player-State-Erkennung
12326+
12327+ // Player-Status speichern (bleibt unverändert)
1232812328 const playerState = await this.getEnhancedPlayerState(entityId);
12329- const wasPlaying = playerState.isActuallyPlaying;
12330-
12331- console.log(`🎵 Enhanced player analysis:`, playerState);
12332-
12333- // 💾 Status für Auto-Resume speichern
12334- this.ttsPlayerWasPlaying = wasPlaying ? entityId : null;
12335- this.ttsStartedAt = Date.now();
12336-
12337- // 💾 VOLLSTÄNDIGEN Player-Zustand speichern
12338- if (wasPlaying) {
12329+ if (playerState.isActuallyPlaying) {
12330+ this.ttsPlayerWasPlaying = entityId;
1233912331 const state = this._hass.states[entityId];
1234012332 this.savedPlayerContext = {
1234112333 entityId: entityId,
1234212334 mediaContentId: state.attributes.media_content_id,
1234312335 mediaContentType: state.attributes.media_content_type || 'music',
1234412336 mediaPosition: state.attributes.media_position || 0,
12345- volumeLevel: state.attributes.volume_level,
12346- mediaTitle: state.attributes.media_title,
12347- mediaArtist: state.attributes.media_artist
1234812337 };
12349- console.log('💾 Saved player context:', this.savedPlayerContext);
12350- }
12351-
12352- // ⏸️ Intelligentes Pausieren
12353- if (wasPlaying) {
12338+ console.log('💾 Player-Kontext gespeichert:', this.savedPlayerContext);
1235412339 await this.smartPausePlayer(entityId);
1235512340 }
12356-
12357- // 🎤 TTS mit verbessertem Fallback-System
12341+
12342+ // Button-Status aktualisieren (bleibt unverändert)
1235812343 this.updateTTSButtonState('speaking');
12344+
12345+ // TTS ausführen (bleibt unverändert)
1235912346 await this.executeSmartTTS(text, entityId);
12347+
12348+ // --- NEUE, ROBUSTERE LOGIK ---
12349+ // Berechne eine dynamische Wartezeit basierend auf der Textlänge.
12350+ // Annahme: ca. 80ms pro Zeichen + 1.5 Sekunden Puffer.
12351+ const calculatedDelay = text.length * 80 + 1500;
12352+ console.log(`⏳ Berechnete TTS-Dauer: ${calculatedDelay}ms`);
12353+
12354+ // Starte den Timer zur Wiederherstellung
12355+ this.ttsResumeTimeout = setTimeout(() => {
12356+ console.log('⏰ Timer abgelaufen, starte Wiederherstellung.');
12357+ this.resumePlayback();
12358+ }, calculatedDelay);
12359+ // --- ENDE NEUE LOGIK ---
1236012360
12361- // 🎧 Event-basierte TTS-Überwachung (ersetzt Timer)
12362- await this.startTTSMonitoring(entityId);
12361+ // --- ENTFERNT ---
12362+ // Die alte, unzuverlässige Überwachung wird entfernt.
12363+ // await this.startTTSMonitoring(entityId);
1236312364
1236412365 return true;
12365-
12366+
1236612367 } catch (error) {
1236712368 console.error('❌ TTS Error:', error);
1236812369 this.updateTTSButtonState('error');
12369- await this.cleanupTTSState();
12370+ // Im Fehlerfall sofort aufräumen
12371+ clearTimeout(this.ttsResumeTimeout);
12372+ await this.finalizeTTSProcess();
1237012373 return false;
1237112374 }
1237212375 }
1237312376
12377+ // in der FastSearchCard-Klasse
12378+
12379+ async resumePlayback() {
12380+ console.log('▶️ Starte Musik-Wiederherstellung...');
12381+ if (this.ttsPlayerWasPlaying && this.savedPlayerContext) {
12382+ await this.restorePlayerContext();
12383+ } else {
12384+ console.log('🤷 Keine Musik zum Wiederherstellen.');
12385+ }
12386+ // Nach der Wiederherstellung den Prozess finalisieren
12387+ await this.finalizeTTSProcess();
12388+ }
12389+
1237412390 // 🔍 ERWEITERTE PLAYER-STATE-ERKENNUNG
1237512391 async getEnhancedPlayerState(entityId) {
1237612392 const state = this._hass.states[entityId];
@@ -12525,124 +12541,30 @@ class FastSearchCard extends HTMLElement {
1252512541 }
1252612542 }
1252712543
12528- async startTTSMonitoring(entityId) {
12529- console.log('🎧 Starting TTS monitoring...');
12530-
12531- let ttsStarted = false;
12532- let lastPosition = null;
12533- let lastMediaId = null;
12534- let positionStableCount = 0;
12535- let checksWithoutChange = 0;
12536-
12537- // Speichere initiale Werte
12538- const initialState = this._hass.states[entityId];
12539- const initialMediaId = initialState?.attributes?.media_content_id;
12540-
12541- this.ttsMonitorInterval = setInterval(async () => {
12542- const currentState = this._hass.states[entityId];
12543- if (!currentState) return;
12544-
12545- const currentPosition = currentState.attributes?.media_position;
12546- const currentMediaId = currentState.attributes?.media_content_id;
12547- const isPlaying = currentState.state === 'playing';
12548-
12549- // TTS Start erkennen
12550- if (!ttsStarted && isPlaying) {
12551- ttsStarted = true;
12552- console.log('🎤 TTS started');
12553- checksWithoutChange = 0;
12554- }
12555-
12556- // TTS Ende erkennen durch verschiedene Methoden:
12557- if (ttsStarted) {
12558- // Methode 1: Player ist nicht mehr playing
12559- if (currentState.state !== 'playing') {
12560- console.log('🎉 TTS completed - player stopped');
12561- clearInterval(this.ttsMonitorInterval);
12562- this.ttsMonitorInterval = null;
12563- await this.restorePlayerContext();
12564- await this.finalizeTTSProcess(entityId);
12565- return;
12566- }
12567-
12568- // Methode 2: Media ID hat sich geändert (zurück zur Original-Musik)
12569- if (currentMediaId && currentMediaId !== lastMediaId && currentMediaId === this.savedPlayerContext?.mediaContentId) {
12570- console.log('🎉 TTS completed - original media restored');
12571- clearInterval(this.ttsMonitorInterval);
12572- this.ttsMonitorInterval = null;
12573- await this.finalizeTTSProcess(entityId);
12574- return;
12575- }
12576-
12577- // Methode 3: Position bewegt sich nicht mehr (TTS fertig, aber Player noch "playing")
12578- if (currentPosition !== undefined && currentPosition !== null) {
12579- if (currentPosition === lastPosition) {
12580- positionStableCount++;
12581- if (positionStableCount > 10) { // 1 Sekunde keine Bewegung
12582- console.log('🎉 TTS completed - position stable');
12583- clearInterval(this.ttsMonitorInterval);
12584- this.ttsMonitorInterval = null;
12585- await this.restorePlayerContext();
12586- await this.finalizeTTSProcess(entityId);
12587- return;
12588- }
12589- } else {
12590- positionStableCount = 0;
12591- }
12592- }
12593-
12594- // Methode 4: Keine Attribute-Änderungen für längere Zeit
12595- const hasChanges = JSON.stringify(currentState.attributes) !== JSON.stringify(initialState.attributes);
12596- if (!hasChanges) {
12597- checksWithoutChange++;
12598- if (checksWithoutChange > 20) { // 2 Sekunden keine Änderungen
12599- console.log('🎉 TTS completed - no attribute changes');
12600- clearInterval(this.ttsMonitorInterval);
12601- this.ttsMonitorInterval = null;
12602- await this.restorePlayerContext();
12603- await this.finalizeTTSProcess(entityId);
12604- return;
12605- }
12606- } else {
12607- checksWithoutChange = 0;
12608- }
12609- }
12610-
12611- lastPosition = currentPosition;
12612- lastMediaId = currentMediaId;
12613-
12614- }, 100); // Alle 100ms prüfen
12615-
12616- // Kürzeres Sicherheits-Timeout - 10 Sekunden sollten reichen
12617- setTimeout(() => {
12618- if (this.ttsMonitorInterval) {
12619- console.log('⚠️ TTS monitoring timeout (10s)');
12620- clearInterval(this.ttsMonitorInterval);
12621- this.ttsMonitorInterval = null;
12622- this.restorePlayerContext();
12623- this.finalizeTTSProcess(entityId);
12624- }
12625- }, 10000); // Reduziert von 30 auf 10 Sekunden
12626- }
12627-
12628- // 🏁 TTS-PROZESS FINALISIEREN
12629- async finalizeTTSProcess(entityId) {
12544+ // in der FastSearchCard-Klasse
12545+
12546+ async finalizeTTSProcess() {
1263012547 console.log('🏁 Finalizing TTS process...');
1263112548
12632- // Aufräumen
12549+ // Aufräumen (bleibt unverändert)
1263312550 await this.cleanupTTSState();
1263412551
12635- // Button zurücksetzen
12552+ // Button zurücksetzen (bleibt unverändert)
1263612553 this.updateTTSButtonState('ready');
1263712554
12638- // Monitor-Interval löschen
12639- if (this.ttsMonitorInterval) {
12640- clearInterval(this.ttsMonitorInterval);
12641- this.ttsMonitorInterval = null;
12642- }
12555+ // Timer-Timeout sicherheitshalber löschen
12556+ clearTimeout(this.ttsResumeTimeout);
12557+ this.ttsResumeTimeout = null;
12558+
12559+ // --- ENTFERNT ---
12560+ // Das Monitor-Interval existiert nicht mehr.
12561+ // if (this.ttsMonitorInterval) {
12562+ // clearInterval(this.ttsMonitorInterval);
12563+ // this.ttsMonitorInterval = null;
12564+ // }
1264312565
1264412566 console.log('✅ TTS process finalized');
12645- }
12567+ }
1264612568
1264712569
1264812570 // 🧹 CLEANUP STATE
0 commit comments