2020-05-17 20:12:58 +00:00
|
|
|
import Vue from 'vue'
|
2020-08-05 03:44:34 +00:00
|
|
|
import { mapActions } from 'vuex'
|
2020-05-17 20:12:58 +00:00
|
|
|
import FtLoader from '../ft-loader/ft-loader.vue'
|
|
|
|
import FtCard from '../ft-card/ft-card.vue'
|
|
|
|
import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
|
|
|
|
import FtListVideo from '../ft-list-video/ft-list-video.vue'
|
|
|
|
|
|
|
|
export default Vue.extend({
|
|
|
|
name: 'WatchVideoPlaylist',
|
|
|
|
components: {
|
|
|
|
'ft-loader': FtLoader,
|
|
|
|
'ft-card': FtCard,
|
|
|
|
'ft-flex-box': FtFlexBox,
|
|
|
|
'ft-list-video': FtListVideo
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
playlistId: {
|
|
|
|
type: String,
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
videoId: {
|
|
|
|
type: String,
|
|
|
|
required: true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
data: function () {
|
|
|
|
return {
|
|
|
|
isLoading: false,
|
|
|
|
shuffleEnabled: false,
|
|
|
|
loopEnabled: false,
|
|
|
|
channelName: '',
|
|
|
|
channelId: '',
|
|
|
|
channelThumbnail: '',
|
|
|
|
playlistTitle: '',
|
|
|
|
playlistItems: [],
|
2020-08-07 03:08:27 +00:00
|
|
|
randomizedPlaylistItems: []
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
usingElectron: function () {
|
|
|
|
return this.$store.getters.getUsingElectron
|
|
|
|
},
|
|
|
|
|
|
|
|
backendPreference: function () {
|
|
|
|
return this.$store.getters.getBackendPreference
|
|
|
|
},
|
|
|
|
|
|
|
|
backendFallback: function () {
|
|
|
|
return this.$store.getters.getBackendFallback
|
|
|
|
},
|
|
|
|
|
|
|
|
currentVideoIndex: function () {
|
|
|
|
const index = this.playlistItems.findIndex((item) => {
|
2020-08-08 02:16:06 +00:00
|
|
|
return item.id === this.videoId
|
2020-05-17 20:12:58 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return index + 1
|
|
|
|
},
|
|
|
|
|
|
|
|
playlistVideoCount: function () {
|
|
|
|
return this.playlistItems.length
|
|
|
|
}
|
|
|
|
},
|
2020-08-08 21:56:05 +00:00
|
|
|
watch: {
|
|
|
|
videoId: function (newId, oldId) {
|
|
|
|
// Check if next video is from the shuffled list or if the user clicked a different video
|
|
|
|
if (this.shuffleEnabled) {
|
|
|
|
const newVideoIndex = this.randomizedPlaylistItems.findIndex((item) => {
|
|
|
|
return item === newId
|
|
|
|
})
|
|
|
|
|
|
|
|
const oldVideoIndex = this.randomizedPlaylistItems.findIndex((item) => {
|
|
|
|
return item === this.oldId
|
|
|
|
})
|
|
|
|
|
|
|
|
if ((newVideoIndex - 1) !== oldVideoIndex) {
|
|
|
|
// User clicked a different video than expected. Re-shuffle the list
|
|
|
|
this.shufflePlaylistItems()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-05-17 20:12:58 +00:00
|
|
|
mounted: function () {
|
2020-08-08 02:16:06 +00:00
|
|
|
if (!this.usingElectron) {
|
2020-05-17 20:12:58 +00:00
|
|
|
this.getPlaylistInformationInvidious()
|
|
|
|
} else {
|
|
|
|
switch (this.backendPreference) {
|
|
|
|
case 'local':
|
|
|
|
this.getPlaylistInformationLocal()
|
|
|
|
break
|
|
|
|
case 'invidious':
|
|
|
|
this.getPlaylistInformationInvidious()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
goToPlaylist: function () {
|
|
|
|
this.$router.push({ path: `/playlist/${this.playlistId}` })
|
|
|
|
},
|
|
|
|
|
|
|
|
goToChannel: function () {
|
|
|
|
this.$router.push({ path: `/channel/${this.channelId}` })
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleLoop: function () {
|
|
|
|
if (this.loopEnabled) {
|
|
|
|
this.loopEnabled = false
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Loop is now disabled')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
} else {
|
|
|
|
this.loopEnabled = true
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Loop is now enabled')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
toggleShuffle: function () {
|
|
|
|
if (this.shuffleEnabled) {
|
|
|
|
this.shuffleEnabled = false
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Shuffle is now disabled')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
} else {
|
|
|
|
this.shuffleEnabled = true
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Shuffle is now enabled')
|
2020-08-05 03:44:34 +00:00
|
|
|
})
|
2020-08-07 03:08:27 +00:00
|
|
|
this.shufflePlaylistItems()
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
playNextVideo: function () {
|
|
|
|
const playlistInfo = {
|
|
|
|
playlistId: this.playlistId
|
|
|
|
}
|
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
if (this.shuffleEnabled) {
|
|
|
|
const videoIndex = this.randomizedPlaylistItems.findIndex((item) => {
|
2020-08-08 21:56:05 +00:00
|
|
|
return item === this.videoId
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
if (videoIndex === this.randomizedPlaylistItems.length - 1) {
|
|
|
|
if (this.loopEnabled) {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
|
|
|
path: `/watch/${this.randomizedPlaylistItems[0]}`,
|
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Playing Next Video')
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
|
|
|
this.shufflePlaylistItems()
|
|
|
|
} else {
|
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('The playlist has ended. Enable loop to continue playing')
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
|
|
|
path: `/watch/${this.randomizedPlaylistItems[videoIndex + 1]}`,
|
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Playing Next Video')
|
2020-05-17 20:12:58 +00:00
|
|
|
})
|
2020-08-07 03:08:27 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const videoIndex = this.playlistItems.findIndex((item) => {
|
2020-08-08 02:16:06 +00:00
|
|
|
return item.id === this.videoId
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
if (videoIndex === this.playlistItems.length - 1) {
|
|
|
|
if (this.loopEnabled) {
|
2020-05-17 20:12:58 +00:00
|
|
|
this.$router.push(
|
|
|
|
{
|
2020-08-08 02:16:06 +00:00
|
|
|
path: `/watch/${this.playlistItems[0].id}`,
|
2020-05-17 20:12:58 +00:00
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
2020-08-07 03:08:27 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Playing Next Video')
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
2020-08-07 03:08:27 +00:00
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('The playlist has ended. Enable loop to continue playing')
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
2020-08-08 02:16:06 +00:00
|
|
|
path: `/watch/${this.playlistItems[videoIndex + 1].id}`,
|
2020-08-07 03:08:27 +00:00
|
|
|
query: playlistInfo
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
2020-08-07 03:08:27 +00:00
|
|
|
)
|
|
|
|
this.showToast({
|
2020-08-08 02:16:06 +00:00
|
|
|
message: this.$t('Playing Next Video')
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-06-04 01:33:47 +00:00
|
|
|
playPreviousVideo: function () {
|
2020-08-05 03:44:34 +00:00
|
|
|
this.showToast({
|
|
|
|
message: 'Playing previous video'
|
|
|
|
})
|
|
|
|
|
2020-06-04 01:33:47 +00:00
|
|
|
const playlistInfo = {
|
|
|
|
playlistId: this.playlistId
|
|
|
|
}
|
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
if (this.shuffleEnabled) {
|
|
|
|
const videoIndex = this.randomizedPlaylistItems.findIndex((item) => {
|
2020-08-08 21:56:05 +00:00
|
|
|
return item === this.videoId
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
2020-06-04 01:33:47 +00:00
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
if (videoIndex === 0) {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
|
|
|
path: `/watch/${this.randomizedPlaylistItems[this.randomizedPlaylistItems.length - 1]}`,
|
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
|
|
|
path: `/watch/${this.randomizedPlaylistItems[videoIndex - 1]}`,
|
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2020-06-04 01:33:47 +00:00
|
|
|
} else {
|
2020-08-07 03:08:27 +00:00
|
|
|
const videoIndex = this.playlistItems.findIndex((item) => {
|
2020-08-08 02:16:06 +00:00
|
|
|
return item.id === this.videoId
|
2020-08-07 03:08:27 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
if (videoIndex === 0) {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
2020-08-08 02:16:06 +00:00
|
|
|
path: `/watch/${this.playlistItems[this.randomizedPlaylistItems.length - 1].id}`,
|
2020-08-07 03:08:27 +00:00
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
this.$router.push(
|
|
|
|
{
|
2020-08-08 02:16:06 +00:00
|
|
|
path: `/watch/${this.playlistItems[videoIndex - 1].id}`,
|
2020-08-07 03:08:27 +00:00
|
|
|
query: playlistInfo
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
2020-06-04 01:33:47 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2020-05-17 20:12:58 +00:00
|
|
|
getPlaylistInformationLocal: function () {
|
|
|
|
this.isLoading = true
|
|
|
|
|
|
|
|
this.$store.dispatch('ytGetPlaylistInfo', this.playlistId).then((result) => {
|
|
|
|
console.log('done')
|
|
|
|
console.log(result)
|
|
|
|
|
|
|
|
this.playlistTitle = result.title
|
|
|
|
this.playlistItems = result.items
|
|
|
|
this.videoCount = result.total_items
|
|
|
|
this.channelName = result.author.name
|
|
|
|
this.channelThumbnail = result.author.avatar
|
|
|
|
this.channelId = result.author.id
|
|
|
|
|
|
|
|
this.playlistItems = result.items
|
|
|
|
this.isLoading = false
|
|
|
|
}).catch((err) => {
|
|
|
|
console.log(err)
|
2020-08-08 02:16:06 +00:00
|
|
|
const errorMessage = this.$t('Local API Error (Click to copy):')
|
|
|
|
this.showToast({
|
|
|
|
message: `${errorMessage} ${err}`,
|
|
|
|
time: 10000,
|
|
|
|
action: () => {
|
|
|
|
navigator.clipboard.writeText(err)
|
|
|
|
}
|
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
if (this.backendPreference === 'local' && this.backendFallback) {
|
2020-08-08 02:16:06 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Falling back to Invidious API')
|
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
this.getPlaylistInformationInvidious()
|
|
|
|
} else {
|
|
|
|
this.isLoading = false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
getPlaylistInformationInvidious: function () {
|
|
|
|
this.isLoading = true
|
|
|
|
|
|
|
|
const payload = {
|
|
|
|
resource: 'playlists',
|
|
|
|
id: this.playlistId,
|
|
|
|
params: {
|
|
|
|
page: this.playlistPage
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.$store.dispatch('invidiousGetPlaylistInfo', payload).then((result) => {
|
|
|
|
console.log('done')
|
|
|
|
console.log(result)
|
|
|
|
|
|
|
|
this.playlistTitle = result.title
|
|
|
|
this.videoCount = result.videoCount
|
|
|
|
this.channelName = result.author
|
|
|
|
this.channelThumbnail = result.authorThumbnails[2].url
|
|
|
|
this.channelId = result.authorId
|
|
|
|
this.playlistItems = this.playlistItems.concat(result.videos)
|
|
|
|
|
|
|
|
if (this.playlistItems.length < result.videoCount) {
|
|
|
|
console.log('getting next page')
|
|
|
|
this.playlistPage++
|
|
|
|
this.getPlaylistInformationInvidious()
|
|
|
|
} else {
|
|
|
|
this.isLoading = false
|
|
|
|
}
|
|
|
|
}).catch((err) => {
|
|
|
|
console.log(err)
|
2020-08-08 02:16:06 +00:00
|
|
|
const errorMessage = this.$t('Invidious API Error (Click to copy):')
|
|
|
|
this.showToast({
|
|
|
|
message: `${errorMessage} ${err}`,
|
|
|
|
time: 10000,
|
|
|
|
action: () => {
|
|
|
|
navigator.clipboard.writeText(err)
|
|
|
|
}
|
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
if (this.backendPreference === 'invidious' && this.backendFallback) {
|
2020-08-08 02:16:06 +00:00
|
|
|
this.showToast({
|
|
|
|
message: this.$t('Falling back to Local API')
|
|
|
|
})
|
2020-05-17 20:12:58 +00:00
|
|
|
this.getPlaylistInformationLocal()
|
|
|
|
} else {
|
|
|
|
this.isLoading = false
|
|
|
|
// TODO: Show toast with error message
|
|
|
|
}
|
|
|
|
})
|
2020-08-05 03:44:34 +00:00
|
|
|
},
|
|
|
|
|
2020-08-07 03:08:27 +00:00
|
|
|
shufflePlaylistItems: function () {
|
|
|
|
// Prevents the array from affecting the original object
|
|
|
|
const remainingItems = [].concat(this.playlistItems)
|
|
|
|
const items = []
|
|
|
|
|
|
|
|
items.push(this.videoId)
|
|
|
|
|
|
|
|
this.playlistItems.forEach((item) => {
|
|
|
|
const randomInt = Math.floor(Math.random() * remainingItems.length)
|
|
|
|
|
2020-08-08 02:16:06 +00:00
|
|
|
if (remainingItems[randomInt].id !== this.videoId) {
|
|
|
|
items.push(remainingItems[randomInt].id)
|
2020-08-07 03:08:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
remainingItems.splice(randomInt, 1)
|
|
|
|
})
|
|
|
|
|
|
|
|
this.randomizedPlaylistItems = items
|
|
|
|
},
|
|
|
|
|
2020-08-05 03:44:34 +00:00
|
|
|
...mapActions([
|
|
|
|
'showToast'
|
|
|
|
])
|
2020-05-17 20:12:58 +00:00
|
|
|
}
|
|
|
|
})
|