first commit

This commit is contained in:
Blizzard
2026-03-05 09:08:21 +08:00
commit 0a61c4ddec
2189 changed files with 38610 additions and 0 deletions
+220
View File
@@ -0,0 +1,220 @@
/**
* 早安电台 — 音频管理器
* 封装 wx.getBackgroundAudioManager(),管理全局背景播放
* 确保小程序切后台后音频不断
* 播放时自动上报收听历史
*/
const api = require('./api')
let bgAudioManager = null
let appInstance = null
let _switching = false // 切换音频时的锁,防止 onStop 事件干扰
/**
* 初始化音频管理器
* @param {Object} app - App 实例
*/
function init(app) {
appInstance = app
bgAudioManager = wx.getBackgroundAudioManager()
// 绑定音频事件
bgAudioManager.onPlay(() => {
_switching = false // 新音频开始播放,释放锁
updatePlayState(true)
})
bgAudioManager.onPause(() => {
updatePlayState(false)
// 暂停时上报进度
reportHistory()
})
bgAudioManager.onStop(() => {
// 如果正在切换音频,不处理 onStop(新的 src 设置会触发旧的 onStop
if (_switching) return
reportHistory()
updatePlayState(false)
appInstance.globalData.currentTime = 0
appInstance.emit('playerStateChange', getState())
})
bgAudioManager.onEnded(() => {
reportHistory()
updatePlayState(false)
appInstance.globalData.currentTime = appInstance.globalData.duration
appInstance.emit('playerStateChange', getState())
})
// 进度更新回调
bgAudioManager.onTimeUpdate(() => {
if (_switching) return
const ct = Math.floor(bgAudioManager.currentTime || 0)
const dur = Math.floor(bgAudioManager.duration || 0)
appInstance.globalData.currentTime = ct
if (dur > 0) {
appInstance.globalData.duration = dur
}
appInstance.emit('timeUpdate', { currentTime: ct, duration: dur })
})
bgAudioManager.onError((err) => {
console.error('[AudioManager] 播放出错:', err)
_switching = false
updatePlayState(false)
})
bgAudioManager.onWaiting(() => {
console.log('[AudioManager] 缓冲中...')
})
}
/**
* 更新播放状态并通知
*/
function updatePlayState(isPlaying) {
appInstance.globalData.isPlaying = isPlaying
appInstance.emit('playerStateChange', getState())
}
/**
* 获取当前播放器状态
*/
function getState() {
return {
activeContent: appInstance.globalData.activeContent,
isPlaying: appInstance.globalData.isPlaying,
currentTime: appInstance.globalData.currentTime,
duration: appInstance.globalData.duration,
playbackRate: appInstance.globalData.playbackRate
}
}
/**
* 获取音频 URL
*/
function getAudioUrl(content) {
if (!content) return ''
if (content.audio && content.audio.url) return content.audio.url
if (content.audioUrl) return content.audioUrl
return ''
}
/**
* 上报收听历史到后端
*/
function reportHistory() {
const content = appInstance.globalData.activeContent
if (!content || !content.id) return
api.addHistory({
programId: content.id,
progress: appInstance.globalData.currentTime || 0,
duration: appInstance.globalData.duration || content.duration || 0
}).catch(function (err) {
console.warn('[AudioManager] 上报历史失败:', err)
})
}
/**
* 播放指定内容
* @param {Object} content - 音频内容对象 { id, title, duration, audioUrl/audio.url, ... }
*/
function playContent(content) {
if (!bgAudioManager || !content) return
var audioUrl = getAudioUrl(content)
if (!audioUrl) {
console.error('[AudioManager] 音频内容缺少 audioUrl:', content)
wx.showToast({ title: '音频地址无效', icon: 'none' })
return
}
// 如果当前有播放内容,先上报历史
var oldContent = appInstance.globalData.activeContent
if (oldContent && oldContent.id && oldContent.id !== content.id) {
reportHistory()
}
// 标记正在切换,防止旧音频的 onStop 干扰
_switching = true
appInstance.globalData.activeContent = content
appInstance.globalData.currentTime = 0
appInstance.globalData.duration = content.duration || 0
// 设置背景音频属性(必须设置 title,否则 iOS 上不允许播放)
bgAudioManager.title = content.title || '早安电台'
bgAudioManager.singer = '早安电台'
bgAudioManager.epname = content.title || '早安电台'
bgAudioManager.coverImgUrl = (content.cover && content.cover.url) || content.coverUrl || ''
// 设置音频源(这会触发旧音频的 onStop,然后自动开始播放新音频)
bgAudioManager.src = audioUrl
appInstance.emit('playerStateChange', getState())
}
/**
* 切换播放/暂停
* 关键:如果音频已结束或 src 被回收,需要重新设置 src 才能恢复播放
*/
function togglePlay() {
if (!bgAudioManager || !appInstance.globalData.activeContent) return
if (appInstance.globalData.isPlaying) {
bgAudioManager.pause()
} else {
// 检查 bgAudioManager 是否还有有效的 src
// 音频结束/被系统回收后,src 会变为空,此时 play() 无效
// 需要重新设置 src 来恢复播放
var currentSrc = ''
try {
currentSrc = bgAudioManager.src
} catch (e) {
currentSrc = ''
}
if (!currentSrc) {
// src 已被清空(音频结束、系统回收等),重新播放
playContent(appInstance.globalData.activeContent)
} else {
bgAudioManager.play()
}
}
}
/**
* 跳转到指定时间(秒)
*/
function seekTo(time) {
if (!bgAudioManager) return
bgAudioManager.seek(time)
appInstance.globalData.currentTime = time
appInstance.emit('timeUpdate', {
currentTime: time,
duration: appInstance.globalData.duration
})
}
/**
* 设置播放速率
* @param {number} rate - 0.5 / 0.75 / 1.0 / 1.25 / 1.5 / 2.0
*/
function setPlaybackRate(rate) {
if (!bgAudioManager) return
bgAudioManager.playbackRate = rate
appInstance.globalData.playbackRate = rate
appInstance.emit('playerStateChange', getState())
}
module.exports = {
init,
getState,
playContent,
togglePlay,
seekTo,
setPlaybackRate
}