123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- export default {
- // 音频播放器实例
- player: null,
-
- // 当前运行环境检测
- isApp: null,
-
- // 初始化方法
- init() {
- // 检测运行环境
- const systemInfo = uni.getSystemInfoSync();
- this.isApp = systemInfo.platform === 'ios' || systemInfo.platform === 'android';
-
- // 初始化播放器
- if (!this.player) {
- this.player = uni.createInnerAudioContext();
- this.player.obeyMuteSwitch = false; // iOS静音模式下也可播放
- this.player.onError((err) => {
- console.error('音频播放器错误:', err);
- uni.showToast({
- title: '播放失败,请稍后再试',
- icon: 'none',
- duration: 2000
- });
- });
- }
- },
-
- // 从单词数据中提取所有音频信息(完整实现)
- extractAudioInfo(wordData) {
- if (!wordData || typeof wordData !== 'object') {
- console.error('无效的单词数据');
- return {
- main: null,
- syllables: [],
- frequencies: []
- };
- }
-
- const audioInfo = {
- main: null,
- syllables: [],
- frequencies: []
- };
-
- // 处理主音频
- if (wordData.yinpin && typeof wordData.yinpin === 'string') {
- audioInfo.main = {
- id: `word_${wordData.id}_main`,
- url: this.normalizeAudioUrl(wordData.yinpin),
- type: 'main',
- text: wordData.name || '未知单词',
- lastCached: 0 // 最后缓存时间戳
- };
- }
-
- // 处理音节音频
- if (Array.isArray(wordData.yinjie)) {
- audioInfo.syllables = wordData.yinjie
- .filter(item => item && typeof item === 'object')
- .map((item, index) => ({
- id: `word_${wordData.id}_syllable_${index}`,
- url: this.normalizeAudioUrl(item.yinpin),
- type: 'syllable',
- text: item.cigen || `音节${index + 1}`,
- index,
- lastCached: 0
- }))
- .filter(item => item.url);
- }
-
- // 处理频度音频
- if (Array.isArray(wordData.pindu)) {
- audioInfo.frequencies = wordData.pindu
- .filter(item => item && typeof item === 'object')
- .map((item, index) => ({
- id: `word_${wordData.id}_frequency_${index}`,
- url: this.normalizeAudioUrl(item.yinpin),
- type: 'frequency',
- text: item.cigen || `频度${index + 1}`,
- index,
- lastCached: 0
- }))
- .filter(item => item.url);
- }
-
- return audioInfo;
- },
-
- // 标准化音频URL(完整实现)
- normalizeAudioUrl(url) {
- if (!url || typeof url !== 'string') return null;
-
- // 已经是完整URL
- if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('blob:')) {
- return url;
- }
-
- // 处理相对路径(根据实际项目配置)
- const baseUrl = 'https://your-audio-server.com/'; // 替换为你的音频服务器地址
- return baseUrl + url.replace(/^\//, '');
- },
-
- // 缓存单词的所有音频(完整实现)
- async cacheWordAudios(wordData) {
- try {
- if (!wordData || !wordData.id) {
- throw new Error('无效的单词数据');
- }
-
- // 提取音频信息
- const audioInfo = this.extractAudioInfo(wordData);
- const allAudios = [];
-
- if (audioInfo.main) allAudios.push(audioInfo.main);
- if (audioInfo.syllables.length) allAudios.push(...audioInfo.syllables);
- if (audioInfo.frequencies.length) allAudios.push(...audioInfo.frequencies);
-
- // 真实下载音频文件(仅App环境)
- if (this.isApp) {
- await this.downloadAudioFiles(allAudios);
- }
-
- // 保存音频信息到缓存
- this.saveAudioInfoToStorage(wordData.id, audioInfo);
-
- return true;
- } catch (error) {
- console.error('缓存单词音频失败:', error);
- return false;
- }
- },
-
- // 下载音频文件(完整实现)
- async downloadAudioFiles(audioList) {
- if (!Array.isArray(audioList)) return;
-
- const downloadTasks = audioList.map(audio => {
- return new Promise((resolve, reject) => {
- // 检查是否已有缓存
- const cacheInfo = this.getAudioCacheInfo(audio.id);
- if (cacheInfo && cacheInfo.cached) {
- audio.lastCached = cacheInfo.timestamp;
- return resolve();
- }
-
- // 开始下载
- uni.downloadFile({
- url: audio.url,
- success: (res) => {
- if (res.statusCode === 200) {
- // 保存到缓存
- uni.setStorageSync(`audio_file_${audio.id}`, res.tempFilePath);
- uni.setStorageSync(`audio_cache_time_${audio.id}`, Date.now());
-
- audio.lastCached = Date.now();
- console.log(`音频缓存成功: ${audio.id}`);
- resolve();
- } else {
- reject(new Error(`下载失败,状态码: ${res.statusCode}`));
- }
- },
- fail: (err) => {
- reject(new Error(`下载失败: ${err.errMsg}`));
- }
- });
- }).catch(err => {
- console.warn(`音频下载失败 ${audio.id}:`, err);
- // 单个失败不影响其他
- });
- });
-
- await Promise.all(downloadTasks);
- },
-
- // 获取音频缓存信息(完整实现)
- getAudioCacheInfo(audioId) {
- if (!audioId) return null;
-
- const cachedPath = uni.getStorageSync(`audio_file_${audioId}`);
- if (!cachedPath) return null;
-
- return {
- cached: true,
- path: cachedPath,
- timestamp: uni.getStorageSync(`audio_cache_time_${audioId}`) || 0
- };
- },
-
- // 保存音频信息到Storage(完整实现)
- saveAudioInfoToStorage(wordId, audioInfo) {
- if (!wordId || !audioInfo) return;
-
- const cacheKey = `word_audio_${wordId}`;
- const cacheData = {
- ...audioInfo,
- timestamp: Date.now(),
- wordId: wordId
- };
-
- try {
- uni.setStorageSync(cacheKey, cacheData);
- } catch (e) {
- console.error('存储音频信息失败:', e);
- }
- },
-
- // 从Storage获取音频信息(完整实现)
- getAudioInfoFromStorage(wordId) {
- if (!wordId) return null;
-
- const cacheKey = `word_audio_${wordId}`;
- try {
- return uni.getStorageSync(cacheKey) || null;
- } catch (e) {
- console.error('读取音频信息失败:', e);
- return null;
- }
- },
-
- // 播放音频(完整实现)
- playAudio(audioInfo) {
- if (!audioInfo || !audioInfo.url) {
- console.error('无效的音频信息');
- return null;
- }
-
- // 确保播放器初始化
- this.init();
-
- // 停止当前播放
- this.player.stop();
-
- // 在App环境下优先使用缓存
- if (this.isApp) {
- const cacheInfo = this.getAudioCacheInfo(audioInfo.id);
- if (cacheInfo && cacheInfo.cached) {
- console.log(`使用缓存播放: ${audioInfo.id}`);
- this.player.src = cacheInfo.path;
- this.player.play();
- return this.player;
- }
- }
-
- // 无缓存或非App环境,使用网络播放
- console.log(`使用网络播放: ${audioInfo.id}`);
- this.player.src = audioInfo.url;
- this.player.play();
-
- // App环境下后台尝试缓存
- if (this.isApp) {
- this.downloadAudioFiles([audioInfo]).then(() => {
- console.log(`音频后台缓存成功: ${audioInfo.id}`);
- }).catch(err => {
- console.warn(`音频后台缓存失败: ${audioInfo.id}`, err);
- });
- }
-
- return this.player;
- },
-
- // // 清理指定单词的缓存(完整实现)
- // clearWordCache(wordId) {
- // if (!wordId) return;
-
- // // 清理音频信息
- // uni.removeStorageSync(`word_audio_${wordId}`);
-
- // // 清理所有相关音频文件
- // const prefix = `word_${wordId}_`;
- // const keys = uni.getStorageInfoSync().keys;
-
- // keys.forEach(key => {
- // if (key.startsWith('audio_file_') && key.includes(prefix)) {
- // uni.removeStorageSync(key);
- // }
- // if (key.startsWith('audio_cache_time_') && key.includes(prefix)) {
- // uni.removeStorageSync(key);
- // }
- // });
- // },
-
- // 清理所有缓存(完整实现)
- clearAllCache() {
- const keys = uni.getStorageInfoSync().keys;
-
- // 清理所有单词音频信息
- keys.filter(key => key.startsWith('word_audio_'))
- .forEach(key => uni.removeStorageSync(key));
-
- // 清理所有音频文件
- keys.filter(key => key.startsWith('audio_file_'))
- .forEach(key => uni.removeStorageSync(key));
- },
-
- // // 获取缓存大小(完整实现)
- // getCacheSize() {
- // const keys = uni.getStorageInfoSync().keys;
- // let size = 0;
-
- // keys.filter(key => key.startsWith('audio_file_'))
- // .forEach(key => {
- // try {
- // const filePath = uni.getStorageSync(key);
- // if (filePath && typeof filePath === 'string') {
- // // 注意:uni-app中无法直接获取文件大小,这里返回文件数量
- // size += 1;
- // }
- // } catch (e) {
- // console.error(`获取缓存大小失败: ${key}`, e);
- // }
- // });
-
- // return {
- // fileCount: size,
- // // 实际项目中可以添加更精确的大小计算
- // estimatedSize: size * 1024 * 100 // 假设每个文件约100KB
- // };
- // }
- };
|