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
This commit is contained in:
parent
d794137057
commit
58b9ce3080
|
@ -29,7 +29,7 @@ import { MetaService } from '@ngx-meta/core'
|
||||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||||
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
|
||||||
import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
|
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 {
|
import {
|
||||||
CustomizationOptions,
|
CustomizationOptions,
|
||||||
P2PMediaLoaderOptions,
|
P2PMediaLoaderOptions,
|
||||||
|
@ -195,6 +195,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.theaterEnabled = getStoredTheater()
|
this.theaterEnabled = getStoredTheater()
|
||||||
|
|
||||||
this.hooks.runAction('action:video-watch.init', 'video-watch')
|
this.hooks.runAction('action:video-watch.init', 'video-watch')
|
||||||
|
|
||||||
|
setTimeout(cleanupVideoWatch, 1500) // Run in timeout to ensure we're not blocking the UI
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy () {
|
ngOnDestroy () {
|
||||||
|
@ -768,9 +770,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
const getStartTime = () => {
|
const getStartTime = () => {
|
||||||
const byUrl = urlOptions.startTime !== undefined
|
const byUrl = urlOptions.startTime !== undefined
|
||||||
const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined)
|
const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined)
|
||||||
|
const byLocalStorage = getStoredVideoWatchHistory(video.uuid)
|
||||||
|
|
||||||
if (byUrl) return timeToInt(urlOptions.startTime)
|
if (byUrl) return timeToInt(urlOptions.startTime)
|
||||||
if (byHistory) return video.userHistory.currentTime
|
if (byHistory) return video.userHistory.currentTime
|
||||||
|
if (byLocalStorage) return byLocalStorage.duration
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -828,7 +832,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
serverUrl: environment.apiUrl,
|
serverUrl: environment.apiUrl,
|
||||||
|
|
||||||
videoCaptions: playerCaptions
|
videoCaptions: playerCaptions,
|
||||||
|
|
||||||
|
videoUUID: video.uuid
|
||||||
},
|
},
|
||||||
|
|
||||||
webtorrent: {
|
webtorrent: {
|
||||||
|
|
|
@ -68,6 +68,51 @@ function getStoredLastSubtitle () {
|
||||||
return getLocalStorage('last-subtitle')
|
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 {
|
export {
|
||||||
|
@ -81,7 +126,10 @@ export {
|
||||||
saveAverageBandwidth,
|
saveAverageBandwidth,
|
||||||
getAverageBandwidthInStore,
|
getAverageBandwidthInStore,
|
||||||
saveLastSubtitle,
|
saveLastSubtitle,
|
||||||
getStoredLastSubtitle
|
getStoredLastSubtitle,
|
||||||
|
saveVideoWatchHistory,
|
||||||
|
getStoredVideoWatchHistory,
|
||||||
|
cleanupVideoWatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -106,6 +106,8 @@ export interface CommonOptions extends CustomizationOptions {
|
||||||
|
|
||||||
videoCaptions: VideoJSCaption[]
|
videoCaptions: VideoJSCaption[]
|
||||||
|
|
||||||
|
videoUUID: string
|
||||||
|
|
||||||
userWatching?: UserWatching
|
userWatching?: UserWatching
|
||||||
|
|
||||||
serverUrl: string
|
serverUrl: string
|
||||||
|
@ -231,7 +233,8 @@ export class PeertubePlayerManager {
|
||||||
subtitle: commonOptions.subtitle,
|
subtitle: commonOptions.subtitle,
|
||||||
videoCaptions: commonOptions.videoCaptions,
|
videoCaptions: commonOptions.videoCaptions,
|
||||||
stopTime: commonOptions.stopTime,
|
stopTime: commonOptions.stopTime,
|
||||||
isLive: commonOptions.isLive
|
isLive: commonOptions.isLive,
|
||||||
|
videoUUID: commonOptions.videoUUID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
getStoredVolume,
|
getStoredVolume,
|
||||||
saveLastSubtitle,
|
saveLastSubtitle,
|
||||||
saveMuteInStore,
|
saveMuteInStore,
|
||||||
|
saveVideoWatchHistory,
|
||||||
saveVolumeInStore
|
saveVolumeInStore
|
||||||
} from './peertube-player-local-storage'
|
} from './peertube-player-local-storage'
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.initializePlayer()
|
this.initializePlayer()
|
||||||
this.runViewAdd()
|
this.runViewAdd()
|
||||||
|
|
||||||
if (options.userWatching) this.runUserWatchVideo(options.userWatching)
|
this.runUserWatchVideo(options.userWatching, options.videoUUID)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +179,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
private runUserWatchVideo (options: UserWatching) {
|
private runUserWatchVideo (options: UserWatching, videoUUID: string) {
|
||||||
let lastCurrentTime = 0
|
let lastCurrentTime = 0
|
||||||
|
|
||||||
this.userWatchingVideoInterval = setInterval(() => {
|
this.userWatchingVideoInterval = setInterval(() => {
|
||||||
|
@ -187,8 +188,12 @@ class PeerTubePlugin extends Plugin {
|
||||||
if (currentTime - lastCurrentTime >= 1) {
|
if (currentTime - lastCurrentTime >= 1) {
|
||||||
lastCurrentTime = currentTime
|
lastCurrentTime = currentTime
|
||||||
|
|
||||||
this.notifyUserIsWatching(currentTime, options.url, options.authorizationHeader)
|
if (options) {
|
||||||
.catch(err => console.error('Cannot notify user is watching.', err))
|
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)
|
}, this.CONSTANTS.USER_WATCHING_VIDEO_INTERVAL)
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,8 @@ type PeerTubePluginOptions = {
|
||||||
stopTime: number | string
|
stopTime: number | string
|
||||||
|
|
||||||
isLive: boolean
|
isLive: boolean
|
||||||
|
|
||||||
|
videoUUID: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlaylistPluginOptions = {
|
type PlaylistPluginOptions = {
|
||||||
|
|
|
@ -531,6 +531,7 @@ export class PeerTubeEmbed {
|
||||||
videoCaptions,
|
videoCaptions,
|
||||||
inactivityTimeout: 2500,
|
inactivityTimeout: 2500,
|
||||||
videoViewUrl: this.getVideoUrl(videoInfo.uuid) + '/views',
|
videoViewUrl: this.getVideoUrl(videoInfo.uuid) + '/views',
|
||||||
|
videoUUID: videoInfo.uuid,
|
||||||
|
|
||||||
isLive: videoInfo.isLive,
|
isLive: videoInfo.isLive,
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue