@@ -1032,19 +1032,15 @@ class RadioBrowserCard extends HTMLElement {
10321032 }
10331033
10341034 async stop ( ) {
1035- // Set _isPlaying to false IMMEDIATELY to prevent keepalive from triggering recovery
1036- this . _isPlaying = false ;
1037- this . _currentStationIndex = - 1 ;
1038- this . _currentStationMetadata = null ;
1039-
1040- // Stop visualizer immediately
1041- this . stopVisualizer ( ) ;
1042-
10431035 // Stop direct playback if active
10441036 if ( this . _isUsingDirectPlayback && this . _audioElement ) {
10451037 this . _audioElement . pause ( ) ;
10461038 this . _audioElement . currentTime = 0 ;
10471039 this . _isUsingDirectPlayback = false ;
1040+ this . _isPlaying = false ;
1041+ this . _currentStationIndex = - 1 ;
1042+ this . _currentStationMetadata = null ;
1043+ this . stopVisualizer ( ) ;
10481044 this . updatePlaylistSelection ( ) ;
10491045 this . updateStationInfo ( ) ;
10501046 this . _saveState ( ) ;
@@ -1059,6 +1055,10 @@ class RadioBrowserCard extends HTMLElement {
10591055 await this . _hass . callService ( 'media_player' , 'media_stop' , {
10601056 entity_id : this . _selectedMediaPlayer
10611057 } ) ;
1058+ this . _isPlaying = false ;
1059+ this . _currentStationIndex = - 1 ;
1060+ this . _currentStationMetadata = null ;
1061+ this . stopVisualizer ( ) ; // Immediately stop visualizer
10621062 this . updatePlaylistSelection ( ) ;
10631063 this . updateStationInfo ( ) ;
10641064 this . _saveState ( ) ;
@@ -2062,218 +2062,106 @@ class RadioBrowserCard extends HTMLElement {
20622062 color: ${ colors . primary } ;
20632063 }
20642064
2065- /* Electric Border Effect - Advanced version with turbulence */
2065+ /* Electric Border Effect */
20662066 .electric-border-active {
20672067 position: relative;
2068- padding: 2px;
2069- border-radius: 8px;
20702068 overflow: visible !important;
2071- background: linear-gradient(
2072- -30deg,
2073- rgba(221, 132, 72, 0.4),
2074- transparent,
2075- rgba(221, 132, 72, 0.4)
2076- ),
2077- linear-gradient(
2078- to bottom,
2079- ${ colors . background } ,
2080- ${ colors . background }
2081- );
2082- }
2083-
2084- .electric-border-active .main-window-inner {
2085- position: relative;
2086- width: 100%;
2087- height: 100%;
2088- }
2089-
2090- .electric-border-active .border-outer {
2091- border: 2px solid rgba(221, 132, 72, 0.5);
2092- border-radius: 8px;
2093- padding-right: 4px;
2094- padding-bottom: 4px;
2095- position: relative;
2096- width: 100%;
2097- height: 100%;
2098- }
2099-
2100- .electric-border-active .main-card-layer {
2101- border-radius: 8px;
2102- border: 2px solid #dd8448;
2103- margin-top: -4px;
2104- margin-left: -4px;
2105- filter: url(#turbulent-displace);
2106- position: relative;
2107- width: calc(100% + 4px);
2108- height: calc(100% + 4px);
2109- background: ${ colors . background } ;
2110- }
2111-
2112- .electric-border-active .glow-layer-1 {
2113- border: 2px solid rgba(221, 132, 72, 0.6);
2114- border-radius: 8px;
2115- width: 100%;
2116- height: 100%;
2117- position: absolute;
2118- top: 0;
2119- left: 0;
2120- right: 0;
2121- bottom: 0;
2122- filter: blur(1px);
2123- pointer-events: none;
2124- }
2125-
2126- .electric-border-active .glow-layer-2 {
2127- border: 2px solid #dd8448;
2128- border-radius: 8px;
2129- width: 100%;
2130- height: 100%;
2131- position: absolute;
2132- top: 0;
2133- left: 0;
2134- right: 0;
2135- bottom: 0;
2136- filter: blur(4px);
2137- pointer-events: none;
21382069 }
21392070
2140- .electric-border-active .overlay-1 {
2071+ .electric-border-active::before {
2072+ content: '';
21412073 position: absolute;
2142- width: 100%;
2143- height: 100%;
2144- top: 0;
2145- left: 0;
2146- right: 0;
2147- bottom: 0;
2148- border-radius: 8px;
2149- opacity: 1;
2150- mix-blend-mode: overlay;
2151- transform: scale(1.1);
2152- filter: blur(16px);
2153- background: linear-gradient(
2154- -30deg,
2155- white,
2074+ top: -3px;
2075+ left: -3px;
2076+ right: -3px;
2077+ bottom: -3px;
2078+ background: conic-gradient(
2079+ from 0deg,
2080+ transparent 0%,
2081+ #00f3ff 10%,
2082+ #00d4ff 20%,
21562083 transparent 30%,
21572084 transparent 70%,
2158- white
2085+ #ff00ea 80%,
2086+ #d400ff 90%,
2087+ transparent 100%
21592088 );
2160- pointer-events: none;
2089+ border-radius: 10px;
2090+ z-index: -1;
2091+ animation: electric-rotate 4s linear infinite;
2092+ filter: blur(8px);
2093+ opacity: 0.8;
21612094 }
21622095
2163- .electric-border-active .overlay-2 {
2096+ .electric-border-active::after {
2097+ content: '';
21642098 position: absolute;
2165- width: 100%;
2166- height: 100%;
2167- top: 0;
2168- left: 0;
2169- right: 0;
2170- bottom: 0;
2171- border-radius: 8px;
2172- opacity: 0.5;
2173- mix-blend-mode: overlay;
2174- transform: scale(1.1);
2175- filter: blur(16px);
2176- background: linear-gradient(
2177- -30deg,
2178- white,
2099+ top: -2px;
2100+ left: -2px;
2101+ right: -2px;
2102+ bottom: -2px;
2103+ background: conic-gradient(
2104+ from 180deg,
2105+ transparent 0%,
2106+ #ff00ea 10%,
2107+ #d400ff 20%,
21792108 transparent 30%,
21802109 transparent 70%,
2181- white
2110+ #00f3ff 80%,
2111+ #00d4ff 90%,
2112+ transparent 100%
21822113 );
2183- pointer-events: none;
2114+ border-radius: 10px;
2115+ z-index: -1;
2116+ animation: electric-rotate-reverse 3s linear infinite;
2117+ filter: blur(6px);
2118+ opacity: 0.6;
21842119 }
21852120
2186- .electric-border-active .background-glow {
2187- position: absolute;
2188- width: 100%;
2189- height: 100%;
2190- top: 0;
2191- left: 0;
2192- right: 0;
2193- bottom: 0;
2194- border-radius: 8px;
2195- filter: blur(32px);
2196- transform: scale(1.1);
2197- opacity: 0.3;
2198- z-index: -1;
2199- background: linear-gradient(
2200- -30deg,
2201- #dd8448,
2202- transparent,
2203- #dd8448
2204- );
2205- pointer-events: none;
2121+ @keyframes electric-rotate {
2122+ 0% {
2123+ transform: rotate(0deg);
2124+ }
2125+ 100% {
2126+ transform: rotate(360deg);
2127+ }
22062128 }
2207- </style>
22082129
2209- <!-- SVG filter for electric turbulence effect -->
2210- <svg style="position: absolute; width: 0; height: 0;">
2211- <defs>
2212- <filter id="turbulent-displace">
2213- <feTurbulence
2214- type="turbulence"
2215- baseFrequency="0.009 0.009"
2216- numOctaves="2"
2217- result="turbulence"
2218- seed="1">
2219- <animate
2220- attributeName="baseFrequency"
2221- dur="40s"
2222- values="0.009 0.009;0.012 0.009;0.009 0.009"
2223- repeatCount="indefinite" />
2224- </feTurbulence>
2225- <feDisplacementMap
2226- in="SourceGraphic"
2227- in2="turbulence"
2228- scale="8"
2229- xChannelSelector="R"
2230- yChannelSelector="G" />
2231- </filter>
2232- </defs>
2233- </svg>
2130+ @keyframes electric-rotate-reverse {
2131+ 0% {
2132+ transform: rotate(360deg);
2133+ }
2134+ 100% {
2135+ transform: rotate(0deg);
2136+ }
2137+ }
2138+ </style>
22342139
22352140 <div class="winamp-container">
22362141 <!-- Main Player Window -->
22372142 <div class="main-window ${ this . _electricBorder ? 'electric-border-active' : '' } ">
2238- ${ this . _electricBorder ? `
2239- <div class="main-window-inner">
2240- <div class="border-outer">
2241- <div class="main-card-layer">
2242- <div class="glow-layer-1"></div>
2243- <div class="glow-layer-2"></div>
2244- <div class="overlay-1"></div>
2245- <div class="overlay-2"></div>
2246- <div class="background-glow"></div>
2247- ` : '' }
2248-
2249- <div class="track-title">Radio Browser</div>
2250- <div class="station-info" style="display: none;"></div>
2251- <div class="sleep-timer-display" style="display: none;"></div>
2252-
2253- <!-- Visualizer -->
2254- <canvas class="visualizer" width="80" height="32"></canvas>
2255-
2256- <!-- Control Buttons -->
2257- <div class="control-buttons">
2258- <button class="control-btn btn-prev" onclick="this.getRootNode().host.playPrevious()" title="Previous (←)"></button>
2259- <button class="control-btn btn-play" onclick="this.getRootNode().host.togglePlay()" title="Play (Space)"></button>
2260- <button class="control-btn btn-pause" onclick="this.getRootNode().host.togglePlay()" title="Pause (Space)"></button>
2261- <button class="control-btn btn-stop" onclick="this.getRootNode().host.stop()" title="Stop"></button>
2262- <button class="control-btn btn-next" onclick="this.getRootNode().host.playNext()" title="Next (→)"></button>
2263- </div>
2264-
2265- <!-- Volume Control -->
2266- <div class="volume-control">
2267- <input type="range" class="volume-slider" min="0" max="100" value="${ currentVolume } "
2268- oninput="this.getRootNode().host.handleVolumeChange(event)"
2269- title="Volume (↑↓)">
2270- </div>
2271-
2272- ${ this . _electricBorder ? `
2273- </div>
2274- </div>
2143+ <div class="track-title">Radio Browser</div>
2144+ <div class="station-info" style="display: none;"></div>
2145+ <div class="sleep-timer-display" style="display: none;"></div>
2146+
2147+ <!-- Visualizer -->
2148+ <canvas class="visualizer" width="80" height="32"></canvas>
2149+
2150+ <!-- Control Buttons -->
2151+ <div class="control-buttons">
2152+ <button class="control-btn btn-prev" onclick="this.getRootNode().host.playPrevious()" title="Previous (←)"></button>
2153+ <button class="control-btn btn-play" onclick="this.getRootNode().host.togglePlay()" title="Play (Space)"></button>
2154+ <button class="control-btn btn-pause" onclick="this.getRootNode().host.togglePlay()" title="Pause (Space)"></button>
2155+ <button class="control-btn btn-stop" onclick="this.getRootNode().host.stop()" title="Stop"></button>
2156+ <button class="control-btn btn-next" onclick="this.getRootNode().host.playNext()" title="Next (→)"></button>
2157+ </div>
2158+
2159+ <!-- Volume Control -->
2160+ <div class="volume-control">
2161+ <input type="range" class="volume-slider" min="0" max="100" value="${ currentVolume } "
2162+ oninput="this.getRootNode().host.handleVolumeChange(event)"
2163+ title="Volume (↑↓)">
22752164 </div>
2276- ` : '' }
22772165 </div>
22782166
22792167 <!-- Playlist Window -->
@@ -2488,10 +2376,8 @@ class RadioBrowserCard extends HTMLElement {
24882376 }
24892377
24902378 // Check if playback state indicates playing
2491- // BUT only attempt recovery if we THINK we're still playing
2492- // If user pressed STOP, _isPlaying will be false and we shouldn't recover
2493- if ( entity . state !== 'playing' && this . _isPlaying ) {
2494- console . warn ( 'Player state is not "playing" but _isPlaying=true, attempting recovery...' ) ;
2379+ if ( entity . state !== 'playing' ) {
2380+ console . warn ( 'Player state is not "playing", attempting recovery...' ) ;
24952381 this . _recoverPlayback ( ) ;
24962382 return ;
24972383 }
0 commit comments