Skip to content

Commit 5c39da9

Browse files
authored
Merge pull request #32 from joshuaaaaa/claude/add-youtube-mp3-playback-AweoS
Claude/add youtube mp3 playback aweo s
2 parents 988e034 + de28065 commit 5c39da9

File tree

1 file changed

+200
-86
lines changed

1 file changed

+200
-86
lines changed

radio-browser-card.js

Lines changed: 200 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,15 +1032,19 @@ 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+
10351043
// Stop direct playback if active
10361044
if (this._isUsingDirectPlayback && this._audioElement) {
10371045
this._audioElement.pause();
10381046
this._audioElement.currentTime = 0;
10391047
this._isUsingDirectPlayback = false;
1040-
this._isPlaying = false;
1041-
this._currentStationIndex = -1;
1042-
this._currentStationMetadata = null;
1043-
this.stopVisualizer();
10441048
this.updatePlaylistSelection();
10451049
this.updateStationInfo();
10461050
this._saveState();
@@ -1055,10 +1059,6 @@ class RadioBrowserCard extends HTMLElement {
10551059
await this._hass.callService('media_player', 'media_stop', {
10561060
entity_id: this._selectedMediaPlayer
10571061
});
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,106 +2062,218 @@ class RadioBrowserCard extends HTMLElement {
20622062
color: ${colors.primary};
20632063
}
20642064
2065-
/* Electric Border Effect */
2065+
/* Electric Border Effect - Advanced version with turbulence */
20662066
.electric-border-active {
20672067
position: relative;
2068+
padding: 2px;
2069+
border-radius: 8px;
20682070
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;
20692138
}
20702139
2071-
.electric-border-active::before {
2072-
content: '';
2140+
.electric-border-active .overlay-1 {
20732141
position: absolute;
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%,
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,
20832156
transparent 30%,
20842157
transparent 70%,
2085-
#ff00ea 80%,
2086-
#d400ff 90%,
2087-
transparent 100%
2158+
white
20882159
);
2089-
border-radius: 10px;
2090-
z-index: -1;
2091-
animation: electric-rotate 4s linear infinite;
2092-
filter: blur(8px);
2093-
opacity: 0.8;
2160+
pointer-events: none;
20942161
}
20952162
2096-
.electric-border-active::after {
2097-
content: '';
2163+
.electric-border-active .overlay-2 {
20982164
position: absolute;
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%,
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,
21082179
transparent 30%,
21092180
transparent 70%,
2110-
#00f3ff 80%,
2111-
#00d4ff 90%,
2112-
transparent 100%
2181+
white
21132182
);
2114-
border-radius: 10px;
2115-
z-index: -1;
2116-
animation: electric-rotate-reverse 3s linear infinite;
2117-
filter: blur(6px);
2118-
opacity: 0.6;
2183+
pointer-events: none;
21192184
}
21202185
2121-
@keyframes electric-rotate {
2122-
0% {
2123-
transform: rotate(0deg);
2124-
}
2125-
100% {
2126-
transform: rotate(360deg);
2127-
}
2128-
}
2129-
2130-
@keyframes electric-rotate-reverse {
2131-
0% {
2132-
transform: rotate(360deg);
2133-
}
2134-
100% {
2135-
transform: rotate(0deg);
2136-
}
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;
21372206
}
21382207
</style>
21392208
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>
2234+
21402235
<div class="winamp-container">
21412236
<!-- Main Player Window -->
21422237
<div class="main-window ${this._electricBorder ? 'electric-border-active' : ''}">
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 (↑↓)">
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>
21642275
</div>
2276+
` : ''}
21652277
</div>
21662278
21672279
<!-- Playlist Window -->
@@ -2376,8 +2488,10 @@ class RadioBrowserCard extends HTMLElement {
23762488
}
23772489

23782490
// Check if playback state indicates playing
2379-
if (entity.state !== 'playing') {
2380-
console.warn('Player state is not "playing", attempting recovery...');
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...');
23812495
this._recoverPlayback();
23822496
return;
23832497
}

0 commit comments

Comments
 (0)