From 58b9ce3080c12678e8c1c28c08da09d6ea60011d Mon Sep 17 00:00:00 2001 From: kontrollanten <6680299+kontrollanten@users.noreply.github.com> Date: Wed, 31 Mar 2021 11:26:32 +0200 Subject: [PATCH] Resume videos for non-logged in users (#3885) * client: resume videos for non-logged in users closes #3866 * fix build for embeded * Update client/src/app/app.component.ts * fix review comments --- .../+video-watch/video-watch.component.ts | 10 +++- .../player/peertube-player-local-storage.ts | 50 ++++++++++++++++++- .../assets/player/peertube-player-manager.ts | 5 +- client/src/assets/player/peertube-plugin.ts | 13 +++-- .../assets/player/peertube-videojs-typings.ts | 2 + client/src/standalone/videos/embed.ts | 1 + 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts index 571d1e99a..075f70f56 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts @@ -29,7 +29,7 @@ import { MetaService } from '@ngx-meta/core' import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' -import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage' +import { cleanupVideoWatch, getStoredP2PEnabled, getStoredTheater, getStoredVideoWatchHistory } from '../../../assets/player/peertube-player-local-storage' import { CustomizationOptions, P2PMediaLoaderOptions, @@ -195,6 +195,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.theaterEnabled = getStoredTheater() this.hooks.runAction('action:video-watch.init', 'video-watch') + + setTimeout(cleanupVideoWatch, 1500) // Run in timeout to ensure we're not blocking the UI } ngOnDestroy () { @@ -768,9 +770,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { const getStartTime = () => { const byUrl = urlOptions.startTime !== undefined const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined) + const byLocalStorage = getStoredVideoWatchHistory(video.uuid) if (byUrl) return timeToInt(urlOptions.startTime) if (byHistory) return video.userHistory.currentTime + if (byLocalStorage) return byLocalStorage.duration return 0 } @@ -828,7 +832,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { serverUrl: environment.apiUrl, - videoCaptions: playerCaptions + videoCaptions: playerCaptions, + + videoUUID: video.uuid }, webtorrent: { diff --git a/client/src/assets/player/peertube-player-local-storage.ts b/client/src/assets/player/peertube-player-local-storage.ts index 75ccfe618..cf2cfb472 100644 --- a/client/src/assets/player/peertube-player-local-storage.ts +++ b/client/src/assets/player/peertube-player-local-storage.ts @@ -68,6 +68,51 @@ function getStoredLastSubtitle () { return getLocalStorage('last-subtitle') } +function saveVideoWatchHistory(videoUUID: string, duration: number) { + return setLocalStorage(`video-watch-history`, JSON.stringify({ + ...getStoredVideoWatchHistory(), + [videoUUID]: { + duration, + date: `${(new Date()).toISOString()}` + } + })) +} + +function getStoredVideoWatchHistory(videoUUID?: string) { + let data + + try { + data = JSON.parse(getLocalStorage('video-watch-history')) + } catch (error) { + console.error('Cannot parse video watch history from local storage: ', error) + } + + data = data || {} + + if (videoUUID) return data[videoUUID] + + return data +} + +function cleanupVideoWatch() { + const data = getStoredVideoWatchHistory() + + const newData = Object.keys(data).reduce((acc, videoUUID) => { + const date = Date.parse(data[videoUUID].date) + + const diff = Math.ceil(((new Date()).getTime() - date) / (1000 * 3600 * 24)) + + if (diff > 30) return acc + + return { + ...acc, + [videoUUID]: data[videoUUID] + } + }, {}) + + setLocalStorage('video-watch-history', JSON.stringify(newData)) +} + // --------------------------------------------------------------------------- export { @@ -81,7 +126,10 @@ export { saveAverageBandwidth, getAverageBandwidthInStore, saveLastSubtitle, - getStoredLastSubtitle + getStoredLastSubtitle, + saveVideoWatchHistory, + getStoredVideoWatchHistory, + cleanupVideoWatch } // --------------------------------------------------------------------------- diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 1d335805b..119dec379 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -106,6 +106,8 @@ export interface CommonOptions extends CustomizationOptions { videoCaptions: VideoJSCaption[] + videoUUID: string + userWatching?: UserWatching serverUrl: string @@ -231,7 +233,8 @@ export class PeertubePlayerManager { subtitle: commonOptions.subtitle, videoCaptions: commonOptions.videoCaptions, stopTime: commonOptions.stopTime, - isLive: commonOptions.isLive + isLive: commonOptions.isLive, + videoUUID: commonOptions.videoUUID } } diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index 75a6e662e..07c7e33f6 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts @@ -13,6 +13,7 @@ import { getStoredVolume, saveLastSubtitle, saveMuteInStore, + saveVideoWatchHistory, saveVolumeInStore } from './peertube-player-local-storage' @@ -120,7 +121,7 @@ class PeerTubePlugin extends Plugin { this.initializePlayer() this.runViewAdd() - if (options.userWatching) this.runUserWatchVideo(options.userWatching) + this.runUserWatchVideo(options.userWatching, options.videoUUID) }) } @@ -178,7 +179,7 @@ class PeerTubePlugin extends Plugin { }, 1000) } - private runUserWatchVideo (options: UserWatching) { + private runUserWatchVideo (options: UserWatching, videoUUID: string) { let lastCurrentTime = 0 this.userWatchingVideoInterval = setInterval(() => { @@ -187,8 +188,12 @@ class PeerTubePlugin extends Plugin { if (currentTime - lastCurrentTime >= 1) { lastCurrentTime = currentTime - this.notifyUserIsWatching(currentTime, options.url, options.authorizationHeader) - .catch(err => console.error('Cannot notify user is watching.', err)) + if (options) { + this.notifyUserIsWatching(currentTime, options.url, options.authorizationHeader) + .catch(err => console.error('Cannot notify user is watching.', err)) + } else { + saveVideoWatchHistory(videoUUID, currentTime) + } } }, this.CONSTANTS.USER_WATCHING_VIDEO_INTERVAL) } diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index e5259092c..4a6c80247 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts @@ -108,6 +108,8 @@ type PeerTubePluginOptions = { stopTime: number | string isLive: boolean + + videoUUID: string } type PlaylistPluginOptions = { diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 614a1cc0b..ae8f176b7 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -531,6 +531,7 @@ export class PeerTubeEmbed { videoCaptions, inactivityTimeout: 2500, videoViewUrl: this.getVideoUrl(videoInfo.uuid) + '/views', + videoUUID: videoInfo.uuid, isLive: videoInfo.isLive,