2020-02-16 18:30:00 +00:00
|
|
|
import Vue from 'vue'
|
2020-08-05 03:44:34 +00:00
|
|
|
import { mapActions } from 'vuex'
|
2020-02-28 03:29:30 +00:00
|
|
|
import xml2vtt from 'yt-xml2vtt'
|
|
|
|
import $ from 'jquery'
|
2020-08-16 22:11:44 +00:00
|
|
|
import fs from 'fs'
|
|
|
|
import electron from 'electron'
|
2020-08-28 19:43:10 +00:00
|
|
|
import ytDashGen from 'yt-dash-manifest-generator'
|
2020-02-16 18:30:00 +00:00
|
|
|
import FtLoader from '../../components/ft-loader/ft-loader.vue'
|
|
|
|
import FtCard from '../../components/ft-card/ft-card.vue'
|
|
|
|
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
|
|
|
|
import FtVideoPlayer from '../../components/ft-video-player/ft-video-player.vue'
|
|
|
|
import WatchVideoInfo from '../../components/watch-video-info/watch-video-info.vue'
|
|
|
|
import WatchVideoDescription from '../../components/watch-video-description/watch-video-description.vue'
|
|
|
|
import WatchVideoComments from '../../components/watch-video-comments/watch-video-comments.vue'
|
2020-05-23 21:29:42 +00:00
|
|
|
import WatchVideoLiveChat from '../../components/watch-video-live-chat/watch-video-live-chat.vue'
|
2020-05-17 20:12:58 +00:00
|
|
|
import WatchVideoPlaylist from '../../components/watch-video-playlist/watch-video-playlist.vue'
|
2020-02-16 18:30:00 +00:00
|
|
|
import WatchVideoRecommendations from '../../components/watch-video-recommendations/watch-video-recommendations.vue'
|
|
|
|
|
|
|
|
export default Vue.extend({
|
|
|
|
name: 'Watch',
|
|
|
|
components: {
|
|
|
|
'ft-loader': FtLoader,
|
|
|
|
'ft-card': FtCard,
|
|
|
|
'ft-element-list': FtElementList,
|
|
|
|
'ft-video-player': FtVideoPlayer,
|
|
|
|
'watch-video-info': WatchVideoInfo,
|
|
|
|
'watch-video-description': WatchVideoDescription,
|
|
|
|
'watch-video-comments': WatchVideoComments,
|
2020-05-23 21:29:42 +00:00
|
|
|
'watch-video-live-chat': WatchVideoLiveChat,
|
2020-05-17 20:12:58 +00:00
|
|
|
'watch-video-playlist': WatchVideoPlaylist,
|
2020-08-05 02:18:39 +00:00
|
|
|
'watch-video-recommendations': WatchVideoRecommendations
|
2020-02-16 18:30:00 +00:00
|
|
|
},
|
2020-10-04 18:42:46 +00:00
|
|
|
beforeRouteLeave: function (to, from, next) {
|
|
|
|
this.handleRouteChange()
|
|
|
|
next()
|
|
|
|
},
|
2020-02-28 03:29:30 +00:00
|
|
|
data: function() {
|
2020-02-16 18:30:00 +00:00
|
|
|
return {
|
|
|
|
isLoading: false,
|
|
|
|
firstLoad: true,
|
2020-04-22 02:59:09 +00:00
|
|
|
useTheatreMode: false,
|
2020-02-16 18:30:00 +00:00
|
|
|
showDashPlayer: true,
|
|
|
|
showLegacyPlayer: false,
|
|
|
|
showYouTubeNoCookieEmbed: false,
|
2020-02-19 03:31:10 +00:00
|
|
|
hidePlayer: false,
|
2020-05-17 20:12:58 +00:00
|
|
|
isLive: false,
|
2020-10-31 14:57:51 +00:00
|
|
|
isLiveContent: false,
|
2020-09-16 02:07:54 +00:00
|
|
|
isUpcoming: false,
|
|
|
|
upcomingTimestamp: null,
|
2020-02-19 03:31:10 +00:00
|
|
|
activeFormat: 'legacy',
|
2020-09-22 01:30:48 +00:00
|
|
|
thumbnail: '',
|
2020-02-16 18:30:00 +00:00
|
|
|
videoId: '',
|
|
|
|
videoTitle: '',
|
|
|
|
videoDescription: '',
|
|
|
|
videoDescriptionHtml: '',
|
|
|
|
videoViewCount: 0,
|
|
|
|
videoLikeCount: 0,
|
|
|
|
videoDislikeCount: 0,
|
2020-08-20 02:39:44 +00:00
|
|
|
videoLengthSeconds: 0,
|
2020-02-16 18:30:00 +00:00
|
|
|
channelName: '',
|
|
|
|
channelThumbnail: '',
|
|
|
|
channelId: '',
|
|
|
|
channelSubscriptionCountText: '',
|
|
|
|
videoPublished: 0,
|
2020-02-18 20:59:01 +00:00
|
|
|
videoStoryboardSrc: '',
|
2020-02-16 18:30:00 +00:00
|
|
|
audioUrl: '',
|
2020-08-28 19:43:10 +00:00
|
|
|
dashSrc: [],
|
2020-06-01 02:47:22 +00:00
|
|
|
activeSourceList: [],
|
2020-02-18 20:59:01 +00:00
|
|
|
videoSourceList: [],
|
2020-06-01 02:47:22 +00:00
|
|
|
audioSourceList: [],
|
2020-02-18 20:59:01 +00:00
|
|
|
captionSourceList: [],
|
2020-02-28 03:29:30 +00:00
|
|
|
recommendedVideos: [],
|
2020-10-08 19:01:46 +00:00
|
|
|
downloadLinks: [],
|
2020-05-17 20:12:58 +00:00
|
|
|
watchingPlaylist: false,
|
2020-09-21 22:39:25 +00:00
|
|
|
playlistId: '',
|
|
|
|
playNextTimeout: null
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2020-08-16 22:11:44 +00:00
|
|
|
isDev: function () {
|
|
|
|
return process.env.NODE_ENV === 'development'
|
|
|
|
},
|
2020-04-18 03:17:45 +00:00
|
|
|
usingElectron: function () {
|
|
|
|
return this.$store.getters.getUsingElectron
|
|
|
|
},
|
2020-08-20 02:39:44 +00:00
|
|
|
historyCache: function () {
|
|
|
|
return this.$store.getters.getHistoryCache
|
|
|
|
},
|
|
|
|
rememberHistory: function () {
|
|
|
|
return this.$store.getters.getRememberHistory
|
|
|
|
},
|
2020-08-22 20:51:04 +00:00
|
|
|
saveWatchedProgress: function () {
|
|
|
|
return this.$store.getters.getSaveWatchedProgress
|
|
|
|
},
|
2020-03-01 03:37:02 +00:00
|
|
|
backendPreference: function () {
|
2020-02-16 18:30:00 +00:00
|
|
|
return this.$store.getters.getBackendPreference
|
|
|
|
},
|
2020-03-01 03:37:02 +00:00
|
|
|
backendFallback: function () {
|
2020-02-16 18:30:00 +00:00
|
|
|
return this.$store.getters.getBackendFallback
|
|
|
|
},
|
2020-03-01 03:37:02 +00:00
|
|
|
invidiousInstance: function () {
|
2020-02-16 18:30:00 +00:00
|
|
|
return this.$store.getters.getInvidiousInstance
|
|
|
|
},
|
2020-04-14 02:59:25 +00:00
|
|
|
proxyVideos: function () {
|
|
|
|
return this.$store.getters.getProxyVideos
|
|
|
|
},
|
2020-04-22 02:59:09 +00:00
|
|
|
defaultTheatreMode: function () {
|
|
|
|
return this.$store.getters.getDefaultTheatreMode
|
|
|
|
},
|
2020-03-01 03:37:02 +00:00
|
|
|
defaultVideoFormat: function () {
|
|
|
|
return this.$store.getters.getDefaultVideoFormat
|
2020-02-19 03:31:10 +00:00
|
|
|
},
|
2020-03-01 03:37:02 +00:00
|
|
|
forceLocalBackendForLegacy: function () {
|
|
|
|
return this.$store.getters.getForceLocalBackendForLegacy
|
|
|
|
},
|
2020-06-01 02:47:22 +00:00
|
|
|
thumbnailPreference: function () {
|
|
|
|
return this.$store.getters.getThumbnailPreference
|
|
|
|
},
|
2020-09-07 18:43:44 +00:00
|
|
|
playNextVideo: function () {
|
|
|
|
return this.$store.getters.getPlayNextVideo
|
|
|
|
},
|
2020-06-01 02:47:22 +00:00
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
youtubeNoCookieEmbeddedFrame: function () {
|
2020-02-16 18:30:00 +00:00
|
|
|
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>`
|
2020-10-06 02:27:32 +00:00
|
|
|
},
|
|
|
|
hideChannelSubscriptions: function () {
|
|
|
|
return this.$store.getters.getHideChannelSubscriptions
|
|
|
|
},
|
|
|
|
hideVideoLikesAndDislikes: function () {
|
|
|
|
return this.$store.getters.getHideVideoLikesAndDislikes
|
2020-08-05 02:18:39 +00:00
|
|
|
}
|
2020-02-16 18:30:00 +00:00
|
|
|
},
|
|
|
|
watch: {
|
2020-02-28 03:29:30 +00:00
|
|
|
$route() {
|
2020-09-07 18:43:44 +00:00
|
|
|
this.handleRouteChange()
|
2020-02-16 18:30:00 +00:00
|
|
|
// react to route changes...
|
|
|
|
this.videoId = this.$route.params.id
|
|
|
|
|
|
|
|
this.firstLoad = true
|
2020-06-02 02:42:29 +00:00
|
|
|
this.activeFormat = this.defaultVideoFormat
|
2020-08-16 22:11:44 +00:00
|
|
|
this.videoStoryboardSrc = ''
|
2020-09-24 22:33:21 +00:00
|
|
|
this.captionSourceList = []
|
2020-10-08 19:01:46 +00:00
|
|
|
this.downloadLinks = []
|
2020-02-16 18:30:00 +00:00
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
this.checkIfPlaylist()
|
|
|
|
|
2020-02-16 18:30:00 +00:00
|
|
|
switch (this.backendPreference) {
|
|
|
|
case 'local':
|
|
|
|
this.getVideoInformationLocal(this.videoId)
|
|
|
|
break
|
|
|
|
case 'invidious':
|
|
|
|
this.getVideoInformationInvidious(this.videoId)
|
2020-03-01 03:37:02 +00:00
|
|
|
|
|
|
|
if (this.forceLocalBackendForLegacy) {
|
|
|
|
this.getVideoInformationLocal(this.videoId)
|
|
|
|
}
|
2020-02-16 18:30:00 +00:00
|
|
|
break
|
|
|
|
}
|
2020-08-05 02:18:39 +00:00
|
|
|
}
|
2020-02-16 18:30:00 +00:00
|
|
|
},
|
2020-05-17 20:12:58 +00:00
|
|
|
mounted: function () {
|
2020-02-16 18:30:00 +00:00
|
|
|
this.videoId = this.$route.params.id
|
2020-03-01 03:37:02 +00:00
|
|
|
this.activeFormat = this.defaultVideoFormat
|
2020-04-22 02:59:09 +00:00
|
|
|
this.useTheatreMode = this.defaultTheatreMode
|
2020-02-19 03:31:10 +00:00
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
this.checkIfPlaylist()
|
|
|
|
|
2020-04-18 03:17:45 +00:00
|
|
|
if (!this.usingElectron) {
|
|
|
|
this.getVideoInformationInvidious()
|
|
|
|
} else {
|
|
|
|
switch (this.backendPreference) {
|
|
|
|
case 'local':
|
|
|
|
this.getVideoInformationLocal()
|
|
|
|
break
|
|
|
|
case 'invidious':
|
|
|
|
this.getVideoInformationInvidious()
|
|
|
|
break
|
|
|
|
}
|
2020-02-16 18:30:00 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2020-09-19 16:19:58 +00:00
|
|
|
changeTimestamp: function(timestamp) {
|
|
|
|
this.$refs.videoPlayer.player.currentTime(timestamp)
|
|
|
|
},
|
2020-02-28 03:29:30 +00:00
|
|
|
toggleTheatreMode: function() {
|
2020-02-18 20:59:01 +00:00
|
|
|
this.useTheatreMode = !this.useTheatreMode
|
|
|
|
},
|
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
getVideoInformationLocal: function() {
|
2020-02-16 18:30:00 +00:00
|
|
|
if (this.firstLoad) {
|
|
|
|
this.isLoading = true
|
|
|
|
}
|
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
this.$store
|
|
|
|
.dispatch('ytGetVideoInformation', this.videoId)
|
2020-08-26 20:45:20 +00:00
|
|
|
.then(async result => {
|
2020-05-17 20:12:58 +00:00
|
|
|
console.log(result)
|
2020-12-02 18:36:08 +00:00
|
|
|
|
|
|
|
const playabilityStatus = result.player_response.playabilityStatus
|
2020-12-21 02:43:40 +00:00
|
|
|
if (playabilityStatus.status === 'UNPLAYABLE') {
|
2020-12-02 18:36:08 +00:00
|
|
|
const errorScreen = playabilityStatus.errorScreen.playerErrorMessageRenderer
|
|
|
|
const reason = errorScreen.reason.simpleText
|
|
|
|
let subReason
|
|
|
|
let skipIndex
|
|
|
|
errorScreen.subreason.runs.forEach((message, index) => {
|
|
|
|
if (index !== skipIndex) {
|
|
|
|
if (message.text.match(/<a.*>/)) {
|
|
|
|
skipIndex = index + 1
|
|
|
|
} else if (!message.text.match(/<\/a>/)) {
|
|
|
|
if (typeof subReason === 'undefined') {
|
|
|
|
subReason = message.text
|
|
|
|
} else {
|
|
|
|
subReason = subReason + message.text
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
throw new Error(`${reason}: ${subReason}`)
|
|
|
|
}
|
|
|
|
|
2020-06-04 01:00:36 +00:00
|
|
|
this.videoTitle = result.videoDetails.title
|
2020-02-28 03:29:30 +00:00
|
|
|
this.videoViewCount = parseInt(
|
|
|
|
result.player_response.videoDetails.viewCount,
|
|
|
|
10
|
|
|
|
)
|
2020-12-02 18:35:03 +00:00
|
|
|
if ('id' in result.videoDetails.author) {
|
2020-12-07 01:18:08 +00:00
|
|
|
this.channelId = result.player_response.videoDetails.channelId
|
2020-12-02 18:35:03 +00:00
|
|
|
this.channelName = result.videoDetails.author.name
|
|
|
|
console.log(result)
|
|
|
|
this.channelThumbnail = result.videoDetails.author.thumbnails[0].url
|
|
|
|
} else {
|
|
|
|
this.channelId = result.player_response.videoDetails.channelId
|
|
|
|
this.channelName = result.player_response.videoDetails.author
|
|
|
|
this.channelThumbnail = result.player_response.embedPreview.thumbnailPreviewRenderer.videoDetails.embeddedPlayerOverlayVideoDetailsRenderer.channelThumbnail.thumbnails[0].url
|
|
|
|
}
|
2020-06-04 01:00:36 +00:00
|
|
|
this.videoPublished = new Date(result.videoDetails.publishDate.replace('-', '/')).getTime()
|
2020-09-22 01:30:48 +00:00
|
|
|
this.videoDescription = result.player_response.videoDetails.shortDescription
|
|
|
|
|
|
|
|
switch (this.thumbnailPreference) {
|
|
|
|
case 'start':
|
|
|
|
this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres1.jpg`
|
|
|
|
break
|
|
|
|
case 'middle':
|
|
|
|
this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres2.jpg`
|
|
|
|
break
|
|
|
|
case 'end':
|
|
|
|
this.thumbnail = `https://i.ytimg.com/vi/${this.videoId}/maxres3.jpg`
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
this.thumbnail = result.videoDetails.thumbnail.thumbnails[result.videoDetails.thumbnail.thumbnails.length - 1].url
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-08-22 18:15:04 +00:00
|
|
|
this.recommendedVideos = result.related_videos.map((video) => {
|
|
|
|
video.videoId = video.id
|
2020-11-29 00:44:17 +00:00
|
|
|
video.authorId = video.author.id
|
2020-08-22 18:15:04 +00:00
|
|
|
video.viewCount = video.view_count
|
|
|
|
video.lengthSeconds = video.length_seconds
|
2020-11-29 00:44:17 +00:00
|
|
|
video.author = video.author.name
|
2020-08-22 18:15:04 +00:00
|
|
|
return video
|
|
|
|
})
|
2020-10-06 02:27:32 +00:00
|
|
|
if (this.hideVideoLikesAndDislikes) {
|
|
|
|
this.videoLikeCount = null
|
|
|
|
this.videoDislikeCount = null
|
|
|
|
} else {
|
2020-12-31 11:22:26 +00:00
|
|
|
this.videoLikeCount = isNaN(result.videoDetails.likes) ? 0 : result.videoDetails.likes
|
|
|
|
this.videoDislikeCount = isNaN(result.videoDetails.dislikes) ? 0 : result.videoDetails.dislikes
|
2020-10-06 02:27:32 +00:00
|
|
|
}
|
2020-10-31 14:57:51 +00:00
|
|
|
this.isLive = result.player_response.videoDetails.isLive
|
|
|
|
this.isLiveContent = result.player_response.videoDetails.isLiveContent
|
2020-09-18 22:11:58 +00:00
|
|
|
this.isUpcoming = result.player_response.videoDetails.isUpcoming ? result.player_response.videoDetails.isUpcoming : false
|
2020-05-17 20:12:58 +00:00
|
|
|
|
2020-09-16 02:07:54 +00:00
|
|
|
if (!this.isLive && !this.isUpcoming) {
|
2020-09-07 15:26:52 +00:00
|
|
|
const captionTracks =
|
|
|
|
result.player_response.captions &&
|
|
|
|
result.player_response.captions.playerCaptionsTracklistRenderer
|
|
|
|
.captionTracks
|
|
|
|
|
|
|
|
if (typeof captionTracks !== 'undefined') {
|
|
|
|
await this.createCaptionUrls(captionTracks)
|
|
|
|
}
|
2020-08-26 21:21:44 +00:00
|
|
|
}
|
|
|
|
|
2020-10-06 02:27:32 +00:00
|
|
|
if (this.videoDislikeCount === null && !this.hideVideoLikesAndDislikes) {
|
2020-06-27 17:59:20 +00:00
|
|
|
this.videoDislikeCount = 0
|
|
|
|
}
|
|
|
|
|
2020-06-04 01:00:36 +00:00
|
|
|
const subCount = result.videoDetails.author.subscriber_count
|
2020-06-02 02:42:29 +00:00
|
|
|
|
2020-10-06 02:27:32 +00:00
|
|
|
if (typeof (subCount) !== 'undefined' && !this.hideChannelSubscriptions) {
|
2020-06-27 17:59:20 +00:00
|
|
|
if (subCount >= 1000000) {
|
|
|
|
this.channelSubscriptionCountText = `${subCount / 1000000}M`
|
|
|
|
} else if (subCount >= 10000) {
|
|
|
|
this.channelSubscriptionCountText = `${subCount / 1000}K`
|
|
|
|
} else {
|
|
|
|
this.channelSubscriptionCountText = subCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
|
|
|
}
|
2020-06-02 02:42:29 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 02:07:54 +00:00
|
|
|
if (this.isLive && !this.isUpcoming) {
|
2020-08-30 14:21:01 +00:00
|
|
|
this.enableLegacyFormat()
|
2020-05-23 21:29:42 +00:00
|
|
|
|
|
|
|
this.videoSourceList = result.formats.filter((format) => {
|
|
|
|
if (typeof (format.mimeType) !== 'undefined') {
|
|
|
|
return format.mimeType.includes('video/ts')
|
|
|
|
}
|
2020-06-05 02:44:58 +00:00
|
|
|
|
|
|
|
return format.itag === 300 || format.itag === 301
|
2020-05-23 21:29:42 +00:00
|
|
|
}).map((format) => {
|
2020-06-05 02:44:58 +00:00
|
|
|
let qualityLabel
|
|
|
|
|
|
|
|
if (format.itag === 300) {
|
|
|
|
qualityLabel = '720p'
|
|
|
|
} else if (format.itag === 301) {
|
|
|
|
qualityLabel = '1080p'
|
|
|
|
} else {
|
|
|
|
qualityLabel = format.qualityLabel
|
|
|
|
}
|
2020-05-23 21:29:42 +00:00
|
|
|
return {
|
|
|
|
url: format.url,
|
|
|
|
type: 'application/x-mpegURL',
|
2020-05-17 20:12:58 +00:00
|
|
|
label: 'Dash',
|
2020-06-05 02:44:58 +00:00
|
|
|
qualityLabel: qualityLabel
|
2020-05-23 21:29:42 +00:00
|
|
|
}
|
2020-06-05 02:44:58 +00:00
|
|
|
}).sort((a, b) => {
|
|
|
|
const qualityA = parseInt(a.qualityLabel.replace('p', ''))
|
|
|
|
const qualityB = parseInt(b.qualityLabel.replace('p', ''))
|
|
|
|
return qualityA - qualityB
|
2020-09-25 02:35:13 +00:00
|
|
|
}).reverse()
|
2020-06-04 01:00:36 +00:00
|
|
|
|
2020-08-07 20:06:48 +00:00
|
|
|
if (this.videoSourceList.length === 0) {
|
|
|
|
this.activeSourceList = result.player_response.streamingData.formats
|
|
|
|
} else {
|
|
|
|
this.activeSourceList = this.videoSourceList
|
|
|
|
}
|
2020-09-16 02:07:54 +00:00
|
|
|
} else if (this.isUpcoming) {
|
2020-09-25 14:14:49 +00:00
|
|
|
const startTimestamp = result.videoDetails.liveBroadcastDetails.startTimestamp
|
|
|
|
|
|
|
|
if (typeof startTimestamp !== 'undefined') {
|
|
|
|
const upcomingTimestamp = new Date(result.videoDetails.liveBroadcastDetails.startTimestamp)
|
|
|
|
this.upcomingTimestamp = upcomingTimestamp.toLocaleString()
|
|
|
|
} else {
|
|
|
|
this.upcomingTimestamp = null
|
|
|
|
}
|
2020-05-17 20:12:58 +00:00
|
|
|
} else {
|
2020-08-20 02:39:44 +00:00
|
|
|
this.videoLengthSeconds = parseInt(result.videoDetails.lengthSeconds)
|
2020-09-30 20:37:23 +00:00
|
|
|
if (result.player_response.streamingData !== undefined) {
|
|
|
|
this.videoSourceList = result.player_response.streamingData.formats.reverse()
|
2020-10-08 19:01:46 +00:00
|
|
|
this.downloadLinks = result.formats.map((format) => {
|
|
|
|
const qualityLabel = format.qualityLabel || format.bitrate
|
|
|
|
const itag = format.itag
|
|
|
|
const fps = format.fps ? (format.fps + 'fps') : 'kbps'
|
|
|
|
const type = format.mimeType.match(/.*;/)[0].replace(';', '')
|
|
|
|
let label = `${qualityLabel} ${fps} - ${type}`
|
|
|
|
|
|
|
|
if (itag !== 18 && itag !== 22) {
|
|
|
|
if (type.includes('video')) {
|
|
|
|
label += ` ${this.$t('Video.video only')}`
|
|
|
|
} else {
|
|
|
|
label += ` ${this.$t('Video.audio only')}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const object = {
|
|
|
|
url: format.url,
|
|
|
|
label: label
|
|
|
|
}
|
|
|
|
|
|
|
|
return object
|
|
|
|
})
|
2020-12-02 18:35:03 +00:00
|
|
|
let captionLinks = result.player_response.captions
|
2020-10-19 15:51:37 +00:00
|
|
|
if (typeof captionLinks !== 'undefined') {
|
|
|
|
captionLinks = captionLinks.playerCaptionsTracklistRenderer.captionTracks.map((caption) => {
|
|
|
|
const label = `${caption.name.simpleText} (${caption.languageCode}) - text/vtt`
|
|
|
|
const object = {
|
|
|
|
url: caption.baseUrl,
|
|
|
|
label: label
|
|
|
|
}
|
|
|
|
|
|
|
|
return object
|
|
|
|
})
|
|
|
|
|
|
|
|
this.downloadLinks = this.downloadLinks.concat(captionLinks)
|
|
|
|
}
|
2020-09-30 20:37:23 +00:00
|
|
|
} else {
|
|
|
|
// video might be region locked or something else. This leads to no formats being available
|
|
|
|
this.showToast({
|
|
|
|
message: this.$t('This video is unavailable because of missing formats. This can happen due to country unavailability.'),
|
|
|
|
time: 7000
|
|
|
|
})
|
2020-09-30 21:01:36 +00:00
|
|
|
this.handleVideoEnded()
|
2020-09-30 20:37:23 +00:00
|
|
|
return
|
|
|
|
}
|
2020-06-01 02:47:22 +00:00
|
|
|
|
2020-09-16 02:07:54 +00:00
|
|
|
if (typeof result.player_response.streamingData.adaptiveFormats !== 'undefined') {
|
2020-10-04 21:01:59 +00:00
|
|
|
if (this.proxyVideos) {
|
|
|
|
this.dashSrc = await this.createInvidiousDashManifest()
|
|
|
|
} else {
|
|
|
|
this.dashSrc = await this.createLocalDashManifest(result.player_response.streamingData.adaptiveFormats)
|
|
|
|
}
|
2020-09-16 02:07:54 +00:00
|
|
|
|
|
|
|
this.audioSourceList = result.player_response.streamingData.adaptiveFormats.filter((format) => {
|
|
|
|
return format.mimeType.includes('audio')
|
2020-10-05 01:20:30 +00:00
|
|
|
}).sort((a, b) => {
|
|
|
|
return a.bitrate - b.bitrate
|
|
|
|
}).map((format, index) => {
|
|
|
|
const label = (x) => {
|
|
|
|
switch (x) {
|
|
|
|
case 0:
|
|
|
|
return this.$t('Video.Audio.Low')
|
|
|
|
case 1:
|
|
|
|
return this.$t('Video.Audio.Medium')
|
|
|
|
case 2:
|
|
|
|
return this.$t('Video.Audio.High')
|
|
|
|
case 3:
|
|
|
|
return this.$t('Video.Audio.Best')
|
|
|
|
default:
|
|
|
|
return format.bitrate
|
|
|
|
}
|
|
|
|
}
|
2020-09-16 02:07:54 +00:00
|
|
|
return {
|
|
|
|
url: format.url,
|
|
|
|
type: format.mimeType,
|
|
|
|
label: 'Audio',
|
2020-10-05 01:20:30 +00:00
|
|
|
qualityLabel: label(index)
|
2020-09-16 02:07:54 +00:00
|
|
|
}
|
2020-10-05 01:20:30 +00:00
|
|
|
}).reverse()
|
2020-09-16 02:07:54 +00:00
|
|
|
|
|
|
|
if (this.activeFormat === 'audio') {
|
|
|
|
this.activeSourceList = this.audioSourceList
|
|
|
|
} else {
|
|
|
|
this.activeSourceList = this.videoSourceList
|
2020-06-01 02:47:22 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.activeSourceList = this.videoSourceList
|
2020-09-16 02:07:54 +00:00
|
|
|
this.audioSourceList = null
|
|
|
|
this.dashSrc = null
|
|
|
|
this.enableLegacyFormat()
|
2020-06-01 02:47:22 +00:00
|
|
|
}
|
2020-02-28 03:29:30 +00:00
|
|
|
|
2020-09-09 22:58:35 +00:00
|
|
|
if (typeof result.player_response.storyboards !== 'undefined') {
|
|
|
|
const templateUrl = result.player_response.storyboards.playerStoryboardSpecRenderer.spec
|
|
|
|
this.createLocalStoryboardUrls(templateUrl)
|
|
|
|
}
|
2020-08-18 23:32:44 +00:00
|
|
|
}
|
2020-08-15 11:03:30 +00:00
|
|
|
|
2020-09-26 22:05:44 +00:00
|
|
|
this.isLoading = false
|
2020-10-31 14:36:35 +00:00
|
|
|
this.updateTitle()
|
2020-02-28 03:29:30 +00:00
|
|
|
})
|
|
|
|
.catch(err => {
|
2020-08-09 03:15:00 +00:00
|
|
|
const errorMessage = this.$t('Local API Error (Click to copy)')
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-09 03:15:00 +00:00
|
|
|
message: `${errorMessage}: ${err}`,
|
2020-08-05 03:44:34 +00:00
|
|
|
time: 10000,
|
|
|
|
action: () => {
|
|
|
|
navigator.clipboard.writeText(err)
|
|
|
|
}
|
|
|
|
})
|
2020-02-28 03:29:30 +00:00
|
|
|
console.log(err)
|
2020-10-31 15:23:26 +00:00
|
|
|
if (!this.usingElectron || (this.backendPreference === 'local' && this.backendFallback && !err.toString().includes('private'))) {
|
2020-08-09 03:15:00 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Falling back to Invidious API')
|
|
|
|
})
|
2020-02-28 03:29:30 +00:00
|
|
|
this.getVideoInformationInvidious()
|
|
|
|
} else {
|
|
|
|
this.isLoading = false
|
|
|
|
}
|
|
|
|
})
|
2020-02-16 18:30:00 +00:00
|
|
|
},
|
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
getVideoInformationInvidious: function() {
|
2020-02-16 18:30:00 +00:00
|
|
|
if (this.firstLoad) {
|
|
|
|
this.isLoading = true
|
|
|
|
}
|
|
|
|
|
2020-08-30 14:21:01 +00:00
|
|
|
this.dashSrc = this.createInvidiousDashManifest()
|
2020-09-07 15:33:10 +00:00
|
|
|
this.videoStoryboardSrc = `${this.invidiousInstance}/api/v1/storyboards/${this.videoId}?height=90`
|
2020-08-30 14:21:01 +00:00
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
this.$store
|
|
|
|
.dispatch('invidiousGetVideoInformation', this.videoId)
|
|
|
|
.then(result => {
|
|
|
|
console.log(result)
|
|
|
|
|
2020-12-02 18:36:08 +00:00
|
|
|
if (result.error) {
|
|
|
|
throw new Error(result.error)
|
|
|
|
}
|
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
this.videoTitle = result.title
|
|
|
|
this.videoViewCount = result.viewCount
|
2020-10-06 02:27:32 +00:00
|
|
|
if (this.hideVideoLikesAndDislikes) {
|
|
|
|
this.videoLikeCount = null
|
|
|
|
this.videoDislikeCount = null
|
|
|
|
} else {
|
|
|
|
this.videoLikeCount = result.likeCount
|
|
|
|
this.videoDislikeCount = result.dislikeCount
|
|
|
|
}
|
|
|
|
if (this.hideChannelSubscriptions) {
|
|
|
|
this.channelSubscriptionCountText = ''
|
|
|
|
} else {
|
|
|
|
this.channelSubscriptionCountText = result.subCountText || 'FT-0'
|
|
|
|
}
|
2020-02-28 03:29:30 +00:00
|
|
|
this.channelId = result.authorId
|
|
|
|
this.channelName = result.author
|
2020-10-13 15:06:04 +00:00
|
|
|
this.channelThumbnail = result.authorThumbnails[1] ? result.authorThumbnails[1].url.replace('https://yt3.ggpht.com', `${this.invidiousInstance}/ggpht/`) : ''
|
2020-02-28 03:29:30 +00:00
|
|
|
this.videoPublished = result.published * 1000
|
|
|
|
this.videoDescriptionHtml = result.descriptionHtml
|
|
|
|
this.recommendedVideos = result.recommendedVideos
|
2020-05-23 21:29:42 +00:00
|
|
|
this.isLive = result.liveNow
|
2020-02-28 03:29:30 +00:00
|
|
|
this.captionSourceList = result.captions.map(caption => {
|
|
|
|
caption.url = this.invidiousInstance + caption.url
|
|
|
|
caption.type = ''
|
|
|
|
caption.dataSource = 'invidious'
|
|
|
|
return caption
|
|
|
|
})
|
2020-02-16 18:30:00 +00:00
|
|
|
|
2020-09-22 01:30:48 +00:00
|
|
|
switch (this.thumbnailPreference) {
|
|
|
|
case 'start':
|
|
|
|
this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres1.jpg`
|
|
|
|
break
|
|
|
|
case 'middle':
|
|
|
|
this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres2.jpg`
|
|
|
|
break
|
|
|
|
case 'end':
|
|
|
|
this.thumbnail = `${this.invidiousInstance}/vi/${this.videoId}/maxres3.jpg`
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
this.thumbnail = result.videoThumbnails[0].url
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2020-05-23 21:29:42 +00:00
|
|
|
if (this.isLive) {
|
|
|
|
this.showLegacyPlayer = true
|
|
|
|
this.showDashPlayer = false
|
|
|
|
this.activeFormat = 'legacy'
|
|
|
|
|
|
|
|
this.videoSourceList = [
|
|
|
|
{
|
|
|
|
url: result.hlsUrl,
|
|
|
|
type: 'application/x-mpegURL',
|
|
|
|
label: 'Dash',
|
|
|
|
qualityLabel: 'Live'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
// Grabs the adaptive formats from Invidious. Might be worth making these work.
|
|
|
|
// The type likely needs to be changed in order for these to be played properly.
|
|
|
|
// this.videoSourceList = result.adaptiveFormats.filter((format) => {
|
|
|
|
// if (typeof (format.type) !== 'undefined') {
|
|
|
|
// return format.type.includes('video/mp4')
|
|
|
|
// }
|
|
|
|
// }).map((format) => {
|
|
|
|
// return {
|
|
|
|
// url: format.url,
|
|
|
|
// type: 'application/x-mpegURL',
|
|
|
|
// label: 'Dash',
|
|
|
|
// qualityLabel: format.qualityLabel
|
|
|
|
// }
|
|
|
|
// })
|
2020-06-04 01:00:36 +00:00
|
|
|
|
|
|
|
this.activeSourceList = this.videoSourceList
|
2020-05-23 21:29:42 +00:00
|
|
|
} else if (this.forceLocalBackendForLegacy) {
|
2020-03-01 03:37:02 +00:00
|
|
|
this.getLegacyFormats()
|
2020-04-14 02:59:25 +00:00
|
|
|
} else {
|
2020-08-20 02:39:44 +00:00
|
|
|
this.videoLengthSeconds = result.lengthSeconds
|
2020-04-14 02:59:25 +00:00
|
|
|
this.videoSourceList = result.formatStreams.reverse()
|
2020-06-01 02:47:22 +00:00
|
|
|
|
2020-10-08 19:01:46 +00:00
|
|
|
this.downloadLinks = result.adaptiveFormats.concat(this.videoSourceList).map((format) => {
|
|
|
|
const qualityLabel = format.qualityLabel || format.bitrate
|
|
|
|
const itag = parseInt(format.itag)
|
|
|
|
const fps = format.fps ? (format.fps + 'fps') : 'kbps'
|
|
|
|
const type = format.type.match(/.*;/)[0].replace(';', '')
|
|
|
|
let label = `${qualityLabel} ${fps} - ${type}`
|
|
|
|
|
|
|
|
if (itag !== 18 && itag !== 22) {
|
|
|
|
if (type.includes('video')) {
|
|
|
|
label += ` ${this.$t('Video.video only')}`
|
|
|
|
} else {
|
|
|
|
label += ` ${this.$t('Video.audio only')}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
const object = {
|
|
|
|
url: format.url,
|
|
|
|
label: label
|
|
|
|
}
|
|
|
|
|
|
|
|
return object
|
2020-10-19 19:16:56 +00:00
|
|
|
}).reverse().concat(result.captions.map((caption) => {
|
|
|
|
const label = `${caption.label} (${caption.languageCode}) - text/vtt`
|
|
|
|
const object = {
|
|
|
|
url: caption.url,
|
|
|
|
label: label
|
|
|
|
}
|
|
|
|
|
|
|
|
return object
|
|
|
|
}))
|
2020-10-08 19:01:46 +00:00
|
|
|
|
2020-06-01 02:47:22 +00:00
|
|
|
this.audioSourceList = result.adaptiveFormats.filter((format) => {
|
|
|
|
return format.type.includes('audio')
|
|
|
|
}).map((format) => {
|
|
|
|
return {
|
|
|
|
url: format.url,
|
|
|
|
type: format.type,
|
|
|
|
label: 'Audio',
|
|
|
|
qualityLabel: parseInt(format.bitrate)
|
|
|
|
}
|
|
|
|
}).sort((a, b) => {
|
|
|
|
return a.qualityLabel - b.qualityLabel
|
|
|
|
})
|
|
|
|
|
|
|
|
if (this.activeFormat === 'audio') {
|
|
|
|
this.activeSourceList = this.audioSourceList
|
|
|
|
} else {
|
|
|
|
this.activeSourceList = this.videoSourceList
|
|
|
|
}
|
2020-03-01 03:37:02 +00:00
|
|
|
}
|
|
|
|
|
2020-10-31 14:36:35 +00:00
|
|
|
this.updateTitle()
|
2020-10-31 15:23:26 +00:00
|
|
|
|
|
|
|
this.isLoading = false
|
2020-02-28 03:29:30 +00:00
|
|
|
})
|
|
|
|
.catch(err => {
|
2020-08-09 03:15:00 +00:00
|
|
|
const errorMessage = this.$t('Invidious API Error (Click to copy)')
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-10-31 15:23:26 +00:00
|
|
|
message: `${errorMessage}: ${err.responseText}`,
|
2020-08-05 03:44:34 +00:00
|
|
|
time: 10000,
|
|
|
|
action: () => {
|
2020-10-31 15:23:26 +00:00
|
|
|
navigator.clipboard.writeText(err.responseText)
|
2020-08-05 03:44:34 +00:00
|
|
|
}
|
|
|
|
})
|
2020-02-28 03:29:30 +00:00
|
|
|
console.log(err)
|
|
|
|
if (this.backendPreference === 'invidious' && this.backendFallback) {
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-09 03:15:00 +00:00
|
|
|
message: this.$t('Falling back to Local API')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
2020-02-28 03:29:30 +00:00
|
|
|
this.getVideoInformationLocal()
|
|
|
|
} else {
|
|
|
|
this.isLoading = false
|
|
|
|
}
|
|
|
|
})
|
2020-02-19 03:31:10 +00:00
|
|
|
},
|
|
|
|
|
2020-08-20 02:39:44 +00:00
|
|
|
addToHistory: function (watchProgress) {
|
|
|
|
const videoData = {
|
|
|
|
videoId: this.videoId,
|
|
|
|
title: this.videoTitle,
|
|
|
|
author: this.channelName,
|
|
|
|
authorId: this.channelId,
|
|
|
|
published: this.videoPublished,
|
|
|
|
description: this.videoDescription,
|
|
|
|
viewCount: this.videoViewCount,
|
|
|
|
lengthSeconds: this.videoLengthSeconds,
|
|
|
|
watchProgress: watchProgress,
|
|
|
|
timeWatched: new Date().getTime(),
|
|
|
|
isLive: false,
|
|
|
|
paid: false,
|
|
|
|
type: 'video'
|
|
|
|
}
|
|
|
|
|
|
|
|
this.updateHistory(videoData)
|
|
|
|
},
|
|
|
|
|
|
|
|
checkIfWatched: function () {
|
|
|
|
const historyIndex = this.historyCache.findIndex((video) => {
|
|
|
|
return video.videoId === this.videoId
|
|
|
|
})
|
|
|
|
|
|
|
|
console.log(historyIndex)
|
|
|
|
|
|
|
|
if (historyIndex !== -1 && !this.isLive) {
|
|
|
|
const watchProgress = this.historyCache[historyIndex].watchProgress
|
2020-09-24 22:33:21 +00:00
|
|
|
|
|
|
|
if (watchProgress < (this.videoLengthSeconds - 10)) {
|
|
|
|
this.$refs.videoPlayer.player.currentTime(watchProgress)
|
|
|
|
}
|
2020-08-20 02:39:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this.rememberHistory && historyIndex !== -1) {
|
|
|
|
this.addToHistory(this.historyCache[historyIndex].watchProgress)
|
|
|
|
} else if (this.rememberHistory) {
|
|
|
|
this.addToHistory(0)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
checkIfPlaylist: function () {
|
|
|
|
if (typeof (this.$route.query) !== 'undefined') {
|
|
|
|
this.playlistId = this.$route.query.playlistId
|
|
|
|
|
|
|
|
if (typeof (this.playlistId) !== 'undefined') {
|
|
|
|
this.watchingPlaylist = true
|
|
|
|
} else {
|
|
|
|
this.watchingPlaylist = false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.watchingPlaylist = false
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-03-01 03:37:02 +00:00
|
|
|
getLegacyFormats: function () {
|
|
|
|
this.$store
|
|
|
|
.dispatch('ytGetVideoInformation', this.videoId)
|
|
|
|
.then(result => {
|
|
|
|
this.videoSourceList = result.player_response.streamingData.formats
|
|
|
|
})
|
2020-08-05 03:44:34 +00:00
|
|
|
.catch(err => {
|
2020-08-09 03:15:00 +00:00
|
|
|
const errorMessage = this.$t('Local API Error (Click to copy)')
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-09 03:15:00 +00:00
|
|
|
message: `${errorMessage}: ${err}`,
|
2020-08-05 03:44:34 +00:00
|
|
|
time: 10000,
|
|
|
|
action: () => {
|
|
|
|
navigator.clipboard.writeText(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
console.log(err)
|
|
|
|
if (!this.usingElectron || (this.backendPreference === 'local' && this.backendFallback)) {
|
2020-08-08 02:16:06 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Falling back to Invidious API')
|
|
|
|
})
|
2020-08-05 03:44:34 +00:00
|
|
|
this.getVideoInformationInvidious()
|
|
|
|
}
|
|
|
|
})
|
2020-03-01 03:37:02 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
enableDashFormat: function () {
|
2020-05-23 21:29:42 +00:00
|
|
|
if (this.activeFormat === 'dash' || this.isLive) {
|
2020-02-20 20:58:21 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-16 02:07:54 +00:00
|
|
|
if (this.dashSrc === null) {
|
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Change Format.Dash formats are not available for this video')
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2020-09-22 22:27:53 +00:00
|
|
|
const watchedProgress = this.getWatchedProgress()
|
2020-02-19 03:31:10 +00:00
|
|
|
this.activeFormat = 'dash'
|
|
|
|
this.hidePlayer = true
|
|
|
|
|
2020-02-28 03:29:30 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
this.hidePlayer = false
|
2020-09-22 22:27:53 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
const player = this.$refs.videoPlayer.player
|
|
|
|
if (player !== null) {
|
|
|
|
player.currentTime(watchedProgress)
|
|
|
|
}
|
|
|
|
}, 500)
|
2020-02-28 03:29:30 +00:00
|
|
|
}, 100)
|
2020-02-19 03:31:10 +00:00
|
|
|
},
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
enableLegacyFormat: function () {
|
2020-02-20 20:58:21 +00:00
|
|
|
if (this.activeFormat === 'legacy') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-22 22:27:53 +00:00
|
|
|
const watchedProgress = this.getWatchedProgress()
|
2020-02-19 03:31:10 +00:00
|
|
|
this.activeFormat = 'legacy'
|
2020-06-01 02:47:22 +00:00
|
|
|
this.activeSourceList = this.videoSourceList
|
|
|
|
this.hidePlayer = true
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
this.hidePlayer = false
|
2020-09-22 22:27:53 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
const player = this.$refs.videoPlayer.player
|
|
|
|
if (player !== null) {
|
|
|
|
player.currentTime(watchedProgress)
|
|
|
|
}
|
|
|
|
}, 500)
|
2020-06-01 02:47:22 +00:00
|
|
|
}, 100)
|
|
|
|
},
|
|
|
|
|
|
|
|
enableAudioFormat: function () {
|
|
|
|
if (this.activeFormat === 'audio') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-16 02:07:54 +00:00
|
|
|
if (this.audioSourceList === null) {
|
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Change Format.Audio formats are not available for this video')
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-22 22:27:53 +00:00
|
|
|
const watchedProgress = this.getWatchedProgress()
|
2020-06-01 02:47:22 +00:00
|
|
|
this.activeFormat = 'audio'
|
|
|
|
this.activeSourceList = this.audioSourceList
|
2020-02-19 03:31:10 +00:00
|
|
|
this.hidePlayer = true
|
|
|
|
|
2020-02-20 20:58:21 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
this.hidePlayer = false
|
2020-09-22 22:27:53 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
const player = this.$refs.videoPlayer.player
|
|
|
|
if (player !== null) {
|
|
|
|
player.currentTime(watchedProgress)
|
|
|
|
}
|
|
|
|
}, 500)
|
2020-02-20 20:58:21 +00:00
|
|
|
}, 100)
|
2020-02-21 18:31:32 +00:00
|
|
|
},
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
handleVideoEnded: function () {
|
|
|
|
if (this.watchingPlaylist) {
|
2020-09-21 22:39:25 +00:00
|
|
|
this.playNextTimeout = setTimeout(() => {
|
2020-05-17 20:12:58 +00:00
|
|
|
this.$refs.watchVideoPlaylist.playNextVideo()
|
|
|
|
}, 5000)
|
2020-08-05 03:44:34 +00:00
|
|
|
|
2020-09-07 18:43:44 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Playing next video in 5 seconds. Click to cancel'),
|
|
|
|
time: 5500,
|
|
|
|
action: () => {
|
2020-09-21 22:39:25 +00:00
|
|
|
clearTimeout(this.playNextTimeout)
|
2020-09-07 18:43:44 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Canceled next video autoplay')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else if (this.playNextVideo) {
|
2020-09-21 22:39:25 +00:00
|
|
|
this.playNextTimeout = setTimeout(() => {
|
2020-09-07 18:43:44 +00:00
|
|
|
const nextVideoId = this.recommendedVideos[0].videoId
|
|
|
|
this.$router.push(
|
|
|
|
{
|
|
|
|
path: `/watch/${nextVideoId}`
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Playing Next Video')
|
|
|
|
})
|
|
|
|
}, 5000)
|
|
|
|
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-09 03:15:00 +00:00
|
|
|
message: this.$t('Playing next video in 5 seconds. Click to cancel'),
|
2020-08-05 03:44:34 +00:00
|
|
|
time: 5500,
|
|
|
|
action: () => {
|
2020-09-21 22:39:25 +00:00
|
|
|
clearTimeout(this.playNextTimeout)
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-09 03:15:00 +00:00
|
|
|
message: this.$t('Canceled next video autoplay')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-09-07 18:43:44 +00:00
|
|
|
handleRouteChange: function () {
|
2020-09-21 22:39:25 +00:00
|
|
|
clearTimeout(this.playNextTimeout)
|
|
|
|
|
2020-09-25 14:14:49 +00:00
|
|
|
if (this.rememberHistory && !this.isUpcoming && !this.isLoading && !this.isLive) {
|
2020-09-07 18:43:44 +00:00
|
|
|
const player = this.$refs.videoPlayer.player
|
|
|
|
|
|
|
|
if (player !== null && this.saveWatchedProgress) {
|
2020-09-11 03:48:06 +00:00
|
|
|
const currentTime = this.getWatchedProgress()
|
2020-09-07 18:43:44 +00:00
|
|
|
const payload = {
|
|
|
|
videoId: this.videoId,
|
|
|
|
watchProgress: currentTime
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('update watch progress')
|
|
|
|
this.updateWatchProgress(payload)
|
|
|
|
}
|
2020-09-22 01:30:48 +00:00
|
|
|
|
2020-09-22 20:19:21 +00:00
|
|
|
if (player !== null && !player.paused() && player.isInPictureInPicture()) {
|
|
|
|
const playerId = this.videoId
|
2020-09-22 01:30:48 +00:00
|
|
|
setTimeout(() => {
|
|
|
|
player.play()
|
|
|
|
player.on('leavepictureinpicture', () => {
|
|
|
|
const watchTime = player.currentTime()
|
|
|
|
if (this.$route.fullPath.includes('/watch')) {
|
|
|
|
const routeId = this.$route.params.id
|
2020-09-22 20:19:21 +00:00
|
|
|
if (routeId === playerId) {
|
2020-09-22 01:30:48 +00:00
|
|
|
const activePlayer = $('.ftVideoPlayer video').get(0)
|
|
|
|
activePlayer.currentTime = watchTime
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
player.pause()
|
|
|
|
player.dispose()
|
|
|
|
})
|
|
|
|
}, 200)
|
|
|
|
}
|
2020-09-07 18:43:44 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-08-16 22:11:44 +00:00
|
|
|
handleVideoError: function (error) {
|
2020-02-21 18:31:32 +00:00
|
|
|
console.log(error)
|
2020-05-23 21:29:42 +00:00
|
|
|
if (this.isLive) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-21 18:31:32 +00:00
|
|
|
if (error.code === 4) {
|
|
|
|
if (this.activeFormat === 'dash') {
|
2020-02-28 03:29:30 +00:00
|
|
|
console.log(
|
|
|
|
'Unable to play dash formats. Reverting to legacy formats...'
|
|
|
|
)
|
2020-02-21 18:31:32 +00:00
|
|
|
this.enableLegacyFormat()
|
|
|
|
} else {
|
|
|
|
this.enableDashFormat()
|
|
|
|
}
|
|
|
|
}
|
2020-08-05 03:44:34 +00:00
|
|
|
},
|
|
|
|
|
2020-08-28 19:43:10 +00:00
|
|
|
createLocalDashManifest: function (formats) {
|
|
|
|
const xmlData = ytDashGen.generate_dash_file_from_formats(formats, this.videoLengthSeconds)
|
|
|
|
const userData = electron.remote.app.getPath('userData')
|
|
|
|
let fileLocation
|
|
|
|
let uriSchema
|
|
|
|
if (this.isDev) {
|
|
|
|
fileLocation = `dashFiles/${this.videoId}.xml`
|
|
|
|
uriSchema = fileLocation
|
|
|
|
// if the location does not exist, writeFileSync will not create the directory, so we have to do that manually
|
|
|
|
if (!fs.existsSync('dashFiles/')) {
|
|
|
|
fs.mkdirSync('dashFiles/')
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fileLocation = `${userData}/dashFiles/${this.videoId}.xml`
|
|
|
|
uriSchema = `file://${fileLocation}`
|
|
|
|
|
|
|
|
if (!fs.existsSync(`${userData}/dashFiles/`)) {
|
|
|
|
fs.mkdirSync(`${userData}/dashFiles/`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fs.writeFileSync(fileLocation, xmlData)
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
url: uriSchema,
|
|
|
|
type: 'application/dash+xml',
|
|
|
|
label: 'Dash',
|
|
|
|
qualityLabel: 'Auto'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
|
|
|
|
createInvidiousDashManifest: function () {
|
|
|
|
let url = `${this.invidiousInstance}/api/manifest/dash/id/${this.videoId}.mpd`
|
|
|
|
|
|
|
|
if (this.proxyVideos || !this.usingElectron) {
|
|
|
|
url = url + '?local=true'
|
|
|
|
}
|
|
|
|
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
url: url,
|
|
|
|
type: 'application/dash+xml',
|
|
|
|
label: 'Dash',
|
|
|
|
qualityLabel: 'Auto'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
|
2020-08-16 22:11:44 +00:00
|
|
|
createLocalStoryboardUrls: function (templateUrl) {
|
|
|
|
const storyboards = templateUrl.split('|')
|
|
|
|
const storyboardArray = []
|
|
|
|
// Second storyboard: L1/M0 - Third storyboard: L2/M0 - Fourth: L3/M0
|
|
|
|
|
|
|
|
const baseUrl = storyboards.shift()
|
|
|
|
// remove the first link because it does not work
|
|
|
|
storyboards.splice(0, 1)
|
|
|
|
storyboards.forEach((storyboard, i) => {
|
|
|
|
// Not sure why the _ variable is needed, but storyboards don't work unless we initialize it.
|
|
|
|
|
|
|
|
/* eslint-disable-next-line */
|
|
|
|
const [width, height, count, sWidth, sHeight, interval, _, sigh] = storyboard.split('#')
|
|
|
|
storyboardArray.push({
|
|
|
|
url: baseUrl.replace('$L', i + 1).replace('$N', 'M0').replace(/<\/?sub>/g, '') + '&sigh=' + sigh,
|
|
|
|
width: Number(width), // Width of one sub image
|
|
|
|
height: Number(height), // Height of one sub image
|
|
|
|
sWidth: Number(sWidth), // Number of images vertically (if full)
|
|
|
|
sHeight: Number(sHeight), // Number of images horizontally (if full)
|
|
|
|
count: Number(count), // Number of images total
|
|
|
|
interval: Number(interval) // How long one image is used
|
|
|
|
})
|
|
|
|
})
|
|
|
|
// TODO: MAKE A VARIABLE WHICH CAN CHOOSE BETWEEN STROYBOARD ARRAY ELEMENTS
|
|
|
|
this.buildVTTFileLocally(storyboardArray[1]).then((results) => {
|
|
|
|
const userData = electron.remote.app.getPath('userData')
|
|
|
|
let fileLocation
|
|
|
|
let uriSchema
|
|
|
|
|
|
|
|
// Dev mode doesn't have access to the file:// schema, so we access
|
|
|
|
// storyboards differently when run in dev
|
|
|
|
if (this.isDev) {
|
|
|
|
fileLocation = `storyboards/${this.videoId}.vtt`
|
|
|
|
uriSchema = fileLocation
|
2020-08-26 19:52:12 +00:00
|
|
|
// if the location does not exist, writeFileSync will not create the directory, so we have to do that manually
|
|
|
|
if (!fs.existsSync('storyboards/')) {
|
|
|
|
fs.mkdirSync('storyboards/')
|
|
|
|
}
|
2020-08-16 22:11:44 +00:00
|
|
|
} else {
|
2020-08-31 18:13:49 +00:00
|
|
|
if (!fs.existsSync(`${userData}/storyboards/`)) {
|
|
|
|
fs.mkdirSync(`${userData}/storyboards/`)
|
|
|
|
}
|
2020-08-16 22:11:44 +00:00
|
|
|
fileLocation = `${userData}/storyboards/${this.videoId}.vtt`
|
|
|
|
uriSchema = `file://${fileLocation}`
|
|
|
|
}
|
|
|
|
fs.writeFileSync(fileLocation, results)
|
|
|
|
|
|
|
|
this.videoStoryboardSrc = uriSchema
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
createCaptionUrls: function (captionTracks) {
|
|
|
|
this.captionSourceList = captionTracks.map(caption => {
|
|
|
|
caption.type = 'text/vtt'
|
|
|
|
caption.charset = 'charset=utf-8'
|
|
|
|
caption.dataSource = 'local'
|
|
|
|
|
|
|
|
$.get(caption.baseUrl, response => {
|
|
|
|
xml2vtt
|
|
|
|
.Parse(new XMLSerializer().serializeToString(response))
|
|
|
|
.then(vtt => {
|
|
|
|
caption.baseUrl = `data:${caption.type};${caption.charset},${vtt}`
|
|
|
|
})
|
|
|
|
.catch(err =>
|
|
|
|
console.log(`Error while converting XML to VTT : ${err}`)
|
|
|
|
)
|
|
|
|
}).fail((xhr, textStatus, error) => {
|
|
|
|
console.log(xhr)
|
|
|
|
console.log(textStatus)
|
|
|
|
console.log(error)
|
|
|
|
})
|
|
|
|
|
|
|
|
return caption
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2020-09-11 03:48:06 +00:00
|
|
|
getWatchedProgress: function () {
|
|
|
|
return this.$refs.videoPlayer && this.$refs.videoPlayer.player ? this.$refs.videoPlayer.player.currentTime() : 0
|
|
|
|
},
|
|
|
|
|
|
|
|
getTimestamp: function () {
|
|
|
|
return Math.floor(this.getWatchedProgress())
|
|
|
|
},
|
|
|
|
|
2020-10-31 14:36:35 +00:00
|
|
|
updateTitle: function () {
|
|
|
|
document.title = `${this.videoTitle} - FreeTube`
|
|
|
|
},
|
|
|
|
|
2020-08-05 03:44:34 +00:00
|
|
|
...mapActions([
|
2020-08-16 22:11:44 +00:00
|
|
|
'showToast',
|
2020-08-20 02:39:44 +00:00
|
|
|
'buildVTTFileLocally',
|
|
|
|
'updateHistory',
|
|
|
|
'updateWatchProgress'
|
2020-08-05 03:44:34 +00:00
|
|
|
])
|
2020-08-05 02:18:39 +00:00
|
|
|
}
|
2020-02-16 18:30:00 +00:00
|
|
|
})
|