Show when and how much you last saw the video + Skip to that time

This commit is contained in:
root
2021-11-16 20:55:40 +05:30
parent be09b8030e
commit d65f77eec3
6 changed files with 100 additions and 39 deletions
+28
View File
@@ -0,0 +1,28 @@
<template>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<span v-bind="attrs" v-on="on">
<slot /> {{ timeAgo }}
</span>
</template>
<span>{{ formattedDate }}</span>
</v-tooltip>
</template>
<script>
import { LibPiped } from '@/tools/libpiped'
export default {
name: 'ExpandableDate',
props: ['date'],
computed: {
timeAgo () {
return LibPiped.timeAgo(this.date)
},
formattedDate () {
return LibPiped.formatFullDate(this.date)
}
}
}
</script>
+16 -3
View File
@@ -32,7 +32,8 @@ export default {
height: Number,
width: Number,
hideChannel: Boolean,
maxHeight: Boolean
maxHeight: Boolean,
srcProgress: Number
},
data: () => ({
alreadyWatched: false,
@@ -43,11 +44,23 @@ export default {
},
watch: {
'video.videoId': 'findIfVideoWatched',
'video.url': 'findIfVideoWatched'
'video.url': 'findIfVideoWatched',
srcProgress: 'findIfVideoWatched'
},
methods: {
calcProgress (prog, dur) {
return Math.min((prog / dur) * 100, 100)
},
async findIfVideoWatched () {
// if it has source progress, it's already seen
if (this.srcProgress) {
this.alreadyWatched = true
this.progress = this.calcProgress(this.srcProgress, this.video.duration)
return
}
let videoId
if (this.video.videoId) {
videoId = this.video.videoId
@@ -59,7 +72,7 @@ export default {
const lastVideo = await findLastWatch(videoId)
if (lastVideo != null) {
this.alreadyWatched = true
this.progress = lastVideo.progress != null ? Math.min((lastVideo.progress / lastVideo.video.duration) * 100, 100) : 100
this.progress = lastVideo.progress != null ? this.calcProgress(lastVideo.progress, lastVideo.video.duration) : 100
}
}
},
+8 -15
View File
@@ -8,15 +8,11 @@
</v-row>
<v-row v-for="(chunk, chunkId) in chunkedByFour" :key="chunkId">
<v-col md="3" v-for="doc in chunk" :key="doc._id">
<VideoItem :video="doc.video">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<span v-bind="attrs" v-on="on">
Watched {{ doc.timeAgo }}
</span>
</template>
<span>{{ doc.formattedDate }}</span>
</v-tooltip><br />
<VideoItem :video="doc.video" :src-progress="doc.progress">
<ExpandableDate :date="doc.timestamp">
Watched
</ExpandableDate>
<br />
</VideoItem>
</v-col>
</v-row>
@@ -27,11 +23,12 @@
import _chunk from 'lodash-es/chunk'
import { deleteWatchedVideos, getWatchedVideos } from '@/store/watched-videos-db'
import { LibPiped } from '@/tools/libpiped'
import VideoItem from '@/components/VideoItem'
import ExpandableDate from '@/components/ExpandableDate'
export default {
components: {
ExpandableDate,
VideoItem
},
data: () => ({
@@ -47,11 +44,7 @@ export default {
methods: {
async loadData () {
this.data = (await getWatchedVideos()).map(doc => {
doc.timeAgo = LibPiped.timeAgo(doc.timestamp)
doc.formattedDate = LibPiped.formatFullDate(doc.timestamp)
return doc
})
this.data = await getWatchedVideos()
this.loaded = true
},
+41 -15
View File
@@ -5,7 +5,7 @@
<Player
ref="player"
:video="video"
:skip-to-time="'t' in $route.query ? Number($route.query.t) : null"
:skip-to-time="skipToTime"
:sponsors="sponsors"
:selectedAutoLoop="selectedAutoLoop"
@videoEnded="videoEnded"
@@ -22,13 +22,19 @@
{{ $tc('counts.views', video.views, { n: addCommas(video.views) }) }}
•
{{ video.uploadDate }}
<!-- TODO make translatable -->
<span v-if="lastWatch">
•
Last watched till {{ lastWatchDurationH }}
<ExpandableDate :date="lastWatch.timestamp" />
</span>
</v-col>
<v-col offset-md="5" md="3" align-self="end">
<v-icon>mdi-thumb-up</v-icon>
<b class="ml-2">{{ addCommas(video.likes) }}</b>
<v-icon class="ml-2">mdi-thumb-down</v-icon>
<b class="ml-2">{{ addCommas(video.dislikes) }}</b>
<v-btn icon class="ml-2" link :href="'https://youtu.be/' + getVideoId()" @click.prevent="onYTClick" target="_blank">
<v-btn icon class="ml-2" link :href="'https://youtu.be/' + videoId" @click.prevent="onYTClick" target="_blank">
<v-icon large>
mdi-youtube
</v-icon>
@@ -94,8 +100,9 @@ import Player from '@/components/Player.vue'
import VideoItem from '@/components/VideoItem.vue'
import ErrorHandler from '@/components/ErrorHandler.vue'
import VideoComment from '@/components/VideoComment'
import { addWatchedVideo, updateWatchedVideoProgress } from '@/store/watched-videos-db'
import { addWatchedVideo, updateWatchedVideoProgress, findLastWatch } from '@/store/watched-videos-db'
import SubscriptionButton from '@/components/SubscriptionButton'
import ExpandableDate from '@/components/ExpandableDate'
export default {
name: 'WatchVideo',
@@ -111,7 +118,8 @@ export default {
comments: null,
channelId: null,
dbID: null
dbID: null,
lastWatch: null
}
},
metaInfo () {
@@ -187,7 +195,7 @@ export default {
const time = this.$refs.player.getCurrentTime()
const url = new URL('https://youtube.com/watch')
url.searchParams.set('v', this.getVideoId())
url.searchParams.set('v', this.videoId)
if (Number.isFinite(time)) {
url.searchParams.set('t', time.toFixed(0))
}
@@ -205,7 +213,7 @@ export default {
fetchVideo () {
return this.$store.dispatch('auth/makeRequest', {
method: 'GET',
path: '/streams/' + this.getVideoId()
path: '/streams/' + this.videoId
})
},
@@ -214,7 +222,7 @@ export default {
return
}
this.sponsors = await this.$store.dispatch('auth/makeRequest', {
path: '/sponsors/' + this.getVideoId(),
path: '/sponsors/' + this.videoId,
params: {
category: JSON.stringify(this.$store.getters['prefs/getPreference']('selectedSkip', ['sponsor', 'interaction', 'selfpromo', 'music_offtopic']))
}
@@ -222,7 +230,7 @@ export default {
},
fetchComments () {
return this.$store.dispatch('auth/makeRequest', {
path: '/comments/' + this.getVideoId()
path: '/comments/' + this.videoId
})
},
@@ -234,7 +242,7 @@ export default {
fetchMoreComments () {
this.$store.dispatch('auth/makeRequest', {
path: '/nextpage/comments/' + this.getVideoId(),
path: '/nextpage/comments/' + this.videoId,
params: {
nextpage: this.comments.nextpage
}
@@ -252,8 +260,10 @@ export default {
},
async getVideoData () {
this.lastWatch = await findLastWatch(this.videoId)
const video = await this.fetchVideo()
video.videoId = this.getVideoId()
video.videoId = this.videoId
video.url = this.$route.fullPath
this.video = video
this.loaded = true
@@ -269,16 +279,12 @@ export default {
.replaceAll('https://www.youtube.com', '')
.replaceAll('\n', '<br>')
)
this.dbID = await addWatchedVideo(this.video)
this.dbID = await addWatchedVideo(video)
},
getComments () {
this.fetchComments().then(data => (this.comments = data))
},
getVideoId () {
return this.$route.query.v || this.$route.params.v
},
onTimeUpdate: debounce(function onTimeUpdate (e) {
if (this.dbID == null || !this.$refs.player) {
return
@@ -289,9 +295,29 @@ export default {
computed: {
isAutoplayEnabled () {
return this.$store.getters['prefs/getPreferenceBoolean']('autoplay', false)
},
videoId () {
return this.$route.query.v || this.$route.params.v
},
skipToTime () {
// 't' in $route.query ? Number($route.query.t) : (lastWatch.progress ? lastWatch.progress : undefined)
// 1st Priority - t in query
// 2nd Priority - Last Watched Progress, if enabled
if ('t' in this.$route.query) {
return Number(this.$route.query.t)
} else if (this.lastWatch && this.lastWatch.progress != null && this.lastWatch.progress !== 0 && this.$store.getters['prefs/getPreferenceBoolean']('skipToLastPoint', true)) {
return this.lastWatch.progress
} else {
return undefined
}
},
lastWatchDurationH () {
return LibPiped.timeFormat(this.lastWatch.progress)
}
},
components: {
ExpandableDate,
SubscriptionButton,
VideoComment,
Player,
+2 -1
View File
@@ -10,7 +10,8 @@ const PrefsStore = {
listen: false,
disableLBRY: false,
proxyLBRY: true,
sponsorblock: true
sponsorblock: true,
skipToLastPoint: true
}
}),
mutations: {
+5 -5
View File
@@ -12,11 +12,11 @@ class LibPiped {
timeStyle: 'full'
})
timeFormat (duration) {
const pad = function (num, size) {
return ('000' + num).slice(size * -1)
}
pad (num, size) {
return ('000' + num).slice(size * -1)
}
timeFormat (duration) {
const time = parseFloat(duration).toFixed(3)
const hours = Math.floor(time / 60 / 60)
const minutes = Math.floor(time / 60) % 60
@@ -26,7 +26,7 @@ class LibPiped {
if (hours > 0) str += hours + ':'
str += pad(minutes, 2) + ':' + pad(seconds, 2)
str += this.pad(minutes, 2) + ':' + this.pad(seconds, 2)
return str
}