211 lines
7.5 KiB
Vue
211 lines
7.5 KiB
Vue
<template>
|
|
<v-card flat>
|
|
<v-container bg fill-height grid-list-lg pb-5>
|
|
<v-layout row wrap pb-5 class="book-layout">
|
|
<v-flex xs12 sm6 lg4>
|
|
<v-card flat class="text-xs-center">
|
|
<v-layout d-inline-block mb-2>
|
|
<div class="d-inline-block f-left">
|
|
<v-img
|
|
v-if="authorImg !== ''"
|
|
:src="authorImg"
|
|
height="55px"
|
|
width="55px"
|
|
contain
|
|
class="author-image ml-2"
|
|
>
|
|
</v-img>
|
|
</div>
|
|
<div class="d-inline-block">
|
|
<v-card-title>
|
|
<div>{{ authorName }}</div>
|
|
</v-card-title>
|
|
</div>
|
|
</v-layout>
|
|
</v-card>
|
|
<v-flex xs12 text-xs-center>
|
|
<v-img
|
|
:src="bookImg"
|
|
height="200px"
|
|
width="200px"
|
|
contain
|
|
class="d-inline-block ml-2"
|
|
>
|
|
</v-img>
|
|
</v-flex>
|
|
<v-flex xs12 text-xs-center>{{ bookTitle }}</v-flex>
|
|
</v-flex>
|
|
<v-flex xs12 sm6>
|
|
<v-list>
|
|
<v-list-tile
|
|
v-for="(item, index) in items"
|
|
v-bind:key="index"
|
|
@click="loadChapter(index, 0, true)"
|
|
>
|
|
<v-list-tile-action>
|
|
<v-icon
|
|
v-if="index == currentChapter"
|
|
>mdi-play</v-icon>
|
|
</v-list-tile-action>
|
|
<v-list-tile-content>
|
|
<v-list-tile-title v-text="item.title"></v-list-tile-title>
|
|
</v-list-tile-content>
|
|
</v-list-tile>
|
|
</v-list>
|
|
</v-flex>
|
|
</v-layout>
|
|
</v-container>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data: () => ({
|
|
audioElement: null,
|
|
authorName: "",
|
|
authorImg: "",
|
|
bookImg: "",
|
|
bookTitle: "",
|
|
currentChapter: 0,
|
|
currentTime: "00:00",
|
|
duration: "00:00",
|
|
items: [],
|
|
progress: 0,
|
|
status: 0, //this.statuses.stopped,
|
|
volume: 5
|
|
}),
|
|
|
|
computed: {
|
|
isOff () {
|
|
return this.audioElement == null;
|
|
},
|
|
|
|
isPaused () {
|
|
return this.status === this.statuses.paused;
|
|
},
|
|
|
|
isPlaying () {
|
|
return this.status === this.statuses.playing;
|
|
},
|
|
|
|
isChapterLoaded () {
|
|
return (this.currentChapter !== null) && this.audioElement;
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
volume (val) { this.updateVolume(); }
|
|
},
|
|
|
|
methods: {
|
|
loadChapter (index = 0, progress = 0, autoplay = false) {
|
|
if (this.audioElement) { this.audioElement.pause(); }
|
|
if (index >= this.items.length) { return false; } // show message?
|
|
|
|
this.currentChapter = index;
|
|
this.audioElement = new Audio(encodeURI(this.items[index].url));
|
|
this.updateVolume();
|
|
this.status = this.statuses.stopped;
|
|
this.audioElement.addEventListener("ended", this.loadNextChapter);
|
|
|
|
this.audioElement.ontimeupdate = this.updateProgress;
|
|
|
|
let bookInstance = this;
|
|
|
|
this.audioElement.addEventListener("durationchange", function () {
|
|
let min = parseInt(bookInstance.audioElement.duration / 60) < 10
|
|
? "0" + parseInt(bookInstance.audioElement.duration / 60)
|
|
: parseInt(bookInstance.audioElement.duration / 60);
|
|
let sec = parseInt(bookInstance.audioElement.duration % 60) < 10
|
|
? "0" + parseInt(bookInstance.audioElement.duration % 60)
|
|
: parseInt(bookInstance.audioElement.duration % 60);
|
|
bookInstance.duration = min + ":" + sec;
|
|
});
|
|
|
|
this.audioElement.addEventListener("canplay", function _listener () {
|
|
bookInstance.audioElement.currentTime = bookInstance.audioElement.duration * progress / 100;
|
|
bookInstance.audioElement.removeEventListener("canplay", _listener, true);
|
|
}, true);
|
|
|
|
if (autoplay) this.play();
|
|
},
|
|
|
|
loadNextChapter (autoplay = true) {
|
|
this.currentChapter++;
|
|
if (this.currentChapter >= this.items.length) {
|
|
this.currentChapter--;
|
|
return false;
|
|
}
|
|
this.loadChapter(this.currentChapter, 0, autoplay);
|
|
},
|
|
|
|
nextChapter () {
|
|
if (this.currentChapter < this.items.length - 1) {
|
|
this.currentChapter++;
|
|
this.loadChapter(this.currentChapter, 0, true);
|
|
}
|
|
},
|
|
|
|
pause () {
|
|
this.status = this.statuses.paused;
|
|
this.audioElement.pause();
|
|
},
|
|
|
|
play () {
|
|
this.status = this.statuses.playing;
|
|
this.audioElement.play();
|
|
},
|
|
|
|
prevChapter () {
|
|
if (this.currentChapter > 0) {
|
|
this.currentChapter--;
|
|
this.loadChapter(this.currentChapter, 0, true);
|
|
}
|
|
},
|
|
|
|
toggleStatus () {
|
|
if (!this.isChapterLoaded) {
|
|
this.loadChapter(this.currentChapter || 0);
|
|
}
|
|
|
|
if (!this.isPlaying) {
|
|
this.play();
|
|
} else {
|
|
this.pause();
|
|
}
|
|
},
|
|
|
|
updateProgress () {
|
|
if (!this.audioElement || !this.audioElement.currentTime) {
|
|
return this.progress = 0;
|
|
}
|
|
|
|
this.progress = (this.audioElement.currentTime / this.audioElement.duration) * 100;
|
|
|
|
let min = parseInt(this.audioElement.currentTime / 60) < 10
|
|
? "0" + parseInt(this.audioElement.currentTime / 60)
|
|
: parseInt(this.audioElement.currentTime / 60);
|
|
let sec = parseInt(this.audioElement.currentTime % 60) < 10
|
|
? "0" + parseInt(this.audioElement.currentTime % 60)
|
|
: parseInt(this.audioElement.currentTime % 60);
|
|
this.currentTime = min + ":" + sec;
|
|
},
|
|
|
|
updateVolume () {
|
|
this.audioElement ? this.audioElement.volume = (this.volume / 10) : null;
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.author-image {
|
|
display: inline-block;
|
|
border-radius: 55px;
|
|
}
|
|
|
|
.book-layout { min-height: calc(100vh - 190px); }
|
|
|
|
.f-left { float: left; }
|
|
</style>
|