Skip to content

Commit 351fdb9

Browse files
absiduePikachuEXE
andauthored
Playlist performance improvements (#4597)
* Implement pagination for user playlists on the Playlist page * Fix the load more loading icon being displayed off-screen * Caching user playlists is unnecessary as they are already in the store * ft-list-video: Only render description element if there is a description * Minor speed ups in the playlists store * ft-list-video: Remove superfluous template around view count * ft-list-video: Replace watched property with historyEntryExists computed property * playlist-info: Fix copying partially loaded user playlists * Fix the playlist number not getting lazy loaded * Reduce nesting levels Co-authored-by: PikachuEXE <[email protected]> --------- Co-authored-by: PikachuEXE <[email protected]>
1 parent 5a6d4d5 commit 351fdb9

13 files changed

+306
-117
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
Set a height to invisible/unloaded elements, so that lazy loading actually works.
3+
If we don't set a height, they all get a height of 0px (because they have no content),
4+
so they all bunch up together and end up loading all of them in one go.
5+
*/
6+
.placeholder {
7+
block-size: 40px;
8+
}
9+
10+
.videoIndex {
11+
color: var(--tertiary-text-color);
12+
text-align: center;
13+
}
14+
15+
.videoIndexIcon {
16+
font-size: 14px;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { defineComponent } from 'vue'
2+
import FtListVideo from '../ft-list-video/ft-list-video.vue'
3+
4+
export default defineComponent({
5+
name: 'FtListVideoNumbered',
6+
components: {
7+
'ft-list-video': FtListVideo
8+
},
9+
props: {
10+
data: {
11+
type: Object,
12+
required: true
13+
},
14+
playlistId: {
15+
type: String,
16+
default: null
17+
},
18+
playlistType: {
19+
type: String,
20+
default: null
21+
},
22+
playlistIndex: {
23+
type: Number,
24+
default: null
25+
},
26+
playlistReverse: {
27+
type: Boolean,
28+
default: false
29+
},
30+
playlistShuffle: {
31+
type: Boolean,
32+
default: false
33+
},
34+
playlistLoop: {
35+
type: Boolean,
36+
default: false
37+
},
38+
playlistItemId: {
39+
type: String,
40+
default: null,
41+
},
42+
appearance: {
43+
type: String,
44+
required: true
45+
},
46+
initialVisibleState: {
47+
type: Boolean,
48+
default: false,
49+
},
50+
alwaysShowAddToPlaylistButton: {
51+
type: Boolean,
52+
default: false,
53+
},
54+
quickBookmarkButtonEnabled: {
55+
type: Boolean,
56+
default: true,
57+
},
58+
canMoveVideoUp: {
59+
type: Boolean,
60+
default: false,
61+
},
62+
canMoveVideoDown: {
63+
type: Boolean,
64+
default: false,
65+
},
66+
canRemoveFromPlaylist: {
67+
type: Boolean,
68+
default: false,
69+
},
70+
videoIndex: {
71+
type: Number,
72+
default: -1
73+
},
74+
isCurrentVideo: {
75+
type: Boolean,
76+
default: false
77+
},
78+
useChannelsHiddenPreference: {
79+
type: Boolean,
80+
default: false,
81+
}
82+
},
83+
data: function () {
84+
return {
85+
visible: false,
86+
show: true
87+
}
88+
},
89+
computed: {
90+
channelsHidden() {
91+
// Some component users like channel view will have this disabled
92+
if (!this.useChannelsHiddenPreference) { return [] }
93+
94+
return JSON.parse(this.$store.getters.getChannelsHidden).map((ch) => {
95+
// Legacy support
96+
if (typeof ch === 'string') {
97+
return { name: ch, preferredName: '', icon: '' }
98+
}
99+
return ch
100+
})
101+
},
102+
103+
// As we only use this component in Playlist and watch-video-playlist,
104+
// where title filtering is never desired, we don't have any title filtering logic here,
105+
// like we do in ft-list-video-lazy
106+
107+
shouldBeVisible() {
108+
return !(this.channelsHidden.some(ch => ch.name === this.data.authorId) ||
109+
this.channelsHidden.some(ch => ch.name === this.data.author))
110+
}
111+
},
112+
created() {
113+
this.visible = this.initialVisibleState
114+
},
115+
methods: {
116+
onVisibilityChanged: function (visible) {
117+
if (visible && this.shouldBeVisible) {
118+
this.visible = visible
119+
} else if (visible) {
120+
this.show = false
121+
}
122+
}
123+
}
124+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<template>
2+
<div
3+
v-show="show"
4+
v-observe-visibility="!initialVisibleState ? {
5+
callback: onVisibilityChanged,
6+
once: true,
7+
} : null"
8+
:class="{ placeholder: !visible }"
9+
>
10+
<template
11+
v-if="visible"
12+
>
13+
<p
14+
class="videoIndex"
15+
>
16+
<font-awesome-icon
17+
v-if="isCurrentVideo"
18+
class="videoIndexIcon"
19+
:icon="['fas', 'play']"
20+
/>
21+
<template
22+
v-else
23+
>
24+
{{ videoIndex + 1 }}
25+
</template>
26+
</p>
27+
<ft-list-video
28+
:data="data"
29+
:playlist-id="playlistId"
30+
:playlist-type="playlistType"
31+
:playlist-index="playlistIndex"
32+
:playlist-reverse="playlistReverse"
33+
:playlist-shuffle="playlistShuffle"
34+
:playlist-loop="playlistLoop"
35+
:playlist-item-id="playlistItemId"
36+
force-list-type="list"
37+
:appearance="appearance"
38+
:always-show-add-to-playlist-button="alwaysShowAddToPlaylistButton"
39+
:quick-bookmark-button-enabled="quickBookmarkButtonEnabled"
40+
:can-move-video-up="canMoveVideoUp"
41+
:can-move-video-down="canMoveVideoDown"
42+
:can-remove-from-playlist="canRemoveFromPlaylist"
43+
@pause-player="$emit('pause-player')"
44+
@move-video-up="$emit('move-video-up')"
45+
@move-video-down="$emit('move-video-down')"
46+
@remove-from-playlist="$emit('remove-from-playlist')"
47+
/>
48+
</template>
49+
</div>
50+
</template>
51+
52+
<script src="./ft-list-video-numbered.js" />
53+
<style scoped src="./ft-list-video-numbered.css" />

src/renderer/components/ft-list-video/ft-list-video.js

+4-11
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ export default defineComponent({
9797
lengthSeconds: 0,
9898
duration: '',
9999
description: '',
100-
watched: false,
101100
watchProgress: 0,
102101
publishedText: '',
103102
isLive: false,
@@ -223,7 +222,7 @@ export default defineComponent({
223222
dropdownOptions: function () {
224223
const options = [
225224
{
226-
label: this.watched
225+
label: this.historyEntryExists
227226
? this.$t('Video.Remove From History')
228227
: this.$t('Video.Mark As Watched'),
229228
value: 'history'
@@ -343,7 +342,7 @@ export default defineComponent({
343342
},
344343

345344
addWatchedStyle: function () {
346-
return this.watched && !this.inHistory
345+
return this.historyEntryExists && !this.inHistory
347346
},
348347

349348
externalPlayer: function () {
@@ -576,15 +575,15 @@ export default defineComponent({
576575
}
577576
this.openInExternalPlayer(payload)
578577

579-
if (this.saveWatchedProgress && !this.watched) {
578+
if (this.saveWatchedProgress && !this.historyEntryExists) {
580579
this.markAsWatched()
581580
}
582581
},
583582

584583
handleOptionsClick: function (option) {
585584
switch (option) {
586585
case 'history':
587-
if (this.watched) {
586+
if (this.historyEntryExists) {
588587
this.removeFromWatched()
589588
} else {
590589
this.markAsWatched()
@@ -727,8 +726,6 @@ export default defineComponent({
727726

728727
checkIfWatched: function () {
729728
if (this.historyEntryExists) {
730-
this.watched = true
731-
732729
const historyEntry = this.historyEntry
733730

734731
if (this.saveWatchedProgress) {
@@ -744,7 +741,6 @@ export default defineComponent({
744741
this.publishedText = ''
745742
}
746743
} else {
747-
this.watched = false
748744
this.watchProgress = 0
749745
}
750746
},
@@ -766,16 +762,13 @@ export default defineComponent({
766762
}
767763
this.updateHistory(videoData)
768764
showToast(this.$t('Video.Video has been marked as watched'))
769-
770-
this.watched = true
771765
},
772766

773767
removeFromWatched: function () {
774768
this.removeFromHistory(this.id)
775769

776770
showToast(this.$t('Video.Video has been removed from your history'))
777771

778-
this.watched = false
779772
this.watchProgress = 0
780773
},
781774

src/renderer/components/ft-list-video/ft-list-video.vue

+9-8
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
{{ $t("Video.Watched") }}
105105
</div>
106106
<div
107-
v-if="watched"
107+
v-if="historyEntryExists"
108108
class="watchedProgressBar"
109109
:style="{inlineSize: progressPercentage + '%'}"
110110
/>
@@ -129,12 +129,13 @@
129129
<span v-else-if="channelName !== null">
130130
{{ channelName }}
131131
</span>
132-
<template v-if="!isLive && !isUpcoming && !isPremium && !hideViews && viewCount != null">
133-
<span class="viewCount">
134-
<template v-if="channelId !== null"> • </template>
135-
{{ $tc('Global.Counts.View Count', viewCount, {count: parsedViewCount}) }}
136-
</span>
137-
</template>
132+
<span
133+
v-if="!isLive && !isUpcoming && !isPremium && !hideViews && viewCount != null"
134+
class="viewCount"
135+
>
136+
<template v-if="channelId !== null || channelName !== null"> • </template>
137+
{{ $tc('Global.Counts.View Count', viewCount, {count: parsedViewCount}) }}
138+
</span>
138139
<span
139140
v-if="uploadedTime !== '' && !isLive && !inHistory"
140141
class="uploadedTime"
@@ -160,7 +161,7 @@
160161
@click="handleOptionsClick"
161162
/>
162163
<p
163-
v-if="((listType === 'list' || forceListType === 'list') && forceListType !== 'grid') &&
164+
v-if="description && ((listType === 'list' || forceListType === 'list') && forceListType !== 'grid') &&
164165
appearance === 'result'"
165166
class="description"
166167
v-html="description"

src/renderer/components/playlist-info/playlist-info.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ export default defineComponent({
235235
},
236236
methods: {
237237
toggleCopyVideosPrompt: function (force = false) {
238-
if (this.moreVideoDataAvailable && !force) {
238+
if (this.moreVideoDataAvailable && !this.isUserPlaylist && !force) {
239239
showToast(this.$t('User Playlists.SinglePlaylistView.Toast["Some videos in the playlist are not loaded yet. Click here to copy anyway."]'), 5000, () => {
240240
this.toggleCopyVideosPrompt(true)
241241
})

src/renderer/components/watch-video-playlist/watch-video-playlist.css

-13
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,6 @@
8585
transition: background 0.2s ease-in;
8686
}
8787

88-
.videoIndexContainer {
89-
text-align: center;
90-
}
91-
92-
.videoIndex {
93-
color: var(--tertiary-text-color);
94-
}
95-
96-
.videoIndexIcon {
97-
font-size: 14px;
98-
color: var(--tertiary-text-color);
99-
}
100-
10188
.videoInfo {
10289
margin-inline-start: 30px;
10390
position: relative;

src/renderer/components/watch-video-playlist/watch-video-playlist.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { defineComponent, nextTick } from 'vue'
22
import { mapMutations } from 'vuex'
33
import FtLoader from '../ft-loader/ft-loader.vue'
44
import FtCard from '../ft-card/ft-card.vue'
5-
import FtListVideoLazy from '../ft-list-video-lazy/ft-list-video-lazy.vue'
5+
import FtListVideoNumbered from '../ft-list-video-numbered/ft-list-video-numbered.vue'
66
import { copyToClipboard, showToast } from '../../helpers/utils'
77
import {
88
getLocalPlaylist,
@@ -16,7 +16,7 @@ export default defineComponent({
1616
components: {
1717
'ft-loader': FtLoader,
1818
'ft-card': FtCard,
19-
'ft-list-video-lazy': FtListVideoLazy,
19+
'ft-list-video-numbered': FtListVideoNumbered
2020
},
2121
props: {
2222
playlistId: {
@@ -473,14 +473,13 @@ export default defineComponent({
473473
parseUserPlaylist: function (playlist, { allowPlayingVideoRemoval = true } = {}) {
474474
this.playlistTitle = playlist.playlistName
475475
this.channelName = ''
476-
this.channelThumbnail = ''
477476
this.channelId = ''
478477

479478
if (this.playlistItems.length === 0 || allowPlayingVideoRemoval) {
480479
this.playlistItems = playlist.videos
481480
} else {
482481
// `this.currentVideo` relies on `playlistItems`
483-
const latestPlaylistContainsCurrentVideo = playlist.videos.find(v => v.playlistItemId === this.playlistItemId) != null
482+
const latestPlaylistContainsCurrentVideo = playlist.videos.some(v => v.playlistItemId === this.playlistItemId)
484483
// Only update list of videos if latest video list still contains currently playing video
485484
if (latestPlaylistContainsCurrentVideo) {
486485
this.playlistItems = playlist.videos
@@ -513,7 +512,7 @@ export default defineComponent({
513512
const currentVideoItem = (this.$refs.currentVideoItem || [])[0]
514513
if (container != null && currentVideoItem != null) {
515514
// Watch view can be ready sooner than this component
516-
container.scrollTop = currentVideoItem.offsetTop - container.offsetTop
515+
container.scrollTop = currentVideoItem.$el.offsetTop - container.offsetTop
517516
}
518517
},
519518

0 commit comments

Comments
 (0)