Work on video player to support dash and other features
Theatre Mode Captions Storyboards
This commit is contained in:
parent
70f53ad51a
commit
4dc8eab9b8
|
@ -2428,6 +2428,27 @@
|
||||||
"fastq": "^1.6.0"
|
"fastq": "^1.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@silvermine/videojs-quality-selector": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@silvermine/videojs-quality-selector/-/videojs-quality-selector-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-votXSPzzydjZsBZT37589sTw31csgncWggaYPWKXTygCkzvc8V876iRNJiTykgaiZd/9qQn7pjwEJsOqnfp/pw==",
|
||||||
|
"requires": {
|
||||||
|
"class.extend": "0.9.1",
|
||||||
|
"underscore": "1.9.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"class.extend": {
|
||||||
|
"version": "0.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/class.extend/-/class.extend-0.9.1.tgz",
|
||||||
|
"integrity": "sha1-tO5BfGk3QKRKkqbWTxyVQGQbCXo="
|
||||||
|
},
|
||||||
|
"underscore": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sindresorhus/is": {
|
"@sindresorhus/is": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
|
||||||
|
@ -6977,6 +6998,11 @@
|
||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fast-xml-parser": {
|
||||||
|
"version": "3.16.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.16.0.tgz",
|
||||||
|
"integrity": "sha512-U+bpScacfgnfNfIKlWHDu4u6rtOaCyxhblOLJ8sZPkhsjgGqdZmVPBhdOyvdMGCDt8CsAv+cssOP3NzQptNt2w=="
|
||||||
|
},
|
||||||
"fastq": {
|
"fastq": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
|
||||||
|
@ -14478,11 +14504,110 @@
|
||||||
"xhr": "2.4.0"
|
"xhr": "2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"videojs-contrib-quality-levels": {
|
||||||
|
"version": "2.0.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-2.0.9.tgz",
|
||||||
|
"integrity": "sha512-HJeaJJQdSufi9Y5T7jlyyhkeq+mWPCog86q6ypoTi66boBMMJTo2abiOSHS9KaOGAJjH72gfvrjVY5FRdjlxYA==",
|
||||||
|
"requires": {
|
||||||
|
"global": "^4.3.2",
|
||||||
|
"video.js": "^6 || ^7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"videojs-font": {
|
"videojs-font": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz",
|
||||||
"integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA=="
|
"integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA=="
|
||||||
},
|
},
|
||||||
|
"videojs-frankly-ttml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-frankly-ttml/-/videojs-frankly-ttml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-lmpTQA7q47V5S2ILpNhHbqOyWBebPGb3OGpTMXzUP1HkhA1ZdGSaBFLUG+manE9ZlONLu8FsoqrEFQoobCR4zA==",
|
||||||
|
"requires": {
|
||||||
|
"video.js": "^5.8.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"global": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/global/-/global-4.3.0.tgz",
|
||||||
|
"integrity": "sha1-737EvurVebRU9evV5/MD21T0Kis=",
|
||||||
|
"requires": {
|
||||||
|
"min-document": "^2.6.1",
|
||||||
|
"process": "~0.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"process": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
|
||||||
|
},
|
||||||
|
"video.js": {
|
||||||
|
"version": "5.20.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/video.js/-/video.js-5.20.5.tgz",
|
||||||
|
"integrity": "sha1-RFza4gS85Fl4LYajGyWjKv1tjv8=",
|
||||||
|
"requires": {
|
||||||
|
"babel-runtime": "^6.9.2",
|
||||||
|
"global": "4.3.0",
|
||||||
|
"safe-json-parse": "4.0.0",
|
||||||
|
"tsml": "1.0.1",
|
||||||
|
"videojs-font": "2.0.0",
|
||||||
|
"videojs-ie8": "1.1.2",
|
||||||
|
"videojs-swf": "5.4.1",
|
||||||
|
"videojs-vtt.js": "0.12.6",
|
||||||
|
"xhr": "2.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"videojs-font": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-r3Rh751LleAzS/+3iy8v8DZKkDQ="
|
||||||
|
},
|
||||||
|
"videojs-vtt.js": {
|
||||||
|
"version": "0.12.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.12.6.tgz",
|
||||||
|
"integrity": "sha512-XFXeGBQiljnElMhwCcZst0RDbZn2n8LU7ZScXryd3a00OaZsHAjdZu/7/RdSr7Z1jHphd45FnOvOQkGK4YrWCQ==",
|
||||||
|
"requires": {
|
||||||
|
"global": "^4.3.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"global": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
|
||||||
|
"requires": {
|
||||||
|
"min-document": "^2.19.0",
|
||||||
|
"process": "^0.11.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"process": {
|
||||||
|
"version": "0.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
|
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"xhr": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xhr/-/xhr-2.2.2.tgz",
|
||||||
|
"integrity": "sha1-LuclcYafhobUFVmp6ihsGJcUNf8=",
|
||||||
|
"requires": {
|
||||||
|
"global": "~4.3.0",
|
||||||
|
"is-function": "^1.0.1",
|
||||||
|
"parse-headers": "^2.0.0",
|
||||||
|
"xtend": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"videojs-http-source-selector": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-http-source-selector/-/videojs-http-source-selector-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-6b5MmKTT2cVnrjtdNj4z1VO91udbXkZkTYA6LlD8WN2aHlG2rqFTmtMab4NK4nlkkkbRnm3c2q2IddL3jffLmg==",
|
||||||
|
"requires": {
|
||||||
|
"global": "^4.3.2",
|
||||||
|
"video.js": "^7.0.0",
|
||||||
|
"videojs-contrib-quality-levels": "^2.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"videojs-ie8": {
|
"videojs-ie8": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/videojs-ie8/-/videojs-ie8-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/videojs-ie8/-/videojs-ie8-1.1.2.tgz",
|
||||||
|
@ -14576,6 +14701,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/videojs-swf/-/videojs-swf-5.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/videojs-swf/-/videojs-swf-5.4.1.tgz",
|
||||||
"integrity": "sha1-IHfvccdJ8seCPvSbq65N0qywj4c="
|
"integrity": "sha1-IHfvccdJ8seCPvSbq65N0qywj4c="
|
||||||
},
|
},
|
||||||
|
"videojs-vtt-thumbnails": {
|
||||||
|
"version": "0.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/videojs-vtt-thumbnails/-/videojs-vtt-thumbnails-0.0.13.tgz",
|
||||||
|
"integrity": "sha512-7VGcpTRF+ppIss/NiZcDkVOE02k/GoMltxUumQ2jaTpR1ZieYTM+dPopmTXubLxOgUP3F71uTLMZVnWEtiHjVA==",
|
||||||
|
"requires": {
|
||||||
|
"global": "^4.3.2",
|
||||||
|
"request": "^2.83.0",
|
||||||
|
"video.js": "^5.19.2 || ^6.6.0 || ^7.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"videojs-vtt.js": {
|
"videojs-vtt.js": {
|
||||||
"version": "0.14.1",
|
"version": "0.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz",
|
||||||
|
@ -15661,6 +15796,14 @@
|
||||||
"node-fetch": "^2.6.0"
|
"node-fetch": "^2.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"yt-xml2srt": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yt-xml2srt/-/yt-xml2srt-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-6JseclPTdiPEuXZ+cwiYl1xtqYDsyGfJqQfVSWmPXWT3bVEdAYPDXspMqQPRRXHdYEGaMD/oBz2mWMhXanKeOA==",
|
||||||
|
"requires": {
|
||||||
|
"fast-xml-parser": "^3.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ytdl-core": {
|
"ytdl-core": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/ytdl-core/-/ytdl-core-1.0.7.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
||||||
"@fortawesome/vue-fontawesome": "^0.1.9",
|
"@fortawesome/vue-fontawesome": "^0.1.9",
|
||||||
|
"@silvermine/videojs-quality-selector": "^1.2.3",
|
||||||
"autolinker": "^3.11.1",
|
"autolinker": "^3.11.1",
|
||||||
"bulma-pro": "^0.1.8",
|
"bulma-pro": "^0.1.8",
|
||||||
"dateformat": "^3.0.3",
|
"dateformat": "^3.0.3",
|
||||||
|
@ -22,7 +23,10 @@
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"opml-to-json": "0.0.3",
|
"opml-to-json": "0.0.3",
|
||||||
"video.js": "^7.6.6",
|
"video.js": "^7.6.6",
|
||||||
|
"videojs-contrib-quality-levels": "^2.0.9",
|
||||||
|
"videojs-http-source-selector": "^1.1.6",
|
||||||
"videojs-replay": "^1.1.0",
|
"videojs-replay": "^1.1.0",
|
||||||
|
"videojs-vtt-thumbnails": "0.0.13",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-electron": "^1.0.6",
|
"vue-electron": "^1.0.6",
|
||||||
"vue-router": "^3.1.5",
|
"vue-router": "^3.1.5",
|
||||||
|
@ -32,6 +36,7 @@
|
||||||
"youtube-comments-fetch": "^1.0.1",
|
"youtube-comments-fetch": "^1.0.1",
|
||||||
"youtube-comments-task": "^1.3.14",
|
"youtube-comments-task": "^1.3.14",
|
||||||
"youtube-suggest": "^1.1.0",
|
"youtube-suggest": "^1.1.0",
|
||||||
|
"yt-xml2srt": "^1.1.0",
|
||||||
"ytdl-core": "^1.0.7",
|
"ytdl-core": "^1.0.7",
|
||||||
"ytpl": "^0.1.20",
|
"ytpl": "^0.1.20",
|
||||||
"ytsr": "^0.1.10"
|
"ytsr": "^0.1.10"
|
||||||
|
|
|
@ -5,4 +5,5 @@
|
||||||
|
|
||||||
.ftVideoPlayer {
|
.ftVideoPlayer {
|
||||||
width: 85%;
|
width: 85%;
|
||||||
|
max-height: 50vh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,10 @@ import FtCard from '../ft-card/ft-card.vue'
|
||||||
// I haven't decided which video player I want to use
|
// I haven't decided which video player I want to use
|
||||||
// Need to expirement with both of them to see which one will work best.
|
// Need to expirement with both of them to see which one will work best.
|
||||||
import videojs from 'video.js'
|
import videojs from 'video.js'
|
||||||
|
import qualitySelector from '@silvermine/videojs-quality-selector'
|
||||||
|
import 'videojs-vtt-thumbnails'
|
||||||
|
import 'videojs-contrib-quality-levels'
|
||||||
|
import 'videojs-http-source-selector'
|
||||||
// import mediaelement from 'mediaelement'
|
// import mediaelement from 'mediaelement'
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
@ -12,21 +16,60 @@ export default Vue.extend({
|
||||||
'ft-card': FtCard
|
'ft-card': FtCard
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: {
|
sourceList: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
dashSrc: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
hlsSrc: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
captionList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => { return [] }
|
default: () => { return [] }
|
||||||
},
|
},
|
||||||
src: {
|
storyboardSrc: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
default: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
id: '',
|
id: '',
|
||||||
player: null,
|
player: null,
|
||||||
|
useDash: false,
|
||||||
|
useHls: false,
|
||||||
|
activeSourceList: [],
|
||||||
dataSetup: {
|
dataSetup: {
|
||||||
aspectRatio: '16:9',
|
aspectRatio: '16:9',
|
||||||
|
nativeTextTracks: false,
|
||||||
|
plugins: {},
|
||||||
|
controlBar: {
|
||||||
|
children: [
|
||||||
|
'playToggle',
|
||||||
|
'volumePanel',
|
||||||
|
'currentTimeDisplay',
|
||||||
|
'timeDivider',
|
||||||
|
'durationDisplay',
|
||||||
|
'progressControl',
|
||||||
|
'liveDisplay',
|
||||||
|
'seekToLive',
|
||||||
|
'remainingTimeDisplay',
|
||||||
|
'customControlSpacer',
|
||||||
|
'playbackRateMenuButton',
|
||||||
|
'chaptersButton',
|
||||||
|
'descriptionsButton',
|
||||||
|
'subsCapsButton',
|
||||||
|
'audioTrackButton',
|
||||||
|
'QualitySelector',
|
||||||
|
'pictureInPictureToggle',
|
||||||
|
'fullscreenToggle'
|
||||||
|
]
|
||||||
|
},
|
||||||
playbackRates: [
|
playbackRates: [
|
||||||
0.25,
|
0.25,
|
||||||
0.5,
|
0.5,
|
||||||
|
@ -47,21 +90,79 @@ export default Vue.extend({
|
||||||
computed: {
|
computed: {
|
||||||
listType: function () {
|
listType: function () {
|
||||||
return this.$store.getters.getListType
|
return this.$store.getters.getListType
|
||||||
|
},
|
||||||
|
|
||||||
|
videoFormatPreference: function () {
|
||||||
|
return this.$store.getters.getVideoFormatPreference
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.id = this._uid
|
this.id = this._uid
|
||||||
setTimeout(this.initializePlayer, 100)
|
|
||||||
|
this.determineFormatType()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initializePlayer: function () {
|
initializePlayer: function () {
|
||||||
console.log(this.id)
|
|
||||||
const videoPlayer = document.getElementById(this.id)
|
const videoPlayer = document.getElementById(this.id)
|
||||||
console.log(videoPlayer)
|
|
||||||
if (videoPlayer !== null) {
|
if (videoPlayer !== null) {
|
||||||
this.player = videojs(videoPlayer)
|
if (!this.useDash && !this.useHls) {
|
||||||
console.log(videojs.players)
|
qualitySelector(videojs, { showQualitySelectionLabelInControlBar: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.player = videojs(videoPlayer)
|
||||||
|
|
||||||
|
this.player.vttThumbnails({
|
||||||
|
src: this.storyboardSrc
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.useDash) {
|
||||||
|
this.dataSetup.plugins.httpSourceSelector = {
|
||||||
|
default: 'auto'
|
||||||
|
}
|
||||||
|
|
||||||
|
this.player.httpSourceSelector()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
determineFormatType: function () {
|
||||||
|
if (this.hlsSrc === null && this.dashSrc !== null && this.videoFormatPreference === 'dash') {
|
||||||
|
this.enableDashFormat()
|
||||||
|
} else {
|
||||||
|
this.enableLegacyFormat()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
enableDashFormat: function () {
|
||||||
|
if (this.dashSrc === null) {
|
||||||
|
console.log('No dash format available.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('using dash format')
|
||||||
|
|
||||||
|
this.useDash = true
|
||||||
|
this.useHls = false
|
||||||
|
this.activeSourceList = this.dashSrc
|
||||||
|
|
||||||
|
console.log(this.activeSourceList)
|
||||||
|
|
||||||
|
setTimeout(this.initializePlayer, 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
enableLegacyFormat: function () {
|
||||||
|
if (this.sourceList.length === 0) {
|
||||||
|
console.log('No sources available')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('using legacy format')
|
||||||
|
|
||||||
|
this.useDash = false
|
||||||
|
this.useHls = false
|
||||||
|
this.activeSourceList = this.sourceList
|
||||||
|
|
||||||
|
setTimeout(this.initializePlayer, 100)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,15 +3,25 @@
|
||||||
<video
|
<video
|
||||||
:id="id"
|
:id="id"
|
||||||
class="ftVideoPlayer video-js vjs-default-skin"
|
class="ftVideoPlayer video-js vjs-default-skin"
|
||||||
width="800"
|
|
||||||
height="600"
|
|
||||||
controls
|
controls
|
||||||
preload="auto"
|
preload="auto"
|
||||||
:data-setup="JSON.stringify(dataSetup)"
|
:data-setup="JSON.stringify(dataSetup)"
|
||||||
>
|
>
|
||||||
<source
|
<source
|
||||||
:src="src"
|
v-for="(source, index) in activeSourceList"
|
||||||
type="video/mp4"
|
:key="index + '_source'"
|
||||||
|
:src="source.url"
|
||||||
|
:type="source.type || source.mimeType"
|
||||||
|
:label="source.qualityLabel"
|
||||||
|
/>
|
||||||
|
<track
|
||||||
|
v-for="(caption, index) in captionList"
|
||||||
|
:key="index + '_caption'"
|
||||||
|
kind="subtitles"
|
||||||
|
:src="caption.baseUrl || caption.url"
|
||||||
|
:srclang="caption.languageCode"
|
||||||
|
:label="caption.label || caption.name.simpleText"
|
||||||
|
:type="caption.type"
|
||||||
>
|
>
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,11 +8,22 @@
|
||||||
color: var(--title-color);
|
color: var(--title-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hideComments {
|
||||||
|
font-size: 13px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--title-color);
|
||||||
|
}
|
||||||
|
|
||||||
.commentThumbnail {
|
.commentThumbnail {
|
||||||
float: left;
|
float: left;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
|
@ -47,7 +58,7 @@
|
||||||
|
|
||||||
.commentMoreReplies {
|
.commentMoreReplies {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
margin-left: 110px;
|
margin-left: 120px;
|
||||||
margin-top: -25px;
|
margin-top: -25px;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -18,6 +18,7 @@ export default Vue.extend({
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
showComments: false,
|
||||||
nextPageToken: null,
|
nextPageToken: null,
|
||||||
commentData: []
|
commentData: []
|
||||||
}
|
}
|
||||||
|
@ -87,6 +88,7 @@ export default Vue.extend({
|
||||||
this.commentData = this.commentData.concat(commentData)
|
this.commentData = this.commentData.concat(commentData)
|
||||||
this.nextPageToken = p.nextPageToken
|
this.nextPageToken = p.nextPageToken
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
|
this.showComments = true
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -127,6 +129,7 @@ export default Vue.extend({
|
||||||
this.commentData = this.commentData.concat(commentData)
|
this.commentData = this.commentData.concat(commentData)
|
||||||
this.nextPageToken = response.continuation
|
this.nextPageToken = response.continuation
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
|
this.showComments = true
|
||||||
}).catch((xhr) => {
|
}).catch((xhr) => {
|
||||||
console.log('found an error')
|
console.log('found an error')
|
||||||
console.log(xhr)
|
console.log(xhr)
|
||||||
|
|
|
@ -10,13 +10,26 @@
|
||||||
>
|
>
|
||||||
Click to view comments
|
Click to view comments
|
||||||
</h4>
|
</h4>
|
||||||
|
<h4
|
||||||
|
v-if="commentData.length > 0 && !isLoading && !showComments"
|
||||||
|
class="getCommentsTitle"
|
||||||
|
@click="showComments = true"
|
||||||
|
>
|
||||||
|
Click to view comments
|
||||||
|
</h4>
|
||||||
<h3
|
<h3
|
||||||
v-if="commentData.length > 0 && !isLoading"
|
v-if="commentData.length > 0 && !isLoading && showComments"
|
||||||
>
|
>
|
||||||
Comments
|
Comments
|
||||||
|
<span
|
||||||
|
class="hideComments"
|
||||||
|
@click="showComments = false"
|
||||||
|
>
|
||||||
|
Hide Comments
|
||||||
|
</span>
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div
|
||||||
v-if="commentData.length > 0"
|
v-if="commentData.length > 0 && showComments"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="(comment, index) in commentData"
|
v-for="(comment, index) in commentData"
|
||||||
|
@ -87,8 +100,15 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="showComments && !isLoading"
|
||||||
|
>
|
||||||
|
<h3 class="center">
|
||||||
|
There are no comments available for this video.
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
<h4
|
<h4
|
||||||
v-if="commentData.length > 0 && !isLoading"
|
v-if="commentData.length > 0 && !isLoading && showComments"
|
||||||
class="getMoreComments"
|
class="getMoreComments"
|
||||||
@click="getCommentData"
|
@click="getCommentData"
|
||||||
>
|
>
|
||||||
|
|
|
@ -83,7 +83,14 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
width: 350px;
|
width: 550px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theatreModeButton {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 10px;
|
||||||
|
position: relative;
|
||||||
|
bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.formatTypeDropdown {
|
.formatTypeDropdown {
|
||||||
|
@ -93,3 +100,13 @@
|
||||||
.shareDropdown {
|
.shareDropdown {
|
||||||
width: 175px;
|
width: 175px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 1700px) {
|
||||||
|
.theatreModeButton {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoOptions {
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,11 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ft-flex-box class="videoOptions">
|
<ft-flex-box class="videoOptions">
|
||||||
|
<ft-button
|
||||||
|
label="Toggle Theatre Mode"
|
||||||
|
class="theatreModeButton"
|
||||||
|
@click="$emit('theatreMode')"
|
||||||
|
/>
|
||||||
<ft-list-dropdown
|
<ft-list-dropdown
|
||||||
:title="formatTypeLabel"
|
:title="formatTypeLabel"
|
||||||
:label-names="formatTypeNames"
|
:label-names="formatTypeNames"
|
||||||
|
|
|
@ -14,6 +14,7 @@ const state = {
|
||||||
useClickBaitRemover: true,
|
useClickBaitRemover: true,
|
||||||
clickBaitRemoverPreference: '',
|
clickBaitRemoverPreference: '',
|
||||||
backendFallback: true,
|
backendFallback: true,
|
||||||
|
videoFormatPreference: 'dash',
|
||||||
autoplay: true,
|
autoplay: true,
|
||||||
useTor: false,
|
useTor: false,
|
||||||
history: true,
|
history: true,
|
||||||
|
@ -61,6 +62,10 @@ const getters = {
|
||||||
|
|
||||||
getClickBaitRemoverPreference: () => {
|
getClickBaitRemoverPreference: () => {
|
||||||
return state.clickBaitRemoverPreference
|
return state.clickBaitRemoverPreference
|
||||||
|
},
|
||||||
|
|
||||||
|
getVideoFormatPreference: () => {
|
||||||
|
return state.videoFormatPreference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -890,7 +890,7 @@ body.vjs-full-window {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -3.4em;
|
top: -3.4em;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-progress-holder:focus .vjs-time-tooltip {
|
.video-js .vjs-progress-holder:focus .vjs-time-tooltip {
|
||||||
|
@ -1292,7 +1292,7 @@ video::-webkit-media-text-track-display {
|
||||||
.vjs-playback-rate > .vjs-menu-button,
|
.vjs-playback-rate > .vjs-menu-button,
|
||||||
.vjs-playback-rate .vjs-playback-rate-value {
|
.vjs-playback-rate .vjs-playback-rate-value {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 30%;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1301,7 +1301,6 @@ video::-webkit-media-text-track-display {
|
||||||
.vjs-playback-rate .vjs-playback-rate-value {
|
.vjs-playback-rate .vjs-playback-rate-value {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
line-height: 2.8;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1895,7 +1894,7 @@ video::-webkit-media-text-track-display {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
width: 5.5em;
|
width: 5.5em;
|
||||||
left: 1.5em;
|
left: 1.5em;
|
||||||
padding-bottom: .5em
|
padding-bottom: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-item,.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-title {
|
.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-item,.video-js .vjs-menu-button-popup .vjs-menu .vjs-menu-title {
|
||||||
|
@ -1943,3 +1942,42 @@ video::-webkit-media-text-track-display {
|
||||||
.video-js .vjs-load-progress {
|
.video-js .vjs-load-progress {
|
||||||
background: rgba(255,255,255,0.3);
|
background: rgba(255,255,255,0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vjs-quality-selector .vjs-menu-button {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-quality-selector .vjs-quality-selector-icon {
|
||||||
|
font-family: 'VideoJS';
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-quality-selector .vjs-quality-selector-icon:before {
|
||||||
|
content: '\f110';
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-quality-changing .vjs-big-play-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vjs-quality-changing .vjs-control-bar {
|
||||||
|
display: flex;
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-js .vjs-vtt-thumbnails {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-js .vjs-vtt-thumbnail-display {
|
||||||
|
position: absolute;
|
||||||
|
transition: transform .1s, opacity .2s;
|
||||||
|
bottom: 20px;
|
||||||
|
pointer-events: none;
|
||||||
|
box-shadow: 0 0 7px rgba(0,0,0,.6);
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,13 @@
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theatreWatchVideo {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 85%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.videoPlayer {
|
.videoPlayer {
|
||||||
width: calc(65% + 30px);
|
width: calc(65% + 30px);
|
||||||
float: left;
|
float: left;
|
||||||
|
@ -13,6 +20,13 @@
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theatrePlayer {
|
||||||
|
width: calc(85% + 30px);
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.watchVideoRecommendations {
|
.watchVideoRecommendations {
|
||||||
width: 27%;
|
width: 27%;
|
||||||
max-width: 425px;
|
max-width: 425px;
|
||||||
|
@ -23,6 +37,14 @@
|
||||||
right: 10px;
|
right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theatreRecommendations {
|
||||||
|
float: none;
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 85%;
|
||||||
|
max-width: none;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 1700px) {
|
@media only screen and (max-width: 1700px) {
|
||||||
.watchVideo {
|
.watchVideo {
|
||||||
float: none;
|
float: none;
|
||||||
|
|
|
@ -24,9 +24,11 @@ export default Vue.extend({
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
firstLoad: true,
|
firstLoad: true,
|
||||||
|
useTheatreMode: true,
|
||||||
showDashPlayer: true,
|
showDashPlayer: true,
|
||||||
showLegacyPlayer: false,
|
showLegacyPlayer: false,
|
||||||
showYouTubeNoCookieEmbed: false,
|
showYouTubeNoCookieEmbed: false,
|
||||||
|
proxyVideos: false,
|
||||||
videoId: '',
|
videoId: '',
|
||||||
videoTitle: '',
|
videoTitle: '',
|
||||||
videoDescription: '',
|
videoDescription: '',
|
||||||
|
@ -39,9 +41,10 @@ export default Vue.extend({
|
||||||
channelId: '',
|
channelId: '',
|
||||||
channelSubscriptionCountText: '',
|
channelSubscriptionCountText: '',
|
||||||
videoPublished: 0,
|
videoPublished: 0,
|
||||||
videoUrl360p: '',
|
videoStoryboardSrc: '',
|
||||||
videoUrl720p: '',
|
|
||||||
audioUrl: '',
|
audioUrl: '',
|
||||||
|
videoSourceList: [],
|
||||||
|
captionSourceList: [],
|
||||||
recommendedVideos: []
|
recommendedVideos: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -64,6 +67,14 @@ export default Vue.extend({
|
||||||
|
|
||||||
youtubeNoCookieEmbeddedFrame: function () {
|
youtubeNoCookieEmbeddedFrame: function () {
|
||||||
return `<iframe width='560' height='315' src='https://www.youtube-nocookie.com/embed/${this.videoId}?rel=0' frameborder='0' allow='autoplay; encrypted-media' allowfullscreen></iframe>`
|
return `<iframe width='560' height='315' src='https://www.youtube-nocookie.com/embed/${this.videoId}?rel=0' frameborder='0' allow='autoplay; encrypted-media' allowfullscreen></iframe>`
|
||||||
|
},
|
||||||
|
|
||||||
|
dashSrc: function () {
|
||||||
|
return {
|
||||||
|
url: `${this.invidiousInstance}/api/manifest/dash/${this.videoId}.mpd`,
|
||||||
|
type: 'application/dash+xml',
|
||||||
|
label: 'Dash'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -85,6 +96,11 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.videoId = this.$route.params.id
|
this.videoId = this.$route.params.id
|
||||||
|
this.videoStoryboardSrc = `${this.invidiousInstance}/api/v1/storyboards/${this.videoId}?height=90`
|
||||||
|
|
||||||
|
if (this.proxyVideos) {
|
||||||
|
this.dashSrc = this.dashSrc + '?local=true'
|
||||||
|
}
|
||||||
|
|
||||||
switch (this.backendPreference) {
|
switch (this.backendPreference) {
|
||||||
case 'local':
|
case 'local':
|
||||||
|
@ -96,6 +112,10 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
toggleTheatreMode: function () {
|
||||||
|
this.useTheatreMode = !this.useTheatreMode
|
||||||
|
},
|
||||||
|
|
||||||
getVideoInformationLocal: function () {
|
getVideoInformationLocal: function () {
|
||||||
if (this.firstLoad) {
|
if (this.firstLoad) {
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
|
@ -112,8 +132,45 @@ export default Vue.extend({
|
||||||
this.videoPublished = result.published
|
this.videoPublished = result.published
|
||||||
this.videoDescription = result.player_response.videoDetails.shortDescription
|
this.videoDescription = result.player_response.videoDetails.shortDescription
|
||||||
this.recommendedVideos = result.related_videos
|
this.recommendedVideos = result.related_videos
|
||||||
|
this.videoSourceList = result.player_response.streamingData.formats
|
||||||
|
|
||||||
this.videoUrl720p = result.player_response.streamingData.formats[1].url
|
// The response provides a storyboard, however it returns a 403 error.
|
||||||
|
// Uncomment this line if that ever changes.
|
||||||
|
// this.videoStoryboardSrc = result.player_response.storyboards.playerStoryboardSpecRenderer.spec
|
||||||
|
|
||||||
|
this.captionSourceList = result.player_response.captions.playerCaptionsTracklistRenderer.captionTracks
|
||||||
|
this.captionSourceList = this.captionSourceList.map((caption) => {
|
||||||
|
caption.baseUrl = `${this.invidiousInstance}/api/v1/captions/${this.videoId}?label=${encodeURI(caption.name.simpleText)}`
|
||||||
|
|
||||||
|
return caption
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: The response returns the captions of the video, however they're returned
|
||||||
|
// in XML / TTML. I haven't found a way to properly convert this for use.
|
||||||
|
// There may be another URL that we can use to grab an appropriate format as well.
|
||||||
|
// Video.js requires that the captions are returned in .vtt format. The below code
|
||||||
|
// Converts it to .srt which may work, but I can't get the player to accept the data.
|
||||||
|
|
||||||
|
// this.captionSourceList = this.captionSourceList.map((caption) => {
|
||||||
|
// caption.type = 'application/ttml+xml'
|
||||||
|
// caption.dataSource = 'local'
|
||||||
|
//
|
||||||
|
// $.get(caption.baseUrl, (response) => {
|
||||||
|
// console.log('response')
|
||||||
|
// console.log(response)
|
||||||
|
// console.log()
|
||||||
|
// xml2srt.Parse(new XMLSerializer().serializeToString(response))
|
||||||
|
// .then(srt => {
|
||||||
|
// caption.track = srt
|
||||||
|
// }).catch(err => console.log(`Error while converting XML to SRT : ${err}`))
|
||||||
|
// }).fail((xhr, textStatus, error) => {
|
||||||
|
// console.log(xhr)
|
||||||
|
// console.log(textStatus)
|
||||||
|
// console.log(error)
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// return caption
|
||||||
|
// })
|
||||||
|
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
@ -147,8 +204,13 @@ export default Vue.extend({
|
||||||
this.videoPublished = result.published * 1000
|
this.videoPublished = result.published * 1000
|
||||||
this.videoDescriptionHtml = result.descriptionHtml
|
this.videoDescriptionHtml = result.descriptionHtml
|
||||||
this.recommendedVideos = result.recommendedVideos
|
this.recommendedVideos = result.recommendedVideos
|
||||||
|
this.videoSourceList = result.formatStreams.reverse()
|
||||||
this.videoUrl720p = result.formatStreams[0].url
|
this.captionSourceList = result.captions.map((caption) => {
|
||||||
|
caption.url = this.invidiousInstance + caption.url
|
||||||
|
caption.type = ''
|
||||||
|
caption.dataSource = 'invidious'
|
||||||
|
return caption
|
||||||
|
})
|
||||||
|
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
|
|
|
@ -6,8 +6,12 @@
|
||||||
/>
|
/>
|
||||||
<ft-video-player
|
<ft-video-player
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
:src="videoUrl720p"
|
:dash-src="dashSrc"
|
||||||
|
:source-list="videoSourceList"
|
||||||
|
:caption-list="captionSourceList"
|
||||||
|
:storyboard-src="videoStoryboardSrc"
|
||||||
class="videoPlayer"
|
class="videoPlayer"
|
||||||
|
:class="{ theatrePlayer: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
<watch-video-info
|
<watch-video-info
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
|
@ -20,7 +24,9 @@
|
||||||
:like-count="videoLikeCount"
|
:like-count="videoLikeCount"
|
||||||
:dislike-count="videoDislikeCount"
|
:dislike-count="videoDislikeCount"
|
||||||
:view-count="videoViewCount"
|
:view-count="videoViewCount"
|
||||||
|
@theatreMode="toggleTheatreMode"
|
||||||
class="watchVideo"
|
class="watchVideo"
|
||||||
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
<watch-video-description
|
<watch-video-description
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
|
@ -28,16 +34,19 @@
|
||||||
:description="videoDescription"
|
:description="videoDescription"
|
||||||
:description-html="videoDescriptionHtml"
|
:description-html="videoDescriptionHtml"
|
||||||
class="watchVideo"
|
class="watchVideo"
|
||||||
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
<watch-video-comments
|
<watch-video-comments
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
:id="videoId"
|
:id="videoId"
|
||||||
class="watchVideo"
|
class="watchVideo"
|
||||||
|
:class="{ theatreWatchVideo: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
<watch-video-recommendations
|
<watch-video-recommendations
|
||||||
v-if="!isLoading"
|
v-if="!isLoading"
|
||||||
:data="recommendedVideos"
|
:data="recommendedVideos"
|
||||||
class="watchVideoRecommendations"
|
class="watchVideoRecommendations"
|
||||||
|
:class="{ theatreRecommendations: useTheatreMode }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in New Issue