2020-02-16 18:30:00 +00:00
|
|
|
import Vue from 'vue'
|
2021-01-13 03:56:31 +00:00
|
|
|
import { mapActions } from 'vuex'
|
2020-02-16 18:30:00 +00:00
|
|
|
import FtCard from '../ft-card/ft-card.vue'
|
|
|
|
|
2020-02-20 20:58:21 +00:00
|
|
|
import $ from 'jquery'
|
2020-02-16 18:30:00 +00:00
|
|
|
import videojs from 'video.js'
|
2020-02-18 20:59:01 +00:00
|
|
|
import qualitySelector from '@silvermine/videojs-quality-selector'
|
2020-11-13 22:29:41 +00:00
|
|
|
import fs from 'fs'
|
2020-11-15 19:13:18 +00:00
|
|
|
import 'videojs-overlay/dist/videojs-overlay'
|
|
|
|
import 'videojs-overlay/dist/videojs-overlay.css'
|
2020-09-01 10:04:54 +00:00
|
|
|
import 'videojs-vtt-thumbnails-freetube'
|
2020-02-18 20:59:01 +00:00
|
|
|
import 'videojs-contrib-quality-levels'
|
|
|
|
import 'videojs-http-source-selector'
|
2020-02-16 18:30:00 +00:00
|
|
|
|
|
|
|
export default Vue.extend({
|
|
|
|
name: 'FtVideoPlayer',
|
|
|
|
components: {
|
|
|
|
'ft-card': FtCard
|
|
|
|
},
|
2020-10-04 18:30:54 +00:00
|
|
|
beforeRouteLeave: function () {
|
2020-12-22 18:58:17 +00:00
|
|
|
if (this.player !== null) {
|
|
|
|
this.exitFullWindow()
|
|
|
|
}
|
2020-10-04 18:30:54 +00:00
|
|
|
if (this.player !== null && !this.player.isInPictureInPicture()) {
|
|
|
|
this.player.dispose()
|
|
|
|
this.player = null
|
|
|
|
clearTimeout(this.mouseTimeout)
|
|
|
|
} else if (this.player.isInPictureInPicture()) {
|
|
|
|
this.player.play()
|
|
|
|
}
|
2021-01-13 20:56:25 +00:00
|
|
|
|
|
|
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
|
|
|
const { powerSaveBlocker } = require('electron')
|
|
|
|
powerSaveBlocker.stop(this.powerSaveBlocker)
|
|
|
|
}
|
2020-10-04 18:30:54 +00:00
|
|
|
},
|
2020-02-16 18:30:00 +00:00
|
|
|
props: {
|
2020-02-19 03:31:10 +00:00
|
|
|
format: {
|
|
|
|
type: String,
|
|
|
|
required: true
|
|
|
|
},
|
2020-02-18 20:59:01 +00:00
|
|
|
sourceList: {
|
|
|
|
type: Array,
|
2020-04-21 20:22:41 +00:00
|
|
|
default: () => { return [] }
|
2020-02-18 20:59:01 +00:00
|
|
|
},
|
2021-05-15 19:08:41 +00:00
|
|
|
adaptiveFormats: {
|
|
|
|
type: Array,
|
|
|
|
default: () => { return [] }
|
|
|
|
},
|
2020-02-18 20:59:01 +00:00
|
|
|
dashSrc: {
|
2020-02-19 03:31:10 +00:00
|
|
|
type: Array,
|
2020-02-18 20:59:01 +00:00
|
|
|
default: null
|
|
|
|
},
|
|
|
|
hlsSrc: {
|
2020-02-19 03:31:10 +00:00
|
|
|
type: Array,
|
2020-02-18 20:59:01 +00:00
|
|
|
default: null
|
|
|
|
},
|
2021-03-17 01:28:25 +00:00
|
|
|
captionHybridList: {
|
2020-02-16 18:30:00 +00:00
|
|
|
type: Array,
|
|
|
|
default: () => { return [] }
|
|
|
|
},
|
2020-02-18 20:59:01 +00:00
|
|
|
storyboardSrc: {
|
2020-02-16 18:30:00 +00:00
|
|
|
type: String,
|
2020-02-18 20:59:01 +00:00
|
|
|
default: ''
|
2020-06-01 02:47:22 +00:00
|
|
|
},
|
|
|
|
thumbnail: {
|
|
|
|
type: String,
|
|
|
|
default: ''
|
2021-05-16 20:01:24 +00:00
|
|
|
},
|
|
|
|
videoId: {
|
|
|
|
type: String,
|
|
|
|
required: true
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
data: function () {
|
|
|
|
return {
|
|
|
|
id: '',
|
2021-01-11 20:45:46 +00:00
|
|
|
powerSaveBlocker: null,
|
2020-03-01 03:37:02 +00:00
|
|
|
volume: 1,
|
2020-02-16 18:30:00 +00:00
|
|
|
player: null,
|
2020-02-18 20:59:01 +00:00
|
|
|
useDash: false,
|
|
|
|
useHls: false,
|
2020-09-25 02:35:13 +00:00
|
|
|
selectedDefaultQuality: '',
|
2021-03-12 21:09:08 +00:00
|
|
|
selectedQuality: '',
|
2021-04-30 21:18:45 +00:00
|
|
|
using60Fps: false,
|
2020-11-13 22:29:41 +00:00
|
|
|
maxFramerate: 0,
|
2020-02-18 20:59:01 +00:00
|
|
|
activeSourceList: [],
|
2021-05-15 19:08:41 +00:00
|
|
|
activeAdaptiveFormats: [],
|
2020-02-21 18:31:32 +00:00
|
|
|
mouseTimeout: null,
|
2021-01-16 03:34:49 +00:00
|
|
|
touchTimeout: null,
|
|
|
|
lastTouchTime: null,
|
2020-02-16 18:30:00 +00:00
|
|
|
dataSetup: {
|
2021-01-15 04:20:42 +00:00
|
|
|
fluid: true,
|
2020-02-18 20:59:01 +00:00
|
|
|
nativeTextTracks: false,
|
|
|
|
plugins: {},
|
|
|
|
controlBar: {
|
|
|
|
children: [
|
|
|
|
'playToggle',
|
|
|
|
'volumePanel',
|
|
|
|
'currentTimeDisplay',
|
|
|
|
'timeDivider',
|
|
|
|
'durationDisplay',
|
|
|
|
'progressControl',
|
|
|
|
'liveDisplay',
|
|
|
|
'seekToLive',
|
|
|
|
'remainingTimeDisplay',
|
|
|
|
'customControlSpacer',
|
|
|
|
'playbackRateMenuButton',
|
2021-01-13 03:56:31 +00:00
|
|
|
'loopButton',
|
2020-02-18 20:59:01 +00:00
|
|
|
'chaptersButton',
|
|
|
|
'descriptionsButton',
|
|
|
|
'subsCapsButton',
|
|
|
|
'audioTrackButton',
|
2020-12-14 23:25:51 +00:00
|
|
|
'pictureInPictureToggle',
|
|
|
|
'fullWindowButton',
|
2020-12-14 22:37:58 +00:00
|
|
|
'qualitySelector',
|
2020-12-14 23:25:51 +00:00
|
|
|
'fullscreenToggle'
|
2020-02-18 20:59:01 +00:00
|
|
|
]
|
|
|
|
},
|
2020-02-16 18:30:00 +00:00
|
|
|
playbackRates: [
|
2020-12-17 16:22:05 +00:00
|
|
|
0.25,
|
2020-12-15 20:09:49 +00:00
|
|
|
0.5,
|
2020-12-17 16:22:05 +00:00
|
|
|
0.75,
|
|
|
|
1,
|
|
|
|
1.25,
|
|
|
|
1.5,
|
|
|
|
1.75,
|
|
|
|
2,
|
|
|
|
2.25,
|
|
|
|
2.5,
|
|
|
|
2.75,
|
|
|
|
3
|
2020-02-16 18:30:00 +00:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2021-01-11 20:45:46 +00:00
|
|
|
usingElectron: function () {
|
|
|
|
return this.$store.getters.getUsingElectron
|
|
|
|
},
|
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
defaultPlayback: function () {
|
|
|
|
return this.$store.getters.getDefaultPlayback
|
2020-02-20 20:58:21 +00:00
|
|
|
},
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
defaultQuality: function () {
|
2020-09-26 16:10:56 +00:00
|
|
|
return parseInt(this.$store.getters.getDefaultQuality)
|
2020-05-17 20:12:58 +00:00
|
|
|
},
|
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
defaultVideoFormat: function () {
|
|
|
|
return this.$store.getters.getDefaultVideoFormat
|
|
|
|
},
|
|
|
|
|
|
|
|
autoplayVideos: function () {
|
|
|
|
return this.$store.getters.getAutoplayVideos
|
2021-05-16 20:01:24 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
useSponsorBlock: function () {
|
|
|
|
return this.$store.getters.getUseSponsorBlock
|
|
|
|
},
|
|
|
|
|
|
|
|
sponsorBlockShowSkippedToast: function () {
|
|
|
|
return this.$store.getters.getSponsorBlockShowSkippedToast
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
mounted: function () {
|
|
|
|
this.id = this._uid
|
2020-02-18 20:59:01 +00:00
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
const volume = sessionStorage.getItem('volume')
|
|
|
|
|
|
|
|
if (volume !== null) {
|
|
|
|
this.volume = volume
|
|
|
|
}
|
|
|
|
|
2020-12-14 23:25:51 +00:00
|
|
|
this.createFullWindowButton()
|
2021-01-13 03:56:31 +00:00
|
|
|
this.createLoopButton()
|
2020-02-18 20:59:01 +00:00
|
|
|
this.determineFormatType()
|
2020-11-13 22:29:41 +00:00
|
|
|
this.determineMaxFramerate()
|
2020-02-16 18:30:00 +00:00
|
|
|
},
|
2020-02-20 20:58:21 +00:00
|
|
|
beforeDestroy: function () {
|
2020-12-22 18:58:17 +00:00
|
|
|
if (this.player !== null) {
|
|
|
|
this.exitFullWindow()
|
|
|
|
|
|
|
|
if (!this.player.isInPictureInPicture()) {
|
|
|
|
this.player.dispose()
|
|
|
|
this.player = null
|
|
|
|
clearTimeout(this.mouseTimeout)
|
|
|
|
}
|
2020-02-20 20:58:21 +00:00
|
|
|
}
|
2021-01-13 20:56:25 +00:00
|
|
|
|
|
|
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
|
|
|
const { powerSaveBlocker } = require('electron')
|
|
|
|
powerSaveBlocker.stop(this.powerSaveBlocker)
|
|
|
|
}
|
2020-02-20 20:58:21 +00:00
|
|
|
},
|
2020-02-16 18:30:00 +00:00
|
|
|
methods: {
|
2020-09-25 02:35:13 +00:00
|
|
|
initializePlayer: async function () {
|
2021-05-15 19:08:41 +00:00
|
|
|
console.log(this.adaptiveFormats)
|
2020-02-16 18:30:00 +00:00
|
|
|
const videoPlayer = document.getElementById(this.id)
|
|
|
|
if (videoPlayer !== null) {
|
2020-05-24 21:32:02 +00:00
|
|
|
if (!this.useDash) {
|
2020-02-18 20:59:01 +00:00
|
|
|
qualitySelector(videojs, { showQualitySelectionLabelInControlBar: true })
|
2020-09-26 21:03:42 +00:00
|
|
|
await this.determineDefaultQualityLegacy()
|
2020-02-18 20:59:01 +00:00
|
|
|
}
|
|
|
|
|
2020-10-28 21:20:07 +00:00
|
|
|
this.player = videojs(videoPlayer, {
|
|
|
|
html5: {
|
2021-03-17 01:28:25 +00:00
|
|
|
preloadTextTracks: false,
|
2020-10-28 21:20:07 +00:00
|
|
|
vhs: {
|
2020-12-27 03:21:06 +00:00
|
|
|
limitRenditionByPlayerDimensions: false,
|
|
|
|
smoothQualityChange: false,
|
2021-03-12 21:09:08 +00:00
|
|
|
allowSeeksWithinUnsafeLiveWindow: true,
|
|
|
|
handlePartialData: true
|
2020-10-28 21:20:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2020-12-14 23:25:51 +00:00
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
this.player.volume(this.volume)
|
|
|
|
this.player.playbackRate(this.defaultPlayback)
|
|
|
|
|
2020-09-25 02:35:13 +00:00
|
|
|
if (this.storyboardSrc !== '') {
|
|
|
|
this.player.vttThumbnails({
|
|
|
|
src: this.storyboardSrc,
|
|
|
|
showTimestamp: true
|
|
|
|
})
|
|
|
|
}
|
2020-02-18 20:59:01 +00:00
|
|
|
|
2020-05-24 21:32:02 +00:00
|
|
|
if (this.useDash) {
|
2021-03-12 21:09:08 +00:00
|
|
|
// this.dataSetup.plugins.httpSourceSelector = {
|
|
|
|
// default: 'auto'
|
|
|
|
// }
|
2020-02-18 20:59:01 +00:00
|
|
|
|
2021-03-12 21:09:08 +00:00
|
|
|
// this.player.httpSourceSelector()
|
|
|
|
this.createDashQualitySelector(this.player.qualityLevels())
|
2020-02-18 20:59:01 +00:00
|
|
|
}
|
2020-02-20 20:58:21 +00:00
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
if (this.autoplayVideos) {
|
2020-02-20 20:58:21 +00:00
|
|
|
// Calling play() won't happen right away, so a quick timeout will make it function properly.
|
|
|
|
setTimeout(() => {
|
|
|
|
this.player.play()
|
2020-05-24 21:32:02 +00:00
|
|
|
}, 200)
|
2020-02-20 20:58:21 +00:00
|
|
|
}
|
|
|
|
|
2020-12-14 23:25:51 +00:00
|
|
|
$(document).on('keydown', this.keyboardShortcutHandler)
|
2020-02-21 18:31:32 +00:00
|
|
|
|
|
|
|
this.player.on('mousemove', this.hideMouseTimeout)
|
|
|
|
this.player.on('mouseleave', this.removeMouseTimeout)
|
2020-10-27 19:20:41 +00:00
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
this.player.on('volumechange', this.updateVolume)
|
2020-10-27 19:20:41 +00:00
|
|
|
this.player.controlBar.getChild('volumePanel').on('mousewheel', this.mouseScrollVolume)
|
2020-02-21 18:31:32 +00:00
|
|
|
|
2020-11-15 19:13:18 +00:00
|
|
|
this.player.on('fullscreenchange', this.fullscreenOverlay)
|
2021-04-22 18:41:50 +00:00
|
|
|
this.player.on('fullscreenchange', this.toggleFullscreenClass)
|
2020-11-15 19:13:18 +00:00
|
|
|
|
2020-02-21 18:31:32 +00:00
|
|
|
const v = this
|
|
|
|
|
2020-08-20 02:39:44 +00:00
|
|
|
this.player.on('ready', function () {
|
|
|
|
v.$emit('ready')
|
2021-01-15 04:20:42 +00:00
|
|
|
v.checkAspectRatio()
|
2021-03-17 01:28:25 +00:00
|
|
|
if (v.captionHybridList.length !== 0) {
|
|
|
|
v.transformAndInsertCaptions()
|
|
|
|
}
|
2020-08-20 02:39:44 +00:00
|
|
|
})
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
this.player.on('ended', function () {
|
|
|
|
v.$emit('ended')
|
|
|
|
})
|
|
|
|
|
2020-02-21 18:31:32 +00:00
|
|
|
this.player.on('error', function (error, message) {
|
|
|
|
v.$emit('error', error.target.player.error_)
|
|
|
|
})
|
2021-01-11 20:45:46 +00:00
|
|
|
|
|
|
|
this.player.on('play', function () {
|
|
|
|
if (this.usingElectron) {
|
|
|
|
const { powerSaveBlocker } = require('electron')
|
|
|
|
|
|
|
|
this.powerSaveBlocker = powerSaveBlocker.start('prevent-display-sleep')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
this.player.on('pause', function () {
|
|
|
|
if (this.usingElectron && this.powerSaveBlocker !== null) {
|
|
|
|
const { powerSaveBlocker } = require('electron')
|
|
|
|
powerSaveBlocker.stop(this.powerSaveBlocker)
|
|
|
|
this.powerSaveBlocker = null
|
|
|
|
}
|
|
|
|
})
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
2021-05-16 20:01:24 +00:00
|
|
|
setTimeout(() => { this.fetchSponsorBlockInfo() }, 100)
|
|
|
|
},
|
|
|
|
|
|
|
|
fetchSponsorBlockInfo() {
|
|
|
|
if (this.useSponsorBlock) {
|
|
|
|
this.$store.dispatch('sponsorBlockSkipSegments', {
|
|
|
|
videoId: this.videoId,
|
|
|
|
categories: ['sponsor']
|
|
|
|
}).then((skipSegments) => {
|
|
|
|
this.player.on('timeupdate', () => {
|
|
|
|
this.skipSponsorBlocks(skipSegments)
|
|
|
|
})
|
|
|
|
skipSegments.forEach(({
|
|
|
|
category,
|
|
|
|
segment: [startTime, endTime]
|
|
|
|
}) => {
|
|
|
|
this.addSponsorBlockMarker({
|
|
|
|
time: startTime,
|
|
|
|
duration: endTime - startTime,
|
|
|
|
color: this.sponsorBlockCategoryColor(category)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
skipSponsorBlocks(skipSegments) {
|
|
|
|
const currentTime = this.player.currentTime()
|
|
|
|
let newTime = null
|
|
|
|
let skippedCategory = null
|
|
|
|
skipSegments.forEach(({ category, segment: [startTime, endTime] }) => {
|
|
|
|
if (startTime <= currentTime && currentTime < endTime) {
|
|
|
|
newTime = endTime
|
|
|
|
skippedCategory = category
|
|
|
|
}
|
|
|
|
})
|
|
|
|
if (newTime !== null) {
|
|
|
|
if (this.sponsorBlockShowSkippedToast) {
|
|
|
|
this.showSkippedSponsorSegmentInformation(skippedCategory)
|
|
|
|
}
|
|
|
|
this.player.currentTime(newTime)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
showSkippedSponsorSegmentInformation(category) {
|
|
|
|
const translatedCategory = this.sponsorBlockTranslatedCategory(category)
|
|
|
|
this.showToast({
|
|
|
|
message: `${this.$t('Video.Skipped segment')} ${translatedCategory}`
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
sponsorBlockTranslatedCategory(category) {
|
|
|
|
switch (category) {
|
|
|
|
case 'sponsor':
|
|
|
|
return this.$t('Video.Sponsor Block category.sponsor')
|
|
|
|
case 'intro':
|
|
|
|
return this.$t('Video.Sponsor Block category.intro')
|
|
|
|
case 'outro':
|
|
|
|
return this.$t('Video.Sponsor Block category.outro')
|
|
|
|
case 'selfpromo':
|
|
|
|
return this.$t('Video.Sponsor Block category.self-promotion')
|
|
|
|
case 'interaction':
|
|
|
|
return this.$t('Video.Sponsor Block category.interaction')
|
|
|
|
case 'music_offtopic':
|
|
|
|
return this.$t('Video.Sponsor Block category.music offtopic')
|
|
|
|
default:
|
|
|
|
console.error(`Unknown translation for SponsorBlock category ${category}`)
|
|
|
|
return category
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
sponsorBlockCategoryColor(category) {
|
|
|
|
// TODO: allow to set these colors in settings
|
|
|
|
switch (category) {
|
|
|
|
case 'sponsor':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
case 'intro':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
case 'outro':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
case 'selfpromo':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
case 'interaction':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
case 'music_offtopic':
|
2021-05-17 19:05:42 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
default:
|
|
|
|
console.error(`Unknown SponsorBlock category ${category}`)
|
2021-05-17 19:06:10 +00:00
|
|
|
return 'var(--accent-color)'
|
2021-05-16 20:01:24 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
addSponsorBlockMarker(marker) {
|
|
|
|
const markerDiv = videojs.dom.createEl('div', {}, {})
|
|
|
|
|
|
|
|
markerDiv.className = 'sponsorBlockMarker'
|
|
|
|
markerDiv.style.height = '100%'
|
|
|
|
markerDiv.style.position = 'absolute'
|
|
|
|
markerDiv.style['background-color'] = marker.color
|
|
|
|
markerDiv.style.width = (marker.duration / this.player.duration()) * 100 + '%'
|
|
|
|
markerDiv.style.marginLeft = (marker.time / this.player.duration()) * 100 + '%'
|
|
|
|
|
|
|
|
this.player.el().querySelector('.vjs-progress-holder').appendChild(markerDiv)
|
2020-02-18 20:59:01 +00:00
|
|
|
},
|
|
|
|
|
2021-01-15 04:20:42 +00:00
|
|
|
checkAspectRatio() {
|
|
|
|
const videoWidth = this.player.videoWidth()
|
|
|
|
const videoHeight = this.player.videoHeight()
|
|
|
|
|
|
|
|
if (videoWidth === 0 || videoHeight === 0) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.checkAspectRatio()
|
|
|
|
}, 200)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-01-21 15:28:45 +00:00
|
|
|
if ((videoWidth - videoHeight) <= 240) {
|
2021-01-15 04:20:42 +00:00
|
|
|
this.player.fluid(false)
|
|
|
|
this.player.aspectRatio('16:9')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
updateVolume: function (event) {
|
|
|
|
const volume = this.player.volume()
|
|
|
|
sessionStorage.setItem('volume', volume)
|
|
|
|
},
|
|
|
|
|
2020-10-27 19:20:41 +00:00
|
|
|
mouseScrollVolume: function (event) {
|
|
|
|
if (event.target) {
|
|
|
|
event.preventDefault()
|
|
|
|
|
|
|
|
if (this.player.muted() && event.wheelDelta > 0) {
|
|
|
|
this.player.muted(false)
|
|
|
|
this.player.volume(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.player.muted()) {
|
|
|
|
if (event.wheelDelta > 0) {
|
|
|
|
this.changeVolume(0.05)
|
|
|
|
} else if (event.wheelDelta < 0) {
|
|
|
|
this.changeVolume(-0.05)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-02-18 20:59:01 +00:00
|
|
|
determineFormatType: function () {
|
2020-02-19 03:31:10 +00:00
|
|
|
if (this.format === 'dash') {
|
2020-02-18 20:59:01 +00:00
|
|
|
this.enableDashFormat()
|
|
|
|
} else {
|
|
|
|
this.enableLegacyFormat()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-11-13 22:29:41 +00:00
|
|
|
determineMaxFramerate: function() {
|
2020-11-15 18:46:18 +00:00
|
|
|
if (this.dashSrc.length === 0) {
|
|
|
|
this.maxFramerate = 60
|
|
|
|
return
|
|
|
|
}
|
2020-11-13 22:29:41 +00:00
|
|
|
fs.readFile(this.dashSrc[0].url, (err, data) => {
|
|
|
|
if (err) {
|
|
|
|
this.maxFramerate = 60
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if (data.includes('frameRate="60"')) {
|
|
|
|
this.maxFramerate = 60
|
|
|
|
} else {
|
|
|
|
this.maxFramerate = 30
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2020-09-26 21:03:42 +00:00
|
|
|
determineDefaultQualityLegacy: function () {
|
2020-05-24 21:46:26 +00:00
|
|
|
if (this.useDash) {
|
2020-09-25 02:35:13 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.sourceList.length === 0) {
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof (this.sourceList[0].qualityLabel) === 'number') {
|
|
|
|
return ''
|
2020-05-24 21:46:26 +00:00
|
|
|
}
|
|
|
|
|
2020-10-05 01:20:30 +00:00
|
|
|
if (this.sourceList[this.sourceList.length - 1].qualityLabel === this.$t('Video.Audio.Low')) {
|
|
|
|
this.selectedDefaultQuality = this.sourceList[0].qualityLabel
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-26 21:03:42 +00:00
|
|
|
let defaultQuality = this.defaultQuality
|
|
|
|
|
|
|
|
if (defaultQuality === 'auto') {
|
|
|
|
defaultQuality = 720
|
|
|
|
}
|
|
|
|
|
2020-09-25 02:35:13 +00:00
|
|
|
let maxAvailableQuality = parseInt(this.sourceList[this.sourceList.length - 1].qualityLabel.replace(/p|k/, ''))
|
|
|
|
|
|
|
|
if (maxAvailableQuality === 4) {
|
|
|
|
maxAvailableQuality = 2160
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maxAvailableQuality === 8) {
|
|
|
|
maxAvailableQuality = 4320
|
|
|
|
}
|
|
|
|
|
2020-09-26 21:03:42 +00:00
|
|
|
if (maxAvailableQuality < defaultQuality) {
|
2020-09-25 02:35:13 +00:00
|
|
|
this.selectedDefaultQuality = this.sourceList[this.sourceList.length - 1].qualityLabel
|
|
|
|
}
|
|
|
|
|
|
|
|
const reversedList = [].concat(this.sourceList).reverse()
|
|
|
|
|
|
|
|
reversedList.forEach((source, index) => {
|
|
|
|
let qualityNumber = parseInt(source.qualityLabel.replace(/p|k/, ''))
|
|
|
|
if (qualityNumber === 4) {
|
|
|
|
qualityNumber = 2160
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
2020-09-25 02:35:13 +00:00
|
|
|
if (qualityNumber === 8) {
|
|
|
|
qualityNumber = 4320
|
|
|
|
}
|
|
|
|
|
2020-09-26 21:03:42 +00:00
|
|
|
if (defaultQuality === qualityNumber) {
|
2020-09-26 16:10:56 +00:00
|
|
|
this.selectedDefaultQuality = source.qualityLabel
|
|
|
|
}
|
|
|
|
|
2020-09-25 02:35:13 +00:00
|
|
|
if (index < (this.sourceList.length - 1)) {
|
|
|
|
let upperQualityNumber = parseInt(reversedList[index + 1].qualityLabel.replace(/p|k/, ''))
|
|
|
|
if (upperQualityNumber === 4) {
|
|
|
|
upperQualityNumber = 2160
|
|
|
|
}
|
|
|
|
if (upperQualityNumber === 8) {
|
|
|
|
upperQualityNumber = 4320
|
|
|
|
}
|
2020-09-26 21:03:42 +00:00
|
|
|
if (defaultQuality >= qualityNumber && defaultQuality < upperQualityNumber) {
|
2020-09-25 02:35:13 +00:00
|
|
|
this.selectedDefaultQuality = source.qualityLabel
|
|
|
|
}
|
2020-09-26 21:03:42 +00:00
|
|
|
} else if (qualityNumber <= defaultQuality) {
|
2020-09-25 02:35:13 +00:00
|
|
|
this.selectedDefaultQuality = source.qualityLabel
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if (this.selectedDefaultQuality === '') {
|
|
|
|
this.selectedDefaultQuality = this.sourceList[this.sourceList.length - 1].qualityLabel
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-09-26 21:03:42 +00:00
|
|
|
determineDefaultQualityDash: function () {
|
|
|
|
if (this.defaultQuality === 'auto') {
|
2021-03-12 21:09:08 +00:00
|
|
|
this.setDashQualityLevel('auto')
|
2020-09-26 21:03:42 +00:00
|
|
|
}
|
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
let formatsToTest
|
2021-05-15 19:08:41 +00:00
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
if (typeof this.activeAdaptiveFormats !== 'undefined' && this.activeAdaptiveFormats.length > 0) {
|
2021-05-15 19:08:41 +00:00
|
|
|
formatsToTest = this.activeAdaptiveFormats.filter((format) => {
|
2021-05-17 01:40:34 +00:00
|
|
|
return format.height === this.defaultQuality
|
2021-05-15 19:08:41 +00:00
|
|
|
})
|
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
if (formatsToTest.length === 0) {
|
|
|
|
formatsToTest = this.activeAdaptiveFormats.filter((format) => {
|
|
|
|
return format.height < this.defaultQuality
|
|
|
|
})
|
2021-05-15 19:08:41 +00:00
|
|
|
}
|
2021-05-17 01:40:34 +00:00
|
|
|
|
|
|
|
formatsToTest = formatsToTest.sort((a, b) => {
|
|
|
|
if (a.height === b.height) {
|
|
|
|
return b.bitrate - a.bitrate
|
|
|
|
} else {
|
|
|
|
return b.height - a.height
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
formatsToTest = this.player.qualityLevels().levels_.filter((format) => {
|
|
|
|
return format.height === this.defaultQuality
|
|
|
|
})
|
|
|
|
|
|
|
|
if (formatsToTest.length === 0) {
|
|
|
|
formatsToTest = this.player.qualityLevels().levels_.filter((format) => {
|
|
|
|
return format.height < this.defaultQuality
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
formatsToTest = formatsToTest.sort((a, b) => {
|
|
|
|
if (a.height === b.height) {
|
|
|
|
return b.bitrate - a.bitrate
|
|
|
|
} else {
|
|
|
|
return b.height - a.height
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2021-05-15 19:08:41 +00:00
|
|
|
|
2021-05-15 19:13:17 +00:00
|
|
|
// TODO: Test formats to determine if HDR / 60 FPS and skip them based on
|
|
|
|
// User settings
|
2021-05-15 19:08:41 +00:00
|
|
|
this.setDashQualityLevel(formatsToTest[0].bitrate)
|
|
|
|
|
|
|
|
// Old logic. Revert if needed
|
|
|
|
/* this.player.qualityLevels().levels_.sort((a, b) => {
|
2021-04-30 21:18:45 +00:00
|
|
|
if (a.height === b.height) {
|
|
|
|
return a.bitrate - b.bitrate
|
|
|
|
} else {
|
|
|
|
return a.height - b.height
|
|
|
|
}
|
2020-09-26 21:03:42 +00:00
|
|
|
}).forEach((ql, index, arr) => {
|
|
|
|
const height = ql.height
|
|
|
|
const width = ql.width
|
|
|
|
const quality = width < height ? width : height
|
|
|
|
let upperLevel = null
|
|
|
|
|
|
|
|
if (index < arr.length - 1) {
|
|
|
|
upperLevel = arr[index + 1]
|
|
|
|
}
|
|
|
|
|
2021-04-30 21:18:45 +00:00
|
|
|
if (this.defaultQuality === quality && upperLevel === null) {
|
|
|
|
this.setDashQualityLevel(height, true)
|
2020-09-26 21:03:42 +00:00
|
|
|
} else if (upperLevel !== null) {
|
|
|
|
const upperHeight = upperLevel.height
|
|
|
|
const upperWidth = upperLevel.width
|
|
|
|
const upperQuality = upperWidth < upperHeight ? upperWidth : upperHeight
|
|
|
|
|
2021-04-30 21:18:45 +00:00
|
|
|
if (this.defaultQuality >= quality && this.defaultQuality === upperQuality) {
|
|
|
|
this.setDashQualityLevel(height, true)
|
|
|
|
} else if (this.defaultQuality >= quality && this.defaultQuality < upperQuality) {
|
2021-03-12 21:09:08 +00:00
|
|
|
this.setDashQualityLevel(height)
|
2020-09-26 21:03:42 +00:00
|
|
|
}
|
|
|
|
} else if (index === 0 && quality > this.defaultQuality) {
|
2021-03-12 21:09:08 +00:00
|
|
|
this.setDashQualityLevel(height)
|
2020-09-26 21:03:42 +00:00
|
|
|
} else if (index === (arr.length - 1) && quality < this.defaultQuality) {
|
2021-03-12 21:09:08 +00:00
|
|
|
this.setDashQualityLevel(height)
|
|
|
|
}
|
2021-05-15 19:08:41 +00:00
|
|
|
}) */
|
2021-03-12 21:09:08 +00:00
|
|
|
},
|
|
|
|
|
2021-05-15 19:08:41 +00:00
|
|
|
setDashQualityLevel: function (bitrate) {
|
|
|
|
let adaptiveFormat = null
|
|
|
|
|
|
|
|
if (bitrate !== 'auto') {
|
|
|
|
adaptiveFormat = this.activeAdaptiveFormats.find((format) => {
|
|
|
|
return format.bitrate === bitrate
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
let qualityLabel = adaptiveFormat ? adaptiveFormat.qualityLabel : ''
|
|
|
|
|
2021-05-15 19:08:41 +00:00
|
|
|
this.player.qualityLevels().levels_.sort((a, b) => {
|
|
|
|
if (a.height === b.height) {
|
|
|
|
return a.bitrate - b.bitrate
|
|
|
|
} else {
|
|
|
|
return a.height - b.height
|
|
|
|
}
|
|
|
|
}).forEach((ql, index, arr) => {
|
|
|
|
if (bitrate === 'auto' || bitrate === ql.bitrate) {
|
|
|
|
ql.enabled = true
|
|
|
|
ql.enabled_(true)
|
2021-05-17 01:40:34 +00:00
|
|
|
if (bitrate !== 'auto' && qualityLabel === '') {
|
|
|
|
qualityLabel = ql.height + 'p'
|
|
|
|
}
|
2021-05-15 19:08:41 +00:00
|
|
|
} else {
|
|
|
|
ql.enabled = false
|
|
|
|
ql.enabled_(false)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
const selectedQuality = bitrate === 'auto' ? 'auto' : qualityLabel
|
2021-05-15 19:08:41 +00:00
|
|
|
|
|
|
|
const qualityElement = document.getElementById('vjs-current-quality')
|
|
|
|
qualityElement.innerText = selectedQuality
|
|
|
|
this.selectedQuality = selectedQuality
|
|
|
|
|
|
|
|
const qualityItems = $('.quality-item').get()
|
|
|
|
|
|
|
|
$('.quality-item').removeClass('quality-selected')
|
|
|
|
|
|
|
|
qualityItems.forEach((item) => {
|
|
|
|
const qualityText = $(item).find('.vjs-menu-item-text').get(0)
|
|
|
|
if (qualityText.innerText === selectedQuality.toLowerCase()) {
|
|
|
|
$(item).addClass('quality-selected')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
/* if (this.selectedQuality === qualityLevel && this.using60Fps === is60Fps) {
|
2021-03-12 21:09:08 +00:00
|
|
|
return
|
|
|
|
}
|
2021-04-30 21:18:45 +00:00
|
|
|
let foundSelectedQuality = false
|
|
|
|
this.using60Fps = is60Fps
|
2021-03-12 21:09:08 +00:00
|
|
|
this.player.qualityLevels().levels_.sort((a, b) => {
|
2021-04-30 21:18:45 +00:00
|
|
|
if (a.height === b.height) {
|
|
|
|
return a.bitrate - b.bitrate
|
|
|
|
} else {
|
|
|
|
return a.height - b.height
|
|
|
|
}
|
2021-03-12 21:09:08 +00:00
|
|
|
}).forEach((ql, index, arr) => {
|
2021-04-30 21:18:45 +00:00
|
|
|
if (foundSelectedQuality) {
|
|
|
|
ql.enabled = false
|
|
|
|
ql.enabled_(false)
|
|
|
|
} else if (qualityLevel === 'auto') {
|
|
|
|
ql.enabled = true
|
|
|
|
ql.enabled_(true)
|
|
|
|
} else if (ql.height === qualityLevel) {
|
2020-09-26 21:03:42 +00:00
|
|
|
ql.enabled = true
|
2021-03-12 21:09:08 +00:00
|
|
|
ql.enabled_(true)
|
2021-04-30 21:18:45 +00:00
|
|
|
foundSelectedQuality = true
|
|
|
|
|
|
|
|
let lowerQuality
|
|
|
|
let higherQuality
|
|
|
|
|
|
|
|
if ((index - 1) !== -1) {
|
|
|
|
lowerQuality = arr[index - 1]
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((index + 1) < arr.length) {
|
|
|
|
higherQuality = arr[index + 1]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof (lowerQuality) !== 'undefined' && lowerQuality.height === ql.height && lowerQuality.bitrate < ql.bitrate && !is60Fps) {
|
|
|
|
ql.enabled = false
|
|
|
|
ql.enabled_(false)
|
|
|
|
foundSelectedQuality = false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof (higherQuality) !== 'undefined' && higherQuality.height === ql.height && higherQuality.bitrate > ql.bitrate && is60Fps) {
|
|
|
|
ql.enabled = false
|
|
|
|
ql.enabled_(false)
|
|
|
|
foundSelectedQuality = false
|
|
|
|
}
|
2020-09-26 21:03:42 +00:00
|
|
|
} else {
|
|
|
|
ql.enabled = false
|
2021-03-12 21:09:08 +00:00
|
|
|
ql.enabled_(false)
|
2020-09-26 21:03:42 +00:00
|
|
|
}
|
|
|
|
})
|
2021-03-12 21:09:08 +00:00
|
|
|
|
2021-04-30 21:18:45 +00:00
|
|
|
let selectedQuality = qualityLevel
|
|
|
|
|
|
|
|
if (selectedQuality !== 'auto' && is60Fps) {
|
|
|
|
selectedQuality = selectedQuality + 'p60'
|
|
|
|
} else if (selectedQuality !== 'auto') {
|
|
|
|
selectedQuality = selectedQuality + 'p'
|
|
|
|
}
|
2021-03-12 21:09:08 +00:00
|
|
|
|
|
|
|
const qualityElement = document.getElementById('vjs-current-quality')
|
|
|
|
qualityElement.innerText = selectedQuality
|
|
|
|
this.selectedQuality = qualityLevel
|
|
|
|
|
|
|
|
const qualityItems = $('.quality-item').get()
|
|
|
|
|
|
|
|
$('.quality-item').removeClass('quality-selected')
|
|
|
|
|
|
|
|
qualityItems.forEach((item) => {
|
|
|
|
const qualityText = $(item).find('.vjs-menu-item-text').get(0)
|
|
|
|
if (qualityText.innerText === selectedQuality) {
|
|
|
|
$(item).addClass('quality-selected')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// const currentTime = this.player.currentTime()
|
|
|
|
|
|
|
|
// this.player.currentTime(0)
|
2021-05-15 19:08:41 +00:00
|
|
|
// this.player.currentTime(currentTime) */
|
2020-09-26 21:03:42 +00:00
|
|
|
},
|
|
|
|
|
2020-02-18 20:59:01 +00:00
|
|
|
enableDashFormat: function () {
|
|
|
|
if (this.dashSrc === null) {
|
|
|
|
console.log('No dash format available.')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.useDash = true
|
|
|
|
this.useHls = false
|
|
|
|
this.activeSourceList = this.dashSrc
|
|
|
|
|
2020-04-22 02:59:09 +00:00
|
|
|
setTimeout(this.initializePlayer, 100)
|
2020-02-18 20:59:01 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
enableLegacyFormat: function () {
|
|
|
|
if (this.sourceList.length === 0) {
|
|
|
|
console.log('No sources available')
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.useDash = false
|
|
|
|
this.useHls = false
|
|
|
|
this.activeSourceList = this.sourceList
|
|
|
|
|
|
|
|
setTimeout(this.initializePlayer, 100)
|
2020-02-20 20:58:21 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
togglePlayPause: function () {
|
|
|
|
if (this.player.paused()) {
|
|
|
|
this.player.play()
|
|
|
|
} else {
|
|
|
|
this.player.pause()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
changeDurationBySeconds: function (seconds) {
|
|
|
|
const currentTime = this.player.currentTime()
|
|
|
|
const newTime = currentTime + seconds
|
|
|
|
|
|
|
|
if (newTime < 0) {
|
|
|
|
this.player.currentTime(0)
|
|
|
|
} else if (newTime > this.player.duration) {
|
|
|
|
this.player.currentTime(this.player.duration)
|
|
|
|
} else {
|
|
|
|
this.player.currentTime(newTime)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
changeDurationByPercentage: function (percentage) {
|
|
|
|
const duration = this.player.duration()
|
|
|
|
const newTime = duration * percentage
|
|
|
|
|
|
|
|
this.player.currentTime(newTime)
|
|
|
|
},
|
|
|
|
|
|
|
|
changePlayBackRate: function (rate) {
|
|
|
|
const newPlaybackRate = this.player.playbackRate() + rate
|
|
|
|
|
|
|
|
if (newPlaybackRate >= 0.25 && newPlaybackRate <= 3) {
|
|
|
|
this.player.playbackRate(newPlaybackRate)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-11-13 22:29:41 +00:00
|
|
|
framebyframe: function (step) {
|
|
|
|
this.player.pause()
|
|
|
|
const qualityHeight = this.useDash ? this.player.qualityLevels()[this.player.qualityLevels().selectedIndex].height : 0
|
|
|
|
let fps
|
|
|
|
// Non-Dash formats are 30fps only
|
|
|
|
if (qualityHeight >= 480 && this.maxFramerate === 60) {
|
|
|
|
fps = 60
|
|
|
|
} else {
|
|
|
|
fps = 30
|
|
|
|
}
|
|
|
|
// The 3 lines below were taken from the videojs-framebyframe node module by Helena Rasche
|
|
|
|
const frameTime = 1 / fps
|
|
|
|
const dist = frameTime * step
|
|
|
|
this.player.currentTime(this.player.currentTime() + dist)
|
|
|
|
},
|
|
|
|
|
2020-02-20 20:58:21 +00:00
|
|
|
changeVolume: function (volume) {
|
|
|
|
const currentVolume = this.player.volume()
|
|
|
|
const newVolume = currentVolume + volume
|
|
|
|
|
|
|
|
if (newVolume < 0) {
|
|
|
|
this.player.volume(0)
|
|
|
|
} else if (newVolume > 1) {
|
|
|
|
this.player.volume(1)
|
|
|
|
} else {
|
|
|
|
this.player.volume(newVolume)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleMute: function () {
|
|
|
|
if (this.player.muted()) {
|
|
|
|
this.player.muted(false)
|
|
|
|
} else {
|
|
|
|
this.player.muted(true)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleCaptions: function () {
|
|
|
|
const tracks = this.player.textTracks().tracks_
|
|
|
|
|
|
|
|
if (tracks.length > 1) {
|
|
|
|
if (tracks[1].mode === 'showing') {
|
|
|
|
tracks[1].mode = 'disabled'
|
|
|
|
} else {
|
|
|
|
tracks[1].mode = 'showing'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2021-01-13 03:56:31 +00:00
|
|
|
createLoopButton: function () {
|
|
|
|
const v = this
|
|
|
|
const VjsButton = videojs.getComponent('Button')
|
|
|
|
const loopButton = videojs.extend(VjsButton, {
|
|
|
|
constructor: function(player, options) {
|
|
|
|
VjsButton.call(this, player, options)
|
|
|
|
},
|
|
|
|
handleClick: function() {
|
|
|
|
v.toggleVideoLoop()
|
|
|
|
},
|
|
|
|
createControlTextEl: function (button) {
|
|
|
|
return $(button).html($('<div id="loopButton" class="vjs-icon-loop loop-white vjs-button loopWhite"></div>')
|
|
|
|
.attr('title', 'Toggle Loop'))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
videojs.registerComponent('loopButton', loopButton)
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleVideoLoop: async function () {
|
|
|
|
if (!this.player.loop()) {
|
|
|
|
const currentTheme = localStorage.getItem('mainColor')
|
|
|
|
const colorNames = this.$store.state.utils.colorClasses
|
|
|
|
const colorValues = this.$store.state.utils.colorValues
|
|
|
|
|
|
|
|
const nameIndex = colorNames.findIndex((color) => {
|
|
|
|
return color === currentTheme
|
|
|
|
})
|
|
|
|
|
|
|
|
const themeTextColor = await this.calculateColorLuminance(colorValues[nameIndex])
|
|
|
|
|
|
|
|
$('#loopButton').addClass('vjs-icon-loop-active')
|
|
|
|
|
|
|
|
if (themeTextColor === '#000000') {
|
|
|
|
$('#loopButton').addClass('loop-black')
|
|
|
|
$('#loopButton').removeClass('loop-white')
|
|
|
|
}
|
|
|
|
|
|
|
|
this.player.loop(true)
|
|
|
|
} else {
|
|
|
|
$('#loopButton').removeClass('vjs-icon-loop-active')
|
|
|
|
$('#loopButton').removeClass('loop-black')
|
|
|
|
$('#loopButton').addClass('loop-white')
|
|
|
|
this.player.loop(false)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
createFullWindowButton: function () {
|
2020-12-14 22:37:58 +00:00
|
|
|
const v = this
|
|
|
|
const VjsButton = videojs.getComponent('Button')
|
|
|
|
const fullWindowButton = videojs.extend(VjsButton, {
|
|
|
|
constructor: function(player, options) {
|
|
|
|
VjsButton.call(this, player, options)
|
|
|
|
},
|
|
|
|
handleClick: function() {
|
|
|
|
v.toggleFullWindow()
|
|
|
|
},
|
|
|
|
createControlTextEl: function (button) {
|
2021-04-22 18:41:50 +00:00
|
|
|
// Add class name to button to be able to target it with CSS selector
|
|
|
|
return $(button)
|
|
|
|
.addClass('vjs-button-fullwindow')
|
|
|
|
.html($('<div id="fullwindow" class="vjs-icon-fullwindow-enter vjs-button"></div>')
|
|
|
|
.attr('title', 'Full Window'))
|
2020-12-14 22:37:58 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
videojs.registerComponent('fullWindowButton', fullWindowButton)
|
|
|
|
},
|
|
|
|
|
2021-03-12 21:09:08 +00:00
|
|
|
createDashQualitySelector: function (levels) {
|
|
|
|
const v = this
|
|
|
|
if (levels.levels_.length === 0) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.createDashQualitySelector(this.player.qualityLevels())
|
|
|
|
}, 200)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const VjsButton = videojs.getComponent('Button')
|
|
|
|
const dashQualitySelector = videojs.extend(VjsButton, {
|
|
|
|
constructor: function(player, options) {
|
|
|
|
VjsButton.call(this, player, options)
|
|
|
|
},
|
|
|
|
handleClick: function(event) {
|
2021-05-15 19:08:41 +00:00
|
|
|
console.log(event)
|
2021-03-12 21:09:08 +00:00
|
|
|
const selectedQuality = event.target.innerText
|
2021-05-15 19:08:41 +00:00
|
|
|
const bitrate = selectedQuality === 'auto' ? 'auto' : parseInt(event.target.attributes.bitrate.value)
|
|
|
|
v.setDashQualityLevel(bitrate)
|
2021-03-12 21:09:08 +00:00
|
|
|
},
|
|
|
|
createControlTextEl: function (button) {
|
|
|
|
const beginningHtml = `<div class="vjs-quality-level-value">
|
|
|
|
<span id="vjs-current-quality">1080p</span>
|
|
|
|
</div>
|
|
|
|
<div class="vjs-quality-level-menu vjs-menu">
|
|
|
|
<ul class="vjs-menu-content" role="menu">`
|
|
|
|
const endingHtml = '</ul></div>'
|
|
|
|
|
2021-05-15 19:08:41 +00:00
|
|
|
let qualityHtml = `<li class="vjs-menu-item quality-item" role="menuitemradio" tabindex="-1" aria-checked="false" aria-disabled="false">
|
2021-03-12 21:09:08 +00:00
|
|
|
<span class="vjs-menu-item-text">Auto</span>
|
|
|
|
<span class="vjs-control-text" aria-live="polite"></span>
|
|
|
|
</li>`
|
|
|
|
|
|
|
|
levels.levels_.sort((a, b) => {
|
2021-04-30 21:18:45 +00:00
|
|
|
if (b.height === a.height) {
|
|
|
|
return b.bitrate - a.bitrate
|
|
|
|
} else {
|
|
|
|
return b.height - a.height
|
|
|
|
}
|
|
|
|
}).forEach((quality, index, array) => {
|
2021-05-17 01:40:34 +00:00
|
|
|
let fps
|
|
|
|
let qualityLabel
|
|
|
|
let bitrate
|
2021-05-15 19:08:41 +00:00
|
|
|
|
2021-05-17 02:30:03 +00:00
|
|
|
if (typeof v.adaptiveFormats !== 'undefined' && v.adaptiveFormats.length > 0) {
|
2021-05-17 01:40:34 +00:00
|
|
|
const adaptiveFormat = v.adaptiveFormats.find((format) => {
|
|
|
|
return format.bitrate === quality.bitrate
|
|
|
|
})
|
2021-05-15 19:08:41 +00:00
|
|
|
|
2021-05-17 01:40:34 +00:00
|
|
|
v.activeAdaptiveFormats.push(adaptiveFormat)
|
|
|
|
|
|
|
|
fps = adaptiveFormat.fps
|
|
|
|
qualityLabel = adaptiveFormat.qualityLabel ? adaptiveFormat.qualityLabel : quality.height + 'p'
|
|
|
|
bitrate = quality.bitrate
|
|
|
|
} else {
|
|
|
|
fps = 30
|
|
|
|
qualityLabel = quality.height + 'p'
|
|
|
|
bitrate = quality.bitrate
|
|
|
|
}
|
2021-05-15 19:08:41 +00:00
|
|
|
|
|
|
|
qualityHtml = qualityHtml + `<li class="vjs-menu-item quality-item" role="menuitemradio" tabindex="-1" aria-checked="false" aria-disabled="false" fps="${fps}" bitrate="${bitrate}">
|
|
|
|
<span class="vjs-menu-item-text" fps="${fps}" bitrate="${bitrate}">${qualityLabel}</span>
|
|
|
|
<span class="vjs-control-text" aria-live="polite"></span>
|
|
|
|
</li>`
|
|
|
|
|
|
|
|
// Old logic, revert if needed.
|
|
|
|
/* let is60Fps = false
|
2021-04-30 21:18:45 +00:00
|
|
|
if (index < array.length - 1 && array[index + 1].height === quality.height) {
|
|
|
|
if (array[index + 1].bitrate < quality.bitrate) {
|
|
|
|
is60Fps = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const qualityText = is60Fps ? quality.height + 'p60' : quality.height + 'p'
|
2021-03-12 21:09:08 +00:00
|
|
|
qualityHtml = qualityHtml + `<li class="vjs-menu-item quality-item" role="menuitemradio" tabindex="-1" aria-checked="false aria-disabled="false">
|
2021-04-30 21:18:45 +00:00
|
|
|
<span class="vjs-menu-item-text">${qualityText}</span>
|
2021-03-12 21:09:08 +00:00
|
|
|
<span class="vjs-control-text" aria-live="polite"></span>
|
2021-05-15 19:08:41 +00:00
|
|
|
</li>` */
|
2021-03-12 21:09:08 +00:00
|
|
|
})
|
|
|
|
return $(button).html(
|
|
|
|
$(beginningHtml + qualityHtml + endingHtml).attr(
|
|
|
|
'title',
|
|
|
|
'Select Quality'
|
|
|
|
))
|
|
|
|
}
|
|
|
|
})
|
|
|
|
videojs.registerComponent('dashQualitySelector', dashQualitySelector)
|
|
|
|
this.player.controlBar.addChild('dashQualitySelector', {}, this.player.controlBar.children_.length - 1)
|
|
|
|
this.determineDefaultQualityDash()
|
|
|
|
},
|
|
|
|
|
2021-03-17 01:28:25 +00:00
|
|
|
transformAndInsertCaptions: async function() {
|
|
|
|
let captionList
|
|
|
|
if (this.captionHybridList[0] instanceof Promise) {
|
|
|
|
captionList = await Promise.all(this.captionHybridList)
|
|
|
|
this.$emit('store-caption-list', captionList)
|
|
|
|
} else {
|
|
|
|
captionList = this.captionHybridList
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const caption of captionList) {
|
|
|
|
this.player.addRemoteTextTrack({
|
|
|
|
kind: 'subtitles',
|
|
|
|
src: caption.baseUrl || caption.url,
|
|
|
|
srclang: caption.languageCode,
|
|
|
|
label: caption.label || caption.name.simpleText,
|
|
|
|
type: caption.type
|
|
|
|
}, true)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-12-14 22:37:58 +00:00
|
|
|
toggleFullWindow: function() {
|
|
|
|
if (!this.player.isFullscreen_) {
|
|
|
|
if (this.player.isFullWindow) {
|
|
|
|
this.player.removeClass('vjs-full-screen')
|
|
|
|
this.player.isFullWindow = false
|
|
|
|
document.documentElement.style.overflow = this.player.docOrigOverflow
|
|
|
|
$('body').removeClass('vjs-full-window')
|
|
|
|
$('#fullwindow').removeClass('vjs-icon-fullwindow-exit')
|
|
|
|
this.player.trigger('exitFullWindow')
|
|
|
|
} else {
|
|
|
|
this.player.addClass('vjs-full-screen')
|
|
|
|
this.player.isFullscreen_ = false
|
|
|
|
this.player.isFullWindow = true
|
|
|
|
this.player.docOrigOverflow = document.documentElement.style.overflow
|
|
|
|
document.documentElement.style.overflow = 'hidden'
|
|
|
|
$('body').addClass('vjs-full-window')
|
|
|
|
$('#fullwindow').addClass('vjs-icon-fullwindow-exit')
|
|
|
|
this.player.trigger('enterFullWindow')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
exitFullWindow: function() {
|
|
|
|
if (this.player.isFullWindow) {
|
|
|
|
this.player.isFullWindow = false
|
|
|
|
document.documentElement.style.overflow = this.player.docOrigOverflow
|
|
|
|
this.player.removeClass('vjs-full-screen')
|
|
|
|
$('body').removeClass('vjs-full-window')
|
|
|
|
$('#fullwindow').removeClass('vjs-icon-fullwindow-exit')
|
|
|
|
this.player.trigger('exitFullWindow')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleFullscreen: function () {
|
|
|
|
if (this.player.isFullscreen()) {
|
|
|
|
this.player.exitFullscreen()
|
|
|
|
} else {
|
|
|
|
this.player.requestFullscreen()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-02-21 18:31:32 +00:00
|
|
|
hideMouseTimeout: function () {
|
|
|
|
if (this.id === '') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const videoPlayer = $(`#${this.id} video`).get(0)
|
|
|
|
if (typeof (videoPlayer) !== 'undefined') {
|
|
|
|
videoPlayer.style.cursor = 'default'
|
|
|
|
clearTimeout(this.mouseTimeout)
|
|
|
|
this.mouseTimeout = window.setTimeout(function () {
|
|
|
|
videoPlayer.style.cursor = 'none'
|
|
|
|
}, 2650)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
removeMouseTimeout: function () {
|
|
|
|
if (this.mouseTimeout !== null) {
|
|
|
|
clearTimeout(this.mouseTimeout)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-11-15 19:13:18 +00:00
|
|
|
fullscreenOverlay: function () {
|
|
|
|
const v = this
|
|
|
|
const title = document.title.replace('- FreeTube', '')
|
|
|
|
|
|
|
|
if (this.player.isFullscreen()) {
|
|
|
|
this.player.ready(function () {
|
|
|
|
v.player.overlay({
|
|
|
|
overlays: [{
|
|
|
|
showBackground: false,
|
|
|
|
content: title,
|
|
|
|
start: 'mousemove',
|
|
|
|
end: 'userinactive'
|
|
|
|
}]
|
|
|
|
})
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
this.player.ready(function () {
|
|
|
|
v.player.overlay({
|
|
|
|
overlays: [{
|
|
|
|
showBackground: false,
|
|
|
|
content: ' ',
|
|
|
|
start: 'play',
|
|
|
|
end: 'loadstart'
|
|
|
|
}]
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2021-04-22 18:41:50 +00:00
|
|
|
toggleFullscreenClass: function () {
|
|
|
|
if (this.player.isFullscreen()) {
|
|
|
|
$('body').addClass('vjs--full-screen-enabled')
|
|
|
|
} else {
|
|
|
|
$('body').removeClass('vjs--full-screen-enabled')
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2021-01-16 03:34:49 +00:00
|
|
|
handleTouchStart: function (event) {
|
|
|
|
const v = this
|
|
|
|
this.touchPauseTimeout = setTimeout(() => {
|
|
|
|
v.togglePlayPause()
|
|
|
|
}, 1000)
|
|
|
|
|
|
|
|
const touchTime = new Date()
|
|
|
|
|
|
|
|
if (this.lastTouchTime !== null && (touchTime.getTime() - this.lastTouchTime.getTime()) < 250) {
|
|
|
|
this.toggleFullscreen()
|
|
|
|
}
|
|
|
|
|
|
|
|
this.lastTouchTime = touchTime
|
|
|
|
},
|
|
|
|
|
|
|
|
handleTouchEnd: function (event) {
|
|
|
|
clearTimeout(this.touchPauseTimeout)
|
|
|
|
},
|
|
|
|
|
2020-02-20 20:58:21 +00:00
|
|
|
keyboardShortcutHandler: function (event) {
|
|
|
|
const activeInputs = $('.ft-input')
|
|
|
|
|
|
|
|
for (let i = 0; i < activeInputs.length; i++) {
|
|
|
|
if (activeInputs[i] === document.activeElement) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-21 19:43:50 +00:00
|
|
|
if (event.ctrlKey) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-20 20:58:21 +00:00
|
|
|
if (this.player !== null) {
|
|
|
|
switch (event.which) {
|
|
|
|
case 32:
|
|
|
|
// Space Bar
|
|
|
|
// Toggle Play/Pause
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.togglePlayPause()
|
|
|
|
break
|
|
|
|
case 74:
|
|
|
|
// J Key
|
|
|
|
// Rewind by 10 seconds
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationBySeconds(-10)
|
|
|
|
break
|
|
|
|
case 75:
|
|
|
|
// K Key
|
|
|
|
// Toggle Play/Pause
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.togglePlayPause()
|
|
|
|
break
|
|
|
|
case 76:
|
|
|
|
// L Key
|
|
|
|
// Fast Forward by 10 seconds
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationBySeconds(10)
|
|
|
|
break
|
|
|
|
case 79:
|
|
|
|
// O Key
|
|
|
|
// Decrease playback rate by 0.25x
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changePlayBackRate(-0.25)
|
|
|
|
break
|
|
|
|
case 80:
|
|
|
|
// P Key
|
|
|
|
// Increase playback rate by 0.25x
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changePlayBackRate(0.25)
|
|
|
|
break
|
|
|
|
case 70:
|
|
|
|
// F Key
|
|
|
|
// Toggle Fullscreen Playback
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.toggleFullscreen()
|
|
|
|
break
|
|
|
|
case 77:
|
|
|
|
// M Key
|
|
|
|
// Toggle Mute
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.toggleMute()
|
|
|
|
break
|
|
|
|
case 67:
|
|
|
|
// C Key
|
|
|
|
// Toggle Captions
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.toggleCaptions()
|
|
|
|
break
|
|
|
|
case 38:
|
|
|
|
// Up Arrow Key
|
|
|
|
// Increase volume
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeVolume(0.05)
|
|
|
|
break
|
|
|
|
case 40:
|
|
|
|
// Down Arrow Key
|
2020-11-15 19:13:18 +00:00
|
|
|
// Decrease Volume
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeVolume(-0.05)
|
|
|
|
break
|
|
|
|
case 37:
|
|
|
|
// Left Arrow Key
|
|
|
|
// Rewind by 5 seconds
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationBySeconds(-5)
|
|
|
|
break
|
|
|
|
case 39:
|
|
|
|
// Right Arrow Key
|
2020-11-15 19:13:18 +00:00
|
|
|
// Fast Forward by 5 seconds
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationBySeconds(5)
|
|
|
|
break
|
|
|
|
case 49:
|
|
|
|
// 1 Key
|
|
|
|
// Jump to 10% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.1)
|
|
|
|
break
|
|
|
|
case 50:
|
|
|
|
// 2 Key
|
|
|
|
// Jump to 20% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.2)
|
|
|
|
break
|
|
|
|
case 51:
|
|
|
|
// 3 Key
|
|
|
|
// Jump to 30% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.3)
|
|
|
|
break
|
|
|
|
case 52:
|
|
|
|
// 4 Key
|
|
|
|
// Jump to 40% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.4)
|
|
|
|
break
|
|
|
|
case 53:
|
|
|
|
// 5 Key
|
|
|
|
// Jump to 50% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.5)
|
|
|
|
break
|
|
|
|
case 54:
|
|
|
|
// 6 Key
|
|
|
|
// Jump to 60% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.6)
|
|
|
|
break
|
|
|
|
case 55:
|
|
|
|
// 7 Key
|
|
|
|
// Jump to 70% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.7)
|
|
|
|
break
|
|
|
|
case 56:
|
|
|
|
// 8 Key
|
|
|
|
// Jump to 80% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.8)
|
|
|
|
break
|
|
|
|
case 57:
|
|
|
|
// 9 Key
|
|
|
|
// Jump to 90% in the video
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0.9)
|
|
|
|
break
|
|
|
|
case 48:
|
|
|
|
// 0 Key
|
|
|
|
// Jump to 0% in the video (The beginning)
|
2020-09-26 15:57:57 +00:00
|
|
|
event.preventDefault()
|
2020-02-20 20:58:21 +00:00
|
|
|
this.changeDurationByPercentage(0)
|
|
|
|
break
|
2020-11-13 22:29:41 +00:00
|
|
|
case 188:
|
|
|
|
// , Key
|
|
|
|
// Return to previous frame
|
|
|
|
this.framebyframe(-1)
|
|
|
|
break
|
|
|
|
case 190:
|
|
|
|
// . Key
|
|
|
|
// Advance to next frame
|
|
|
|
this.framebyframe(1)
|
|
|
|
break
|
2020-12-15 19:07:40 +00:00
|
|
|
case 68:
|
|
|
|
// D Key
|
|
|
|
// Toggle Picture in Picture Mode
|
|
|
|
if (!this.player.isInPictureInPicture()) {
|
|
|
|
this.player.requestPictureInPicture()
|
|
|
|
} else if (this.player.isInPictureInPicture()) {
|
|
|
|
this.player.exitPictureInPicture()
|
|
|
|
}
|
|
|
|
break
|
2020-12-14 22:37:58 +00:00
|
|
|
case 27:
|
|
|
|
// esc Key
|
|
|
|
// Exit full window
|
|
|
|
event.preventDefault()
|
|
|
|
this.exitFullWindow()
|
|
|
|
break
|
2020-12-15 19:07:40 +00:00
|
|
|
case 83:
|
|
|
|
// S Key
|
|
|
|
// Toggle Full Window Mode
|
|
|
|
this.toggleFullWindow()
|
|
|
|
break
|
2020-02-20 20:58:21 +00:00
|
|
|
}
|
|
|
|
}
|
2021-01-13 03:56:31 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
...mapActions([
|
2021-05-16 20:01:24 +00:00
|
|
|
'showToast',
|
2021-01-13 03:56:31 +00:00
|
|
|
'calculateColorLuminance'
|
|
|
|
])
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
|
|
|
})
|