|  |  | @ -14,6 +14,15 @@ import { decode as base642Buffer } from '@/utils/base64'; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | const PLAY_PAUSE_FADE_DURATION = 200; |  |  |  | const PLAY_PAUSE_FADE_DURATION = 200; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | /** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  * @readonly | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  * @enum {string} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | const UNPLAYABLE_CONDITION = { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   PLAY_NEXT_TRACK: 'playNextTrack', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   PLAY_PREV_TRACK: 'playPrevTrack', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | }; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | const electron = |  |  |  | const electron = | 
			
		
	
		
		
			
				
					
					|  |  |  |   process.env.IS_ELECTRON === true ? window.require('electron') : null; |  |  |  |   process.env.IS_ELECTRON === true ? window.require('electron') : null; | 
			
		
	
		
		
			
				
					
					|  |  |  | const ipcRenderer = |  |  |  | const ipcRenderer = | 
			
		
	
	
		
		
			
				
					|  |  | @ -164,6 +173,9 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |   get currentTrack() { |  |  |  |   get currentTrack() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     return this._currentTrack; |  |  |  |     return this._currentTrack; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   get currentTrackID() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return this._currentTrack?.id ?? 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   get playlistSource() { |  |  |  |   get playlistSource() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     return this._playlistSource; |  |  |  |     return this._playlistSource; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | @ -199,7 +211,7 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (this._enabled) { |  |  |  |     if (this._enabled) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       // 恢复当前播放歌曲
 |  |  |  |       // 恢复当前播放歌曲
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       this._replaceCurrentTrack(this._currentTrack.id, false).then(() => { |  |  |  |       this._replaceCurrentTrack(this.currentTrackID, false).then(() => { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         this._howler?.seek(localStorage.getItem('playerCurrentTrackTime') ?? 0); |  |  |  |         this._howler?.seek(localStorage.getItem('playerCurrentTrackTime') ?? 0); | 
			
		
	
		
		
			
				
					
					|  |  |  |       }); // update audio source and init howler
 |  |  |  |       }); // update audio source and init howler
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       this._initMediaSession(); |  |  |  |       this._initMediaSession(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -278,7 +290,7 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |     // 返回 [trackID, index]
 |  |  |  |     // 返回 [trackID, index]
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     return [this.list[next], next]; |  |  |  |     return [this.list[next], next]; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   async _shuffleTheList(firstTrackID = this._currentTrack.id) { |  |  |  |   async _shuffleTheList(firstTrackID = this.currentTrackID) { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     let list = this._list.filter(tid => tid !== firstTrackID); |  |  |  |     let list = this._list.filter(tid => tid !== firstTrackID); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (firstTrackID === 'first') list = this._list; |  |  |  |     if (firstTrackID === 'first') list = this._list; | 
			
		
	
		
		
			
				
					
					|  |  |  |     this._shuffledList = shuffle(list); |  |  |  |     this._shuffledList = shuffle(list); | 
			
		
	
	
		
		
			
				
					|  |  | @ -321,6 +333,25 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |         this._nextTrackCallback(); |  |  |  |         this._nextTrackCallback(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       }, |  |  |  |       }, | 
			
		
	
		
		
			
				
					
					|  |  |  |     }); |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     this._howler.on('loaderror', (_, errCode) => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       // https://developer.mozilla.org/en-US/docs/Web/API/MediaError/code
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       // code 3: MEDIA_ERR_DECODE
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       if (errCode === 3) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this._playNextTrack(this._isPersonalFM); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         const t = this.progress; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         this._replaceCurrentTrackAudio(this.currentTrack, false, false).then( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           replaced => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // 如果 replaced 为 false,代表当前的 track 已经不是这里想要替换的track
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // 此时则不修改当前的歌曲进度
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if (replaced) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               this._howler?.seek(t); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               this.play(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (autoplay) { |  |  |  |     if (autoplay) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       this.play(); |  |  |  |       this.play(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (this._currentTrack.name) { |  |  |  |       if (this._currentTrack.name) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -452,33 +483,61 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |   _replaceCurrentTrack( |  |  |  |   _replaceCurrentTrack( | 
			
		
	
		
		
			
				
					
					|  |  |  |     id, |  |  |  |     id, | 
			
		
	
		
		
			
				
					
					|  |  |  |     autoplay = true, |  |  |  |     autoplay = true, | 
			
		
	
		
		
			
				
					
					|  |  |  |     ifUnplayableThen = 'playNextTrack' |  |  |  |     ifUnplayableThen = UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |   ) { |  |  |  |   ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (autoplay && this._currentTrack.name) { |  |  |  |     if (autoplay && this._currentTrack.name) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       this._scrobble(this.currentTrack, this._howler?.seek()); |  |  |  |       this._scrobble(this.currentTrack, this._howler?.seek()); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     return getTrackDetail(id).then(data => { |  |  |  |     return getTrackDetail(id).then(data => { | 
			
		
	
		
		
			
				
					
					|  |  |  |       let track = data.songs[0]; |  |  |  |       const track = data.songs[0]; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       this._currentTrack = track; |  |  |  |       this._currentTrack = track; | 
			
		
	
		
		
			
				
					
					|  |  |  |       this._updateMediaSessionMetaData(track); |  |  |  |       this._updateMediaSessionMetaData(track); | 
			
		
	
		
		
			
				
					
					|  |  |  |       return this._getAudioSource(track).then(source => { |  |  |  |       return this._replaceCurrentTrackAudio( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         if (source) { |  |  |  |         track, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         autoplay, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         true, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         ifUnplayableThen | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   /** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    * @returns 是否成功加载音频,并使用加载完成的音频替换了howler实例 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |    */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   _replaceCurrentTrackAudio( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     track, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     autoplay, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     isCacheNextTrack, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ifUnplayableThen = UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   ) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     return this._getAudioSource(track).then(source => { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       if (source) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let replaced = false; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (track.id === this.currentTrackID) { | 
			
		
	
		
		
			
				
					
					|  |  |  |           this._playAudioSource(source, autoplay); |  |  |  |           this._playAudioSource(source, autoplay); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           replaced = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if (isCacheNextTrack) { | 
			
		
	
		
		
			
				
					
					|  |  |  |           this._cacheNextTrack(); |  |  |  |           this._cacheNextTrack(); | 
			
		
	
		
		
			
				
					
					|  |  |  |           return source; |  |  |  |         } | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |         return replaced; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |           store.dispatch('showToast', `无法播放 ${track.name}`); |  |  |  |       } else { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |           if (ifUnplayableThen === 'playNextTrack') { |  |  |  |         store.dispatch('showToast', `无法播放 ${track.name}`); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             if (this.isPersonalFM) { |  |  |  |         switch (ifUnplayableThen) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |               this.playNextFMTrack(); |  |  |  |           case UNPLAYABLE_CONDITION.PLAY_NEXT_TRACK: | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } else { |  |  |  |             this._playNextTrack(this.isPersonalFM); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |               this.playNextTrack(); |  |  |  |             break; | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |           case UNPLAYABLE_CONDITION.PLAY_PREV_TRACK: | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |           } else { |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             this.playPrevTrack(); |  |  |  |             this.playPrevTrack(); | 
			
		
	
		
		
			
				
					
					|  |  |  |           } |  |  |  |             break; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           default: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             store.dispatch( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               'showToast', | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               `undefined Unplayable condition: ${ifUnplayableThen}` | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             break; | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |       }); |  |  |  |         return false; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       } | 
			
		
	
		
		
			
				
					
					|  |  |  |     }); |  |  |  |     }); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   _cacheNextTrack() { |  |  |  |   _cacheNextTrack() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -511,11 +570,7 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.playPrevTrack(); |  |  |  |         this.playPrevTrack(); | 
			
		
	
		
		
			
				
					
					|  |  |  |       }); |  |  |  |       }); | 
			
		
	
		
		
			
				
					
					|  |  |  |       navigator.mediaSession.setActionHandler('nexttrack', () => { |  |  |  |       navigator.mediaSession.setActionHandler('nexttrack', () => { | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (this.isPersonalFM) { |  |  |  |         this._playNextTrack(this.isPersonalFM); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |           this.playNextFMTrack(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           this.playNextTrack(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       }); |  |  |  |       }); | 
			
		
	
		
		
			
				
					
					|  |  |  |       navigator.mediaSession.setActionHandler('stop', () => { |  |  |  |       navigator.mediaSession.setActionHandler('stop', () => { | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.pause(); |  |  |  |         this.pause(); | 
			
		
	
	
		
		
			
				
					|  |  | @ -579,11 +634,9 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |   _nextTrackCallback() { |  |  |  |   _nextTrackCallback() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this._scrobble(this._currentTrack, 0, true); |  |  |  |     this._scrobble(this._currentTrack, 0, true); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!this.isPersonalFM && this.repeatMode === 'one') { |  |  |  |     if (!this.isPersonalFM && this.repeatMode === 'one') { | 
			
		
	
		
		
			
				
					
					|  |  |  |       this._replaceCurrentTrack(this._currentTrack.id); |  |  |  |       this._replaceCurrentTrack(this.currentTrackID); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     } else if (this.isPersonalFM) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       this.playNextFMTrack(); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       this.playNextTrack(); |  |  |  |       this._playNextTrack(this.isPersonalFM); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   _loadPersonalFMNextTrack() { |  |  |  |   _loadPersonalFMNextTrack() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -628,11 +681,14 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     ipcRenderer?.send('pauseDiscordPresence', track); |  |  |  |     ipcRenderer?.send('pauseDiscordPresence', track); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |   _playNextTrack(isPersonal) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   currentTrackID() { |  |  |  |     if (isPersonal) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     const { list, current } = this._getListAndCurrent(); |  |  |  |       this.playNextFMTrack(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |     return list[current]; |  |  |  |     } else { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       this.playNextTrack(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |   appendTrack(trackID) { |  |  |  |   appendTrack(trackID) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.list.append(trackID); |  |  |  |     this.list.append(trackID); | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | @ -697,7 +753,11 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |     const [trackID, index] = this._getPrevTrack(); |  |  |  |     const [trackID, index] = this._getPrevTrack(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (trackID === undefined) return false; |  |  |  |     if (trackID === undefined) return false; | 
			
		
	
		
		
			
				
					
					|  |  |  |     this.current = index; |  |  |  |     this.current = index; | 
			
		
	
		
		
			
				
					
					|  |  |  |     this._replaceCurrentTrack(trackID, true, 'playPrevTrack'); |  |  |  |     this._replaceCurrentTrack( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       trackID, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       true, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       UNPLAYABLE_CONDITION.PLAY_PREV_TRACK | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ); | 
			
		
	
		
		
			
				
					
					|  |  |  |     return true; |  |  |  |     return true; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   saveSelfToLocalStorage() { |  |  |  |   saveSelfToLocalStorage() { | 
			
		
	
	
		
		
			
				
					|  |  | @ -838,20 +898,14 @@ export default class { | 
			
		
	
		
		
			
				
					
					|  |  |  |   addTrackToPlayNext(trackID, playNow = false) { |  |  |  |   addTrackToPlayNext(trackID, playNow = false) { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this._playNextList.push(trackID); |  |  |  |     this._playNextList.push(trackID); | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (playNow) { |  |  |  |     if (playNow) { | 
			
		
	
		
		
			
				
					
					|  |  |  |       if (this.isPersonalFM) { |  |  |  |       this.playNextTrack(); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         this.playNextFMTrack(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         this.playNextTrack(); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       } |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
		
		
			
				
					
					|  |  |  |   playPersonalFM() { |  |  |  |   playPersonalFM() { | 
			
		
	
		
		
			
				
					
					|  |  |  |     this._isPersonalFM = true; |  |  |  |     this._isPersonalFM = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (!this._enabled) this._enabled = true; |  |  |  |     if (!this._enabled) this._enabled = true; | 
			
		
	
		
		
			
				
					
					|  |  |  |     if (this._currentTrack.id !== this._personalFMTrack.id) { |  |  |  |     if (this.currentTrackID !== this._personalFMTrack.id) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |       this._replaceCurrentTrack(this._personalFMTrack.id).then(() => |  |  |  |       this._replaceCurrentTrack(this._personalFMTrack.id, true); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         this.playOrPause() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       ); |  |  |  |  | 
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |     } else { |  |  |  |     } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |       this.playOrPause(); |  |  |  |       this.playOrPause(); | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |