Browse Source

'实现音频播放'

hfll
hflllll 1 month ago
parent
commit
a39e289e72
3 changed files with 400 additions and 6 deletions
  1. +12
    -1
      api/modules/music.js
  2. +365
    -3
      subPages/home/book.vue
  3. +23
    -2
      subPages/user/share.vue

+ 12
- 1
api/modules/music.js View File

@ -9,6 +9,17 @@ export default{
method: "GET",
needToken: true
})
}
},
// 文字转语音
async textToVoice(data){
return request({
url: "/tts/textToVoice",
method: "POST",
needToken: true,
data
})
},
}

+ 365
- 3
subPages/home/book.vue View File

@ -224,6 +224,7 @@
export default {
data() {
return {
voiceId: '',
courseId: '',
showNavbar: true,
currentPage: 1,
@ -233,10 +234,17 @@ export default {
//
isPlaying: false,
currentTime: 0,
totalTime: 317, // 5:17 = 317
totalTime: 0,
isLoop: false,
playSpeed: 1.0,
speedOptions: [1.0, 1.25, 1.5, 2.0],
//
currentPageAudios: [], //
currentAudioIndex: 0, //
audioContext: null, //
currentAudio: null, //
//
audioCache: {}, // {pageIndex: {audios: [], totalDuration: 0}}
courseIdList: [],
bookTitle: '',
courseList: [
@ -271,6 +279,114 @@ export default {
}
},
methods: {
//
async getCurrentPageAudio() {
//
const cacheKey = `${this.courseId}_${this.currentPage}`;
if (this.audioCache[cacheKey]) {
console.log('从缓存加载音频数据:', cacheKey);
//
this.currentPageAudios = this.audioCache[cacheKey].audios;
this.totalTime = this.audioCache[cacheKey].totalDuration;
this.currentAudioIndex = 0;
this.isPlaying = false;
this.currentTime = 0;
return;
}
//
this.currentPageAudios = [];
this.currentAudioIndex = 0;
this.isPlaying = false;
this.currentTime = 0;
this.totalTime = 0;
// [] text
const currentPageData = this.bookPages[this.currentPage - 1];
if (currentPageData) {
// text
const textItems = currentPageData.filter(item => item.type === 'text');
if (textItems.length > 0) {
//
const audioPromises = textItems.map(async (item, index) => {
try {
// - 使contenttext
const radioRes = await this.$api.music.textToVoice({
text: item.content,
voiceId: this.voiceId,
});
console.log(`音频请求响应 ${index + 1}:`, radioRes);
if(radioRes.code === 200){
// APIBase64WAVuniapp
const base64Data = radioRes.result;
// uniapp使base64
const audioUrl = `data:audio/wav;base64,${base64Data}`;
//
item.audioUrl = audioUrl;
console.log(`音频URL设置成功 ${index + 1}:`, audioUrl);
return {
url: audioUrl,
text: item.content,
duration: 0, //
index: index //
};
} else {
console.error(`音频请求失败 ${index + 1}:`, radioRes);
return null;
}
} catch (error) {
console.error(`音频请求异常 ${index + 1}:`, error);
return null;
}
});
//
const audioResults = await Promise.all(audioPromises);
//
this.currentPageAudios = audioResults
.filter(result => result !== null)
.sort((a, b) => a.index - b.index)
.map(result => ({
url: result.url,
text: result.text,
duration: result.duration
}));
console.log('所有音频请求完成,共获取', this.currentPageAudios.length, '个音频');
}
//
if (this.currentPageAudios.length > 0) {
await this.calculateTotalDuration();
//
const cacheKey = `${this.courseId}_${this.currentPage}`;
this.audioCache[cacheKey] = {
audios: [...this.currentPageAudios], //
totalDuration: this.totalTime
};
console.log('音频数据已缓存:', cacheKey, this.audioCache[cacheKey]);
//
this.limitCacheSize(10);
}
}
},
// id
async getVoiceList() {
const voiceRes = await this.$api.music.list()
if(voiceRes.code === 200){
this.voiceId = voiceRes.result.id
console.log('111');
await this.getCurrentPageAudio()
}
},
toggleNavbar() {
this.showNavbar = !this.showNavbar
},
@ -310,35 +426,233 @@ export default {
}
this.currentWordMeaning = null
},
//
async calculateTotalDuration() {
let totalDuration = 0;
for (let i = 0; i < this.currentPageAudios.length; i++) {
const audio = this.currentPageAudios[i];
try {
const duration = await this.getAudioDuration(audio.url);
audio.duration = duration;
totalDuration += duration;
} catch (error) {
console.error('获取音频时长失败:', error);
// 1005
const estimatedDuration = Math.max(5, audio.text.length / 20);
audio.duration = estimatedDuration;
totalDuration += estimatedDuration;
}
}
this.totalTime = totalDuration;
console.log('音频总时长:', totalDuration, '秒');
},
//
getAudioDuration(audioUrl) {
return new Promise((resolve, reject) => {
const audio = uni.createInnerAudioContext();
audio.src = audioUrl;
audio.onCanplay(() => {
resolve(audio.duration || 5); // 5
audio.destroy();
});
audio.onError((error) => {
console.error('音频加载失败:', error);
reject(error);
audio.destroy();
});
//
setTimeout(() => {
reject(new Error('获取音频时长超时'));
audio.destroy();
}, 3000);
});
},
//
togglePlay() {
this.isPlaying = !this.isPlaying;
// /
if (this.currentPageAudios.length === 0) {
uni.showToast({
title: '当前页面没有音频内容',
icon: 'none'
});
return;
}
if (this.isPlaying) {
this.pauseAudio();
} else {
this.playAudio();
}
},
//
playAudio() {
if (this.currentPageAudios.length === 0) return;
//
if (!this.currentAudio || this.currentAudio.src !== this.currentPageAudios[this.currentAudioIndex].url) {
this.createAudioInstance();
}
this.currentAudio.play();
this.isPlaying = true;
},
//
pauseAudio() {
if (this.currentAudio) {
this.currentAudio.pause();
}
this.isPlaying = false;
},
//
createAudioInstance() {
//
if (this.currentAudio) {
this.currentAudio.destroy();
}
const audio = uni.createInnerAudioContext();
audio.src = this.currentPageAudios[this.currentAudioIndex].url;
audio.playbackRate = this.playSpeed;
//
audio.onPlay(() => {
console.log('音频开始播放');
this.isPlaying = true;
});
audio.onPause(() => {
console.log('音频暂停');
this.isPlaying = false;
});
audio.onTimeUpdate(() => {
this.updateCurrentTime();
});
audio.onEnded(() => {
console.log('当前音频播放结束');
this.onAudioEnded();
});
audio.onError((error) => {
console.error('音频播放错误:', error);
this.isPlaying = false;
uni.showToast({
title: '音频播放失败',
icon: 'none'
});
});
this.currentAudio = audio;
},
//
updateCurrentTime() {
if (!this.currentAudio) return;
let totalTime = 0;
//
for (let i = 0; i < this.currentAudioIndex; i++) {
totalTime += this.currentPageAudios[i].duration;
}
//
totalTime += this.currentAudio.currentTime;
this.currentTime = totalTime;
},
//
onAudioEnded() {
if (this.currentAudioIndex < this.currentPageAudios.length - 1) {
//
this.currentAudioIndex++;
this.playAudio();
} else {
//
if (this.isLoop) {
//
this.currentAudioIndex = 0;
this.playAudio();
} else {
//
this.isPlaying = false;
this.currentTime = this.totalTime;
}
}
},
toggleLoop() {
this.isLoop = !this.isLoop;
},
toggleSpeed() {
const currentIndex = this.speedOptions.indexOf(this.playSpeed);
const nextIndex = (currentIndex + 1) % this.speedOptions.length;
this.playSpeed = this.speedOptions[nextIndex];
//
if (this.currentAudio) {
this.currentAudio.playbackRate = this.playSpeed;
}
},
//
previousAudio() {
if (this.currentPageAudios.length === 0) return;
if (this.currentAudioIndex > 0) {
this.currentAudioIndex--;
if (this.isPlaying) {
this.playAudio();
}
}
},
//
nextAudio() {
if (this.currentPageAudios.length === 0) return;
if (this.currentAudioIndex < this.currentPageAudios.length - 1) {
this.currentAudioIndex++;
if (this.isPlaying) {
this.playAudio();
}
}
},
async previousPage() {
if (this.currentPage > 1) {
//
this.pauseAudio();
this.currentPage--;
//
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) {
await this.getBookPages(this.courseIdList[this.currentPage - 1]);
}
//
await this.getCurrentPageAudio();
}
},
async nextPage() {
if (this.currentPage < this.bookPages.length) {
//
this.pauseAudio();
this.currentPage++;
//
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) {
await this.getBookPages(this.courseIdList[this.currentPage - 1]);
}
//
await this.getCurrentPageAudio();
}
},
formatTime(seconds) {
@ -360,19 +674,31 @@ export default {
})
},
async goToPage(page) {
//
this.pauseAudio();
this.currentPage = page
console.log('跳转到页面:', page)
//
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) {
await this.getBookPages(this.courseIdList[this.currentPage - 1]);
}
//
await this.getCurrentPageAudio();
},
async onSwiperChange(e) {
//
this.pauseAudio();
this.currentPage = e.detail.current + 1
//
if (this.courseIdList[this.currentPage - 1] && this.bookPages[this.currentPage - 1].length === 0) {
await this.getBookPages(this.courseIdList[this.currentPage - 1]);
}
//
await this.getCurrentPageAudio();
},
async getCourseList(id) {
const res = await this.$api.book.coursePage({
@ -423,7 +749,43 @@ export default {
this.courseId = args.courseId
//
await Promise.all([this.getCourseList(this.courseId), this.getCoursePageList(args.bookId)])
await this.getVoiceList()
},
//
onUnload() {
if (this.currentAudio) {
this.currentAudio.destroy();
this.currentAudio = null;
}
this.isPlaying = false;
//
this.clearAudioCache();
},
//
onHide() {
this.pauseAudio();
},
//
clearAudioCache() {
this.audioCache = {};
console.log('音频缓存已清理');
},
// 访
limitCacheSize(maxSize = 10) {
const cacheKeys = Object.keys(this.audioCache);
if (cacheKeys.length > maxSize) {
//
const keysToDelete = cacheKeys.slice(0, cacheKeys.length - maxSize);
keysToDelete.forEach(key => {
delete this.audioCache[key];
});
console.log('缓存大小已限制,删除了', keysToDelete.length, '个缓存项');
}
}
}
</script>


+ 23
- 2
subPages/user/share.vue View File

@ -9,7 +9,7 @@
<image
class="share-image"
:src="Qrcode"
mode="widthFix"
mode="aspectFit"
></image>
</view>
</view>
@ -44,12 +44,29 @@ export default {
icon: 'none'
})
},
save() {
uni.saveImageToPhotosAlbum({
filePath: this.Qrcode,
success: (res) => {
uni.showToast({
title: '保存成功',
icon: 'success'
})
},
fail: (err) => {
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
async getQrcode() {
// const res = await this.$api.promotion.qrCode()
// if (res.code === 200) {
uni.getImageInfo({
src: `${this.$config.baseURL}/promotion/qrCode?token=${uni.getStorageSync('token')}`,
success: function (image) {
success: (image) => {
console.log(image.width);
console.log(image.path);
this.Qrcode = image.path;
@ -75,6 +92,7 @@ export default {
}
.content {
height: 100vh;
flex: 1;
padding-bottom: 200rpx;
display: flex;
@ -82,11 +100,14 @@ export default {
justify-content: center;
.image-container {
// background: red;
display: flex;
// height: 100%;
justify-content: center;
align-items: center;
.share-image {
height: 90vh;
width: 670rpx;
border-radius: 16rpx;
}


Loading…
Cancel
Save