Simplify playlist / history search and add video stats string for legacy videos
This commit is contained in:
parent
222c41c863
commit
dbf69f242a
|
@ -36,8 +36,7 @@ const DBActions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
HISTORY: {
|
HISTORY: {
|
||||||
UPDATE_WATCH_PROGRESS: 'db-action-history-update-watch-progress',
|
UPDATE_WATCH_PROGRESS: 'db-action-history-update-watch-progress'
|
||||||
SEARCH: 'db-action-history-search'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
PLAYLISTS: {
|
PLAYLISTS: {
|
||||||
|
|
|
@ -38,11 +38,6 @@ class History {
|
||||||
return db.history.find({}).sort({ timeWatched: -1 })
|
return db.history.find({}).sort({ timeWatched: -1 })
|
||||||
}
|
}
|
||||||
|
|
||||||
static search(query) {
|
|
||||||
const re = new RegExp(query, 'i')
|
|
||||||
return db.history.find({ $or: [{ author: { $regex: re } }, { title: { $regex: re } }] }).sort({ timeWatched: -1 })
|
|
||||||
}
|
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return db.history.update({ videoId: record.videoId }, record, { upsert: true })
|
return db.history.update({ videoId: record.videoId }, record, { upsert: true })
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,6 @@ class History {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
static search(query) {
|
|
||||||
return ipcRenderer.invoke(
|
|
||||||
IpcChannels.DB_HISTORY,
|
|
||||||
{ action: DBActions.HISTORY.SEARCH, data: query }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return ipcRenderer.invoke(
|
return ipcRenderer.invoke(
|
||||||
IpcChannels.DB_HISTORY,
|
IpcChannels.DB_HISTORY,
|
||||||
|
|
|
@ -25,10 +25,6 @@ class History {
|
||||||
return baseHandlers.history.find()
|
return baseHandlers.history.find()
|
||||||
}
|
}
|
||||||
|
|
||||||
static search(query) {
|
|
||||||
return baseHandlers.history.search(query)
|
|
||||||
}
|
|
||||||
|
|
||||||
static upsert(record) {
|
static upsert(record) {
|
||||||
return baseHandlers.history.upsert(record)
|
return baseHandlers.history.upsert(record)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,4 @@ db.profiles = Datastore.create({ filename: dbPath('profiles'), autoload: true })
|
||||||
db.playlists = Datastore.create({ filename: dbPath('playlists'), autoload: true })
|
db.playlists = Datastore.create({ filename: dbPath('playlists'), autoload: true })
|
||||||
db.history = Datastore.create({ filename: dbPath('history'), autoload: true })
|
db.history = Datastore.create({ filename: dbPath('history'), autoload: true })
|
||||||
|
|
||||||
db.history.ensureIndex({ fieldName: 'author' })
|
|
||||||
db.history.ensureIndex({ fieldName: 'title' })
|
|
||||||
|
|
||||||
export default db
|
export default db
|
||||||
|
|
|
@ -456,9 +456,6 @@ function runApp() {
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
case DBActions.HISTORY.SEARCH:
|
|
||||||
return await baseHandlers.history.search(data)
|
|
||||||
|
|
||||||
case DBActions.GENERAL.DELETE:
|
case DBActions.GENERAL.DELETE:
|
||||||
await baseHandlers.history.delete(data)
|
await baseHandlers.history.delete(data)
|
||||||
syncOtherWindows(
|
syncOtherWindows(
|
||||||
|
|
|
@ -208,12 +208,6 @@ export default Vue.extend({
|
||||||
return this.$store.getters.getSaveWatchedProgress
|
return this.$store.getters.getSaveWatchedProgress
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
data: function () {
|
|
||||||
this.parseVideoData()
|
|
||||||
this.checkIfWatched()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.parseVideoData()
|
this.parseVideoData()
|
||||||
this.checkIfWatched()
|
this.checkIfWatched()
|
||||||
|
|
|
@ -1414,7 +1414,7 @@ export default Vue.extend({
|
||||||
console.log(this.format)
|
console.log(this.format)
|
||||||
if (this.format !== 'dash') {
|
if (this.format !== 'dash') {
|
||||||
this.showToast({
|
this.showToast({
|
||||||
message: 'Video statistics are not available for legacy videos'
|
message: this.$t('Video.Stats.Video statistics are not available for legacy videos')
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.showStatsModal = !this.showStatsModal
|
this.showStatsModal = !this.showStatsModal
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
import { DBHistoryHandlers } from '../../../datastores/handlers/index'
|
import { DBHistoryHandlers } from '../../../datastores/handlers/index'
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
historyCache: [],
|
historyCache: []
|
||||||
searchHistoryCache: []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
getHistoryCache: () => {
|
getHistoryCache: () => {
|
||||||
return state.historyCache
|
return state.historyCache
|
||||||
},
|
|
||||||
getSearchHistoryCache: () => {
|
|
||||||
return state.searchHistoryCache
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,15 +47,6 @@ const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async searchHistory({ commit }, query) {
|
|
||||||
try {
|
|
||||||
const results = await DBHistoryHandlers.search(query)
|
|
||||||
commit('setSearchHistoryCache', results)
|
|
||||||
} catch (errMessage) {
|
|
||||||
console.error(errMessage)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async updateWatchProgress({ commit }, { videoId, watchProgress }) {
|
async updateWatchProgress({ commit }, { videoId, watchProgress }) {
|
||||||
try {
|
try {
|
||||||
await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)
|
await DBHistoryHandlers.updateWatchProgress(videoId, watchProgress)
|
||||||
|
@ -79,10 +66,6 @@ const mutations = {
|
||||||
state.historyCache = historyCache
|
state.historyCache = historyCache
|
||||||
},
|
},
|
||||||
|
|
||||||
setSearchHistoryCache(state, result) {
|
|
||||||
state.searchHistoryCache = result
|
|
||||||
},
|
|
||||||
|
|
||||||
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
hoistEntryToTopOfHistoryCache(state, { currentIndex, updatedEntry }) {
|
||||||
state.historyCache.splice(currentIndex, 1)
|
state.historyCache.splice(currentIndex, 1)
|
||||||
state.historyCache.unshift(updatedEntry)
|
state.historyCache.unshift(updatedEntry)
|
||||||
|
|
|
@ -13,20 +13,14 @@ const state = {
|
||||||
removeOnWatched: true,
|
removeOnWatched: true,
|
||||||
videos: []
|
videos: []
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
searchPlaylistCache: {
|
|
||||||
videos: []
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getters = {
|
const getters = {
|
||||||
getAllPlaylists: () => state.playlists,
|
getAllPlaylists: () => state.playlists,
|
||||||
getFavorites: () => state.playlists[0],
|
getFavorites: () => state.playlists[0],
|
||||||
getPlaylist: (playlistId) => state.playlists.find(playlist => playlist._id === playlistId),
|
getPlaylist: (playlistId) => state.playlists.find(playlist => playlist._id === playlistId),
|
||||||
getWatchLater: () => state.playlists[1],
|
getWatchLater: () => state.playlists[1]
|
||||||
getSearchPlaylistCache: () => {
|
|
||||||
return state.searchPlaylistCache
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
@ -136,25 +130,10 @@ const actions = {
|
||||||
} catch (errMessage) {
|
} catch (errMessage) {
|
||||||
console.error(errMessage)
|
console.error(errMessage)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
async searchFavoritePlaylist({ commit }, query) {
|
|
||||||
const re = new RegExp(query, 'i')
|
|
||||||
// filtering in the frontend because the documents are the playlists and not the videos
|
|
||||||
const results = state.playlists[0].videos.slice()
|
|
||||||
.filter((video) => {
|
|
||||||
return video.author.match(re) ||
|
|
||||||
video.title.match(re)
|
|
||||||
})
|
|
||||||
commit('setPlaylistCache', results)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
setPlaylistCache(state, result) {
|
|
||||||
state.searchPlaylistCache = {
|
|
||||||
videos: result
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addPlaylist(state, payload) {
|
addPlaylist(state, payload) {
|
||||||
state.playlists.push(payload)
|
state.playlists.push(payload)
|
||||||
},
|
},
|
||||||
|
|
|
@ -20,19 +20,19 @@ export default Vue.extend({
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
dataLimit: 100,
|
dataLimit: 100,
|
||||||
hasQuery: false
|
searchDataLimit: 100,
|
||||||
|
showLoadMoreButton: false,
|
||||||
|
hasQuery: false,
|
||||||
|
query: '',
|
||||||
|
activeData: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
historyCache: function () {
|
historyCache: function () {
|
||||||
if (!this.hasQuery) {
|
return this.$store.getters.getHistoryCache
|
||||||
return this.$store.getters.getHistoryCache
|
|
||||||
} else {
|
|
||||||
return this.$store.getters.getSearchHistoryCache
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
activeData: function () {
|
fullData: function () {
|
||||||
if (this.historyCache.length < this.dataLimit) {
|
if (this.historyCache.length < this.dataLimit) {
|
||||||
return this.historyCache
|
return this.historyCache
|
||||||
} else {
|
} else {
|
||||||
|
@ -40,30 +40,79 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
query() {
|
||||||
|
this.searchDataLimit = 100
|
||||||
|
this.filterHistory()
|
||||||
|
},
|
||||||
|
activeData() {
|
||||||
|
this.refreshPage()
|
||||||
|
},
|
||||||
|
fullData() {
|
||||||
|
this.activeData = this.fullData
|
||||||
|
this.filterHistory()
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
console.log(this.historyCache)
|
|
||||||
|
|
||||||
const limit = sessionStorage.getItem('historyLimit')
|
const limit = sessionStorage.getItem('historyLimit')
|
||||||
|
|
||||||
if (limit !== null) {
|
if (limit !== null) {
|
||||||
this.dataLimit = limit
|
this.dataLimit = limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.activeData = this.fullData
|
||||||
|
|
||||||
|
if (this.activeData.length < this.historyCache.length) {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
increaseLimit: function () {
|
increaseLimit: function () {
|
||||||
this.dataLimit += 100
|
if (this.query !== '') {
|
||||||
sessionStorage.setItem('historyLimit', this.dataLimit)
|
this.searchDataLimit += 100
|
||||||
|
this.filterHistory()
|
||||||
|
} else {
|
||||||
|
this.dataLimit += 100
|
||||||
|
sessionStorage.setItem('historyLimit', this.dataLimit)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
filterHistory: function(query) {
|
filterHistory: function(query) {
|
||||||
this.hasQuery = query !== ''
|
if (this.query === '') {
|
||||||
this.$store.dispatch('searchHistory', query)
|
this.activeData = this.fullData
|
||||||
|
if (this.activeData.length < this.historyCache.length) {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const filteredQuery = this.historyCache.filter((video) => {
|
||||||
|
if (typeof (video.title) !== 'string' || typeof (video.author) !== 'string') {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return video.title.toLowerCase().includes(this.query.toLowerCase()) || video.author.toLowerCase().includes(this.query.toLowerCase())
|
||||||
|
}
|
||||||
|
}).sort((a, b) => {
|
||||||
|
return b.timeWatched - a.timeWatched
|
||||||
|
})
|
||||||
|
if (filteredQuery.length <= this.searchDataLimit) {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
}
|
||||||
|
this.activeData = filteredQuery.length < this.searchDataLimit ? filteredQuery : filteredQuery.slice(0, this.searchDataLimit)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
load: function() {
|
refreshPage: function() {
|
||||||
|
const scrollPos = window.scrollY || window.scrollTop || document.getElementsByTagName('html')[0].scrollTop
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
setTimeout(() => {
|
Vue.nextTick(() => {
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}, 100)
|
Vue.nextTick(() => {
|
||||||
|
window.scrollTo(0, scrollPos)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ft-loader
|
<ft-loader
|
||||||
v-if="isLoading"
|
v-show="isLoading"
|
||||||
:fullscreen="true"
|
:fullscreen="true"
|
||||||
/>
|
/>
|
||||||
<ft-card
|
<ft-card
|
||||||
v-else
|
v-show="!isLoading"
|
||||||
class="card"
|
class="card"
|
||||||
>
|
>
|
||||||
<h3>{{ $t("History.History") }}</h3>
|
<h3>{{ $t("History.History") }}</h3>
|
||||||
|
@ -14,21 +14,21 @@
|
||||||
:placeholder="$t('History.Search bar placeholder')"
|
:placeholder="$t('History.Search bar placeholder')"
|
||||||
:show-clear-text-button="true"
|
:show-clear-text-button="true"
|
||||||
:show-action-button="false"
|
:show-action-button="false"
|
||||||
@input="filterHistory"
|
@input="(input) => query = input"
|
||||||
/>
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length === 0"
|
v-show="activeData.length === 0"
|
||||||
>
|
>
|
||||||
<p class="message">
|
<p class="message">
|
||||||
{{ $t("History['Your history list is currently empty.']") }}
|
{{ $t("History['Your history list is currently empty.']") }}
|
||||||
</p>
|
</p>
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
<ft-element-list
|
<ft-element-list
|
||||||
v-else
|
v-if="activeData.length > 0 && !isLoading"
|
||||||
:data="activeData"
|
:data="activeData"
|
||||||
/>
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length < historyCache.length"
|
v-if="showLoadMoreButton"
|
||||||
>
|
>
|
||||||
<ft-button
|
<ft-button
|
||||||
label="Load More"
|
label="Load More"
|
||||||
|
|
|
@ -22,19 +22,19 @@ export default Vue.extend({
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
dataLimit: 100,
|
dataLimit: 100,
|
||||||
hasQuery: false
|
searchDataLimit: 100,
|
||||||
|
showLoadMoreButton: false,
|
||||||
|
query: '',
|
||||||
|
hasQuery: false,
|
||||||
|
activeData: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
favoritesPlaylist: function () {
|
favoritesPlaylist: function () {
|
||||||
if (!this.hasQuery) {
|
return this.$store.getters.getFavorites
|
||||||
return this.$store.getters.getFavorites
|
|
||||||
} else {
|
|
||||||
return this.$store.getters.getSearchPlaylistCache
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
activeData: function () {
|
fullData: function () {
|
||||||
const data = [].concat(this.favoritesPlaylist.videos).reverse()
|
const data = [].concat(this.favoritesPlaylist.videos).reverse()
|
||||||
if (this.favoritesPlaylist.videos.length < this.dataLimit) {
|
if (this.favoritesPlaylist.videos.length < this.dataLimit) {
|
||||||
return data
|
return data
|
||||||
|
@ -44,7 +44,70 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
query() {
|
||||||
|
this.searchDataLimit = 100
|
||||||
|
this.filterPlaylist()
|
||||||
|
},
|
||||||
activeData() {
|
activeData() {
|
||||||
|
this.refreshPage()
|
||||||
|
},
|
||||||
|
fullData() {
|
||||||
|
this.activeData = this.fullData
|
||||||
|
this.filterPlaylist()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
const limit = sessionStorage.getItem('favoritesLimit')
|
||||||
|
|
||||||
|
if (limit !== null) {
|
||||||
|
this.dataLimit = limit
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.activeData.length < this.favoritesPlaylist.videos.length) {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeData = this.fullData
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
increaseLimit: function () {
|
||||||
|
if (this.query !== '') {
|
||||||
|
this.searchDataLimit += 100
|
||||||
|
this.filterPlaylist()
|
||||||
|
} else {
|
||||||
|
this.dataLimit += 100
|
||||||
|
sessionStorage.setItem('favoritesLimit', this.dataLimit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filterPlaylist: function() {
|
||||||
|
if (this.query === '') {
|
||||||
|
this.activeData = this.fullData
|
||||||
|
if (this.activeData.length < this.favoritesPlaylist.videos.length) {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const filteredQuery = this.favoritesPlaylist.videos.filter((video) => {
|
||||||
|
if (typeof (video.title) !== 'string' || typeof (video.author) !== 'string') {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return video.title.toLowerCase().includes(this.query.toLowerCase()) || video.author.toLowerCase().includes(this.query.toLowerCase())
|
||||||
|
}
|
||||||
|
}).sort((a, b) => {
|
||||||
|
return b.timeAdded - a.timeAdded
|
||||||
|
})
|
||||||
|
if (filteredQuery.length <= this.searchDataLimit) {
|
||||||
|
this.showLoadMoreButton = false
|
||||||
|
} else {
|
||||||
|
this.showLoadMoreButton = true
|
||||||
|
}
|
||||||
|
this.activeData = filteredQuery.length < this.searchDataLimit ? filteredQuery : filteredQuery.slice(0, this.searchDataLimit)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refreshPage: function() {
|
||||||
const scrollPos = window.scrollY || window.scrollTop || document.getElementsByTagName('html')[0].scrollTop
|
const scrollPos = window.scrollY || window.scrollTop || document.getElementsByTagName('html')[0].scrollTop
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
|
@ -54,22 +117,5 @@ export default Vue.extend({
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
|
||||||
mounted: function () {
|
|
||||||
const limit = sessionStorage.getItem('favoritesLimit')
|
|
||||||
|
|
||||||
if (limit !== null) {
|
|
||||||
this.dataLimit = limit
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
increaseLimit: function () {
|
|
||||||
this.dataLimit += 100
|
|
||||||
sessionStorage.setItem('favoritesLimit', this.dataLimit)
|
|
||||||
},
|
|
||||||
filterPlaylist: function(query) {
|
|
||||||
this.hasQuery = query !== ''
|
|
||||||
this.$store.dispatch('searchFavoritePlaylist', query)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<ft-loader
|
<ft-loader
|
||||||
v-if="isLoading"
|
v-show="isLoading"
|
||||||
:fullscreen="true"
|
:fullscreen="true"
|
||||||
/>
|
/>
|
||||||
<ft-card
|
<ft-card
|
||||||
v-else
|
v-show="!isLoading"
|
||||||
class="card"
|
class="card"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3>
|
||||||
|
@ -21,21 +21,21 @@
|
||||||
:placeholder="$t('User Playlists.Search bar placeholder')"
|
:placeholder="$t('User Playlists.Search bar placeholder')"
|
||||||
:show-clear-text-button="true"
|
:show-clear-text-button="true"
|
||||||
:show-action-button="false"
|
:show-action-button="false"
|
||||||
@input="filterPlaylist"
|
@input="(input) => query = input"
|
||||||
/>
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length === 0"
|
v-show="activeData.length === 0"
|
||||||
>
|
>
|
||||||
<p class="message">
|
<p class="message">
|
||||||
{{ $t("User Playlists['Your saved videos are empty. Click on the save button on the corner of a video to have it listed here']") }}
|
{{ $t("User Playlists['Your saved videos are empty. Click on the save button on the corner of a video to have it listed here']") }}
|
||||||
</p>
|
</p>
|
||||||
</ft-flex-box>
|
</ft-flex-box>
|
||||||
<ft-element-list
|
<ft-element-list
|
||||||
v-else
|
v-if="activeData.length > 0 && !isLoading"
|
||||||
:data="activeData"
|
:data="activeData"
|
||||||
/>
|
/>
|
||||||
<ft-flex-box
|
<ft-flex-box
|
||||||
v-if="activeData.length < favoritesPlaylist.videos.length"
|
v-if="showLoadMoreButton"
|
||||||
>
|
>
|
||||||
<ft-button
|
<ft-button
|
||||||
label="Load More"
|
label="Load More"
|
||||||
|
|
|
@ -556,6 +556,7 @@ Video:
|
||||||
shuffling playlists: shuffling playlists
|
shuffling playlists: shuffling playlists
|
||||||
looping playlists: looping playlists
|
looping playlists: looping playlists
|
||||||
Stats:
|
Stats:
|
||||||
|
Video statistics are not available for legacy videos: Video statistics are not available for legacy videos
|
||||||
Video ID: Video ID
|
Video ID: Video ID
|
||||||
Resolution: Resolution
|
Resolution: Resolution
|
||||||
Player Dimensions: Player Dimensions
|
Player Dimensions: Player Dimensions
|
||||||
|
|
Loading…
Reference in New Issue