diff --git a/src/components/ExpandableDate.vue b/src/components/ExpandableDate.vue new file mode 100644 index 0000000..c03442e --- /dev/null +++ b/src/components/ExpandableDate.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/components/VideoItem.vue b/src/components/VideoItem.vue index b4286b2..40e94b3 100644 --- a/src/components/VideoItem.vue +++ b/src/components/VideoItem.vue @@ -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 } } }, diff --git a/src/routes/WatchHistory.vue b/src/routes/WatchHistory.vue index 973d5db..9f81314 100644 --- a/src/routes/WatchHistory.vue +++ b/src/routes/WatchHistory.vue @@ -8,15 +8,11 @@ - - - - {{ doc.formattedDate }} -
+ + + Watched + +
@@ -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 }, diff --git a/src/routes/WatchVideo.vue b/src/routes/WatchVideo.vue index bd8a7cd..2a6329a 100644 --- a/src/routes/WatchVideo.vue +++ b/src/routes/WatchVideo.vue @@ -5,7 +5,7 @@ + + • + Last watched till {{ lastWatchDurationH }} + + mdi-thumb-up {{ addCommas(video.likes) }} mdi-thumb-down {{ addCommas(video.dislikes) }} - + mdi-youtube @@ -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', '
') ) - 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, diff --git a/src/store/prefs-store.js b/src/store/prefs-store.js index b1b6589..754c7f0 100644 --- a/src/store/prefs-store.js +++ b/src/store/prefs-store.js @@ -10,7 +10,8 @@ const PrefsStore = { listen: false, disableLBRY: false, proxyLBRY: true, - sponsorblock: true + sponsorblock: true, + skipToLastPoint: true } }), mutations: { diff --git a/src/tools/libpiped.js b/src/tools/libpiped.js index 1e199f2..88d27d9 100644 --- a/src/tools/libpiped.js +++ b/src/tools/libpiped.js @@ -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 }