mirror of https://github.com/Chocobozzz/PeerTube
Add ability for admins to set default p2p policy
parent
c77fdc605b
commit
a9bfa85d2c
|
@ -0,0 +1,21 @@
|
||||||
|
import { getCheckbox } from '../utils'
|
||||||
|
|
||||||
|
export class AnonymousSettingsPage {
|
||||||
|
|
||||||
|
async openSettings () {
|
||||||
|
const link = await $$('.menu-link').filter(async i => {
|
||||||
|
return await i.getText() === 'My settings'
|
||||||
|
}).then(links => links[0])
|
||||||
|
|
||||||
|
await link.click()
|
||||||
|
|
||||||
|
await $('my-user-video-settings').waitForDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickOnP2PCheckbox () {
|
||||||
|
const p2p = getCheckbox('p2pEnabled')
|
||||||
|
await p2p.waitForClickable()
|
||||||
|
|
||||||
|
await p2p.click()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import { go } from '../utils'
|
import { getCheckbox, go } from '../utils'
|
||||||
|
|
||||||
export class MyAccountPage {
|
export class MyAccountPage {
|
||||||
|
|
||||||
|
@ -27,6 +27,21 @@ export class MyAccountPage {
|
||||||
await nsfw.scrollIntoView(false) // Avoid issues with fixed header on firefox
|
await nsfw.scrollIntoView(false) // Avoid issues with fixed header on firefox
|
||||||
await nsfw.selectByAttribute('value', newValue)
|
await nsfw.selectByAttribute('value', newValue)
|
||||||
|
|
||||||
|
await this.submitVideoSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickOnP2PCheckbox () {
|
||||||
|
const p2p = getCheckbox('p2pEnabled')
|
||||||
|
|
||||||
|
await p2p.waitForClickable()
|
||||||
|
await p2p.scrollIntoView(false) // Avoid issues with fixed header on firefox
|
||||||
|
|
||||||
|
await p2p.click()
|
||||||
|
|
||||||
|
await this.submitVideoSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async submitVideoSettings () {
|
||||||
const submit = $('my-user-video-settings input[type=submit]')
|
const submit = $('my-user-video-settings input[type=submit]')
|
||||||
await submit.scrollIntoView(false)
|
await submit.scrollIntoView(false)
|
||||||
await submit.click()
|
await submit.click()
|
|
@ -1,5 +1,5 @@
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { clickOnCheckbox } from '../utils'
|
import { getCheckbox, selectCustomSelect } from '../utils'
|
||||||
|
|
||||||
export class VideoUploadPage {
|
export class VideoUploadPage {
|
||||||
async navigateTo () {
|
async navigateTo () {
|
||||||
|
@ -32,7 +32,7 @@ export class VideoUploadPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
setAsNSFW () {
|
setAsNSFW () {
|
||||||
return clickOnCheckbox('nsfw')
|
return getCheckbox('nsfw').click()
|
||||||
}
|
}
|
||||||
|
|
||||||
async validSecondUploadStep (videoName: string) {
|
async validSecondUploadStep (videoName: string) {
|
||||||
|
@ -47,6 +47,10 @@ export class VideoUploadPage {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAsPublic () {
|
||||||
|
return selectCustomSelect('privacy', 'Public')
|
||||||
|
}
|
||||||
|
|
||||||
private getSecondStepSubmitButton () {
|
private getSecondStepSubmitButton () {
|
||||||
return $('.submit-container my-button')
|
return $('.submit-container my-button')
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,23 @@ export class VideoWatchPage {
|
||||||
return $('my-video-comment-add').isExisting()
|
return $('my-video-comment-add').isExisting()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isPrivacyWarningDisplayed () {
|
||||||
|
return $('my-privacy-concerns').isDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
async goOnAssociatedEmbed () {
|
async goOnAssociatedEmbed () {
|
||||||
let url = await browser.getUrl()
|
let url = await browser.getUrl()
|
||||||
url = url.replace('/w/', '/videos/embed/')
|
url = url.replace('/w/', '/videos/embed/')
|
||||||
url = url.replace(':3333', ':9001')
|
url = url.replace(':3333', ':9001')
|
||||||
|
|
||||||
return go(url)
|
await go(url)
|
||||||
|
await $('.vjs-big-play-button').waitForDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
|
async isEmbedWarningDisplayed () {
|
||||||
|
const text = await $('.vjs-dock-description').getText()
|
||||||
|
|
||||||
|
return !!text.trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
goOnP2PMediaLoaderEmbed () {
|
goOnP2PMediaLoaderEmbed () {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { LoginPage } from '../po/login.po'
|
import { LoginPage } from '../po/login.po'
|
||||||
import { MyAccountPage } from '../po/my-account'
|
import { MyAccountPage } from '../po/my-account.po'
|
||||||
import { PlayerPage } from '../po/player.po'
|
import { PlayerPage } from '../po/player.po'
|
||||||
import { VideoListPage } from '../po/video-list.po'
|
import { VideoListPage } from '../po/video-list.po'
|
||||||
import { VideoUpdatePage } from '../po/video-update.po'
|
import { VideoUpdatePage } from '../po/video-update.po'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { LoginPage } from '../po/login.po'
|
import { LoginPage } from '../po/login.po'
|
||||||
import { VideoUploadPage } from '../po/video-upload.po'
|
import { VideoUploadPage } from '../po/video-upload.po'
|
||||||
import { VideoWatchPage } from '../po/video-watch.po'
|
import { VideoWatchPage } from '../po/video-watch.po'
|
||||||
import { isMobileDevice, isSafari, waitServerUp } from '../utils'
|
import { go, isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||||
|
|
||||||
describe('Custom server defaults', () => {
|
describe('Custom server defaults', () => {
|
||||||
let videoUploadPage: VideoUploadPage
|
let videoUploadPage: VideoUploadPage
|
||||||
|
@ -10,9 +10,7 @@ describe('Custom server defaults', () => {
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
await waitServerUp()
|
await waitServerUp()
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
loginPage = new LoginPage()
|
loginPage = new LoginPage()
|
||||||
videoUploadPage = new VideoUploadPage()
|
videoUploadPage = new VideoUploadPage()
|
||||||
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
||||||
|
@ -20,18 +18,69 @@ describe('Custom server defaults', () => {
|
||||||
await browser.maximizeWindow()
|
await browser.maximizeWindow()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should upload a video with custom default values', async function () {
|
describe('Publish default values', function () {
|
||||||
await loginPage.loginAsRootUser()
|
before(async function () {
|
||||||
await videoUploadPage.navigateTo()
|
await loginPage.loginAsRootUser()
|
||||||
await videoUploadPage.uploadVideo()
|
})
|
||||||
await videoUploadPage.validSecondUploadStep('video')
|
|
||||||
|
|
||||||
await videoWatchPage.waitWatchVideoName('video')
|
it('Should upload a video with custom default values', async function () {
|
||||||
|
await videoUploadPage.navigateTo()
|
||||||
|
await videoUploadPage.uploadVideo()
|
||||||
|
await videoUploadPage.validSecondUploadStep('video')
|
||||||
|
|
||||||
expect(await videoWatchPage.getPrivacy()).toBe('Internal')
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
expect(await videoWatchPage.getLicence()).toBe('Attribution - Non Commercial')
|
|
||||||
expect(await videoWatchPage.isDownloadEnabled()).toBeFalsy()
|
expect(await videoWatchPage.getPrivacy()).toBe('Internal')
|
||||||
expect(await videoWatchPage.areCommentsEnabled()).toBeFalsy()
|
expect(await videoWatchPage.getLicence()).toBe('Attribution - Non Commercial')
|
||||||
|
expect(await videoWatchPage.isDownloadEnabled()).toBeFalsy()
|
||||||
|
expect(await videoWatchPage.areCommentsEnabled()).toBeFalsy()
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await loginPage.logout()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('P2P', function () {
|
||||||
|
let videoUrl: string
|
||||||
|
|
||||||
|
async function goOnVideoWatchPage () {
|
||||||
|
await go(videoUrl)
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkP2P (enabled: boolean) {
|
||||||
|
await goOnVideoWatchPage()
|
||||||
|
expect(await videoWatchPage.isPrivacyWarningDisplayed()).toEqual(enabled)
|
||||||
|
|
||||||
|
await videoWatchPage.goOnAssociatedEmbed()
|
||||||
|
expect(await videoWatchPage.isEmbedWarningDisplayed()).toEqual(enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await loginPage.loginAsRootUser()
|
||||||
|
await videoUploadPage.navigateTo()
|
||||||
|
await videoUploadPage.uploadVideo()
|
||||||
|
await videoUploadPage.setAsPublic()
|
||||||
|
await videoUploadPage.validSecondUploadStep('video')
|
||||||
|
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
|
||||||
|
videoUrl = await browser.getUrl()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
await goOnVideoWatchPage()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should have P2P disabled for a logged in user', async function () {
|
||||||
|
await checkP2P(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should have P2P disabled for anonymous users', async function () {
|
||||||
|
await loginPage.logout()
|
||||||
|
|
||||||
|
await checkP2P(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { AnonymousSettingsPage } from '../po/anonymous-settings.po'
|
||||||
|
import { LoginPage } from '../po/login.po'
|
||||||
|
import { MyAccountPage } from '../po/my-account.po'
|
||||||
|
import { VideoUploadPage } from '../po/video-upload.po'
|
||||||
|
import { VideoWatchPage } from '../po/video-watch.po'
|
||||||
|
import { go, isMobileDevice, isSafari, waitServerUp } from '../utils'
|
||||||
|
|
||||||
|
describe('User settings', () => {
|
||||||
|
let videoUploadPage: VideoUploadPage
|
||||||
|
let loginPage: LoginPage
|
||||||
|
let videoWatchPage: VideoWatchPage
|
||||||
|
let myAccountPage: MyAccountPage
|
||||||
|
let anonymousSettingsPage: AnonymousSettingsPage
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await waitServerUp()
|
||||||
|
|
||||||
|
loginPage = new LoginPage()
|
||||||
|
videoUploadPage = new VideoUploadPage()
|
||||||
|
videoWatchPage = new VideoWatchPage(isMobileDevice(), isSafari())
|
||||||
|
myAccountPage = new MyAccountPage()
|
||||||
|
anonymousSettingsPage = new AnonymousSettingsPage()
|
||||||
|
|
||||||
|
await browser.maximizeWindow()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('P2P', function () {
|
||||||
|
let videoUrl: string
|
||||||
|
|
||||||
|
async function goOnVideoWatchPage () {
|
||||||
|
await go(videoUrl)
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkP2P (enabled: boolean) {
|
||||||
|
await goOnVideoWatchPage()
|
||||||
|
expect(await videoWatchPage.isPrivacyWarningDisplayed()).toEqual(enabled)
|
||||||
|
|
||||||
|
await videoWatchPage.goOnAssociatedEmbed()
|
||||||
|
expect(await videoWatchPage.isEmbedWarningDisplayed()).toEqual(enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await loginPage.loginAsRootUser()
|
||||||
|
await videoUploadPage.navigateTo()
|
||||||
|
await videoUploadPage.uploadVideo()
|
||||||
|
await videoUploadPage.validSecondUploadStep('video')
|
||||||
|
|
||||||
|
await videoWatchPage.waitWatchVideoName('video')
|
||||||
|
|
||||||
|
videoUrl = await browser.getUrl()
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
await goOnVideoWatchPage()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should have P2P enabled for a logged in user', async function () {
|
||||||
|
await checkP2P(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should disable P2P for a logged in user', async function () {
|
||||||
|
await myAccountPage.navigateToMySettings()
|
||||||
|
await myAccountPage.clickOnP2PCheckbox()
|
||||||
|
|
||||||
|
await checkP2P(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should have P2P enabled for anonymous users', async function () {
|
||||||
|
await loginPage.logout()
|
||||||
|
|
||||||
|
await checkP2P(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should disable P2P for an anonymous user', async function () {
|
||||||
|
await anonymousSettingsPage.openSettings()
|
||||||
|
await anonymousSettingsPage.clickOnP2PCheckbox()
|
||||||
|
|
||||||
|
await checkP2P(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,6 +1,6 @@
|
||||||
import { AdminConfigPage } from '../po/admin-config.po'
|
import { AdminConfigPage } from '../po/admin-config.po'
|
||||||
import { LoginPage } from '../po/login.po'
|
import { LoginPage } from '../po/login.po'
|
||||||
import { MyAccountPage } from '../po/my-account'
|
import { MyAccountPage } from '../po/my-account.po'
|
||||||
import { VideoListPage } from '../po/video-list.po'
|
import { VideoListPage } from '../po/video-list.po'
|
||||||
import { VideoSearchPage } from '../po/video-search.po'
|
import { VideoSearchPage } from '../po/video-search.po'
|
||||||
import { VideoUploadPage } from '../po/video-upload.po'
|
import { VideoUploadPage } from '../po/video-upload.po'
|
||||||
|
|
|
@ -1,7 +1,22 @@
|
||||||
function clickOnCheckbox (name: string) {
|
function getCheckbox (name: string) {
|
||||||
return $(`my-peertube-checkbox[inputname=${name}] label`).click()
|
return $(`my-peertube-checkbox[inputname=${name}] label`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectCustomSelect (id: string, valueLabel: string) {
|
||||||
|
await $(`[formcontrolname=${id}] .ng-arrow-wrapper`).click()
|
||||||
|
|
||||||
|
const option = await $$(`[formcontrolname=${id}] .ng-option`).filter(async o => {
|
||||||
|
const text = await o.getText()
|
||||||
|
|
||||||
|
return text.trimStart().startsWith(valueLabel)
|
||||||
|
}).then(options => options[0])
|
||||||
|
|
||||||
|
await option.waitForDisplayed()
|
||||||
|
|
||||||
|
return option.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
clickOnCheckbox
|
getCheckbox,
|
||||||
|
selectCustomSelect
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,9 @@ function buildConfig (suiteFile: string = undefined) {
|
||||||
comments_enabled: false,
|
comments_enabled: false,
|
||||||
privacy: 4,
|
privacy: 4,
|
||||||
licence: 4
|
licence: 4
|
||||||
|
},
|
||||||
|
p2p: {
|
||||||
|
enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core'
|
import { Component, Input, OnInit } from '@angular/core'
|
||||||
import { ServerService } from '@app/core'
|
import { ServerService, User, UserService } from '@app/core'
|
||||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
||||||
import { HTMLServerConfig, Video } from '@shared/models'
|
import { HTMLServerConfig, Video } from '@shared/models'
|
||||||
import { getStoredP2PEnabled } from '../../../../../assets/player/peertube-player-local-storage'
|
import { isP2PEnabled } from '../../../../../assets/player/utils'
|
||||||
import { isWebRTCDisabled } from '../../../../../assets/player/utils'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-privacy-concerns',
|
selector: 'my-privacy-concerns',
|
||||||
|
@ -15,33 +14,32 @@ export class PrivacyConcernsComponent implements OnInit {
|
||||||
|
|
||||||
@Input() video: Video
|
@Input() video: Video
|
||||||
|
|
||||||
display = true
|
display = false
|
||||||
|
|
||||||
private serverConfig: HTMLServerConfig
|
private serverConfig: HTMLServerConfig
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private serverService: ServerService
|
private serverService: ServerService,
|
||||||
|
private userService: UserService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
if (isWebRTCDisabled() || this.isTrackerDisabled() || this.isP2PDisabled() || this.alreadyAccepted()) {
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
this.display = false
|
.subscribe(user => this.updateDisplay(user))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
acceptedPrivacyConcern () {
|
acceptedPrivacyConcern () {
|
||||||
peertubeLocalStorage.setItem(PrivacyConcernsComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true')
|
peertubeLocalStorage.setItem(PrivacyConcernsComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true')
|
||||||
|
|
||||||
this.display = false
|
this.display = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private isTrackerDisabled () {
|
private updateDisplay (user: User) {
|
||||||
return this.video.isLocal && this.serverConfig.tracker.enabled === false
|
if (isP2PEnabled(this.video, this.serverConfig, user.p2pEnabled) && !this.alreadyAccepted()) {
|
||||||
}
|
this.display = true
|
||||||
|
}
|
||||||
private isP2PDisabled () {
|
|
||||||
return getStoredP2PEnabled() === false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private alreadyAccepted () {
|
private alreadyAccepted () {
|
||||||
|
|
|
@ -1,16 +1,9 @@
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
import { Component, EventEmitter, Input, Output } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import {
|
import { AuthService, ComponentPagination, HooksService, Notifier, SessionStorageService, UserService } from '@app/core'
|
||||||
AuthService,
|
|
||||||
ComponentPagination,
|
|
||||||
HooksService,
|
|
||||||
LocalStorageService,
|
|
||||||
Notifier,
|
|
||||||
SessionStorageService,
|
|
||||||
UserService
|
|
||||||
} from '@app/core'
|
|
||||||
import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
|
import { VideoPlaylist, VideoPlaylistElement, VideoPlaylistService } from '@app/shared/shared-video-playlist'
|
||||||
import { peertubeLocalStorage, peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
|
import { peertubeSessionStorage } from '@root-helpers/peertube-web-storage'
|
||||||
|
import { getBoolOrDefault } from '@root-helpers/local-storage-utils'
|
||||||
import { VideoPlaylistPrivacy } from '@shared/models'
|
import { VideoPlaylistPrivacy } from '@shared/models'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -19,8 +12,7 @@ import { VideoPlaylistPrivacy } from '@shared/models'
|
||||||
styleUrls: [ './video-watch-playlist.component.scss' ]
|
styleUrls: [ './video-watch-playlist.component.scss' ]
|
||||||
})
|
})
|
||||||
export class VideoWatchPlaylistComponent {
|
export class VideoWatchPlaylistComponent {
|
||||||
static LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'auto_play_video_playlist'
|
static SESSION_STORAGE_LOOP_PLAYLIST = 'loop_playlist'
|
||||||
static SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST = 'loop_playlist'
|
|
||||||
|
|
||||||
@Input() playlist: VideoPlaylist
|
@Input() playlist: VideoPlaylist
|
||||||
|
|
||||||
|
@ -47,19 +39,15 @@ export class VideoWatchPlaylistComponent {
|
||||||
private auth: AuthService,
|
private auth: AuthService,
|
||||||
private notifier: Notifier,
|
private notifier: Notifier,
|
||||||
private videoPlaylist: VideoPlaylistService,
|
private videoPlaylist: VideoPlaylistService,
|
||||||
private localStorageService: LocalStorageService,
|
|
||||||
private sessionStorage: SessionStorageService,
|
private sessionStorage: SessionStorageService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
// defaults to true
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
this.autoPlayNextVideoPlaylist = this.auth.isLoggedIn()
|
.subscribe(user => this.autoPlayNextVideoPlaylist = user.autoPlayNextVideoPlaylist)
|
||||||
? this.auth.getUser().autoPlayNextVideoPlaylist
|
|
||||||
: this.localStorageService.getItem(VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) !== 'false'
|
|
||||||
|
|
||||||
this.setAutoPlayNextVideoPlaylistSwitchText()
|
this.setAutoPlayNextVideoPlaylistSwitchText()
|
||||||
|
|
||||||
// defaults to false
|
this.loopPlaylist = getBoolOrDefault(this.sessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_LOOP_PLAYLIST), false)
|
||||||
this.loopPlaylist = this.sessionStorage.getItem(VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST) === 'true'
|
|
||||||
this.setLoopPlaylistSwitchText()
|
this.setLoopPlaylistSwitchText()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,16 +189,9 @@ export class VideoWatchPlaylistComponent {
|
||||||
this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
|
this.autoPlayNextVideoPlaylist = !this.autoPlayNextVideoPlaylist
|
||||||
this.setAutoPlayNextVideoPlaylistSwitchText()
|
this.setAutoPlayNextVideoPlaylistSwitchText()
|
||||||
|
|
||||||
peertubeLocalStorage.setItem(
|
const details = { autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist }
|
||||||
VideoWatchPlaylistComponent.LOCAL_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
|
|
||||||
this.autoPlayNextVideoPlaylist.toString()
|
|
||||||
)
|
|
||||||
|
|
||||||
if (this.auth.isLoggedIn()) {
|
if (this.auth.isLoggedIn()) {
|
||||||
const details = {
|
|
||||||
autoPlayNextVideoPlaylist: this.autoPlayNextVideoPlaylist
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userService.updateMyProfile(details)
|
this.userService.updateMyProfile(details)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
|
@ -219,6 +200,8 @@ export class VideoWatchPlaylistComponent {
|
||||||
|
|
||||||
error: err => this.notifier.error(err.message)
|
error: err => this.notifier.error(err.message)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
this.userService.updateMyAnonymousProfile(details)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +210,7 @@ export class VideoWatchPlaylistComponent {
|
||||||
this.setLoopPlaylistSwitchText()
|
this.setLoopPlaylistSwitchText()
|
||||||
|
|
||||||
peertubeSessionStorage.setItem(
|
peertubeSessionStorage.setItem(
|
||||||
VideoWatchPlaylistComponent.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO_PLAYLIST,
|
VideoWatchPlaylistComponent.SESSION_STORAGE_LOOP_PLAYLIST,
|
||||||
this.loopPlaylist.toString()
|
this.loopPlaylist.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'
|
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core'
|
||||||
import { AuthService, Notifier, SessionStorageService, User, UserService } from '@app/core'
|
import { AuthService, Notifier, User, UserService } from '@app/core'
|
||||||
import { Video } from '@app/shared/shared-main'
|
import { Video } from '@app/shared/shared-main'
|
||||||
import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature'
|
import { MiniatureDisplayOptions } from '@app/shared/shared-video-miniature'
|
||||||
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
|
import { VideoPlaylist } from '@app/shared/shared-video-playlist'
|
||||||
import { UserLocalStorageKeys } from '@root-helpers/users'
|
|
||||||
import { RecommendationInfo } from './recommendation-info.model'
|
import { RecommendationInfo } from './recommendation-info.model'
|
||||||
import { RecommendedVideosStore } from './recommended-videos.store'
|
import { RecommendedVideosStore } from './recommended-videos.store'
|
||||||
|
|
||||||
|
@ -39,24 +38,14 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private notifier: Notifier,
|
private notifier: Notifier,
|
||||||
private store: RecommendedVideosStore,
|
private store: RecommendedVideosStore
|
||||||
private sessionStorageService: SessionStorageService
|
|
||||||
) {
|
) {
|
||||||
this.videos$ = this.store.recommendations$
|
this.videos$ = this.store.recommendations$
|
||||||
this.hasVideos$ = this.store.hasRecommendations$
|
this.hasVideos$ = this.store.hasRecommendations$
|
||||||
this.videos$.subscribe(videos => this.gotRecommendations.emit(videos))
|
this.videos$.subscribe(videos => this.gotRecommendations.emit(videos))
|
||||||
|
|
||||||
if (this.authService.isLoggedIn()) {
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
this.autoPlayNextVideo = this.authService.getUser().autoPlayNextVideo
|
.subscribe(user => this.autoPlayNextVideo = user.autoPlayNextVideo)
|
||||||
} else {
|
|
||||||
this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
|
|
||||||
|
|
||||||
this.sessionStorageService.watch([ UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO ]).subscribe(
|
|
||||||
() => {
|
|
||||||
this.autoPlayNextVideo = this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.autoPlayNextVideoTooltip = $localize`When active, the next video is automatically played after the current one.`
|
this.autoPlayNextVideoTooltip = $localize`When active, the next video is automatically played after the current one.`
|
||||||
}
|
}
|
||||||
|
@ -77,13 +66,9 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
|
||||||
}
|
}
|
||||||
|
|
||||||
switchAutoPlayNextVideo () {
|
switchAutoPlayNextVideo () {
|
||||||
this.sessionStorageService.setItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO, this.autoPlayNextVideo.toString())
|
const details = { autoPlayNextVideo: this.autoPlayNextVideo }
|
||||||
|
|
||||||
if (this.authService.isLoggedIn()) {
|
if (this.authService.isLoggedIn()) {
|
||||||
const details = {
|
|
||||||
autoPlayNextVideo: this.autoPlayNextVideo
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userService.updateMyProfile(details)
|
this.userService.updateMyProfile(details)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
|
@ -92,6 +77,8 @@ export class RecommendedVideosComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
error: err => this.notifier.error(err.message)
|
error: err => this.notifier.error(err.message)
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
this.userService.updateMyAnonymousProfile(details)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||||
import { forkJoin, Subscription } from 'rxjs'
|
import { forkJoin, Subscription } from 'rxjs'
|
||||||
|
import { isP2PEnabled } from 'src/assets/player/utils'
|
||||||
import { PlatformLocation } from '@angular/common'
|
import { PlatformLocation } from '@angular/common'
|
||||||
import { Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
import { Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
|
@ -14,6 +15,7 @@ import {
|
||||||
RestExtractor,
|
RestExtractor,
|
||||||
ScreenService,
|
ScreenService,
|
||||||
ServerService,
|
ServerService,
|
||||||
|
User,
|
||||||
UserService
|
UserService
|
||||||
} from '@app/core'
|
} from '@app/core'
|
||||||
import { HooksService } from '@app/core/plugins/hooks.service'
|
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||||
|
@ -237,31 +239,34 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
'filter:api.video-watch.video.get.result'
|
'filter:api.video-watch.video.get.result'
|
||||||
)
|
)
|
||||||
|
|
||||||
forkJoin([ videoObs, this.videoCaptionService.listCaptions(videoId) ])
|
forkJoin([
|
||||||
.subscribe({
|
videoObs,
|
||||||
next: ([ video, captionsResult ]) => {
|
this.videoCaptionService.listCaptions(videoId),
|
||||||
const queryParams = this.route.snapshot.queryParams
|
this.userService.getAnonymousOrLoggedUser()
|
||||||
|
]).subscribe({
|
||||||
|
next: ([ video, captionsResult, loggedInOrAnonymousUser ]) => {
|
||||||
|
const queryParams = this.route.snapshot.queryParams
|
||||||
|
|
||||||
const urlOptions = {
|
const urlOptions = {
|
||||||
resume: queryParams.resume,
|
resume: queryParams.resume,
|
||||||
|
|
||||||
startTime: queryParams.start,
|
startTime: queryParams.start,
|
||||||
stopTime: queryParams.stop,
|
stopTime: queryParams.stop,
|
||||||
|
|
||||||
muted: queryParams.muted,
|
muted: queryParams.muted,
|
||||||
loop: queryParams.loop,
|
loop: queryParams.loop,
|
||||||
subtitle: queryParams.subtitle,
|
subtitle: queryParams.subtitle,
|
||||||
|
|
||||||
playerMode: queryParams.mode,
|
playerMode: queryParams.mode,
|
||||||
peertubeLink: false
|
peertubeLink: false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onVideoFetched(video, captionsResult.data, urlOptions)
|
this.onVideoFetched({ video, videoCaptions: captionsResult.data, loggedInOrAnonymousUser, urlOptions })
|
||||||
.catch(err => this.handleGlobalError(err))
|
.catch(err => this.handleGlobalError(err))
|
||||||
},
|
},
|
||||||
|
|
||||||
error: err => this.handleRequestError(err)
|
error: err => this.handleRequestError(err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadPlaylist (playlistId: string) {
|
private loadPlaylist (playlistId: string) {
|
||||||
|
@ -323,11 +328,14 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.notifier.error(errorMessage)
|
this.notifier.error(errorMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onVideoFetched (
|
private async onVideoFetched (options: {
|
||||||
video: VideoDetails,
|
video: VideoDetails
|
||||||
videoCaptions: VideoCaption[],
|
videoCaptions: VideoCaption[]
|
||||||
urlOptions: URLOptions
|
urlOptions: URLOptions
|
||||||
) {
|
loggedInOrAnonymousUser: User
|
||||||
|
}) {
|
||||||
|
const { video, videoCaptions, urlOptions, loggedInOrAnonymousUser } = options
|
||||||
|
|
||||||
this.subscribeToLiveEventsIfNeeded(this.video, video)
|
this.subscribeToLiveEventsIfNeeded(this.video, video)
|
||||||
|
|
||||||
this.video = video
|
this.video = video
|
||||||
|
@ -346,7 +354,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
if (res === false) return this.location.back()
|
if (res === false) return this.location.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.buildPlayer(urlOptions)
|
this.buildPlayer(urlOptions, loggedInOrAnonymousUser)
|
||||||
.catch(err => console.error('Cannot build the player', err))
|
.catch(err => console.error('Cannot build the player', err))
|
||||||
|
|
||||||
this.setOpenGraphTags()
|
this.setOpenGraphTags()
|
||||||
|
@ -359,7 +367,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.hooks.runAction('action:video-watch.video.loaded', 'video-watch', hookOptions)
|
this.hooks.runAction('action:video-watch.video.loaded', 'video-watch', hookOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async buildPlayer (urlOptions: URLOptions) {
|
private async buildPlayer (urlOptions: URLOptions, loggedInOrAnonymousUser: User) {
|
||||||
// Flush old player if needed
|
// Flush old player if needed
|
||||||
this.flushPlayer()
|
this.flushPlayer()
|
||||||
|
|
||||||
|
@ -380,6 +388,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
video: this.video,
|
video: this.video,
|
||||||
videoCaptions: this.videoCaptions,
|
videoCaptions: this.videoCaptions,
|
||||||
urlOptions,
|
urlOptions,
|
||||||
|
loggedInOrAnonymousUser,
|
||||||
user: this.user
|
user: this.user
|
||||||
}
|
}
|
||||||
const { playerMode, playerOptions } = await this.hooks.wrapFun(
|
const { playerMode, playerOptions } = await this.hooks.wrapFun(
|
||||||
|
@ -517,9 +526,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
video: VideoDetails
|
video: VideoDetails
|
||||||
videoCaptions: VideoCaption[]
|
videoCaptions: VideoCaption[]
|
||||||
urlOptions: CustomizationOptions & { playerMode: PlayerMode }
|
urlOptions: CustomizationOptions & { playerMode: PlayerMode }
|
||||||
|
loggedInOrAnonymousUser: User
|
||||||
user?: AuthUser
|
user?: AuthUser
|
||||||
}) {
|
}) {
|
||||||
const { video, videoCaptions, urlOptions, user } = params
|
const { video, videoCaptions, urlOptions, loggedInOrAnonymousUser, user } = params
|
||||||
|
|
||||||
const getStartTime = () => {
|
const getStartTime = () => {
|
||||||
const byUrl = urlOptions.startTime !== undefined
|
const byUrl = urlOptions.startTime !== undefined
|
||||||
|
@ -547,6 +557,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
const options: PeertubePlayerManagerOptions = {
|
const options: PeertubePlayerManagerOptions = {
|
||||||
common: {
|
common: {
|
||||||
autoplay: this.isAutoplay(),
|
autoplay: this.isAutoplay(),
|
||||||
|
p2pEnabled: isP2PEnabled(video, this.serverConfig, loggedInOrAnonymousUser.p2pEnabled),
|
||||||
|
|
||||||
nextVideo: () => this.playNextVideoInAngularZone(),
|
nextVideo: () => this.playNextVideoInAngularZone(),
|
||||||
|
|
||||||
playerElement: this.playerElement,
|
playerElement: this.playerElement,
|
||||||
|
|
|
@ -14,7 +14,8 @@ import {
|
||||||
ScrollService,
|
ScrollService,
|
||||||
ServerService,
|
ServerService,
|
||||||
ThemeService,
|
ThemeService,
|
||||||
User
|
User,
|
||||||
|
UserLocalStorageService
|
||||||
} from '@app/core'
|
} from '@app/core'
|
||||||
import { HooksService } from '@app/core/plugins/hooks.service'
|
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||||
import { PluginService } from '@app/core/plugins/plugin.service'
|
import { PluginService } from '@app/core/plugins/plugin.service'
|
||||||
|
@ -70,6 +71,7 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
private ngbConfig: NgbConfig,
|
private ngbConfig: NgbConfig,
|
||||||
private loadingBar: LoadingBarService,
|
private loadingBar: LoadingBarService,
|
||||||
private scrollService: ScrollService,
|
private scrollService: ScrollService,
|
||||||
|
private userLocalStorage: UserLocalStorageService,
|
||||||
public menu: MenuService
|
public menu: MenuService
|
||||||
) {
|
) {
|
||||||
this.ngbConfig.animation = false
|
this.ngbConfig.animation = false
|
||||||
|
@ -86,6 +88,8 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
document.getElementById('incompatible-browser').className += ' browser-ok'
|
document.getElementById('incompatible-browser').className += ' browser-ok'
|
||||||
|
|
||||||
|
this.loadUser()
|
||||||
|
|
||||||
this.serverConfig = this.serverService.getHTMLConfig()
|
this.serverConfig = this.serverService.getHTMLConfig()
|
||||||
|
|
||||||
this.hooks.runAction('action:application.init', 'common')
|
this.hooks.runAction('action:application.init', 'common')
|
||||||
|
@ -300,4 +304,15 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
}, undefined, $localize`Go to the videos upload page`)
|
}, undefined, $localize`Go to the videos upload page`)
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private loadUser () {
|
||||||
|
const tokens = this.userLocalStorage.getTokens()
|
||||||
|
if (!tokens) return
|
||||||
|
|
||||||
|
const user = this.userLocalStorage.getLoggedInUser()
|
||||||
|
if (!user) return
|
||||||
|
|
||||||
|
// Initialize user
|
||||||
|
this.authService.buildAuthUser(user, tokens)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
import { Observable, of } from 'rxjs'
|
import { Observable, of } from 'rxjs'
|
||||||
import { map } from 'rxjs/operators'
|
import { map } from 'rxjs/operators'
|
||||||
import { User } from '@app/core/users/user.model'
|
import { User } from '@app/core/users/user.model'
|
||||||
import {
|
import { UserTokens } from '@root-helpers/users'
|
||||||
flushUserInfoFromLocalStorage,
|
|
||||||
getUserInfoFromLocalStorage,
|
|
||||||
saveUserInfoIntoLocalStorage,
|
|
||||||
TokenOptions,
|
|
||||||
Tokens
|
|
||||||
} from '@root-helpers/users'
|
|
||||||
import { hasUserRight } from '@shared/core-utils/users'
|
import { hasUserRight } from '@shared/core-utils/users'
|
||||||
import {
|
import {
|
||||||
MyUser as ServerMyUserModel,
|
MyUser as ServerMyUserModel,
|
||||||
|
@ -19,31 +13,15 @@ import {
|
||||||
} from '@shared/models'
|
} from '@shared/models'
|
||||||
|
|
||||||
export class AuthUser extends User implements ServerMyUserModel {
|
export class AuthUser extends User implements ServerMyUserModel {
|
||||||
tokens: Tokens
|
tokens: UserTokens
|
||||||
specialPlaylists: MyUserSpecialPlaylist[]
|
specialPlaylists: MyUserSpecialPlaylist[]
|
||||||
|
|
||||||
canSeeVideosLink = true
|
canSeeVideosLink = true
|
||||||
|
|
||||||
static load () {
|
constructor (userHash: Partial<ServerMyUserModel>, hashTokens: Partial<UserTokens>) {
|
||||||
const tokens = Tokens.load()
|
|
||||||
if (!tokens) return null
|
|
||||||
|
|
||||||
const userInfo = getUserInfoFromLocalStorage()
|
|
||||||
if (!userInfo) return null
|
|
||||||
|
|
||||||
return new AuthUser(userInfo, tokens)
|
|
||||||
}
|
|
||||||
|
|
||||||
static flush () {
|
|
||||||
flushUserInfoFromLocalStorage()
|
|
||||||
|
|
||||||
Tokens.flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (userHash: Partial<ServerMyUserModel>, hashTokens: TokenOptions) {
|
|
||||||
super(userHash)
|
super(userHash)
|
||||||
|
|
||||||
this.tokens = new Tokens(hashTokens)
|
this.tokens = new UserTokens(hashTokens)
|
||||||
this.specialPlaylists = userHash.specialPlaylists
|
this.specialPlaylists = userHash.specialPlaylists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,20 +55,6 @@ export class AuthUser extends User implements ServerMyUserModel {
|
||||||
return user.role === UserRole.USER
|
return user.role === UserRole.USER
|
||||||
}
|
}
|
||||||
|
|
||||||
save () {
|
|
||||||
saveUserInfoIntoLocalStorage({
|
|
||||||
id: this.id,
|
|
||||||
username: this.username,
|
|
||||||
email: this.email,
|
|
||||||
role: this.role,
|
|
||||||
nsfwPolicy: this.nsfwPolicy,
|
|
||||||
webTorrentEnabled: this.webTorrentEnabled,
|
|
||||||
autoPlayVideo: this.autoPlayVideo
|
|
||||||
})
|
|
||||||
|
|
||||||
this.tokens.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
computeCanSeeVideosLink (quotaObservable: Observable<UserVideoQuota>): Observable<boolean> {
|
computeCanSeeVideosLink (quotaObservable: Observable<UserVideoQuota>): Observable<boolean> {
|
||||||
if (!this.isUploadDisabled()) {
|
if (!this.isUploadDisabled()) {
|
||||||
this.canSeeVideosLink = true
|
this.canSeeVideosLink = true
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
import { Notifier } from '@app/core/notification/notifier.service'
|
import { Notifier } from '@app/core/notification/notifier.service'
|
||||||
import { objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index'
|
import { objectToUrlEncoded, peertubeLocalStorage, UserTokens } from '@root-helpers/index'
|
||||||
import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
|
import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { RestExtractor } from '../rest/rest-extractor.service'
|
import { RestExtractor } from '../rest/rest-extractor.service'
|
||||||
|
@ -34,6 +34,7 @@ export class AuthService {
|
||||||
|
|
||||||
loginChangedSource: Observable<AuthStatus>
|
loginChangedSource: Observable<AuthStatus>
|
||||||
userInformationLoaded = new ReplaySubject<boolean>(1)
|
userInformationLoaded = new ReplaySubject<boolean>(1)
|
||||||
|
tokensRefreshed = new ReplaySubject<void>(1)
|
||||||
hotkeys: Hotkey[]
|
hotkeys: Hotkey[]
|
||||||
|
|
||||||
private clientId: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID)
|
private clientId: string = peertubeLocalStorage.getItem(AuthService.LOCAL_STORAGE_OAUTH_CLIENT_KEYS.CLIENT_ID)
|
||||||
|
@ -52,9 +53,6 @@ export class AuthService {
|
||||||
this.loginChanged = new Subject<AuthStatus>()
|
this.loginChanged = new Subject<AuthStatus>()
|
||||||
this.loginChangedSource = this.loginChanged.asObservable()
|
this.loginChangedSource = this.loginChanged.asObservable()
|
||||||
|
|
||||||
// Return null if there is nothing to load
|
|
||||||
this.user = AuthUser.load()
|
|
||||||
|
|
||||||
// Set HotKeys
|
// Set HotKeys
|
||||||
this.hotkeys = [
|
this.hotkeys = [
|
||||||
new Hotkey('m s', (event: KeyboardEvent): boolean => {
|
new Hotkey('m s', (event: KeyboardEvent): boolean => {
|
||||||
|
@ -76,6 +74,10 @@ export class AuthService {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildAuthUser (userInfo: Partial<User>, tokens: UserTokens) {
|
||||||
|
this.user = new AuthUser(userInfo, tokens)
|
||||||
|
}
|
||||||
|
|
||||||
loadClientCredentials () {
|
loadClientCredentials () {
|
||||||
// Fetch the client_id/client_secret
|
// Fetch the client_id/client_secret
|
||||||
this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL)
|
this.http.get<OAuthClientLocal>(AuthService.BASE_CLIENT_URL)
|
||||||
|
@ -180,8 +182,6 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
||||||
|
|
||||||
this.user = null
|
this.user = null
|
||||||
|
|
||||||
AuthUser.flush()
|
|
||||||
|
|
||||||
this.setStatus(AuthStatus.LoggedOut)
|
this.setStatus(AuthStatus.LoggedOut)
|
||||||
|
|
||||||
this.hotkeysService.remove(this.hotkeys)
|
this.hotkeysService.remove(this.hotkeys)
|
||||||
|
@ -239,7 +239,6 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: res => {
|
next: res => {
|
||||||
this.user.patch(res)
|
this.user.patch(res)
|
||||||
this.user.save()
|
|
||||||
|
|
||||||
this.userInformationLoaded.next(true)
|
this.userInformationLoaded.next(true)
|
||||||
}
|
}
|
||||||
|
@ -262,7 +261,6 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
||||||
}
|
}
|
||||||
|
|
||||||
this.user = new AuthUser(obj, hashTokens)
|
this.user = new AuthUser(obj, hashTokens)
|
||||||
this.user.save()
|
|
||||||
|
|
||||||
this.setStatus(AuthStatus.LoggedIn)
|
this.setStatus(AuthStatus.LoggedIn)
|
||||||
this.userInformationLoaded.next(true)
|
this.userInformationLoaded.next(true)
|
||||||
|
@ -272,7 +270,7 @@ Ensure you have correctly configured PeerTube (config/ directory), in particular
|
||||||
|
|
||||||
private handleRefreshToken (obj: UserRefreshToken) {
|
private handleRefreshToken (obj: UserRefreshToken) {
|
||||||
this.user.refreshTokens(obj.access_token, obj.refresh_token)
|
this.user.refreshTokens(obj.access_token, obj.refresh_token)
|
||||||
this.user.save()
|
this.tokensRefreshed.next()
|
||||||
}
|
}
|
||||||
|
|
||||||
private setStatus (status: AuthStatus) {
|
private setStatus (status: AuthStatus) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import { ServerConfigResolver } from './routing/server-config-resolver.service'
|
||||||
import { ScopedTokensService } from './scoped-tokens'
|
import { ScopedTokensService } from './scoped-tokens'
|
||||||
import { ServerService } from './server'
|
import { ServerService } from './server'
|
||||||
import { ThemeService } from './theme'
|
import { ThemeService } from './theme'
|
||||||
import { UserService } from './users'
|
import { UserLocalStorageService, UserService } from './users'
|
||||||
import { LocalStorageService, ScreenService, SessionStorageService } from './wrappers'
|
import { LocalStorageService, ScreenService, SessionStorageService } from './wrappers'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -79,6 +79,7 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra
|
||||||
RestService,
|
RestService,
|
||||||
|
|
||||||
UserService,
|
UserService,
|
||||||
|
UserLocalStorageService,
|
||||||
|
|
||||||
ScreenService,
|
ScreenService,
|
||||||
LocalStorageService,
|
LocalStorageService,
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
|
export * from './user-local-storage.service'
|
||||||
export * from './user.model'
|
export * from './user.model'
|
||||||
export * from './user.service'
|
export * from './user.service'
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
import { filter, throttleTime } from 'rxjs'
|
||||||
|
import { Injectable } from '@angular/core'
|
||||||
|
import { AuthService, AuthStatus } from '@app/core/auth'
|
||||||
|
import { UserLocalStorageKeys, UserTokens } from '@root-helpers/users'
|
||||||
|
import { getBoolOrDefault } from '@root-helpers/local-storage-utils'
|
||||||
|
import { UserRole, UserUpdateMe } from '@shared/models'
|
||||||
|
import { NSFWPolicyType } from '@shared/models/videos'
|
||||||
|
import { ServerService } from '../server'
|
||||||
|
import { LocalStorageService } from '../wrappers/storage.service'
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class UserLocalStorageService {
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private authService: AuthService,
|
||||||
|
private server: ServerService,
|
||||||
|
private localStorageService: LocalStorageService
|
||||||
|
) {
|
||||||
|
this.authService.userInformationLoaded.subscribe({
|
||||||
|
next: () => {
|
||||||
|
const user = this.authService.getUser()
|
||||||
|
|
||||||
|
this.setLoggedInUser(user)
|
||||||
|
this.setUserInfo(user)
|
||||||
|
this.setTokens(user.tokens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.authService.loginChangedSource
|
||||||
|
.pipe(filter(status => status === AuthStatus.LoggedOut))
|
||||||
|
.subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.flushLoggedInUser()
|
||||||
|
this.flushUserInfo()
|
||||||
|
this.flushTokens()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.authService.tokensRefreshed
|
||||||
|
.subscribe({
|
||||||
|
next: () => {
|
||||||
|
const user = this.authService.getUser()
|
||||||
|
|
||||||
|
this.setTokens(user.tokens)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
getLoggedInUser () {
|
||||||
|
const usernameLocalStorage = this.localStorageService.getItem(UserLocalStorageKeys.USERNAME)
|
||||||
|
|
||||||
|
if (!usernameLocalStorage) return undefined
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ID), 10),
|
||||||
|
username: this.localStorageService.getItem(UserLocalStorageKeys.USERNAME),
|
||||||
|
email: this.localStorageService.getItem(UserLocalStorageKeys.EMAIL),
|
||||||
|
role: parseInt(this.localStorageService.getItem(UserLocalStorageKeys.ROLE), 10) as UserRole,
|
||||||
|
|
||||||
|
...this.getUserInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoggedInUser (user: {
|
||||||
|
id: number
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
role: UserRole
|
||||||
|
}) {
|
||||||
|
this.localStorageService.setItem(UserLocalStorageKeys.ID, user.id.toString())
|
||||||
|
this.localStorageService.setItem(UserLocalStorageKeys.USERNAME, user.username)
|
||||||
|
this.localStorageService.setItem(UserLocalStorageKeys.EMAIL, user.email)
|
||||||
|
this.localStorageService.setItem(UserLocalStorageKeys.ROLE, user.role.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
flushLoggedInUser () {
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.ID)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.USERNAME)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.EMAIL)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.ROLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
getUserInfo () {
|
||||||
|
let videoLanguages: string[]
|
||||||
|
|
||||||
|
try {
|
||||||
|
const languagesString = this.localStorageService.getItem(UserLocalStorageKeys.VIDEO_LANGUAGES)
|
||||||
|
videoLanguages = languagesString && languagesString !== 'undefined'
|
||||||
|
? JSON.parse(languagesString)
|
||||||
|
: null
|
||||||
|
} catch (err) {
|
||||||
|
videoLanguages = null
|
||||||
|
console.error('Cannot parse desired video languages from localStorage.', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const htmlConfig = this.server.getHTMLConfig()
|
||||||
|
|
||||||
|
const defaultNSFWPolicy = htmlConfig.instance.defaultNSFWPolicy
|
||||||
|
const defaultP2PEnabled = htmlConfig.defaults.p2p.enabled
|
||||||
|
|
||||||
|
return {
|
||||||
|
nsfwPolicy: this.localStorageService.getItem<NSFWPolicyType>(UserLocalStorageKeys.NSFW_POLICY) || defaultNSFWPolicy,
|
||||||
|
p2pEnabled: getBoolOrDefault(this.localStorageService.getItem(UserLocalStorageKeys.P2P_ENABLED), defaultP2PEnabled),
|
||||||
|
theme: this.localStorageService.getItem(UserLocalStorageKeys.THEME) || 'instance-default',
|
||||||
|
videoLanguages,
|
||||||
|
|
||||||
|
autoPlayVideo: getBoolOrDefault(this.localStorageService.getItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO), true),
|
||||||
|
autoPlayNextVideo: getBoolOrDefault(this.localStorageService.getItem(UserLocalStorageKeys.AUTO_PLAY_NEXT_VIDEO), false),
|
||||||
|
autoPlayNextVideoPlaylist: getBoolOrDefault(this.localStorageService.getItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserInfo (profile: UserUpdateMe) {
|
||||||
|
const localStorageKeys: { [ id in keyof UserUpdateMe ]: string } = {
|
||||||
|
nsfwPolicy: UserLocalStorageKeys.NSFW_POLICY,
|
||||||
|
p2pEnabled: UserLocalStorageKeys.P2P_ENABLED,
|
||||||
|
autoPlayNextVideo: UserLocalStorageKeys.AUTO_PLAY_VIDEO,
|
||||||
|
autoPlayNextVideoPlaylist: UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST,
|
||||||
|
theme: UserLocalStorageKeys.THEME,
|
||||||
|
videoLanguages: UserLocalStorageKeys.VIDEO_LANGUAGES
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj = Object.keys(localStorageKeys)
|
||||||
|
.filter(key => key in profile)
|
||||||
|
.map(key => ([ localStorageKeys[key], profile[key] ]))
|
||||||
|
|
||||||
|
for (const [ key, value ] of obj) {
|
||||||
|
try {
|
||||||
|
if (value === undefined) {
|
||||||
|
this.localStorageService.removeItem(key)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const localStorageValue = typeof value === 'string'
|
||||||
|
? value
|
||||||
|
: JSON.stringify(value)
|
||||||
|
|
||||||
|
this.localStorageService.setItem(key, localStorageValue)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Cannot set ${key}->${value} in localStorage. Likely due to a value impossible to stringify.`, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flushUserInfo () {
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.NSFW_POLICY)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.P2P_ENABLED)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.THEME)
|
||||||
|
this.localStorageService.removeItem(UserLocalStorageKeys.VIDEO_LANGUAGES)
|
||||||
|
}
|
||||||
|
|
||||||
|
listenUserInfoChange () {
|
||||||
|
return this.localStorageService.watch([
|
||||||
|
UserLocalStorageKeys.NSFW_POLICY,
|
||||||
|
UserLocalStorageKeys.P2P_ENABLED,
|
||||||
|
UserLocalStorageKeys.AUTO_PLAY_VIDEO,
|
||||||
|
UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST,
|
||||||
|
UserLocalStorageKeys.THEME,
|
||||||
|
UserLocalStorageKeys.VIDEO_LANGUAGES
|
||||||
|
]).pipe(
|
||||||
|
throttleTime(200),
|
||||||
|
filter(() => this.authService.isLoggedIn() !== true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
getTokens () {
|
||||||
|
return UserTokens.getUserTokens(this.localStorageService)
|
||||||
|
}
|
||||||
|
|
||||||
|
setTokens (tokens: UserTokens) {
|
||||||
|
UserTokens.saveToLocalStorage(this.localStorageService, tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
flushTokens () {
|
||||||
|
UserTokens.flushLocalStorage(this.localStorageService)
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,11 @@ export class User implements UserServerModel {
|
||||||
autoPlayVideo: boolean
|
autoPlayVideo: boolean
|
||||||
autoPlayNextVideo: boolean
|
autoPlayNextVideo: boolean
|
||||||
autoPlayNextVideoPlaylist: boolean
|
autoPlayNextVideoPlaylist: boolean
|
||||||
webTorrentEnabled: boolean
|
|
||||||
|
p2pEnabled: boolean
|
||||||
|
// FIXME: deprecated in 4.1
|
||||||
|
webTorrentEnabled: never
|
||||||
|
|
||||||
videosHistoryEnabled: boolean
|
videosHistoryEnabled: boolean
|
||||||
videoLanguages: string[]
|
videoLanguages: string[]
|
||||||
|
|
||||||
|
@ -84,7 +88,7 @@ export class User implements UserServerModel {
|
||||||
this.videoCommentsCount = hash.videoCommentsCount
|
this.videoCommentsCount = hash.videoCommentsCount
|
||||||
|
|
||||||
this.nsfwPolicy = hash.nsfwPolicy
|
this.nsfwPolicy = hash.nsfwPolicy
|
||||||
this.webTorrentEnabled = hash.webTorrentEnabled
|
this.p2pEnabled = hash.p2pEnabled
|
||||||
this.autoPlayVideo = hash.autoPlayVideo
|
this.autoPlayVideo = hash.autoPlayVideo
|
||||||
this.autoPlayNextVideo = hash.autoPlayNextVideo
|
this.autoPlayNextVideo = hash.autoPlayNextVideo
|
||||||
this.autoPlayNextVideoPlaylist = hash.autoPlayNextVideoPlaylist
|
this.autoPlayNextVideoPlaylist = hash.autoPlayNextVideoPlaylist
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { SortMeta } from 'primeng/api'
|
import { SortMeta } from 'primeng/api'
|
||||||
import { from, Observable, of } from 'rxjs'
|
import { from, Observable, of } from 'rxjs'
|
||||||
import { catchError, concatMap, filter, first, map, shareReplay, tap, throttleTime, toArray } from 'rxjs/operators'
|
import { catchError, concatMap, first, map, shareReplay, tap, toArray } from 'rxjs/operators'
|
||||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { AuthService } from '@app/core/auth'
|
import { AuthService } from '@app/core/auth'
|
||||||
import { getBytes } from '@root-helpers/bytes'
|
import { getBytes } from '@root-helpers/bytes'
|
||||||
import { UserLocalStorageKeys } from '@root-helpers/users'
|
|
||||||
import {
|
import {
|
||||||
ActorImage,
|
ActorImage,
|
||||||
ResultList,
|
ResultList,
|
||||||
|
@ -17,10 +16,9 @@ import {
|
||||||
UserUpdateMe,
|
UserUpdateMe,
|
||||||
UserVideoQuota
|
UserVideoQuota
|
||||||
} from '@shared/models'
|
} from '@shared/models'
|
||||||
import { ServerService } from '../'
|
|
||||||
import { environment } from '../../../environments/environment'
|
import { environment } from '../../../environments/environment'
|
||||||
import { RestExtractor, RestPagination, RestService } from '../rest'
|
import { RestExtractor, RestPagination, RestService } from '../rest'
|
||||||
import { LocalStorageService, SessionStorageService } from '../wrappers/storage.service'
|
import { UserLocalStorageService } from './'
|
||||||
import { User } from './user.model'
|
import { User } from './user.model'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -33,12 +31,10 @@ export class UserService {
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: HttpClient,
|
private authHttp: HttpClient,
|
||||||
private server: ServerService,
|
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private restExtractor: RestExtractor,
|
private restExtractor: RestExtractor,
|
||||||
private restService: RestService,
|
private restService: RestService,
|
||||||
private localStorageService: LocalStorageService,
|
private userLocalStorageService: UserLocalStorageService
|
||||||
private sessionStorageService: SessionStorageService
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
hasSignupInThisSession () {
|
hasSignupInThisSession () {
|
||||||
|
@ -73,6 +69,23 @@ export class UserService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
updateMyAnonymousProfile (profile: UserUpdateMe) {
|
||||||
|
this.userLocalStorageService.setUserInfo(profile)
|
||||||
|
}
|
||||||
|
|
||||||
|
listenAnonymousUpdate () {
|
||||||
|
return this.userLocalStorageService.listenUserInfoChange()
|
||||||
|
.pipe(map(() => this.getAnonymousUser()))
|
||||||
|
}
|
||||||
|
|
||||||
|
getAnonymousUser () {
|
||||||
|
return new User(this.userLocalStorageService.getUserInfo())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
updateMyProfile (profile: UserUpdateMe) {
|
updateMyProfile (profile: UserUpdateMe) {
|
||||||
const url = UserService.BASE_USERS_URL + 'me'
|
const url = UserService.BASE_USERS_URL + 'me'
|
||||||
|
|
||||||
|
@ -83,53 +96,6 @@ export class UserService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMyAnonymousProfile (profile: UserUpdateMe) {
|
|
||||||
const localStorageKeys: { [ id in keyof UserUpdateMe ]: string } = {
|
|
||||||
nsfwPolicy: UserLocalStorageKeys.NSFW_POLICY,
|
|
||||||
webTorrentEnabled: UserLocalStorageKeys.WEBTORRENT_ENABLED,
|
|
||||||
autoPlayNextVideo: UserLocalStorageKeys.AUTO_PLAY_VIDEO,
|
|
||||||
autoPlayNextVideoPlaylist: UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST,
|
|
||||||
theme: UserLocalStorageKeys.THEME,
|
|
||||||
videoLanguages: UserLocalStorageKeys.VIDEO_LANGUAGES
|
|
||||||
}
|
|
||||||
|
|
||||||
const obj = Object.keys(localStorageKeys)
|
|
||||||
.filter(key => key in profile)
|
|
||||||
.map(key => ([ localStorageKeys[key], profile[key] ]))
|
|
||||||
|
|
||||||
for (const [ key, value ] of obj) {
|
|
||||||
try {
|
|
||||||
if (value === undefined) {
|
|
||||||
this.localStorageService.removeItem(key)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const localStorageValue = typeof value === 'string'
|
|
||||||
? value
|
|
||||||
: JSON.stringify(value)
|
|
||||||
|
|
||||||
this.localStorageService.setItem(key, localStorageValue)
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`Cannot set ${key}->${value} in localStorage. Likely due to a value impossible to stringify.`, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
listenAnonymousUpdate () {
|
|
||||||
return this.localStorageService.watch([
|
|
||||||
UserLocalStorageKeys.NSFW_POLICY,
|
|
||||||
UserLocalStorageKeys.WEBTORRENT_ENABLED,
|
|
||||||
UserLocalStorageKeys.AUTO_PLAY_VIDEO,
|
|
||||||
UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST,
|
|
||||||
UserLocalStorageKeys.THEME,
|
|
||||||
UserLocalStorageKeys.VIDEO_LANGUAGES
|
|
||||||
]).pipe(
|
|
||||||
throttleTime(200),
|
|
||||||
filter(() => this.authService.isLoggedIn() !== true),
|
|
||||||
map(() => this.getAnonymousUser())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteMe () {
|
deleteMe () {
|
||||||
const url = UserService.BASE_USERS_URL + 'me'
|
const url = UserService.BASE_USERS_URL + 'me'
|
||||||
|
|
||||||
|
@ -287,36 +253,6 @@ export class UserService {
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
getAnonymousUser () {
|
|
||||||
let videoLanguages: string[]
|
|
||||||
|
|
||||||
try {
|
|
||||||
const languagesString = this.localStorageService.getItem(UserLocalStorageKeys.VIDEO_LANGUAGES)
|
|
||||||
videoLanguages = languagesString && languagesString !== 'undefined'
|
|
||||||
? JSON.parse(languagesString)
|
|
||||||
: null
|
|
||||||
} catch (err) {
|
|
||||||
videoLanguages = null
|
|
||||||
console.error('Cannot parse desired video languages from localStorage.', err)
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultNSFWPolicy = this.server.getHTMLConfig().instance.defaultNSFWPolicy
|
|
||||||
|
|
||||||
return new User({
|
|
||||||
// local storage keys
|
|
||||||
nsfwPolicy: this.localStorageService.getItem(UserLocalStorageKeys.NSFW_POLICY) || defaultNSFWPolicy,
|
|
||||||
webTorrentEnabled: this.localStorageService.getItem(UserLocalStorageKeys.WEBTORRENT_ENABLED) !== 'false',
|
|
||||||
theme: this.localStorageService.getItem(UserLocalStorageKeys.THEME) || 'instance-default',
|
|
||||||
videoLanguages,
|
|
||||||
|
|
||||||
autoPlayNextVideoPlaylist: this.localStorageService.getItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO_PLAYLIST) !== 'false',
|
|
||||||
autoPlayVideo: this.localStorageService.getItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO) === 'true',
|
|
||||||
|
|
||||||
// session storage keys
|
|
||||||
autoPlayNextVideo: this.sessionStorageService.getItem(UserLocalStorageKeys.SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO) === 'true'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getUsers (parameters: {
|
getUsers (parameters: {
|
||||||
pagination: RestPagination
|
pagination: RestPagination
|
||||||
sort: SortMeta
|
sort: SortMeta
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
<my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon>
|
<my-global-icon iconName="p2p" aria-hidden="true"></my-global-icon>
|
||||||
<ng-container i18n>Help share videos</ng-container>
|
<ng-container i18n>Help share videos</ng-container>
|
||||||
|
|
||||||
<my-input-switch class="ml-auto" [checked]="user.webTorrentEnabled"></my-input-switch>
|
<my-input-switch class="ml-auto" [checked]="user.p2pEnabled"></my-input-switch>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
|
|
@ -196,9 +196,9 @@ export class MenuComponent implements OnInit {
|
||||||
|
|
||||||
toggleUseP2P () {
|
toggleUseP2P () {
|
||||||
if (!this.user) return
|
if (!this.user) return
|
||||||
this.user.webTorrentEnabled = !this.user.webTorrentEnabled
|
this.user.p2pEnabled = !this.user.p2pEnabled
|
||||||
|
|
||||||
this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
|
this.userService.updateMyProfile({ p2pEnabled: this.user.p2pEnabled })
|
||||||
.subscribe(() => this.authService.refreshUserInformation())
|
.subscribe(() => this.authService.refreshUserInformation())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { HttpClient, HttpParams } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core'
|
import { ComponentPaginationLight, RestExtractor, RestPagination, RestService } from '@app/core'
|
||||||
import { Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
import { Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||||
import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
|
|
||||||
import {
|
import {
|
||||||
ResultList,
|
ResultList,
|
||||||
Video as VideoServerModel,
|
Video as VideoServerModel,
|
||||||
|
@ -25,11 +24,7 @@ export class SearchService {
|
||||||
private restService: RestService,
|
private restService: RestService,
|
||||||
private videoService: VideoService,
|
private videoService: VideoService,
|
||||||
private playlistService: VideoPlaylistService
|
private playlistService: VideoPlaylistService
|
||||||
) {
|
) { }
|
||||||
// Add ability to override search endpoint if the user updated this local storage key
|
|
||||||
const searchUrl = peertubeLocalStorage.getItem('search-url')
|
|
||||||
if (searchUrl) SearchService.BASE_SEARCH_URL = searchUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
searchVideos (parameters: {
|
searchVideos (parameters: {
|
||||||
search?: string
|
search?: string
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<my-peertube-checkbox
|
<my-peertube-checkbox
|
||||||
inputName="webTorrentEnabled" formControlName="webTorrentEnabled" [recommended]="true"
|
inputName="p2pEnabled" formControlName="p2pEnabled" [recommended]="true"
|
||||||
i18n-labelText labelText="Help share videos being played"
|
i18n-labelText labelText="Help share videos being played"
|
||||||
>
|
>
|
||||||
<ng-container ngProjectAs="description">
|
<ng-container ngProjectAs="description">
|
||||||
|
|
|
@ -34,7 +34,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.buildForm({
|
this.buildForm({
|
||||||
nsfwPolicy: null,
|
nsfwPolicy: null,
|
||||||
webTorrentEnabled: null,
|
p2pEnabled: null,
|
||||||
autoPlayVideo: null,
|
autoPlayVideo: null,
|
||||||
autoPlayNextVideo: null,
|
autoPlayNextVideo: null,
|
||||||
videoLanguages: null
|
videoLanguages: null
|
||||||
|
@ -48,7 +48,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
|
||||||
|
|
||||||
this.form.patchValue({
|
this.form.patchValue({
|
||||||
nsfwPolicy: this.user.nsfwPolicy || this.defaultNSFWPolicy,
|
nsfwPolicy: this.user.nsfwPolicy || this.defaultNSFWPolicy,
|
||||||
webTorrentEnabled: this.user.webTorrentEnabled,
|
p2pEnabled: this.user.p2pEnabled,
|
||||||
autoPlayVideo: this.user.autoPlayVideo === true,
|
autoPlayVideo: this.user.autoPlayVideo === true,
|
||||||
autoPlayNextVideo: this.user.autoPlayNextVideo,
|
autoPlayNextVideo: this.user.autoPlayNextVideo,
|
||||||
videoLanguages: this.user.videoLanguages
|
videoLanguages: this.user.videoLanguages
|
||||||
|
@ -65,7 +65,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
|
||||||
|
|
||||||
updateDetails (onlyKeys?: string[]) {
|
updateDetails (onlyKeys?: string[]) {
|
||||||
const nsfwPolicy = this.form.value['nsfwPolicy']
|
const nsfwPolicy = this.form.value['nsfwPolicy']
|
||||||
const webTorrentEnabled = this.form.value['webTorrentEnabled']
|
const p2pEnabled = this.form.value['p2pEnabled']
|
||||||
const autoPlayVideo = this.form.value['autoPlayVideo']
|
const autoPlayVideo = this.form.value['autoPlayVideo']
|
||||||
const autoPlayNextVideo = this.form.value['autoPlayNextVideo']
|
const autoPlayNextVideo = this.form.value['autoPlayNextVideo']
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
|
||||||
|
|
||||||
let details: UserUpdateMe = {
|
let details: UserUpdateMe = {
|
||||||
nsfwPolicy,
|
nsfwPolicy,
|
||||||
webTorrentEnabled,
|
p2pEnabled,
|
||||||
autoPlayVideo,
|
autoPlayVideo,
|
||||||
autoPlayNextVideo,
|
autoPlayNextVideo,
|
||||||
videoLanguages
|
videoLanguages
|
||||||
|
|
|
@ -10,14 +10,6 @@ function getStoredVolume () {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStoredP2PEnabled (): boolean {
|
|
||||||
const value = getLocalStorage('webtorrent_enabled')
|
|
||||||
if (value !== null && value !== undefined) return value === 'true'
|
|
||||||
|
|
||||||
// By default webtorrent is enabled
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStoredMute () {
|
function getStoredMute () {
|
||||||
const value = getLocalStorage('mute')
|
const value = getLocalStorage('mute')
|
||||||
if (value !== null && value !== undefined) return value === 'true'
|
if (value !== null && value !== undefined) return value === 'true'
|
||||||
|
@ -123,7 +115,6 @@ function cleanupVideoWatch () {
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getStoredVolume,
|
getStoredVolume,
|
||||||
getStoredP2PEnabled,
|
|
||||||
getStoredMute,
|
getStoredMute,
|
||||||
getStoredTheater,
|
getStoredTheater,
|
||||||
saveVolumeInStore,
|
saveVolumeInStore,
|
||||||
|
|
|
@ -31,7 +31,7 @@ import { copyToClipboard } from '../../root-helpers/utils'
|
||||||
import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
|
import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager'
|
||||||
import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
|
import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder'
|
||||||
import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
|
import { segmentValidatorFactory } from './p2p-media-loader/segment-validator'
|
||||||
import { getAverageBandwidthInStore, getStoredP2PEnabled, saveAverageBandwidth } from './peertube-player-local-storage'
|
import { getAverageBandwidthInStore, saveAverageBandwidth } from './peertube-player-local-storage'
|
||||||
import {
|
import {
|
||||||
NextPreviousVideoButtonOptions,
|
NextPreviousVideoButtonOptions,
|
||||||
P2PMediaLoaderPluginOptions,
|
P2PMediaLoaderPluginOptions,
|
||||||
|
@ -86,6 +86,7 @@ export interface CommonOptions extends CustomizationOptions {
|
||||||
onPlayerElementChange: (element: HTMLVideoElement) => void
|
onPlayerElementChange: (element: HTMLVideoElement) => void
|
||||||
|
|
||||||
autoplay: boolean
|
autoplay: boolean
|
||||||
|
p2pEnabled: boolean
|
||||||
|
|
||||||
nextVideo?: () => void
|
nextVideo?: () => void
|
||||||
hasNextVideo?: () => boolean
|
hasNextVideo?: () => boolean
|
||||||
|
@ -374,7 +375,7 @@ export class PeertubePlayerManager {
|
||||||
requiredSegmentsPriority: 1,
|
requiredSegmentsPriority: 1,
|
||||||
simultaneousHttpDownloads: 1,
|
simultaneousHttpDownloads: 1,
|
||||||
segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
|
segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
|
||||||
useP2P: getStoredP2PEnabled(),
|
useP2P: commonOptions.p2pEnabled,
|
||||||
consumeOnly
|
consumeOnly
|
||||||
},
|
},
|
||||||
segments: {
|
segments: {
|
||||||
|
@ -437,6 +438,7 @@ export class PeertubePlayerManager {
|
||||||
|
|
||||||
const webtorrent = {
|
const webtorrent = {
|
||||||
autoplay,
|
autoplay,
|
||||||
|
playerRefusedP2P: commonOptions.p2pEnabled === false,
|
||||||
videoDuration: commonOptions.videoDuration,
|
videoDuration: commonOptions.videoDuration,
|
||||||
playerElement: commonOptions.playerElement,
|
playerElement: commonOptions.playerElement,
|
||||||
videoFiles: webtorrentOptions.videoFiles.length !== 0
|
videoFiles: webtorrentOptions.videoFiles.length !== 0
|
||||||
|
|
|
@ -137,6 +137,8 @@ type WebtorrentPluginOptions = {
|
||||||
videoFiles: VideoFile[]
|
videoFiles: VideoFile[]
|
||||||
|
|
||||||
startTime: number | string
|
startTime: number | string
|
||||||
|
|
||||||
|
playerRefusedP2P: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
type P2PMediaLoaderPluginOptions = {
|
type P2PMediaLoaderPluginOptions = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { VideoFile } from '@shared/models'
|
import { HTMLServerConfig, Video, VideoFile } from '@shared/models'
|
||||||
|
|
||||||
function toTitleCase (str: string) {
|
function toTitleCase (str: string) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||||
|
@ -8,6 +8,13 @@ function isWebRTCDisabled () {
|
||||||
return !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false
|
return !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isP2PEnabled (video: Video, config: HTMLServerConfig, userP2PEnabled: boolean) {
|
||||||
|
if (video.isLocal && config.tracker.enabled === false) return false
|
||||||
|
if (isWebRTCDisabled()) return false
|
||||||
|
|
||||||
|
return userP2PEnabled
|
||||||
|
}
|
||||||
|
|
||||||
function isIOS () {
|
function isIOS () {
|
||||||
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
||||||
return true
|
return true
|
||||||
|
@ -97,6 +104,7 @@ export {
|
||||||
getRtcConfig,
|
getRtcConfig,
|
||||||
toTitleCase,
|
toTitleCase,
|
||||||
isWebRTCDisabled,
|
isWebRTCDisabled,
|
||||||
|
isP2PEnabled,
|
||||||
|
|
||||||
buildVideoOrPlaylistEmbed,
|
buildVideoOrPlaylistEmbed,
|
||||||
videoFileMaxByResolution,
|
videoFileMaxByResolution,
|
||||||
|
|
|
@ -2,13 +2,7 @@ import videojs from 'video.js'
|
||||||
import * as WebTorrent from 'webtorrent'
|
import * as WebTorrent from 'webtorrent'
|
||||||
import { timeToInt } from '@shared/core-utils'
|
import { timeToInt } from '@shared/core-utils'
|
||||||
import { VideoFile } from '@shared/models'
|
import { VideoFile } from '@shared/models'
|
||||||
import {
|
import { getAverageBandwidthInStore, getStoredMute, getStoredVolume, saveAverageBandwidth } from '../peertube-player-local-storage'
|
||||||
getAverageBandwidthInStore,
|
|
||||||
getStoredMute,
|
|
||||||
getStoredP2PEnabled,
|
|
||||||
getStoredVolume,
|
|
||||||
saveAverageBandwidth
|
|
||||||
} from '../peertube-player-local-storage'
|
|
||||||
import { PeerTubeResolution, PlayerNetworkInfo, WebtorrentPluginOptions } from '../peertube-videojs-typings'
|
import { PeerTubeResolution, PlayerNetworkInfo, WebtorrentPluginOptions } from '../peertube-videojs-typings'
|
||||||
import { getRtcConfig, isIOS, videoFileMaxByResolution, videoFileMinByResolution } from '../utils'
|
import { getRtcConfig, isIOS, videoFileMaxByResolution, videoFileMinByResolution } from '../utils'
|
||||||
import { PeertubeChunkStore } from './peertube-chunk-store'
|
import { PeertubeChunkStore } from './peertube-chunk-store'
|
||||||
|
@ -74,9 +68,10 @@ class WebTorrentPlugin extends Plugin {
|
||||||
|
|
||||||
this.startTime = timeToInt(options.startTime)
|
this.startTime = timeToInt(options.startTime)
|
||||||
|
|
||||||
// Disable auto play on iOS
|
// Custom autoplay handled by webtorrent because we lazy play the video
|
||||||
this.autoplay = options.autoplay
|
this.autoplay = options.autoplay
|
||||||
this.playerRefusedP2P = !getStoredP2PEnabled()
|
|
||||||
|
this.playerRefusedP2P = options.playerRefusedP2P
|
||||||
|
|
||||||
this.videoFiles = options.videoFiles
|
this.videoFiles = options.videoFiles
|
||||||
this.videoDuration = options.videoDuration
|
this.videoDuration = options.videoDuration
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
export * from './users'
|
export * from './users'
|
||||||
export * from './bytes'
|
export * from './bytes'
|
||||||
export * from './images'
|
export * from './images'
|
||||||
|
export * from './local-storage-utils'
|
||||||
export * from './peertube-web-storage'
|
export * from './peertube-web-storage'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
export * from './plugins-manager'
|
export * from './plugins-manager'
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
function getBoolOrDefault (value: string, defaultValue: boolean) {
|
||||||
|
if (value === 'true') return true
|
||||||
|
if (value === 'false') return false
|
||||||
|
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getBoolOrDefault
|
||||||
|
}
|
|
@ -1,3 +1,2 @@
|
||||||
export * from './user-local-storage-keys'
|
export * from './user-local-storage-keys'
|
||||||
export * from './user-local-storage-manager'
|
|
||||||
export * from './user-tokens'
|
export * from './user-tokens'
|
||||||
|
|
|
@ -1,15 +1,25 @@
|
||||||
export const UserLocalStorageKeys = {
|
export const UserLocalStorageKeys = {
|
||||||
ID: 'id',
|
ID: 'id',
|
||||||
|
USERNAME: 'username',
|
||||||
ROLE: 'role',
|
ROLE: 'role',
|
||||||
EMAIL: 'email',
|
EMAIL: 'email',
|
||||||
|
|
||||||
VIDEOS_HISTORY_ENABLED: 'videos-history-enabled',
|
VIDEOS_HISTORY_ENABLED: 'videos-history-enabled',
|
||||||
USERNAME: 'username',
|
|
||||||
NSFW_POLICY: 'nsfw_policy',
|
NSFW_POLICY: 'nsfw_policy',
|
||||||
WEBTORRENT_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled',
|
P2P_ENABLED: 'peertube-videojs-' + 'webtorrent_enabled',
|
||||||
|
|
||||||
AUTO_PLAY_VIDEO: 'auto_play_video',
|
AUTO_PLAY_VIDEO: 'auto_play_video',
|
||||||
SESSION_STORAGE_AUTO_PLAY_NEXT_VIDEO: 'auto_play_next_video',
|
AUTO_PLAY_NEXT_VIDEO: 'auto_play_next_video',
|
||||||
AUTO_PLAY_VIDEO_PLAYLIST: 'auto_play_video_playlist',
|
AUTO_PLAY_VIDEO_PLAYLIST: 'auto_play_video_playlist',
|
||||||
|
|
||||||
THEME: 'theme',
|
THEME: 'theme',
|
||||||
LAST_ACTIVE_THEME: 'last_active_theme',
|
LAST_ACTIVE_THEME: 'last_active_theme',
|
||||||
|
|
||||||
VIDEO_LANGUAGES: 'video_languages'
|
VIDEO_LANGUAGES: 'video_languages'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const UserTokenLocalStorageKeys = {
|
||||||
|
ACCESS_TOKEN: 'access_token',
|
||||||
|
REFRESH_TOKEN: 'refresh_token',
|
||||||
|
TOKEN_TYPE: 'token_type'
|
||||||
|
}
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
import { NSFWPolicyType, UserRole } from '@shared/models'
|
|
||||||
import { peertubeLocalStorage } from '../peertube-web-storage'
|
|
||||||
import { UserLocalStorageKeys } from './user-local-storage-keys'
|
|
||||||
|
|
||||||
function getUserInfoFromLocalStorage () {
|
|
||||||
const usernameLocalStorage = peertubeLocalStorage.getItem(UserLocalStorageKeys.USERNAME)
|
|
||||||
|
|
||||||
if (!usernameLocalStorage) return undefined
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: parseInt(peertubeLocalStorage.getItem(UserLocalStorageKeys.ID), 10),
|
|
||||||
username: peertubeLocalStorage.getItem(UserLocalStorageKeys.USERNAME),
|
|
||||||
email: peertubeLocalStorage.getItem(UserLocalStorageKeys.EMAIL),
|
|
||||||
role: parseInt(peertubeLocalStorage.getItem(UserLocalStorageKeys.ROLE), 10) as UserRole,
|
|
||||||
nsfwPolicy: peertubeLocalStorage.getItem(UserLocalStorageKeys.NSFW_POLICY) as NSFWPolicyType,
|
|
||||||
webTorrentEnabled: peertubeLocalStorage.getItem(UserLocalStorageKeys.WEBTORRENT_ENABLED) === 'true',
|
|
||||||
autoPlayVideo: peertubeLocalStorage.getItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO) === 'true',
|
|
||||||
videosHistoryEnabled: peertubeLocalStorage.getItem(UserLocalStorageKeys.VIDEOS_HISTORY_ENABLED) === 'true'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function flushUserInfoFromLocalStorage () {
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.ID)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.USERNAME)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.EMAIL)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.ROLE)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.NSFW_POLICY)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.WEBTORRENT_ENABLED)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO)
|
|
||||||
peertubeLocalStorage.removeItem(UserLocalStorageKeys.VIDEOS_HISTORY_ENABLED)
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveUserInfoIntoLocalStorage (info: {
|
|
||||||
id: number
|
|
||||||
username: string
|
|
||||||
email: string
|
|
||||||
role: UserRole
|
|
||||||
nsfwPolicy: NSFWPolicyType
|
|
||||||
webTorrentEnabled: boolean
|
|
||||||
autoPlayVideo: boolean
|
|
||||||
}) {
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.ID, info.id.toString())
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.USERNAME, info.username)
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.EMAIL, info.email)
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.ROLE, info.role.toString())
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.NSFW_POLICY, info.nsfwPolicy.toString())
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.WEBTORRENT_ENABLED, JSON.stringify(info.webTorrentEnabled))
|
|
||||||
peertubeLocalStorage.setItem(UserLocalStorageKeys.AUTO_PLAY_VIDEO, JSON.stringify(info.autoPlayVideo))
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
getUserInfoFromLocalStorage,
|
|
||||||
saveUserInfoIntoLocalStorage,
|
|
||||||
flushUserInfoFromLocalStorage
|
|
||||||
}
|
|
|
@ -1,46 +1,11 @@
|
||||||
import { peertubeLocalStorage } from '../peertube-web-storage'
|
import { UserTokenLocalStorageKeys } from './user-local-storage-keys'
|
||||||
|
|
||||||
export type TokenOptions = {
|
|
||||||
accessToken: string
|
|
||||||
refreshToken: string
|
|
||||||
tokenType: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private class only used by User
|
|
||||||
export class Tokens {
|
|
||||||
private static KEYS = {
|
|
||||||
ACCESS_TOKEN: 'access_token',
|
|
||||||
REFRESH_TOKEN: 'refresh_token',
|
|
||||||
TOKEN_TYPE: 'token_type'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export class UserTokens {
|
||||||
accessToken: string
|
accessToken: string
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
tokenType: string
|
tokenType: string
|
||||||
|
|
||||||
static load () {
|
constructor (hash?: Partial<UserTokens>) {
|
||||||
const accessTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.ACCESS_TOKEN)
|
|
||||||
const refreshTokenLocalStorage = peertubeLocalStorage.getItem(this.KEYS.REFRESH_TOKEN)
|
|
||||||
const tokenTypeLocalStorage = peertubeLocalStorage.getItem(this.KEYS.TOKEN_TYPE)
|
|
||||||
|
|
||||||
if (accessTokenLocalStorage && refreshTokenLocalStorage && tokenTypeLocalStorage) {
|
|
||||||
return new Tokens({
|
|
||||||
accessToken: accessTokenLocalStorage,
|
|
||||||
refreshToken: refreshTokenLocalStorage,
|
|
||||||
tokenType: tokenTypeLocalStorage
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
static flush () {
|
|
||||||
peertubeLocalStorage.removeItem(this.KEYS.ACCESS_TOKEN)
|
|
||||||
peertubeLocalStorage.removeItem(this.KEYS.REFRESH_TOKEN)
|
|
||||||
peertubeLocalStorage.removeItem(this.KEYS.TOKEN_TYPE)
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor (hash?: TokenOptions) {
|
|
||||||
if (hash) {
|
if (hash) {
|
||||||
this.accessToken = hash.accessToken
|
this.accessToken = hash.accessToken
|
||||||
this.refreshToken = hash.refreshToken
|
this.refreshToken = hash.refreshToken
|
||||||
|
@ -53,9 +18,29 @@ export class Tokens {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
save () {
|
static getUserTokens (localStorage: Pick<Storage, 'getItem'>) {
|
||||||
peertubeLocalStorage.setItem(Tokens.KEYS.ACCESS_TOKEN, this.accessToken)
|
const accessTokenLocalStorage = localStorage.getItem(UserTokenLocalStorageKeys.ACCESS_TOKEN)
|
||||||
peertubeLocalStorage.setItem(Tokens.KEYS.REFRESH_TOKEN, this.refreshToken)
|
const refreshTokenLocalStorage = localStorage.getItem(UserTokenLocalStorageKeys.REFRESH_TOKEN)
|
||||||
peertubeLocalStorage.setItem(Tokens.KEYS.TOKEN_TYPE, this.tokenType)
|
const tokenTypeLocalStorage = localStorage.getItem(UserTokenLocalStorageKeys.TOKEN_TYPE)
|
||||||
|
|
||||||
|
if (!accessTokenLocalStorage || !refreshTokenLocalStorage || !tokenTypeLocalStorage) return null
|
||||||
|
|
||||||
|
return new UserTokens({
|
||||||
|
accessToken: accessTokenLocalStorage,
|
||||||
|
refreshToken: refreshTokenLocalStorage,
|
||||||
|
tokenType: tokenTypeLocalStorage
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static saveToLocalStorage (localStorage: Pick<Storage, 'setItem'>, tokens: UserTokens) {
|
||||||
|
localStorage.setItem(UserTokenLocalStorageKeys.ACCESS_TOKEN, tokens.accessToken)
|
||||||
|
localStorage.setItem(UserTokenLocalStorageKeys.REFRESH_TOKEN, tokens.refreshToken)
|
||||||
|
localStorage.setItem(UserTokenLocalStorageKeys.TOKEN_TYPE, tokens.tokenType)
|
||||||
|
}
|
||||||
|
|
||||||
|
static flushLocalStorage (localStorage: Pick<Storage, 'removeItem'>) {
|
||||||
|
localStorage.removeItem(UserTokenLocalStorageKeys.ACCESS_TOKEN)
|
||||||
|
localStorage.removeItem(UserTokenLocalStorageKeys.REFRESH_TOKEN)
|
||||||
|
localStorage.removeItem(UserTokenLocalStorageKeys.TOKEN_TYPE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
OAuth2ErrorCode,
|
OAuth2ErrorCode,
|
||||||
ResultList,
|
ResultList,
|
||||||
UserRefreshToken,
|
UserRefreshToken,
|
||||||
|
Video,
|
||||||
VideoCaption,
|
VideoCaption,
|
||||||
VideoDetails,
|
VideoDetails,
|
||||||
VideoPlaylist,
|
VideoPlaylist,
|
||||||
|
@ -16,9 +17,11 @@ import {
|
||||||
import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../assets/player/peertube-player-manager'
|
import { P2PMediaLoaderOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../assets/player/peertube-player-manager'
|
||||||
import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
|
import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
|
||||||
import { TranslationsManager } from '../../assets/player/translations-manager'
|
import { TranslationsManager } from '../../assets/player/translations-manager'
|
||||||
|
import { isP2PEnabled } from '../../assets/player/utils'
|
||||||
|
import { getBoolOrDefault } from '../../root-helpers/local-storage-utils'
|
||||||
import { peertubeLocalStorage } from '../../root-helpers/peertube-web-storage'
|
import { peertubeLocalStorage } from '../../root-helpers/peertube-web-storage'
|
||||||
import { PluginsManager } from '../../root-helpers/plugins-manager'
|
import { PluginsManager } from '../../root-helpers/plugins-manager'
|
||||||
import { Tokens } from '../../root-helpers/users'
|
import { UserLocalStorageKeys, UserTokens } from '../../root-helpers/users'
|
||||||
import { objectToUrlEncoded } from '../../root-helpers/utils'
|
import { objectToUrlEncoded } from '../../root-helpers/utils'
|
||||||
import { RegisterClientHelpers } from '../../types/register-client-option.model'
|
import { RegisterClientHelpers } from '../../types/register-client-option.model'
|
||||||
import { PeerTubeEmbedApi } from './embed-api'
|
import { PeerTubeEmbedApi } from './embed-api'
|
||||||
|
@ -48,7 +51,7 @@ export class PeerTubeEmbed {
|
||||||
mode: PlayerMode
|
mode: PlayerMode
|
||||||
scope = 'peertube'
|
scope = 'peertube'
|
||||||
|
|
||||||
userTokens: Tokens
|
userTokens: UserTokens
|
||||||
headers = new Headers()
|
headers = new Headers()
|
||||||
LOCAL_STORAGE_OAUTH_CLIENT_KEYS = {
|
LOCAL_STORAGE_OAUTH_CLIENT_KEYS = {
|
||||||
CLIENT_ID: 'client_id',
|
CLIENT_ID: 'client_id',
|
||||||
|
@ -118,7 +121,7 @@ export class PeerTubeEmbed {
|
||||||
return res.json()
|
return res.json()
|
||||||
}).then((obj: UserRefreshToken & { code?: OAuth2ErrorCode }) => {
|
}).then((obj: UserRefreshToken & { code?: OAuth2ErrorCode }) => {
|
||||||
if (!obj || obj.code === OAuth2ErrorCode.INVALID_GRANT) {
|
if (!obj || obj.code === OAuth2ErrorCode.INVALID_GRANT) {
|
||||||
Tokens.flush()
|
UserTokens.flushLocalStorage(peertubeLocalStorage)
|
||||||
this.removeTokensFromHeaders()
|
this.removeTokensFromHeaders()
|
||||||
|
|
||||||
return resolve()
|
return resolve()
|
||||||
|
@ -126,7 +129,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
this.userTokens.accessToken = obj.access_token
|
this.userTokens.accessToken = obj.access_token
|
||||||
this.userTokens.refreshToken = obj.refresh_token
|
this.userTokens.refreshToken = obj.refresh_token
|
||||||
this.userTokens.save()
|
UserTokens.saveToLocalStorage(peertubeLocalStorage, this.userTokens)
|
||||||
|
|
||||||
this.setHeadersFromTokens()
|
this.setHeadersFromTokens()
|
||||||
|
|
||||||
|
@ -138,7 +141,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
return refreshingTokenPromise
|
return refreshingTokenPromise
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
Tokens.flush()
|
UserTokens.flushLocalStorage(peertubeLocalStorage)
|
||||||
|
|
||||||
this.removeTokensFromHeaders()
|
this.removeTokensFromHeaders()
|
||||||
}).then(() => fetch(url, {
|
}).then(() => fetch(url, {
|
||||||
|
@ -258,7 +261,7 @@ export class PeerTubeEmbed {
|
||||||
}
|
}
|
||||||
|
|
||||||
async init () {
|
async init () {
|
||||||
this.userTokens = Tokens.load()
|
this.userTokens = UserTokens.getUserTokens(peertubeLocalStorage)
|
||||||
await this.initCore()
|
await this.initCore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,6 +518,8 @@ export class PeerTubeEmbed {
|
||||||
muted: this.muted,
|
muted: this.muted,
|
||||||
loop: this.loop,
|
loop: this.loop,
|
||||||
|
|
||||||
|
p2pEnabled: this.isP2PEnabled(videoInfo),
|
||||||
|
|
||||||
captions: videoCaptions.length !== 0,
|
captions: videoCaptions.length !== 0,
|
||||||
subtitle: this.subtitle,
|
subtitle: this.subtitle,
|
||||||
|
|
||||||
|
@ -669,7 +674,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
const title = this.title ? videoInfo.name : undefined
|
const title = this.title ? videoInfo.name : undefined
|
||||||
|
|
||||||
const description = this.warningTitle && (!videoInfo.isLocal || this.config.tracker.enabled)
|
const description = this.warningTitle && this.isP2PEnabled(videoInfo)
|
||||||
? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>'
|
? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>'
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
|
@ -784,6 +789,15 @@ export class PeerTubeEmbed {
|
||||||
translate: (value: string) => Promise.resolve(peertubeTranslate(value, translations))
|
translate: (value: string) => Promise.resolve(peertubeTranslate(value, translations))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isP2PEnabled (video: Video) {
|
||||||
|
const userP2PEnabled = getBoolOrDefault(
|
||||||
|
peertubeLocalStorage.getItem(UserLocalStorageKeys.P2P_ENABLED),
|
||||||
|
this.config.defaults.p2p.enabled
|
||||||
|
)
|
||||||
|
|
||||||
|
return isP2PEnabled(video, this.config, userP2PEnabled)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerTubeEmbed.main()
|
PeerTubeEmbed.main()
|
||||||
|
|
|
@ -92,6 +92,11 @@ defaults:
|
||||||
# No licence by default
|
# No licence by default
|
||||||
licence: null
|
licence: null
|
||||||
|
|
||||||
|
p2p:
|
||||||
|
# Enable P2P by default
|
||||||
|
# Can be enabled/disabled by anonymous users and logged in users
|
||||||
|
enabled: true
|
||||||
|
|
||||||
# From the project root directory
|
# From the project root directory
|
||||||
storage:
|
storage:
|
||||||
tmp: 'storage/tmp/' # Use to download data (imports etc), store uploaded files before and during processing...
|
tmp: 'storage/tmp/' # Use to download data (imports etc), store uploaded files before and during processing...
|
||||||
|
@ -216,7 +221,7 @@ security:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
tracker:
|
tracker:
|
||||||
# If you disable the tracker, you disable the P2P aspect of PeerTube
|
# If you disable the tracker, you disable the P2P on your PeerTube instance
|
||||||
enabled: true
|
enabled: true
|
||||||
# Only handle requests on your videos
|
# Only handle requests on your videos
|
||||||
# If you set this to false it means you have a public tracker
|
# If you set this to false it means you have a public tracker
|
||||||
|
|
|
@ -90,6 +90,11 @@ defaults:
|
||||||
# No licence by default
|
# No licence by default
|
||||||
licence: null
|
licence: null
|
||||||
|
|
||||||
|
p2p:
|
||||||
|
# Enable P2P by default
|
||||||
|
# Can be enabled/disabled by anonymous users and logged in users
|
||||||
|
enabled: true
|
||||||
|
|
||||||
# From the project root directory
|
# From the project root directory
|
||||||
storage:
|
storage:
|
||||||
tmp: '/var/www/peertube/storage/tmp/' # Use to download data (imports etc), store uploaded files before and during processing...
|
tmp: '/var/www/peertube/storage/tmp/' # Use to download data (imports etc), store uploaded files before and during processing...
|
||||||
|
|
|
@ -183,6 +183,7 @@ async function createUser (req: express.Request, res: express.Response) {
|
||||||
password: body.password,
|
password: body.password,
|
||||||
email: body.email,
|
email: body.email,
|
||||||
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
||||||
|
p2pEnabled: CONFIG.DEFAULTS.P2P.ENABLED,
|
||||||
autoPlayVideo: true,
|
autoPlayVideo: true,
|
||||||
role: body.role,
|
role: body.role,
|
||||||
videoQuota: body.videoQuota,
|
videoQuota: body.videoQuota,
|
||||||
|
@ -232,6 +233,7 @@ async function registerUser (req: express.Request, res: express.Response) {
|
||||||
password: body.password,
|
password: body.password,
|
||||||
email: body.email,
|
email: body.email,
|
||||||
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
||||||
|
p2pEnabled: CONFIG.DEFAULTS.P2P.ENABLED,
|
||||||
autoPlayVideo: true,
|
autoPlayVideo: true,
|
||||||
role: UserRole.USER,
|
role: UserRole.USER,
|
||||||
videoQuota: CONFIG.USER.VIDEO_QUOTA,
|
videoQuota: CONFIG.USER.VIDEO_QUOTA,
|
||||||
|
|
|
@ -197,7 +197,7 @@ async function updateMe (req: express.Request, res: express.Response) {
|
||||||
const keysToUpdate: (keyof UserUpdateMe & keyof AttributesOnly<UserModel>)[] = [
|
const keysToUpdate: (keyof UserUpdateMe & keyof AttributesOnly<UserModel>)[] = [
|
||||||
'password',
|
'password',
|
||||||
'nsfwPolicy',
|
'nsfwPolicy',
|
||||||
'webTorrentEnabled',
|
'p2pEnabled',
|
||||||
'autoPlayVideo',
|
'autoPlayVideo',
|
||||||
'autoPlayNextVideo',
|
'autoPlayNextVideo',
|
||||||
'autoPlayNextVideoPlaylist',
|
'autoPlayNextVideoPlaylist',
|
||||||
|
@ -213,6 +213,12 @@ async function updateMe (req: express.Request, res: express.Response) {
|
||||||
if (body[key] !== undefined) user.set(key, body[key])
|
if (body[key] !== undefined) user.set(key, body[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (body.p2pEnabled !== undefined) {
|
||||||
|
user.set('p2pEnabled', body.p2pEnabled)
|
||||||
|
} else if (body.webTorrentEnabled !== undefined) { // FIXME: deprecated in 4.1
|
||||||
|
user.set('p2pEnabled', body.webTorrentEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
if (body.email !== undefined) {
|
if (body.email !== undefined) {
|
||||||
if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
|
if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
|
||||||
user.pendingEmail = body.email
|
user.pendingEmail = body.email
|
||||||
|
|
|
@ -49,7 +49,7 @@ function isUserNSFWPolicyValid (value: any) {
|
||||||
return exists(value) && nsfwPolicies.includes(value)
|
return exists(value) && nsfwPolicies.includes(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isUserWebTorrentEnabledValid (value: any) {
|
function isUserP2PEnabledValid (value: any) {
|
||||||
return isBooleanValid(value)
|
return isBooleanValid(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ export {
|
||||||
isUserAdminFlagsValid,
|
isUserAdminFlagsValid,
|
||||||
isUserEmailVerifiedValid,
|
isUserEmailVerifiedValid,
|
||||||
isUserNSFWPolicyValid,
|
isUserNSFWPolicyValid,
|
||||||
isUserWebTorrentEnabledValid,
|
isUserP2PEnabledValid,
|
||||||
isUserAutoPlayVideoValid,
|
isUserAutoPlayVideoValid,
|
||||||
isUserAutoPlayNextVideoValid,
|
isUserAutoPlayNextVideoValid,
|
||||||
isUserAutoPlayNextVideoPlaylistValid,
|
isUserAutoPlayNextVideoPlaylistValid,
|
||||||
|
|
|
@ -78,6 +78,9 @@ const CONFIG = {
|
||||||
COMMENTS_ENABLED: config.get<boolean>('defaults.publish.comments_enabled'),
|
COMMENTS_ENABLED: config.get<boolean>('defaults.publish.comments_enabled'),
|
||||||
PRIVACY: config.get<VideoPrivacy>('defaults.publish.privacy'),
|
PRIVACY: config.get<VideoPrivacy>('defaults.publish.privacy'),
|
||||||
LICENCE: config.get<number>('defaults.publish.licence')
|
LICENCE: config.get<number>('defaults.publish.licence')
|
||||||
|
},
|
||||||
|
P2P: {
|
||||||
|
ENABLED: config.get<boolean>('defaults.p2p.enabled')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const LAST_MIGRATION_VERSION = 670
|
const LAST_MIGRATION_VERSION = 675
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,7 @@ async function createOAuthAdminIfNotExist () {
|
||||||
role,
|
role,
|
||||||
verified: true,
|
verified: true,
|
||||||
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
||||||
|
p2pEnabled: CONFIG.DEFAULTS.P2P.ENABLED,
|
||||||
videoQuota: -1,
|
videoQuota: -1,
|
||||||
videoQuotaDaily: -1
|
videoQuotaDaily: -1
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
|
||||||
|
async function up (utils: {
|
||||||
|
transaction: Sequelize.Transaction
|
||||||
|
queryInterface: Sequelize.QueryInterface
|
||||||
|
sequelize: Sequelize.Sequelize
|
||||||
|
db: any
|
||||||
|
}): Promise<void> {
|
||||||
|
await utils.queryInterface.renameColumn('user', 'webTorrentEnabled', 'p2pEnabled')
|
||||||
|
|
||||||
|
await utils.sequelize.query('ALTER TABLE "user" ALTER COLUMN "p2pEnabled" DROP DEFAULT')
|
||||||
|
}
|
||||||
|
|
||||||
|
function down (options) {
|
||||||
|
throw new Error('Not implemented.')
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
up,
|
||||||
|
down
|
||||||
|
}
|
|
@ -226,6 +226,7 @@ async function createUserFromExternal (pluginAuth: string, options: {
|
||||||
password: null,
|
password: null,
|
||||||
email: options.email,
|
email: options.email,
|
||||||
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
|
||||||
|
p2pEnabled: CONFIG.DEFAULTS.P2P.ENABLED,
|
||||||
autoPlayVideo: true,
|
autoPlayVideo: true,
|
||||||
role: options.role,
|
role: options.role,
|
||||||
videoQuota: CONFIG.USER.VIDEO_QUOTA,
|
videoQuota: CONFIG.USER.VIDEO_QUOTA,
|
||||||
|
|
|
@ -61,6 +61,9 @@ class ServerConfigManager {
|
||||||
commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
|
commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
|
||||||
privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY,
|
privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY,
|
||||||
licence: CONFIG.DEFAULTS.PUBLISH.LICENCE
|
licence: CONFIG.DEFAULTS.PUBLISH.LICENCE
|
||||||
|
},
|
||||||
|
p2p: {
|
||||||
|
enabled: CONFIG.DEFAULTS.P2P.ENABLED
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
isUserDisplayNameValid,
|
isUserDisplayNameValid,
|
||||||
isUserNoModal,
|
isUserNoModal,
|
||||||
isUserNSFWPolicyValid,
|
isUserNSFWPolicyValid,
|
||||||
|
isUserP2PEnabledValid,
|
||||||
isUserPasswordValid,
|
isUserPasswordValid,
|
||||||
isUserPasswordValidOrEmpty,
|
isUserPasswordValidOrEmpty,
|
||||||
isUserRoleValid,
|
isUserRoleValid,
|
||||||
|
@ -239,6 +240,9 @@ const usersUpdateMeValidator = [
|
||||||
body('autoPlayVideo')
|
body('autoPlayVideo')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'),
|
.custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'),
|
||||||
|
body('p2pEnabled')
|
||||||
|
.optional()
|
||||||
|
.custom(isUserP2PEnabledValid).withMessage('Should have a valid p2p enabled boolean'),
|
||||||
body('videoLanguages')
|
body('videoLanguages')
|
||||||
.optional()
|
.optional()
|
||||||
.custom(isUserVideoLanguages).withMessage('Should have a valid video languages attribute'),
|
.custom(isUserVideoLanguages).withMessage('Should have a valid video languages attribute'),
|
||||||
|
|
|
@ -55,7 +55,7 @@ import {
|
||||||
isUserVideoQuotaDailyValid,
|
isUserVideoQuotaDailyValid,
|
||||||
isUserVideoQuotaValid,
|
isUserVideoQuotaValid,
|
||||||
isUserVideosHistoryEnabledValid,
|
isUserVideosHistoryEnabledValid,
|
||||||
isUserWebTorrentEnabledValid
|
isUserP2PEnabledValid
|
||||||
} from '../../helpers/custom-validators/users'
|
} from '../../helpers/custom-validators/users'
|
||||||
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
|
import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto'
|
||||||
import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants'
|
import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants'
|
||||||
|
@ -267,10 +267,9 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
|
||||||
nsfwPolicy: NSFWPolicyType
|
nsfwPolicy: NSFWPolicyType
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(true)
|
@Is('p2pEnabled', value => throwIfNotValid(value, isUserP2PEnabledValid, 'P2P enabled'))
|
||||||
@Is('UserWebTorrentEnabled', value => throwIfNotValid(value, isUserWebTorrentEnabledValid, 'WebTorrent enabled'))
|
|
||||||
@Column
|
@Column
|
||||||
webTorrentEnabled: boolean
|
p2pEnabled: boolean
|
||||||
|
|
||||||
@AllowNull(false)
|
@AllowNull(false)
|
||||||
@Default(true)
|
@Default(true)
|
||||||
|
@ -892,7 +891,11 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> {
|
||||||
emailVerified: this.emailVerified,
|
emailVerified: this.emailVerified,
|
||||||
|
|
||||||
nsfwPolicy: this.nsfwPolicy,
|
nsfwPolicy: this.nsfwPolicy,
|
||||||
webTorrentEnabled: this.webTorrentEnabled,
|
|
||||||
|
// FIXME: deprecated in 4.1
|
||||||
|
webTorrentEnabled: this.p2pEnabled,
|
||||||
|
p2pEnabled: this.p2pEnabled,
|
||||||
|
|
||||||
videosHistoryEnabled: this.videosHistoryEnabled,
|
videosHistoryEnabled: this.videosHistoryEnabled,
|
||||||
autoPlayVideo: this.autoPlayVideo,
|
autoPlayVideo: this.autoPlayVideo,
|
||||||
autoPlayNextVideo: this.autoPlayNextVideo,
|
autoPlayNextVideo: this.autoPlayNextVideo,
|
||||||
|
|
|
@ -21,18 +21,7 @@ describe('Test config defaults', function () {
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(30000)
|
this.timeout(30000)
|
||||||
|
|
||||||
const overrideConfig = {
|
server = await createSingleServer(1)
|
||||||
defaults: {
|
|
||||||
publish: {
|
|
||||||
comments_enabled: false,
|
|
||||||
download_enabled: false,
|
|
||||||
privacy: VideoPrivacy.INTERNAL,
|
|
||||||
licence: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server = await createSingleServer(1, overrideConfig)
|
|
||||||
await setAccessTokensToServers([ server ])
|
await setAccessTokensToServers([ server ])
|
||||||
await setDefaultVideoChannel([ server ])
|
await setDefaultVideoChannel([ server ])
|
||||||
|
|
||||||
|
@ -40,6 +29,23 @@ describe('Test config defaults', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Default publish values', function () {
|
describe('Default publish values', function () {
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
const overrideConfig = {
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
comments_enabled: false,
|
||||||
|
download_enabled: false,
|
||||||
|
privacy: VideoPrivacy.INTERNAL,
|
||||||
|
licence: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await server.kill()
|
||||||
|
await server.run(overrideConfig)
|
||||||
|
})
|
||||||
|
|
||||||
const attributes = {
|
const attributes = {
|
||||||
name: 'video',
|
name: 'video',
|
||||||
downloadEnabled: undefined,
|
downloadEnabled: undefined,
|
||||||
|
@ -117,6 +123,45 @@ describe('Test config defaults', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Default P2P values', function () {
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
const overrideConfig = {
|
||||||
|
defaults: {
|
||||||
|
p2p: {
|
||||||
|
enabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await server.kill()
|
||||||
|
await server.run(overrideConfig)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should not have P2P enabled', async function () {
|
||||||
|
const config = await server.config.getConfig()
|
||||||
|
|
||||||
|
expect(config.defaults.p2p.enabled).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should create a user with this default setting', async function () {
|
||||||
|
await server.users.create({ username: 'user_p2p_1' })
|
||||||
|
const userToken = await server.login.getAccessToken('user_p2p_1')
|
||||||
|
|
||||||
|
const { p2pEnabled } = await server.users.getMyInfo({ token: userToken })
|
||||||
|
expect(p2pEnabled).to.be.false
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should register a user with this default setting', async function () {
|
||||||
|
await server.users.register({ username: 'user_p2p_2' })
|
||||||
|
|
||||||
|
const userToken = await server.login.getAccessToken('user_p2p_2')
|
||||||
|
|
||||||
|
const { p2pEnabled } = await server.users.getMyInfo({ token: userToken })
|
||||||
|
expect(p2pEnabled).to.be.false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
await cleanupTests([ server ])
|
await cleanupTests([ server ])
|
||||||
})
|
})
|
||||||
|
|
|
@ -292,7 +292,7 @@ describe('Test follows', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () {
|
it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () {
|
||||||
this.timeout(60000)
|
this.timeout(120000)
|
||||||
|
|
||||||
await servers[1].videos.upload({ attributes: { name: 'server2' } })
|
await servers[1].videos.upload({ attributes: { name: 'server2' } })
|
||||||
await servers[2].videos.upload({ attributes: { name: 'server3' } })
|
await servers[2].videos.upload({ attributes: { name: 'server3' } })
|
||||||
|
|
|
@ -559,6 +559,28 @@ describe('Test users', function () {
|
||||||
expect(user.autoPlayNextVideo).to.be.true
|
expect(user.autoPlayNextVideo).to.be.true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should be able to change the p2p attribute', async function () {
|
||||||
|
{
|
||||||
|
await server.users.updateMe({
|
||||||
|
token: userToken,
|
||||||
|
webTorrentEnabled: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const user = await server.users.getMyInfo({ token: userToken })
|
||||||
|
expect(user.p2pEnabled).to.be.false
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
await server.users.updateMe({
|
||||||
|
token: userToken,
|
||||||
|
p2pEnabled: true
|
||||||
|
})
|
||||||
|
|
||||||
|
const user = await server.users.getMyInfo({ token: userToken })
|
||||||
|
expect(user.p2pEnabled).to.be.true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('Should be able to change the email attribute', async function () {
|
it('Should be able to change the email attribute', async function () {
|
||||||
await server.users.updateMe({
|
await server.users.updateMe({
|
||||||
token: userToken,
|
token: userToken,
|
||||||
|
|
|
@ -55,6 +55,10 @@ export interface ServerConfig {
|
||||||
privacy: VideoPrivacy
|
privacy: VideoPrivacy
|
||||||
licence: number
|
licence: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p2p: {
|
||||||
|
enabled: boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
webadmin: {
|
webadmin: {
|
||||||
|
|
|
@ -5,7 +5,10 @@ export interface UserUpdateMe {
|
||||||
description?: string
|
description?: string
|
||||||
nsfwPolicy?: NSFWPolicyType
|
nsfwPolicy?: NSFWPolicyType
|
||||||
|
|
||||||
|
// FIXME: deprecated in favour of p2pEnabled in 4.1
|
||||||
webTorrentEnabled?: boolean
|
webTorrentEnabled?: boolean
|
||||||
|
p2pEnabled?: boolean
|
||||||
|
|
||||||
autoPlayVideo?: boolean
|
autoPlayVideo?: boolean
|
||||||
autoPlayNextVideo?: boolean
|
autoPlayNextVideo?: boolean
|
||||||
autoPlayNextVideoPlaylist?: boolean
|
autoPlayNextVideoPlaylist?: boolean
|
||||||
|
|
|
@ -20,7 +20,11 @@ export interface User {
|
||||||
autoPlayVideo: boolean
|
autoPlayVideo: boolean
|
||||||
autoPlayNextVideo: boolean
|
autoPlayNextVideo: boolean
|
||||||
autoPlayNextVideoPlaylist: boolean
|
autoPlayNextVideoPlaylist: boolean
|
||||||
|
|
||||||
|
// @deprecated in favour of p2pEnabled
|
||||||
webTorrentEnabled: boolean
|
webTorrentEnabled: boolean
|
||||||
|
p2pEnabled: boolean
|
||||||
|
|
||||||
videosHistoryEnabled: boolean
|
videosHistoryEnabled: boolean
|
||||||
videoLanguages: string[]
|
videoLanguages: string[]
|
||||||
|
|
||||||
|
|
|
@ -6679,7 +6679,7 @@ components:
|
||||||
type: integer
|
type: integer
|
||||||
description: The user daily video quota in bytes
|
description: The user daily video quota in bytes
|
||||||
example: -1
|
example: -1
|
||||||
webtorrentEnabled:
|
p2pEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: Enable P2P in the player
|
description: Enable P2P in the player
|
||||||
UserWithStats:
|
UserWithStats:
|
||||||
|
@ -6780,7 +6780,7 @@ components:
|
||||||
- 'true'
|
- 'true'
|
||||||
- 'false'
|
- 'false'
|
||||||
- both
|
- both
|
||||||
webTorrentEnabled:
|
p2pEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: whether to enable P2P in the player or not
|
description: whether to enable P2P in the player or not
|
||||||
autoPlayVideo:
|
autoPlayVideo:
|
||||||
|
|
Loading…
Reference in New Issue