@@ -54,11 +54,21 @@ hideTips.subscribe((value) => {
5454 }
5555} ) ;
5656export const isSmallDevice = writable ( false ) ;
57+ function storedVolume ( ) {
58+ if ( ! browser ) return 100 ;
59+ const parsed = parseInt ( localStorage . getItem ( 'volume' ) ?? '100' , 10 ) ;
60+ return Number . isFinite ( parsed ) ? Math . min ( 100 , Math . max ( 0 , parsed ) ) : 100 ;
61+ }
62+ const initialVolume = storedVolume ( ) ;
63+ const initialAudio = browser ? new Audio ( ) : null ;
64+ if ( initialAudio ) {
65+ initialAudio . volume = initialVolume / 100 ;
66+ }
5767export const audioPlayer = writable ( {
58- audio : browser ? new Audio ( ) : null ,
68+ audio : initialAudio ,
5969 onEnded : ( ) => { } ,
6070 playing : false ,
61- volume : 100 ,
71+ volume : initialVolume ,
6272 currentTime : 0 ,
6373 changeVolume : false
6474} ) ;
@@ -88,6 +98,7 @@ export const recentlyPlayedManager = {
8898
8999let endedHandler : ( ( this : HTMLAudioElement , ev : Event ) => void ) | null = null ;
90100let durationChangeHandler : ( ( this : HTMLAudioElement , ev : Event ) => void ) | null = null ;
101+ let listenersBoundTo : HTMLAudioElement | null = null ;
91102
92103export const currentDuration = derived ( audioPlayer , ( $audioPlayer ) => {
93104 return $audioPlayer . audio ?. duration ?? 0 ;
@@ -97,71 +108,71 @@ let currentTime = 0;
97108let lastListenTime = 0 ;
98109let lastListenSongId = '' ;
99110
100- audioPlayer . subscribe ( ( value ) => {
101- if ( browser ) {
102- if ( value . audio instanceof HTMLAudioElement ) {
103- if ( ! value . changeVolume ) {
104- if ( endedHandler ) {
105- value . audio . removeEventListener ( 'ended' , endedHandler ) ;
106- endedHandler = null ;
107- }
108-
109- if ( value . onEnded ) {
110- endedHandler = ( ) => {
111- value . onEnded ( ) ;
112- } ;
113- value . audio . addEventListener ( 'ended' , endedHandler ) ;
114- }
111+ function bindAudioListeners ( audio : HTMLAudioElement ) {
112+ if ( listenersBoundTo === audio ) return ;
115113
116- value . audio . ontimeupdate = ( ) => {
117- currentTime = value . audio ?. currentTime ?? 0 ;
118- if ( value . playing ) {
119- curTime . set ( value . audio ?. currentTime ?? currentTime ) ;
120- setCurTime . set ( value . audio ?. currentTime ?? currentTime ) ;
121- }
122- const song = get ( activeSong ) ;
123- const state = get ( queueState ) ;
124- if ( value . playing && song ?. id ) {
125- if ( song . id !== lastListenSongId ) {
126- lastListenSongId = song . id ;
127- lastListenTime = value . audio ?. currentTime ?? 0 ;
128- } else {
129- const nextTime = value . audio ?. currentTime ?? 0 ;
130- const delta = nextTime - lastListenTime ;
131- lastListenTime = nextTime ;
132- if ( delta > 0 && delta <= 2.5 ) {
133- statsManager . recordListeningSeconds ( song , state . source , delta ) ;
134- }
135- }
136- }
137- } ;
138-
139- if ( durationChangeHandler ) {
140- value . audio . removeEventListener ( 'durationchange' , durationChangeHandler ) ;
141- durationChangeHandler = null ;
142- }
114+ if ( listenersBoundTo ) {
115+ if ( endedHandler ) {
116+ listenersBoundTo . removeEventListener ( 'ended' , endedHandler ) ;
117+ endedHandler = null ;
118+ }
119+ listenersBoundTo . ontimeupdate = null ;
120+ if ( durationChangeHandler ) {
121+ listenersBoundTo . removeEventListener ( 'durationchange' , durationChangeHandler ) ;
122+ durationChangeHandler = null ;
123+ }
124+ }
143125
144- durationChangeHandler = ( ) => {
145- audioPlayer . update ( ( state ) => ( { ...state } ) ) ;
146- } ;
147- value . audio . addEventListener ( 'durationchange' , durationChangeHandler ) ;
126+ listenersBoundTo = audio ;
148127
149- if ( value . audio instanceof HTMLAudioElement && value . currentTime !== undefined ) {
150- value . audio . currentTime = value . currentTime ;
151- }
128+ endedHandler = ( ) => {
129+ get ( audioPlayer ) . onEnded ( ) ;
130+ } ;
131+ audio . addEventListener ( 'ended' , endedHandler ) ;
132+
133+ audio . ontimeupdate = ( ) => {
134+ const player = get ( audioPlayer ) ;
135+ currentTime = player . audio ?. currentTime ?? 0 ;
136+ if ( player . playing ) {
137+ curTime . set ( player . audio ?. currentTime ?? currentTime ) ;
138+ setCurTime . set ( player . audio ?. currentTime ?? currentTime ) ;
139+ }
140+ const song = get ( activeSong ) ;
141+ const state = get ( queueState ) ;
142+ if ( player . playing && song ?. id ) {
143+ if ( song . id !== lastListenSongId ) {
144+ lastListenSongId = song . id ;
145+ lastListenTime = player . audio ?. currentTime ?? 0 ;
152146 } else {
153- if ( value . audio instanceof HTMLAudioElement && value . volume !== undefined ) {
154- value . audio . volume = value . volume / 100 ;
155- localStorage . setItem ( 'volume' , value . volume . toString ( ) ) ;
156- value . changeVolume = false ;
157- return ;
158- } else {
159- value . changeVolume = false ;
160- return ;
147+ const nextTime = player . audio ?. currentTime ?? 0 ;
148+ const delta = nextTime - lastListenTime ;
149+ lastListenTime = nextTime ;
150+ if ( delta > 0 && delta <= 2.5 ) {
151+ statsManager . recordListeningSeconds ( song , state . source , delta ) ;
161152 }
162153 }
163154 }
155+ } ;
156+
157+ durationChangeHandler = ( ) => {
158+ audioPlayer . update ( ( state ) => ( { ...state } ) ) ;
159+ } ;
160+ audio . addEventListener ( 'durationchange' , durationChangeHandler ) ;
161+ }
162+
163+ audioPlayer . subscribe ( ( value ) => {
164+ if ( ! browser || ! ( value . audio instanceof HTMLAudioElement ) ) return ;
165+
166+ if ( value . changeVolume ) {
167+ if ( value . volume !== undefined ) {
168+ value . audio . volume = value . volume / 100 ;
169+ localStorage . setItem ( 'volume' , value . volume . toString ( ) ) ;
170+ }
171+ value . changeVolume = false ;
172+ return ;
164173 }
174+
175+ bindAudioListeners ( value . audio ) ;
165176} ) ;
166177function createTitle ( ) {
167178 const { subscribe, set } = writable ( '' ) ;
0 commit comments