I'm building a movie streaming single page web application (it fetches torrent magnet url, and streams it to a custom video player) using Node/expressJS in back, VueJs 2.0 in front, with Vue-Router. This is all working great. However, I'm now trying to add subtitles to the player and am getting stuck a little.
This is my middleware used to download subtitles and convert them to VTT format, using opensubtitles-api
and srt-to-vtt
npm packages.
This is my player.vue
Vue component
<template>
<div class="player" ref='player' @mousemove="showControls" :class="{'playing': isPlaying, 'loading': videoLoading}">
<span class="player__loader" v-if="videoLoading || !initialized">
<i class='nc-icon-outline loader_circle-04 spin'></i>
</span>
<video class="player__video viewer" @click="togglePlay" @dblclick.prevent="toggleFullscreen" @timeupdate="handleProgress" @loadeddata="initVideos" ref="video" @seeking="videoLoading = true" @seeked="videoLoading = false" @waiting="videoLoading = true">
<source :src="'http://localhost:5000/api/stream/' + movieid" type="video/mp4">
<track :src="'http://localhost:5000/api/subtitles/' + movieid" kind="subtitles" srclang="en" default></track>
</video>
<div class="player__controls" ref="controls" v-if="initialized">
<div class="progress" @click="scrub"><span class="progress__filled" :style="{'flex-basis': percent + '%'}"></span></div>
<div class='player__actions'>
<div class="utils-flex-center">
<button class="player__button" data-skip="-10">
<i class='nc-icon-glyph arrows-1_triangle-left-63'></i>
</button>
<button class="player__button" title="Toggle Play" @click="togglePlay">
<i class='nc-icon-glyph' :class="isPlaying ? 'media-1_button-pause' : 'media-1_button-play'"></i>
</button>
<button class="player__button" data-skip="10">
<i class='nc-icon-glyph arrows-1_triangle-right-62'></i>
</button>
<input type="range" name="volume" class="player__slider" min="0" max="1" step="0.05" value="1" @input="soundUpdate" @change="soundUpdate">
</div>
<div class="utils-flex-center">
<button class="player__button"><i class='nc-icon-glyph ui-3_menu-right'></i></button>
<button class="player__button" @click="toggleFullscreen"><i class='nc-icon-glyph arrows-2_zoom'></i></button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'player',
data () {
return {
videoUri: null,
isPlaying: false,
initialized: false,
duration: 0,
currentTime: 0,
el: null,
videoLoading: false,
controlsTimeout: null,
discretePos: 0
}
},
computed: {
percent: function() { return (this.currentTime / this.duration) * 100 || 0 }
},
props: {
movieid: {
required: false,
type: String
}
},
methods: {
showControls: function(e) {
let controls = this.$refs.player,
_this = this;
if (!controls)
return ;
else if (this.discretePos >= e.pageX + e.pageY + 10 || this.discretePos <= e.pageX + e.pageY - 10) {
controls.classList.remove('discrete')
}
if (this.controlsTimeout)
clearTimeout(this.controlsTimeout);
this.controlsTimeout = setTimeout(function() {
controls.classList.add('discrete')
_this.discretePos = e.pageX + e.pageY
}, 500);
},
initVideos: function(e) {
let video = this.el = e.currentTarget;
this.duration = video.duration
this.isPlaying = !video.paused
this.initialized = true
},
togglePlay: function() {
let video = this.el;
this.isPlaying = !this.isPlaying
const method = this.isPlaying ? 'play' : 'pause';
console.log(method + ' called')
video[method]();
},
handleProgress: function(e) {
this.currentTime = e.currentTarget.currentTime
this.videoLoading = false;
},
scrub: function(e) {
const scrubTime = (e.offsetX / e.currentTarget.offsetWidth) * this.duration;
this.currentTime = this.el.currentTime = scrubTime;
},
soundUpdate: function(e) {
console.log(e.currentTarget.value)
this.el.volume = e.currentTarget.value
},
toggleFullscreen: function(player) {
var element = this.$refs.player
if (document.webkitIsFullScreen)
document.webkitCancelFullScreen()
else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
}
}
}
};
</script>
As you can see, I'm getting my video source from my route /api/stream
, and am trying to do the same with subtitles, using /api/subtitles
.
My route is pretty simple, and calls this express middleware:
//SubsController.js
module.exports = {
getSubtitles: function(req, res, next) {
var download = function (url, dest, cb) {
console.log('downloading subtitles...')
let file = fs.createWriteStream(dest);
let request = http.get(url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close(cb);
})
})
}
OpenSubtitles.login().then(resp => {
OpenSubtitles.search({
sublanguageid: 'eng', // Can be an array.join, 'all', or be omitted.
extensions: ['srt', 'vtt'], // Accepted extensions, defaults to 'srt'.
imdbid: req.params.movieid, // 'tt528809' is fine too.
}).then(subtitles => {
let url = subtitles.en.url; //CARE LANGUE (fr ?)
let dest = '/goinfre/pd/subtitles'
download(url, dest, function() {
console.log('subtitles downloaded.')
fs.createReadStream(dest)
.pipe(srt2vtt())
.pipe(res)
return next()
});
})
}).catch(err => {
console.log(err)
return next('problem downloading subtitles')
});
}
which will use opensubtitles-api
and srt-to-vtt
npm packages to download the proper srt subtitle, then convert it to the VTT format.
My question is, what would be the best way to achieve this? Do I need to think differently?
I was thinking about res.sendFile
but I don't think it's what I want to do.
If you need more code to fully understand this problem, just let me know!
Thanks for reading.
via pds42
No comments:
Post a Comment