@@ -355,6 +355,8 @@ class FastSearchCard extends HTMLElement {
355355 this.isTTSActive = false; // Verhindert überlappende TTS-Calls
356356 this.ttsAbortController = null; // Ermöglicht TTS-Abbruch
357357 this.ttsResumeTimeout = null;
358+ this.savedPlayerContext = null; // 🆕 Für Player-Kontext speichern
359+ this.ttsMonitorInterval = null; // 🆕 Für Event-Monitoring
358360
359361 }
360362
@@ -12331,6 +12333,21 @@ class FastSearchCard extends HTMLElement {
1233112333 // 💾 Status für Auto-Resume speichern
1233212334 this.ttsPlayerWasPlaying = wasPlaying ? entityId : null;
1233312335 this.ttsStartedAt = Date.now();
12336+
12337+ // 💾 VOLLSTÄNDIGEN Player-Zustand speichern
12338+ if (wasPlaying) {
12339+ const state = this._hass.states[entityId];
12340+ this.savedPlayerContext = {
12341+ entityId: entityId,
12342+ mediaContentId: state.attributes.media_content_id,
12343+ mediaContentType: state.attributes.media_content_type || 'music',
12344+ mediaPosition: state.attributes.media_position || 0,
12345+ volumeLevel: state.attributes.volume_level,
12346+ mediaTitle: state.attributes.media_title,
12347+ mediaArtist: state.attributes.media_artist
12348+ };
12349+ console.log('💾 Saved player context:', this.savedPlayerContext);
12350+ }
1233412351
1233512352 // ⏸️ Intelligentes Pausieren
1233612353 if (wasPlaying) {
@@ -12341,8 +12358,8 @@ class FastSearchCard extends HTMLElement {
1234112358 this.updateTTSButtonState('speaking');
1234212359 await this.executeSmartTTS(text, entityId);
1234312360
12344- // ⏰ Intelligente Auto-Resume-Logik
12345- await this.scheduleSmartResume(text, entityId);
12361+ // 🎧 Event-basierte TTS-Überwachung (ersetzt Timer)
12362+ await this.startTTSMonitoring( entityId);
1234612363
1234712364 return true;
1234812365
@@ -12354,24 +12371,6 @@ class FastSearchCard extends HTMLElement {
1235412371 }
1235512372 }
1235612373
12357- // ⏰ INTELLIGENTE AUTO-RESUME-LOGIK
12358- async scheduleSmartResume(text, entityId) {
12359- if (!this.ttsPlayerWasPlaying) return;
12360-
12361- // 🕒 Verbesserte Duration-Berechnung
12362- const duration = this.calculateEnhancedTTSDuration(text);
12363-
12364- console.log(`⏰ Scheduling auto-resume in ${duration}ms`);
12365-
12366- // 🎯 Timer-basierte Resume-Logik
12367- const resumeTimeout = setTimeout(async () => {
12368- await this.attemptSmartResume(entityId);
12369- }, duration);
12370-
12371- // 🔄 Speichere Timeout für möglichen Abbruch
12372- this.ttsResumeTimeout = resumeTimeout;
12373- }
12374-
1237512374 // 🔍 ERWEITERTE PLAYER-STATE-ERKENNUNG
1237612375 async getEnhancedPlayerState(entityId) {
1237712376 const state = this._hass.states[entityId];
@@ -12494,16 +12493,7 @@ class FastSearchCard extends HTMLElement {
1249412493 message: text
1249512494 });
1249612495
12497- console.log(`✅ TTS successful with: ${service}`);
12498-
12499- // 🆕 HINZUFÜGEN: Expliziter Play-Befehl nach TTS
12500- console.log(`▶️ Starting TTS playback...`);
12501- await new Promise(resolve => setTimeout(resolve, 300)); // Kurz warten
12502- await this._hass.callService('media_player', 'media_play', {
12503- entity_id: entityId
12504- });
12505- console.log(`🎵 TTS playback started`);
12506-
12496+ console.log(`✅ TTS successful with: ${service}`);
1250712497 return service; // Return successful service
1250812498
1250912499 } catch (error) {
@@ -12517,47 +12507,123 @@ class FastSearchCard extends HTMLElement {
1251712507 }
1251812508 }
1251912509
12520- // 🔄 SMART RESUME ATTEMPT
12521- async attemptSmartResume(entityId) {
12522- if (!this.ttsPlayerWasPlaying || this.ttsPlayerWasPlaying !== entityId) {
12523- console.log('⏭️ No auto-resume needed');
12524- await this.cleanupTTSState(); // 🆕 HINZUGEFÜGT
12525- this.updateTTSButtonState('ready'); // 🆕 HINZUGEFÜGT
12526- return;
12527- }
12528-
12529- const ttsAge = Date.now() - (this.ttsStartedAt || 0);
12530-
12531- // 🚫 Sicherheits-Checks
12532- if (ttsAge > 15000) { // 🆕 War: 60000 - GEÄNDERT zu 15 Sekunden
12533- console.log('⏭️ Skipping auto-resume (too old)');
12534- await this.cleanupTTSState();
12535- this.updateTTSButtonState('ready');
12536- return;
12510+ // 🔄 RESTORE PLAYER CONTEXT (Event-basierte Wiederherstellung)
12511+ async restorePlayerContext() {
12512+ if (!this.savedPlayerContext) {
12513+ console.log('⏭️ No saved player context to restore');
12514+ return false;
1253712515 }
1253812516
12539- // 🔍 Player-Status Double-Check
12540- const currentState = this._hass.states[entityId];
12541- if (currentState?.state === 'playing') {
12542- console.log('⏭️ Player already playing, no resume needed');
12543- await this.cleanupTTSState(); // 🆕 HINZUGEFÜGT
12544- this.updateTTSButtonState('ready'); // 🆕 HINZUGEFÜGT
12545- return;
12546- }
12517+ const context = this.savedPlayerContext;
12518+ console.log('🔄 Restoring player context:', context);
1254712519
1254812520 try {
12549- // 🎯 Verwende smartPlayPause für Resume
12550- console.log('🎵 Auto-resuming music...');
12551- await this.smartPlayPause({ id: entityId });
12552- console.log(`✅ Resumed using smartPlayPause`);
12521+ // 1️⃣ Originalinhalt wiederherstellen
12522+ console.log('🎵 Restoring original media...');
12523+ await this._hass.callService('media_player', 'play_media', {
12524+ entity_id: context.entityId,
12525+ media_content_id: context.mediaContentId,
12526+ media_content_type: context.mediaContentType
12527+ });
12528+
12529+ // 2️⃣ Kurz warten, damit Player den neuen Inhalt lädt
12530+ await new Promise(resolve => setTimeout(resolve, 800));
12531+
12532+ // 3️⃣ Zur gespeicherten Position springen
12533+ if (context.mediaPosition && context.mediaPosition > 0) {
12534+ console.log(`⏭️ Seeking to position: ${context.mediaPosition}s`);
12535+ await this._hass.callService('media_player', 'media_seek', {
12536+ entity_id: context.entityId,
12537+ seek_position: context.mediaPosition
12538+ });
12539+ }
12540+
12541+ // 4️⃣ Lautstärke wiederherstellen (falls geändert)
12542+ if (context.volumeLevel && context.volumeLevel > 0) {
12543+ await this._hass.callService('media_player', 'volume_set', {
12544+ entity_id: context.entityId,
12545+ volume_level: context.volumeLevel
12546+ });
12547+ }
12548+
12549+ console.log('✅ Player context successfully restored');
12550+ return true;
12551+
1255312552 } catch (error) {
12554- console.error('❌ Auto-resume failed:', error);
12553+ console.error('❌ Failed to restore player context:', error);
12554+ return false;
1255512555 } finally {
12556- await this.cleanupTTSState();
12557- this.updateTTSButtonState('ready'); // 🆕 HINZUGEFÜGT
12556+ // 5️⃣ Aufräumen
12557+ this.savedPlayerContext = null;
12558+ console.log('🧹 Saved player context cleared');
1255812559 }
12560+ }
12561+
12562+ // 🎧 EVENT-BASIERTE TTS-ÜBERWACHUNG (ersetzt Timer-Logik)
12563+ async startTTSMonitoring(entityId) {
12564+ console.log('🎧 Starting TTS monitoring...');
12565+
12566+ let checkCount = 0;
12567+ const maxChecks = 60; // Max 60 Sekunden überwachen
12568+
12569+ const monitorInterval = setInterval(async () => {
12570+ checkCount++;
12571+
12572+ // 🚫 Abbruch-Bedingungen
12573+ if (!this.isTTSActive || checkCount > maxChecks) {
12574+ console.log('🛑 TTS monitoring stopped (timeout or inactive)');
12575+ clearInterval(monitorInterval);
12576+ await this.finalizeTTSProcess(entityId);
12577+ return;
12578+ }
12579+
12580+ // 🔍 Player-Status prüfen
12581+ const currentState = this._hass.states[entityId];
12582+ const playerState = currentState?.state;
12583+
12584+ console.log(`🔍 TTS Monitor check ${checkCount}: Player state = ${playerState}`);
12585+
12586+ // 🎯 TTS beendet erkennen: Player ist nicht mehr 'playing'
12587+ if (playerState !== 'playing') {
12588+ console.log('🎉 TTS completed! Player no longer playing');
12589+ clearInterval(monitorInterval);
12590+
12591+ // Kurz warten für sauberen Übergang
12592+ await new Promise(resolve => setTimeout(resolve, 500));
12593+
12594+ // Player-Kontext wiederherstellen
12595+ await this.restorePlayerContext();
12596+
12597+ // Button-Status zurücksetzen
12598+ await this.finalizeTTSProcess(entityId);
12599+ }
12600+
12601+ }, 1000); // Jede Sekunde prüfen
12602+
12603+ // Store interval for potential cleanup
12604+ this.ttsMonitorInterval = monitorInterval;
1255912605 }
1256012606
12607+ // 🏁 TTS-PROZESS FINALISIEREN
12608+ async finalizeTTSProcess(entityId) {
12609+ console.log('🏁 Finalizing TTS process...');
12610+
12611+ // Aufräumen
12612+ await this.cleanupTTSState();
12613+
12614+ // Button zurücksetzen
12615+ this.updateTTSButtonState('ready');
12616+
12617+ // Monitor-Interval löschen
12618+ if (this.ttsMonitorInterval) {
12619+ clearInterval(this.ttsMonitorInterval);
12620+ this.ttsMonitorInterval = null;
12621+ }
12622+
12623+ console.log('✅ TTS process finalized');
12624+ }
12625+
12626+
1256112627 // 🧹 CLEANUP STATE
1256212628 async cleanupTTSState() {
1256312629 this.isTTSActive = false;
0 commit comments