Lazy load static objects

pull/2356/head
Chocobozzz 2019-12-18 15:31:54 +01:00
parent 5dfb7c1dec
commit ba430d7516
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
55 changed files with 554 additions and 365 deletions

View File

@ -5,7 +5,8 @@ import { ContactAdminModalComponent } from '@app/+about/about-instance/contact-a
import { InstanceService } from '@app/shared/instance/instance.service'
import { MarkdownService } from '@app/shared/renderer'
import { forkJoin } from 'rxjs'
import { first } from 'rxjs/operators'
import { map, switchMap } from 'rxjs/operators'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-about-instance',
@ -33,6 +34,8 @@ export class AboutInstanceComponent implements OnInit {
languages: string[] = []
categories: string[] = []
serverConfig: ServerConfig
constructor (
private notifier: Notifier,
private serverService: ServerService,
@ -42,25 +45,35 @@ export class AboutInstanceComponent implements OnInit {
) {}
get instanceName () {
return this.serverService.getConfig().instance.name
return this.serverConfig.instance.name
}
get isContactFormEnabled () {
return this.serverService.getConfig().email.enabled && this.serverService.getConfig().contactForm.enabled
return this.serverConfig.email.enabled && this.serverConfig.contactForm.enabled
}
get isNSFW () {
return this.serverService.getConfig().instance.isNSFW
return this.serverConfig.instance.isNSFW
}
ngOnInit () {
forkJoin([
this.instanceService.getAbout(),
this.serverService.localeObservable.pipe(first()),
this.serverService.videoLanguagesLoaded.pipe(first()),
this.serverService.videoCategoriesLoaded.pipe(first())
]).subscribe(
async ([ about, translations ]) => {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.instanceService.getAbout()
.pipe(
switchMap(about => {
return forkJoin([
this.instanceService.buildTranslatedLanguages(about),
this.instanceService.buildTranslatedCategories(about)
]).pipe(map(([ languages, categories ]) => ({ about, languages, categories })))
})
).subscribe(
async ({ about, languages, categories }) => {
this.languages = languages
this.categories = categories
this.shortDescription = about.instance.shortDescription
this.creationReason = about.instance.creationReason
@ -68,9 +81,6 @@ export class AboutInstanceComponent implements OnInit {
this.businessModel = about.instance.businessModel
this.html = await this.instanceService.buildHtml(about)
this.languages = this.instanceService.buildTranslatedLanguages(about, translations)
this.categories = this.instanceService.buildTranslatedCategories(about, translations)
},
() => this.notifier.error(this.i18n('Cannot get about information from server'))

View File

@ -6,6 +6,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
import { FormReactive, InstanceValidatorsService } from '@app/shared'
import { InstanceService } from '@app/shared/instance/instance.service'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-contact-admin-modal',
@ -18,6 +19,7 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
error: string
private openedModal: NgbModalRef
private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
@ -32,10 +34,14 @@ export class ContactAdminModalComponent extends FormReactive implements OnInit {
}
get instanceName () {
return this.serverService.getConfig().instance.name
return this.serverConfig.instance.name
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.buildForm({
fromName: this.instanceValidatorsService.FROM_NAME,
fromEmail: this.instanceValidatorsService.FROM_EMAIL,

View File

@ -8,7 +8,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { SelectItem } from 'primeng/api'
import { forkJoin } from 'rxjs'
import { first } from 'rxjs/operators'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-edit-custom-config',
@ -24,6 +24,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
languageItems: SelectItem[] = []
categoryItems: SelectItem[] = []
private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
private customConfigValidatorsService: CustomConfigValidatorsService,
@ -84,7 +86,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
}
get availableThemes () {
return this.serverService.getConfig().theme.registered
return this.serverConfig.theme.registered
.map(t => t.name)
}
@ -93,6 +95,10 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
const formGroupData: { [key in keyof CustomConfig ]: any } = {
instance: {
name: this.customConfigValidatorsService.INSTANCE_NAME,
@ -218,16 +224,13 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
forkJoin([
this.configService.getCustomConfig(),
this.serverService.videoLanguagesLoaded.pipe(first()), // First so the observable completes
this.serverService.videoCategoriesLoaded.pipe(first())
this.serverService.getVideoLanguages(),
this.serverService.getVideoCategories()
]).subscribe(
([ config ]) => {
([ config, languages, categories ]) => {
this.customConfig = config
const languages = this.serverService.getVideoLanguages()
this.languageItems = languages.map(l => ({ label: l.label, value: l.id }))
const categories = this.serverService.getVideoCategories()
this.categoryItems = categories.map(l => ({ label: l.label, value: l.id }))
this.updateForm()
@ -249,12 +252,14 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
async formValidated () {
this.configService.updateCustomConfig(this.form.value)
.pipe(
)
.subscribe(
res => {
this.customConfig = res
// Reload general configuration
this.serverService.loadConfig()
this.serverService.resetConfig()
this.updateForm()

View File

@ -1,4 +1,4 @@
import { Component } from '@angular/core'
import { Component, OnInit } from '@angular/core'
import { UserRight } from '../../../../../shared'
import { AuthService, ServerService } from '@app/core'
@ -6,14 +6,18 @@ import { AuthService, ServerService } from '@app/core'
templateUrl: './moderation.component.html',
styleUrls: [ './moderation.component.scss' ]
})
export class ModerationComponent {
autoBlacklistVideosEnabled: boolean
export class ModerationComponent implements OnInit {
autoBlacklistVideosEnabled = false
constructor (
private auth: AuthService,
private serverService: ServerService
) {
this.autoBlacklistVideosEnabled = this.serverService.getConfig().autoBlacklist.videos.ofUsers.enabled
) { }
ngOnInit (): void {
this.serverService.getConfig()
.subscribe(config => this.autoBlacklistVideosEnabled = config.autoBlacklist.videos.ofUsers.enabled)
}
hasVideoAbusesRight () {

View File

@ -33,11 +33,18 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
private i18n: I18n
) {
super()
}
// don't filter if auto-blacklist not enabled as this will be only list
if (this.serverService.getConfig().autoBlacklist.videos.ofUsers.enabled) {
this.listBlacklistTypeFilter = VideoBlacklistType.MANUAL
}
ngOnInit () {
this.serverService.getConfig()
.subscribe(config => {
// don't filter if auto-blacklist not enabled as this will be only list
if (config.autoBlacklist.videos.ofUsers.enabled) {
this.listBlacklistTypeFilter = VideoBlacklistType.MANUAL
}
})
this.initialize()
this.videoBlacklistActions = [
{
@ -47,10 +54,6 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit {
]
}
ngOnInit () {
this.initialize()
}
getVideoUrl (videoBlacklist: VideoBlacklist) {
return Video.buildClientUrl(videoBlacklist.video.uuid)
}

View File

@ -34,6 +34,8 @@ export class UserCreateComponent extends UserEdit implements OnInit {
}
ngOnInit () {
super.ngOnInit()
const defaultValues = {
role: UserRole.USER.toString(),
videoQuota: '-1',

View File

@ -1,21 +1,30 @@
import { AuthService, ServerService } from '../../../core'
import { FormReactive } from '../../../shared'
import { USER_ROLE_LABELS, UserRole, VideoResolution } from '../../../../../../shared'
import { ServerConfig, USER_ROLE_LABELS, UserRole, VideoResolution } from '../../../../../../shared'
import { ConfigService } from '@app/+admin/config/shared/config.service'
import { UserAdminFlag } from '@shared/models/users/user-flag.model'
import { OnInit } from '@angular/core'
export abstract class UserEdit extends FormReactive {
export abstract class UserEdit extends FormReactive implements OnInit {
videoQuotaOptions: { value: string, label: string }[] = []
videoQuotaDailyOptions: { value: string, label: string }[] = []
username: string
userId: number
protected serverConfig: ServerConfig
protected abstract serverService: ServerService
protected abstract configService: ConfigService
protected abstract auth: AuthService
abstract isCreation (): boolean
abstract getFormButtonTitle (): string
ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
}
getRoles () {
const authUser = this.auth.getUser()
@ -32,12 +41,12 @@ export abstract class UserEdit extends FormReactive {
isTranscodingInformationDisplayed () {
const formVideoQuota = parseInt(this.form.value['videoQuota'], 10)
return this.serverService.getConfig().transcoding.enabledResolutions.length !== 0 &&
return this.serverConfig.transcoding.enabledResolutions.length !== 0 &&
formVideoQuota > 0
}
computeQuotaWithTranscoding () {
const transcodingConfig = this.serverService.getConfig().transcoding
const transcodingConfig = this.serverConfig.transcoding
const resolutions = transcodingConfig.enabledResolutions
const higherResolution = VideoResolution.H_4K

View File

@ -43,6 +43,8 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy {
}
ngOnInit () {
super.ngOnInit()
const defaultValues = { videoQuota: '-1', videoQuotaDaily: '-1' }
this.buildForm({
email: this.userValidatorsService.USER_EMAIL,

View File

@ -4,7 +4,7 @@ import { SortMeta } from 'primeng/components/common/sortmeta'
import { ConfirmService, ServerService } from '../../../core'
import { RestPagination, RestTable, UserService } from '../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { User } from '../../../../../../shared'
import { ServerConfig, User } from '../../../../../../shared'
import { UserBanModalComponent } from '@app/shared/moderation'
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
@ -25,6 +25,8 @@ export class UserListComponent extends RestTable implements OnInit {
selectedUsers: User[] = []
bulkUserActions: DropdownAction<User[]>[] = []
private serverConfig: ServerConfig
constructor (
private notifier: Notifier,
private confirmService: ConfirmService,
@ -41,10 +43,14 @@ export class UserListComponent extends RestTable implements OnInit {
}
get requiresEmailVerification () {
return this.serverService.getConfig().signup.requiresEmailVerification
return this.serverConfig.signup.requiresEmailVerification
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.initialize()
this.bulkUserActions = [

View File

@ -6,6 +6,7 @@ import { FormValidatorService } from '@app/shared/forms/form-validators/form-val
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
import { User } from '../../../../../../shared'
import { tap } from 'rxjs/operators'
import { forkJoin } from 'rxjs'
@Component({
selector: 'my-account-change-email',
@ -45,29 +46,29 @@ export class MyAccountChangeEmailComponent extends FormReactive implements OnIni
const password = this.form.value[ 'password' ]
const email = this.form.value[ 'new-email' ]
this.userService.changeEmail(password, email)
.pipe(
tap(() => this.authService.refreshUserInformation())
)
.subscribe(
() => {
this.form.reset()
forkJoin([
this.serverService.getConfig(),
this.userService.changeEmail(password, email)
]).pipe(tap(() => this.authService.refreshUserInformation()))
.subscribe(
([ config ]) => {
this.form.reset()
if (this.serverService.getConfig().signup.requiresEmailVerification) {
this.success = this.i18n('Please check your emails to verify your new email.')
} else {
this.success = this.i18n('Email updated.')
}
},
err => {
if (err.status === 401) {
this.error = this.i18n('You current password is invalid.')
return
}
this.error = err.message
if (config.signup.requiresEmailVerification) {
this.success = this.i18n('Please check your emails to verify your new email.')
} else {
this.success = this.i18n('Email updated.')
}
)
},
err => {
if (err.status === 401) {
this.error = this.i18n('You current password is invalid.')
return
}
this.error = err.message
}
)
}
}

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'
import { Notifier, ServerService } from '@app/core'
import { UserUpdateMe } from '../../../../../../shared'
import { ServerConfig, UserUpdateMe } from '../../../../../../shared'
import { AuthService } from '../../../core'
import { FormReactive, User, UserService } from '../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
@ -16,6 +16,8 @@ export class MyAccountInterfaceSettingsComponent extends FormReactive implements
@Input() user: User = null
@Input() userInformationLoaded: Subject<any>
private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
private authService: AuthService,
@ -28,11 +30,15 @@ export class MyAccountInterfaceSettingsComponent extends FormReactive implements
}
get availableThemes () {
return this.serverService.getConfig().theme.registered
return this.serverConfig.theme.registered
.map(t => t.name)
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.buildForm({
theme: null
})

View File

@ -21,7 +21,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
webNotifications: { [ id in keyof UserNotificationSetting ]: boolean } = {} as any
labelNotifications: { [ id in keyof UserNotificationSetting ]: string } = {} as any
rightNotifications: { [ id in keyof Partial<UserNotificationSetting> ]: UserRight } = {} as any
emailEnabled: boolean
emailEnabled = false
private savePreferences = debounce(this.savePreferencesImpl.bind(this), 500)
@ -31,7 +31,6 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
private serverService: ServerService,
private notifier: Notifier
) {
this.labelNotifications = {
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
newCommentOnMyVideo: this.i18n('New comment on your video'),
@ -55,11 +54,14 @@ export class MyAccountNotificationPreferencesComponent implements OnInit {
newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW,
autoInstanceFollowing: UserRight.MANAGE_CONFIGURATION
}
this.emailEnabled = this.serverService.getConfig().email.enabled
}
ngOnInit () {
this.serverService.getConfig()
.subscribe(config => {
this.emailEnabled = config.email.enabled
})
this.userInformationLoaded.subscribe(() => this.loadNotificationSettings())
}

View File

@ -41,11 +41,9 @@ export class MyAccountVideoSettingsComponent extends FormReactive implements OnI
})
forkJoin([
this.serverService.videoLanguagesLoaded.pipe(first()),
this.serverService.getVideoLanguages(),
this.userInformationLoaded.pipe(first())
]).subscribe(() => {
const languages = this.serverService.getVideoLanguages()
]).subscribe(([ languages ]) => {
this.languageItems = [ { label: this.i18n('Unknown language'), value: '_unknown' } ]
this.languageItems = this.languageItems
.concat(languages.map(l => ({ label: l.label, value: l.id })))

View File

@ -9,6 +9,7 @@ import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { VideoChannelValidatorsService } from '@app/shared/forms/form-validators/video-channel-validators.service'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-account-video-channel-update',
@ -21,6 +22,7 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
private paramsSub: Subscription
private oldSupportField: string
private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
@ -37,6 +39,10 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.buildForm({
'display-name': this.videoChannelValidatorsService.VIDEO_CHANNEL_DISPLAY_NAME,
description: this.videoChannelValidatorsService.VIDEO_CHANNEL_DESCRIPTION,
@ -109,11 +115,11 @@ export class MyAccountVideoChannelUpdateComponent extends MyAccountVideoChannelE
}
get maxAvatarSize () {
return this.serverService.getConfig().avatar.file.size.max
return this.serverConfig.avatar.file.size.max
}
get avatarExtensions () {
return this.serverService.getConfig().avatar.file.extensions.join(',')
return this.serverConfig.avatar.file.extensions.join(',')
}
isCreation () {

View File

@ -47,15 +47,14 @@ export class MyAccountVideoPlaylistCreateComponent extends MyAccountVideoPlaylis
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
.catch(err => console.error('Cannot populate user video channels.', err))
this.serverService.videoPlaylistPrivaciesLoaded.subscribe(
() => {
this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies()
this.serverService.getVideoPlaylistPrivacies()
.subscribe(videoPlaylistPrivacies => {
this.videoPlaylistPrivacies = videoPlaylistPrivacies
this.form.patchValue({
privacy: VideoPlaylistPrivacy.PRIVATE
this.form.patchValue({
privacy: VideoPlaylistPrivacy.PRIVATE
})
})
}
)
}
formValidated () {

View File

@ -1,7 +1,7 @@
import { Component, OnDestroy, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { AuthService, Notifier, ServerService } from '@app/core'
import { Subscription } from 'rxjs'
import { forkJoin, Subscription } from 'rxjs'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { MyAccountVideoPlaylistEdit } from '@app/+my-account/my-account-video-playlists/my-account-video-playlist-edit'
@ -56,13 +56,17 @@ export class MyAccountVideoPlaylistUpdateComponent extends MyAccountVideoPlaylis
this.paramsSub = this.route.params
.pipe(
map(routeParams => routeParams['videoPlaylistId']),
switchMap(videoPlaylistId => this.videoPlaylistService.getVideoPlaylist(videoPlaylistId)),
delayWhen(() => this.serverService.videoPlaylistPrivaciesLoaded)
switchMap(videoPlaylistId => {
return forkJoin([
this.videoPlaylistService.getVideoPlaylist(videoPlaylistId),
this.serverService.getVideoPlaylistPrivacies()
])
})
)
.subscribe(
videoPlaylistToUpdate => {
this.videoPlaylistPrivacies = this.serverService.getVideoPlaylistPrivacies()
([ videoPlaylistToUpdate, videoPlaylistPrivacies]) => {
this.videoPlaylistToUpdate = videoPlaylistToUpdate
this.videoPlaylistPrivacies = videoPlaylistPrivacies
this.hydrateFormFromPlaylist()
},

View File

@ -1,20 +1,28 @@
import { Component } from '@angular/core'
import { Component, OnInit } from '@angular/core'
import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { TopMenuDropdownParam } from '@app/shared/menu/top-menu-dropdown.component'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-my-account',
templateUrl: './my-account.component.html',
styleUrls: [ './my-account.component.scss' ]
})
export class MyAccountComponent {
export class MyAccountComponent implements OnInit {
menuEntries: TopMenuDropdownParam[] = []
private serverConfig: ServerConfig
constructor (
private serverService: ServerService,
private i18n: I18n
) {
) { }
ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
const libraryEntries: TopMenuDropdownParam = {
label: this.i18n('My library'),
@ -91,7 +99,7 @@ export class MyAccountComponent {
}
isVideoImportEnabled () {
const importConfig = this.serverService.getConfig().import.videos
const importConfig = this.serverConfig.import.videos
return importConfig.http.enabled || importConfig.torrent.enabled
}

View File

@ -1,26 +1,35 @@
import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
import { ServerService } from '../../core/server'
import { VideoChannel } from '@app/shared/video-channel/video-channel.model'
import { Account } from '@app/shared/account/account.model'
import { Notifier } from '@app/core'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-actor-avatar-info',
templateUrl: './actor-avatar-info.component.html',
styleUrls: [ './actor-avatar-info.component.scss' ]
})
export class ActorAvatarInfoComponent {
export class ActorAvatarInfoComponent implements OnInit {
@ViewChild('avatarfileInput', { static: false }) avatarfileInput: ElementRef<HTMLInputElement>
@Input() actor: VideoChannel | Account
@Output() avatarChange = new EventEmitter<FormData>()
private serverConfig: ServerConfig
constructor (
private serverService: ServerService,
private notifier: Notifier
) {}
ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
}
onAvatarChange () {
const avatarfile = this.avatarfileInput.nativeElement.files[ 0 ]
if (avatarfile.size > this.maxAvatarSize) {
@ -35,10 +44,10 @@ export class ActorAvatarInfoComponent {
}
get maxAvatarSize () {
return this.serverService.getConfig().avatar.file.size.max
return this.serverConfig.avatar.file.size.max
}
get avatarExtensions () {
return this.serverService.getConfig().avatar.file.extensions.join(',')
return this.serverConfig.avatar.file.extensions.join(',')
}
}

View File

@ -16,7 +16,7 @@ const registerRoutes: Routes = [
}
},
resolve: {
serverConfigLoaded: ServerConfigResolver
serverConfig: ServerConfigResolver
}
}
]

View File

@ -4,10 +4,11 @@ import { UserService, UserValidatorsService } from '@app/shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { UserRegister } from '@shared/models/users/user-register.model'
import { FormGroup } from '@angular/forms'
import { About } from '@shared/models/server'
import { About, ServerConfig } from '@shared/models/server'
import { InstanceService } from '@app/shared/instance/instance.service'
import { HooksService } from '@app/core/plugins/hooks.service'
import { NgbAccordion } from '@ng-bootstrap/ng-bootstrap'
import { ActivatedRoute } from '@angular/router'
@Component({
selector: 'my-register',
@ -34,7 +35,10 @@ export class RegisterComponent implements OnInit {
formStepUser: FormGroup
formStepChannel: FormGroup
private serverConfig: ServerConfig
constructor (
private route: ActivatedRoute,
private authService: AuthService,
private userValidatorsService: UserValidatorsService,
private notifier: Notifier,
@ -48,10 +52,12 @@ export class RegisterComponent implements OnInit {
}
get requiresEmailVerification () {
return this.serverService.getConfig().signup.requiresEmailVerification
return this.serverConfig.signup.requiresEmailVerification
}
ngOnInit (): void {
this.serverConfig = this.route.snapshot.data.serverConfig
this.instanceService.getAbout()
.subscribe(
async about => {

View File

@ -5,6 +5,7 @@ import { ServerService } from '@app/core/server'
import { FormReactive, UserService } from '@app/shared'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { UserValidatorsService } from '@app/shared/forms/form-validators/user-validators.service'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-verify-account-ask-send-email',
@ -13,6 +14,7 @@ import { UserValidatorsService } from '@app/shared/forms/form-validators/user-va
})
export class VerifyAccountAskSendEmailComponent extends FormReactive implements OnInit {
private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
@ -27,10 +29,14 @@ export class VerifyAccountAskSendEmailComponent extends FormReactive implements
}
get requiresEmailVerification () {
return this.serverService.getConfig().signup.requiresEmailVerification
return this.serverConfig.signup.requiresEmailVerification
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.buildForm({
'verify-email-email': this.userValidatorsService.USER_EMAIL
})

View File

@ -15,7 +15,7 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { POP_STATE_MODAL_DISMISS } from '@app/shared/misc/constants'
import { WelcomeModalComponent } from '@app/modal/welcome-modal.component'
import { InstanceConfigWarningModalComponent } from '@app/modal/instance-config-warning-modal.component'
import { UserRole } from '@shared/models'
import { ServerConfig, UserRole } from '@shared/models'
import { User } from '@app/shared'
import { InstanceService } from '@app/shared/instance/instance.service'
@ -33,6 +33,8 @@ export class AppComponent implements OnInit {
customCSS: SafeHtml
private serverConfig: ServerConfig
constructor (
private i18n: I18n,
private viewportScroller: ViewportScroller,
@ -52,7 +54,7 @@ export class AppComponent implements OnInit {
) { }
get instanceName () {
return this.serverService.getConfig().instance.name
return this.serverConfig.instance.name
}
get defaultRoute () {
@ -62,6 +64,10 @@ export class AppComponent implements OnInit {
ngOnInit () {
document.getElementById('incompatible-browser').className += ' browser-ok'
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.loadPlugins()
this.themeService.initialize()
@ -72,14 +78,6 @@ export class AppComponent implements OnInit {
this.authService.refreshUserInformation()
}
// Load custom data from server
this.serverService.loadConfig()
this.serverService.loadVideoCategories()
this.serverService.loadVideoLanguages()
this.serverService.loadVideoLicences()
this.serverService.loadVideoPrivacies()
this.serverService.loadVideoPlaylistPrivacies()
// Do not display menu on small screens
if (this.screenService.isInSmallView()) {
this.isMenuDisplayed = false
@ -187,10 +185,8 @@ export class AppComponent implements OnInit {
private injectJS () {
// Inject JS
this.serverService.configLoaded
.subscribe(() => {
const config = this.serverService.getConfig()
this.serverService.getConfig()
.subscribe(config => {
if (config.instance.customizations.javascript) {
try {
// tslint:disable:no-eval
@ -204,17 +200,14 @@ export class AppComponent implements OnInit {
private injectCSS () {
// Inject CSS if modified (admin config settings)
this.serverService.configLoaded
.pipe(skip(1)) // We only want to subscribe to reloads, because the CSS is already injected by the server
this.serverService.configReloaded
.subscribe(() => {
const headStyle = document.querySelector('style.custom-css-style')
if (headStyle) headStyle.parentNode.removeChild(headStyle)
const config = this.serverService.getConfig()
// We test customCSS if the admin removed the css
if (this.customCSS || config.instance.customizations.css) {
const styleTag = '<style>' + config.instance.customizations.css + '</style>'
if (this.customCSS || this.serverConfig.instance.customizations.css) {
const styleTag = '<style>' + this.serverConfig.instance.customizations.css + '</style>'
this.customCSS = this.domSanitizer.bypassSecurityTrustHtml(styleTag)
}
})
@ -227,25 +220,22 @@ export class AppComponent implements OnInit {
}
private async openModalsIfNeeded () {
this.serverService.configLoaded
this.authService.userInformationLoaded
.pipe(
first(),
switchMap(() => this.authService.userInformationLoaded),
map(() => this.authService.getUser()),
filter(user => user.role === UserRole.ADMINISTRATOR)
).subscribe(user => setTimeout(() => this.openAdminModals(user))) // setTimeout because of ngIf in template
).subscribe(user => setTimeout(() => this._openAdminModalsIfNeeded(user))) // setTimeout because of ngIf in template
}
private async openAdminModals (user: User) {
private async _openAdminModalsIfNeeded (user: User) {
if (user.noWelcomeModal !== true) return this.welcomeModal.show()
const config = this.serverService.getConfig()
if (user.noInstanceConfigWarningModal === true || !config.signup.allowed) return
if (user.noInstanceConfigWarningModal === true || !this.serverConfig.signup.allowed) return
this.instanceService.getAbout()
.subscribe(about => {
if (
config.instance.name.toLowerCase() === 'peertube' ||
this.serverConfig.instance.name.toLowerCase() === 'peertube' ||
!about.instance.terms ||
!about.instance.administrator ||
!about.instance.maintenanceLifetime

View File

@ -25,10 +25,10 @@ export function metaFactory (serverService: ServerService): MetaLoader {
return new MetaStaticLoader({
pageTitlePositioning: PageTitlePositioning.PrependPageTitle,
pageTitleSeparator: ' - ',
get applicationName () { return serverService.getConfig().instance.name },
get applicationName () { return serverService.getTmpConfig().instance.name },
defaults: {
get title () { return serverService.getConfig().instance.name },
get description () { return serverService.getConfig().instance.shortDescription }
get title () { return serverService.getTmpConfig().instance.name },
get description () { return serverService.getTmpConfig().instance.shortDescription }
}
})
}

View File

@ -70,9 +70,9 @@ export class PluginService implements ClientHook {
}
initializePlugins () {
this.server.configLoaded
.subscribe(() => {
this.plugins = this.server.getConfig().plugin.registered
this.server.getConfig()
.subscribe(config => {
this.plugins = config.plugin.registered
this.buildScopeStruct()

View File

@ -16,15 +16,15 @@ export class RedirectService {
private serverService: ServerService
) {
// The config is first loaded from the cache so try to get the default route
const config = this.serverService.getConfig()
if (config && config.instance && config.instance.defaultClientRoute) {
RedirectService.DEFAULT_ROUTE = config.instance.defaultClientRoute
const tmpConfig = this.serverService.getTmpConfig()
if (tmpConfig && tmpConfig.instance && tmpConfig.instance.defaultClientRoute) {
RedirectService.DEFAULT_ROUTE = tmpConfig.instance.defaultClientRoute
}
// Load default route
this.serverService.configLoaded
.subscribe(() => {
const defaultRouteConfig = this.serverService.getConfig().instance.defaultClientRoute
this.serverService.getConfig()
.subscribe(config => {
const defaultRouteConfig = config.instance.defaultClientRoute
if (defaultRouteConfig) {
RedirectService.DEFAULT_ROUTE = defaultRouteConfig

View File

@ -1,17 +1,13 @@
import { Injectable } from '@angular/core'
import { Resolve } from '@angular/router'
import { ServerService } from '@app/core/server'
import { ServerConfig } from '@shared/models'
@Injectable()
export class ServerConfigResolver implements Resolve<boolean> {
constructor (
private server: ServerService
) {}
export class ServerConfigResolver implements Resolve<ServerConfig> {
constructor (private server: ServerService) {}
resolve () {
// FIXME: directly returning this.server.configLoaded does not seem to work
return new Promise<boolean>(res => {
return this.server.configLoaded.subscribe(() => res(true))
})
return this.server.getConfig()
}
}

View File

@ -1,34 +1,36 @@
import { map, shareReplay, switchMap, tap } from 'rxjs/operators'
import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Inject, Injectable, LOCALE_ID } from '@angular/core'
import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
import { Observable, of, ReplaySubject } from 'rxjs'
import { Observable, of, Subject } from 'rxjs'
import { getCompleteLocale, ServerConfig } from '../../../../../shared'
import { environment } from '../../../environments/environment'
import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
import { VideoConstant } from '../../../../../shared/models/videos'
import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n'
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
import { sortBy } from '@app/shared/misc/utils'
import { VideoPlaylistPrivacy } from '@shared/models/videos/playlist/video-playlist-privacy.model'
import { cloneDeep } from 'lodash-es'
@Injectable()
export class ServerService {
private static BASE_SERVER_URL = environment.apiUrl + '/api/v1/server/'
private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/'
private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
private static CONFIG_LOCAL_STORAGE_KEY = 'server-config'
configLoaded = new ReplaySubject<boolean>(1)
videoPrivaciesLoaded = new ReplaySubject<boolean>(1)
videoPlaylistPrivaciesLoaded = new ReplaySubject<boolean>(1)
videoCategoriesLoaded = new ReplaySubject<boolean>(1)
videoLicencesLoaded = new ReplaySubject<boolean>(1)
videoLanguagesLoaded = new ReplaySubject<boolean>(1)
localeObservable: Observable<any>
configReloaded = new Subject<void>()
private localeObservable: Observable<any>
private videoLicensesObservable: Observable<VideoConstant<number>[]>
private videoCategoriesObservable: Observable<VideoConstant<number>[]>
private videoPrivaciesObservable: Observable<VideoConstant<number>[]>
private videoPlaylistPrivaciesObservable: Observable<VideoConstant<number>[]>
private videoLanguagesObservable: Observable<VideoConstant<string>[]>
private configObservable: Observable<ServerConfig>
private configReset = false
private configLoaded = false
private config: ServerConfig = {
instance: {
name: 'PeerTube',
@ -121,132 +123,141 @@ export class ServerService {
enabled: true
}
}
private videoCategories: Array<VideoConstant<number>> = []
private videoLicences: Array<VideoConstant<number>> = []
private videoLanguages: Array<VideoConstant<string>> = []
private videoPrivacies: Array<VideoConstant<VideoPrivacy>> = []
private videoPlaylistPrivacies: Array<VideoConstant<VideoPlaylistPrivacy>> = []
constructor (
private http: HttpClient,
@Inject(LOCALE_ID) private localeId: string
) {
this.loadServerLocale()
this.loadConfigLocally()
}
loadConfig () {
this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
.pipe(tap(this.saveConfigLocally))
.subscribe(data => {
this.config = data
this.configLoaded.next(true)
})
}
loadVideoCategories () {
return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'categories', this.videoCategories, this.videoCategoriesLoaded, true)
}
loadVideoLicences () {
return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'licences', this.videoLicences, this.videoLicencesLoaded)
}
loadVideoLanguages () {
return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'languages', this.videoLanguages, this.videoLanguagesLoaded, true)
}
loadVideoPrivacies () {
return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'privacies', this.videoPrivacies, this.videoPrivaciesLoaded)
}
loadVideoPlaylistPrivacies () {
return this.loadAttributeEnum(
ServerService.BASE_VIDEO_PLAYLIST_URL,
'privacies',
this.videoPlaylistPrivacies,
this.videoPlaylistPrivaciesLoaded
)
}
getConfig () {
return cloneDeep(this.config)
}
getServerVersionAndCommit () {
const serverVersion = this.config.serverVersion
const commit = this.config.serverCommit || ''
let result = `v${serverVersion}`
let result = serverVersion
if (commit) result += '...' + commit
return result
}
resetConfig () {
this.configLoaded = false
this.configReset = true
}
getConfig () {
if (this.configLoaded) return of(this.config)
if (!this.configObservable) {
this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
.pipe(
tap(this.saveConfigLocally),
tap(() => this.configLoaded = true),
tap(() => {
if (this.configReset) {
this.configReloaded.next()
this.configReset = false
}
}),
share()
)
}
return this.configObservable
}
getTmpConfig () {
return this.config
}
getVideoCategories () {
return cloneDeep(this.videoCategories)
if (!this.videoCategoriesObservable) {
this.videoCategoriesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'categories', true)
}
return this.videoCategoriesObservable.pipe(first())
}
getVideoLicences () {
return cloneDeep(this.videoLicences)
if (!this.videoLicensesObservable) {
this.videoLicensesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'licences')
}
return this.videoLicensesObservable.pipe(first())
}
getVideoLanguages () {
return cloneDeep(this.videoLanguages)
if (!this.videoLanguagesObservable) {
this.videoLanguagesObservable = this.loadAttributeEnum<string>(ServerService.BASE_VIDEO_URL, 'languages', true)
}
return this.videoLanguagesObservable.pipe(first())
}
getVideoPrivacies () {
return cloneDeep(this.videoPrivacies)
if (!this.videoPrivaciesObservable) {
this.videoPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'privacies')
}
return this.videoPrivaciesObservable.pipe(first())
}
getVideoPlaylistPrivacies () {
return cloneDeep(this.videoPlaylistPrivacies)
}
private loadAttributeEnum (
baseUrl: string,
attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
hashToPopulate: VideoConstant<string | number>[],
notifier: ReplaySubject<boolean>,
sort = false
) {
this.localeObservable
.pipe(
switchMap(translations => {
return this.http.get<{ [id: string]: string }>(baseUrl + attributeName)
.pipe(map(data => ({ data, translations })))
})
)
.subscribe(({ data, translations }) => {
Object.keys(data)
.forEach(dataKey => {
const label = data[ dataKey ]
hashToPopulate.push({
id: attributeName === 'languages' ? dataKey : parseInt(dataKey, 10),
label: peertubeTranslate(label, translations)
})
})
if (sort === true) sortBy(hashToPopulate, 'label')
notifier.next(true)
})
}
private loadServerLocale () {
const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
// Default locale, nothing to translate
if (isDefaultLocale(completeLocale)) {
this.localeObservable = of({}).pipe(shareReplay())
return
if (!this.videoPlaylistPrivaciesObservable) {
this.videoPlaylistPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_PLAYLIST_URL, 'privacies')
}
this.localeObservable = this.http
.get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
.pipe(shareReplay())
return this.videoPlaylistPrivaciesObservable.pipe(first())
}
getServerLocale () {
if (!this.localeObservable) {
const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
// Default locale, nothing to translate
if (isDefaultLocale(completeLocale)) {
this.localeObservable = of({}).pipe(shareReplay())
} else {
this.localeObservable = this.http
.get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
.pipe(shareReplay())
}
}
return this.localeObservable.pipe(first())
}
private loadAttributeEnum <T extends string | number> (
baseUrl: string,
attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
sort = false
) {
return this.getServerLocale()
.pipe(
switchMap(translations => {
return this.http.get<{ [ id: string ]: string }>(baseUrl + attributeName)
.pipe(map(data => ({ data, translations })))
}),
map(({ data, translations }) => {
const hashToPopulate: VideoConstant<T>[] = []
Object.keys(data)
.forEach(dataKey => {
const label = data[ dataKey ]
hashToPopulate.push({
id: (attributeName === 'languages' ? dataKey : parseInt(dataKey, 10)) as T,
label: peertubeTranslate(label, translations)
})
})
if (sort === true) sortBy(hashToPopulate, 'label')
return hashToPopulate
}),
shareReplay()
)
}
private saveConfigLocally (config: ServerConfig) {

View File

@ -3,7 +3,7 @@ import { AuthService } from '@app/core/auth'
import { ServerService } from '@app/core/server'
import { environment } from '../../../environments/environment'
import { PluginService } from '@app/core/plugins/plugin.service'
import { ServerConfigTheme } from '@shared/models'
import { ServerConfig, ServerConfigTheme } from '@shared/models'
import { peertubeLocalStorage } from '@app/shared/misc/peertube-web-storage'
import { first } from 'rxjs/operators'
@ -20,6 +20,8 @@ export class ThemeService {
private themeFromLocalStorage: ServerConfigTheme
private themeDOMLinksFromLocalStorage: HTMLLinkElement[] = []
private serverConfig: ServerConfig
constructor (
private auth: AuthService,
private pluginService: PluginService,
@ -30,9 +32,12 @@ export class ThemeService {
// Try to load from local storage first, so we don't have to wait network requests
this.loadAndSetFromLocalStorage()
this.server.configLoaded
.subscribe(() => {
const themes = this.server.getConfig().theme.registered
this.serverConfig = this.server.getTmpConfig()
this.server.getConfig()
.subscribe(config => {
this.serverConfig = config
const themes = this.serverConfig.theme.registered
this.removeThemeFromLocalStorageIfNeeded(themes)
this.injectThemes(themes)
@ -77,7 +82,7 @@ export class ThemeService {
if (theme !== 'instance-default') return theme
}
return this.server.getConfig().theme.default
return this.serverConfig.theme.default
}
private loadTheme (name: string) {

View File

@ -15,7 +15,7 @@ const loginRoutes: Routes = [
}
},
resolve: {
serverConfigLoaded: ServerConfigResolver
serverConfig: ServerConfigResolver
}
}
]

View File

@ -7,7 +7,8 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
import { LoginValidatorsService } from '@app/shared/forms/form-validators/login-validators.service'
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { Router } from '@angular/router'
import { ActivatedRoute, Router } from '@angular/router'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-login',
@ -23,10 +24,12 @@ export class LoginComponent extends FormReactive implements OnInit {
forgotPasswordEmail = ''
private openedForgotPasswordModal: NgbModalRef
private serverConfig: ServerConfig
constructor (
public router: Router,
protected formValidatorService: FormValidatorService,
private router: Router,
private route: ActivatedRoute,
private modalService: NgbModal,
private loginValidatorsService: LoginValidatorsService,
private authService: AuthService,
@ -40,14 +43,16 @@ export class LoginComponent extends FormReactive implements OnInit {
}
get signupAllowed () {
return this.serverService.getConfig().signup.allowed === true
return this.serverConfig.signup.allowed === true
}
isEmailDisabled () {
return this.serverService.getConfig().email.enabled === false
return this.serverConfig.email.enabled === false
}
ngOnInit () {
this.serverConfig = this.route.snapshot.data.serverConfig
this.buildForm({
username: this.loginValidatorsService.LOGIN_USERNAME,
password: this.loginValidatorsService.LOGIN_PASSWORD

View File

@ -4,6 +4,7 @@ import { AuthService, AuthStatus, RedirectService, ServerService, ThemeService }
import { User } from '../shared/users/user.model'
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
import { HotkeysService } from 'angular2-hotkeys'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-menu',
@ -18,6 +19,7 @@ export class MenuComponent implements OnInit {
userHasAdminAccess = false
helpVisible = false
private serverConfig: ServerConfig
private routesPerRight: { [ role in UserRight ]?: string } = {
[UserRight.MANAGE_USERS]: '/admin/users',
[UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
@ -36,6 +38,10 @@ export class MenuComponent implements OnInit {
) {}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.isLoggedIn = this.authService.isLoggedIn()
if (this.isLoggedIn === true) this.user = this.authService.getUser()
this.computeIsUserHasAdminAccess()
@ -64,8 +70,8 @@ export class MenuComponent implements OnInit {
}
isRegistrationAllowed () {
return this.serverService.getConfig().signup.allowed &&
this.serverService.getConfig().signup.allowedForCurrentIP
return this.serverConfig.signup.allowed &&
this.serverConfig.signup.allowedForCurrentIP
}
getFirstAdminRightAvailable () {

View File

@ -1,10 +1,10 @@
import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges } from '@angular/core'
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
import { ValidatorFn } from '@angular/forms'
import { VideoValidatorsService } from '@app/shared'
import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { AdvancedSearch } from '@app/search/advanced-search.model'
import { VideoConstant } from '../../../../shared'
import { ServerConfig, VideoConstant } from '../../../../shared'
@Component({
selector: 'my-search-filters',
@ -33,6 +33,8 @@ export class SearchFiltersComponent implements OnInit {
originallyPublishedStartYear: string
originallyPublishedEndYear: string
private serverConfig: ServerConfig
constructor (
private i18n: I18n,
private videoValidatorsService: VideoValidatorsService,
@ -99,9 +101,13 @@ export class SearchFiltersComponent implements OnInit {
}
ngOnInit () {
this.serverService.videoCategoriesLoaded.subscribe(() => this.videoCategories = this.serverService.getVideoCategories())
this.serverService.videoLicencesLoaded.subscribe(() => this.videoLicences = this.serverService.getVideoLicences())
this.serverService.videoLanguagesLoaded.subscribe(() => this.videoLanguages = this.serverService.getVideoLanguages())
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.serverService.getVideoCategories().subscribe(categories => this.videoCategories = categories)
this.serverService.getVideoLicences().subscribe(licences => this.videoLicences = licences)
this.serverService.getVideoLanguages().subscribe(languages => this.videoLanguages = languages)
this.loadFromDurationRange()
this.loadFromPublishedRange()

View File

@ -2,6 +2,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'
import { ServerService } from '@app/core'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-preview-upload',
@ -24,6 +25,7 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor {
imageSrc: SafeResourceUrl
allowedExtensionsMessage = ''
private serverConfig: ServerConfig
private file: File
constructor (
@ -32,14 +34,18 @@ export class PreviewUploadComponent implements OnInit, ControlValueAccessor {
) {}
get videoImageExtensions () {
return this.serverService.getConfig().video.image.extensions
return this.serverConfig.video.image.extensions
}
get maxVideoImageSize () {
return this.serverService.getConfig().video.image.size.max
return this.serverConfig.video.image.size.max
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.allowedExtensionsMessage = this.videoImageExtensions.join(', ')
}

View File

@ -1,6 +1,6 @@
<div class="feature-table">
<table class="table" *ngIf="config">
<table class="table" *ngIf="serverConfig">
<tr>
<td i18n class="label">PeerTube version</td>
@ -19,7 +19,7 @@
<tr>
<td i18n class="label">User registration allowed</td>
<td>
<my-feature-boolean [value]="config.signup.allowed"></my-feature-boolean>
<my-feature-boolean [value]="serverConfig.signup.allowed"></my-feature-boolean>
</td>
</tr>
@ -30,15 +30,15 @@
<tr>
<td i18n class="sub-label">Transcoding in multiple resolutions</td>
<td>
<my-feature-boolean [value]="config.transcoding.enabledResolutions.length !== 0"></my-feature-boolean>
<my-feature-boolean [value]="serverConfig.transcoding.enabledResolutions.length !== 0"></my-feature-boolean>
</td>
</tr>
<tr>
<td i18n class="sub-label">Video uploads</td>
<td>
<span *ngIf="config.autoBlacklist.videos.ofUsers.enabled">Requires manual validation by moderators</span>
<span *ngIf="!config.autoBlacklist.videos.ofUsers.enabled">Automatically published</span>
<span *ngIf="serverConfig.autoBlacklist.videos.ofUsers.enabled">Requires manual validation by moderators</span>
<span *ngIf="!serverConfig.autoBlacklist.videos.ofUsers.enabled">Automatically published</span>
</td>
</tr>
@ -69,14 +69,14 @@
<tr>
<td i18n class="sub-label">HTTP import (YouTube, Vimeo, direct URL...)</td>
<td>
<my-feature-boolean [value]="config.import.videos.http.enabled"></my-feature-boolean>
<my-feature-boolean [value]="serverConfig.import.videos.http.enabled"></my-feature-boolean>
</td>
</tr>
<tr>
<td i18n class="sub-label">Torrent import</td>
<td>
<my-feature-boolean [value]="config.import.videos.torrent.enabled"></my-feature-boolean>
<my-feature-boolean [value]="serverConfig.import.videos.torrent.enabled"></my-feature-boolean>
</td>
</tr>
@ -88,7 +88,7 @@
<tr>
<td i18n class="sub-label">P2P enabled</td>
<td>
<my-feature-boolean [value]="config.tracker.enabled"></my-feature-boolean>
<my-feature-boolean [value]="serverConfig.tracker.enabled"></my-feature-boolean>
</td>
</tr>
</table>

View File

@ -10,7 +10,7 @@ import { ServerConfig } from '@shared/models'
})
export class InstanceFeaturesTableComponent implements OnInit {
quotaHelpIndication = ''
config: ServerConfig
serverConfig: ServerConfig
constructor (
private i18n: I18n,
@ -19,29 +19,34 @@ export class InstanceFeaturesTableComponent implements OnInit {
}
get initialUserVideoQuota () {
return this.serverService.getConfig().user.videoQuota
return this.serverConfig.user.videoQuota
}
get dailyUserVideoQuota () {
return Math.min(this.initialUserVideoQuota, this.serverService.getConfig().user.videoQuotaDaily)
return Math.min(this.initialUserVideoQuota, this.serverConfig.user.videoQuotaDaily)
}
ngOnInit () {
this.serverService.configLoaded
.subscribe(() => {
this.config = this.serverService.getConfig()
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => {
this.serverConfig = config
this.buildQuotaHelpIndication()
})
}
buildNSFWLabel () {
const policy = this.serverService.getConfig().instance.defaultNSFWPolicy
const policy = this.serverConfig.instance.defaultNSFWPolicy
if (policy === 'do_not_list') return this.i18n('Hidden')
if (policy === 'blur') return this.i18n('Blurred with confirmation request')
if (policy === 'display') return this.i18n('Displayed')
}
getServerVersionAndCommit () {
return this.serverService.getServerVersionAndCommit()
}
private getApproximateTime (seconds: number) {
const hours = Math.floor(seconds / 3600)
let pluralSuffix = ''
@ -53,10 +58,6 @@ export class InstanceFeaturesTableComponent implements OnInit {
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
}
getServerVersionAndCommit () {
return this.serverService.getServerVersionAndCommit()
}
private buildQuotaHelpIndication () {
if (this.initialUserVideoQuota === -1) return

View File

@ -1,4 +1,4 @@
import { catchError } from 'rxjs/operators'
import { catchError, map } from 'rxjs/operators'
import { HttpClient } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { environment } from '../../../environments/environment'
@ -7,6 +7,7 @@ import { About } from '../../../../../shared/models/server'
import { MarkdownService } from '@app/shared/renderer'
import { peertubeTranslate } from '@shared/models'
import { ServerService } from '@app/core'
import { forkJoin } from 'rxjs'
@Injectable()
export class InstanceService {
@ -57,25 +58,35 @@ export class InstanceService {
return html
}
buildTranslatedLanguages (about: About, translations: any) {
const languagesArray = this.serverService.getVideoLanguages()
buildTranslatedLanguages (about: About) {
return forkJoin([
this.serverService.getVideoLanguages(),
this.serverService.getServerLocale()
]).pipe(
map(([ languagesArray, translations ]) => {
return about.instance.languages
.map(l => {
const languageObj = languagesArray.find(la => la.id === l)
return about.instance.languages
.map(l => {
const languageObj = languagesArray.find(la => la.id === l)
return peertubeTranslate(languageObj.label, translations)
})
return peertubeTranslate(languageObj.label, translations)
})
})
)
}
buildTranslatedCategories (about: About, translations: any) {
const categoriesArray = this.serverService.getVideoCategories()
buildTranslatedCategories (about: About) {
return forkJoin([
this.serverService.getVideoCategories(),
this.serverService.getServerLocale()
]).pipe(
map(([ categoriesArray, translations ]) => {
return about.instance.categories
.map(c => {
const categoryObj = categoriesArray.find(ca => ca.id === c)
return about.instance.categories
.map(c => {
const categoryObj = categoriesArray.find(ca => ca.id === c)
return peertubeTranslate(categoryObj.label, translations)
})
return peertubeTranslate(categoryObj.label, translations)
})
})
)
}
}

View File

@ -1,4 +1,4 @@
import { Component, EventEmitter, Input, OnChanges, Output, ViewChild } from '@angular/core'
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild } from '@angular/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { DropdownAction } from '@app/shared/buttons/action-dropdown.component'
import { UserBanModalComponent } from '@app/shared/moderation/user-ban-modal.component'
@ -7,12 +7,13 @@ import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core'
import { User, UserRight } from '../../../../../shared/models/users'
import { Account } from '@app/shared/account/account.model'
import { BlocklistService } from '@app/shared/blocklist'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-user-moderation-dropdown',
templateUrl: './user-moderation-dropdown.component.html'
})
export class UserModerationDropdownComponent implements OnChanges {
export class UserModerationDropdownComponent implements OnInit, OnChanges {
@ViewChild('userBanModal', { static: false }) userBanModal: UserBanModalComponent
@Input() user: User
@ -26,6 +27,8 @@ export class UserModerationDropdownComponent implements OnChanges {
userActions: DropdownAction<{ user: User, account: Account }>[][] = []
private serverConfig: ServerConfig
constructor (
private authService: AuthService,
private notifier: Notifier,
@ -38,7 +41,13 @@ export class UserModerationDropdownComponent implements OnChanges {
) { }
get requiresEmailVerification () {
return this.serverService.getConfig().signup.requiresEmailVerification
return this.serverConfig.signup.requiresEmailVerification
}
ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
}
ngOnChanges () {

View File

@ -60,7 +60,7 @@ export class OverviewService {
.pipe(
// Translate categories
switchMap(() => {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
tap(translations => {
for (const c of videosOverviewResult.categories) {

View File

@ -22,7 +22,7 @@ export class VideoCaptionService {
return this.authHttp.get<ResultList<VideoCaption>>(VideoService.BASE_VIDEO_URL + videoId + '/captions')
.pipe(
switchMap(captionsResult => {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(map(translations => ({ captionsResult, translations })))
}),
map(({ captionsResult, translations }) => {

View File

@ -91,7 +91,7 @@ export class VideoImportService {
}
private extractVideoImports (result: ResultList<VideoImport>): Observable<ResultList<VideoImport>> {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
map(translations => {
result.data.forEach(d =>

View File

@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
import { Video } from '@app/shared/video/video.model'
import { VideoPlaylistElementType, VideoPlaylistElementUpdate } from '@shared/models'
import { ServerConfig, VideoPlaylistElementType, VideoPlaylistElementUpdate } from '@shared/models'
import { AuthService, ConfirmService, Notifier, ServerService } from '@app/core'
import { ActivatedRoute } from '@angular/router'
import { I18n } from '@ngx-translate/i18n-polyfill'
@ -17,7 +17,7 @@ import { VideoPlaylistElement } from '@app/shared/video-playlist/video-playlist-
templateUrl: './video-playlist-element-miniature.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class VideoPlaylistElementMiniatureComponent {
export class VideoPlaylistElementMiniatureComponent implements OnInit {
@ViewChild('moreDropdown', { static: false }) moreDropdown: NgbDropdown
@Input() playlist: VideoPlaylist
@ -39,6 +39,8 @@ export class VideoPlaylistElementMiniatureComponent {
stopTimestamp: number
} = {} as any
private serverConfig: ServerConfig
constructor (
private authService: AuthService,
private serverService: ServerService,
@ -51,6 +53,15 @@ export class VideoPlaylistElementMiniatureComponent {
private cdr: ChangeDetectorRef
) {}
ngOnInit (): void {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => {
this.serverConfig = config
this.cdr.detectChanges()
})
}
isUnavailable (e: VideoPlaylistElement) {
return e.type === VideoPlaylistElementType.UNAVAILABLE
}
@ -80,7 +91,7 @@ export class VideoPlaylistElementMiniatureComponent {
}
isVideoBlur (video: Video) {
return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig())
return video.isVideoNSFWForUser(this.authService.getUser(), this.serverConfig)
}
removeFromPlaylist (playlistElement: VideoPlaylistElement) {

View File

@ -173,7 +173,7 @@ export class VideoPlaylistService {
}
extractPlaylists (result: ResultList<VideoPlaylistServerModel>) {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
map(translations => {
const playlistsJSON = result.data
@ -190,12 +190,12 @@ export class VideoPlaylistService {
}
extractPlaylist (playlist: VideoPlaylistServerModel) {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(map(translations => new VideoPlaylist(playlist, translations)))
}
extractVideoPlaylistElements (result: ResultList<ServerVideoPlaylistElement>) {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
map(translations => {
const elementsJson = result.data

View File

@ -13,7 +13,7 @@ import { Notifier, ServerService } from '@app/core'
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date'
import { ResultList } from '@shared/models'
import { ResultList, ServerConfig } from '@shared/models'
enum GroupDate {
UNKNOWN = 0,
@ -61,6 +61,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
onDataSubject = new Subject<any[]>()
protected serverConfig: ServerConfig
protected abstract notifier: Notifier
protected abstract authService: AuthService
protected abstract route: ActivatedRoute
@ -85,6 +87,10 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.groupedDateLabels = {
[GroupDate.UNKNOWN]: null,
[GroupDate.TODAY]: this.i18n('Today'),
@ -251,7 +257,7 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor
}
let path = this.router.url
if (!path || path === '/') path = this.serverService.getConfig().instance.defaultClientRoute
if (!path || path === '/') path = this.serverConfig.instance.defaultClientRoute
this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' })
}

View File

@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Inject, Input, LOCALE
import { User } from '../users'
import { Video } from './video.model'
import { ServerService } from '@app/core'
import { VideoPrivacy, VideoState } from '../../../../../shared'
import { ServerConfig, VideoPrivacy, VideoState } from '../../../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { VideoActionsDisplayType } from '@app/shared/video/video-actions-dropdown.component'
import { ScreenService } from '@app/shared/misc/screen.service'
@ -55,6 +55,7 @@ export class VideoMiniatureComponent implements OnInit {
report: true
}
showActions = false
serverConfig: ServerConfig
private ownerDisplayTypeChosen: 'account' | 'videoChannel'
@ -66,10 +67,14 @@ export class VideoMiniatureComponent implements OnInit {
) { }
get isVideoBlur () {
return this.video.isVideoNSFWForUser(this.user, this.serverService.getConfig())
return this.video.isVideoNSFWForUser(this.user, this.serverConfig)
}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.setUpBy()
// We rely on mouseenter to lazy load actions

View File

@ -64,7 +64,7 @@ export class VideoService implements VideosProvider {
}
getVideo (options: { videoId: string }): Observable<VideoDetails> {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
switchMap(translations => {
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + options.videoId)
@ -315,7 +315,7 @@ export class VideoService implements VideosProvider {
}
extractVideos (result: ResultList<VideoServerModel>) {
return this.serverService.localeObservable
return this.serverService.getServerLocale()
.pipe(
map(translations => {
const videosJson = result.data

View File

@ -5,7 +5,7 @@ import { VideoCaptionsValidatorsService } from '@app/shared/forms/form-validator
import { ServerService } from '@app/core'
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
import { VideoConstant } from '../../../../../../shared'
import { ServerConfig, VideoConstant } from '../../../../../../shared'
@Component({
selector: 'my-video-caption-add-modal',
@ -15,6 +15,7 @@ import { VideoConstant } from '../../../../../../shared'
export class VideoCaptionAddModalComponent extends FormReactive implements OnInit {
@Input() existingCaptions: string[]
@Input() serverConfig: ServerConfig
@Output() captionAdded = new EventEmitter<VideoCaptionEdit>()
@ -35,15 +36,16 @@ export class VideoCaptionAddModalComponent extends FormReactive implements OnIni
}
get videoCaptionExtensions () {
return this.serverService.getConfig().videoCaption.file.extensions
return this.serverConfig.videoCaption.file.extensions
}
get videoCaptionMaxSize () {
return this.serverService.getConfig().videoCaption.file.size.max
return this.serverConfig.videoCaption.file.size.max
}
ngOnInit () {
this.videoCaptionLanguages = this.serverService.getVideoLanguages()
this.serverService.getVideoLanguages()
.subscribe(languages => this.videoCaptionLanguages = languages)
this.buildForm({
language: this.videoCaptionsValidatorsService.VIDEO_CAPTION_LANGUAGE,

View File

@ -269,5 +269,5 @@
</div>
<my-video-caption-add-modal
#videoCaptionAddModal [existingCaptions]="existingCaptions" (captionAdded)="onCaptionAdded($event)"
#videoCaptionAddModal [existingCaptions]="existingCaptions" [serverConfig]="serverConfig" (captionAdded)="onCaptionAdded($event)"
></my-video-caption-add-modal>

View File

@ -12,7 +12,7 @@ import { VideoCaptionService } from '@app/shared/video-caption'
import { VideoCaptionAddModalComponent } from '@app/videos/+video-edit/shared/video-caption-add-modal.component'
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
import { removeElementFromArray } from '@app/shared/misc/utils'
import { VideoConstant, VideoPrivacy } from '../../../../../../shared'
import { ServerConfig, VideoConstant, VideoPrivacy } from '../../../../../../shared'
import { VideoService } from '@app/shared/video/video.service'
@Component({
@ -51,6 +51,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
calendarTimezone: string
calendarDateFormat: string
serverConfig: ServerConfig
private schedulerInterval: any
private firstPatchDone = false
private initialVideoCaptions: string[] = []
@ -130,12 +132,19 @@ export class VideoEditComponent implements OnInit, OnDestroy {
ngOnInit () {
this.updateForm()
this.videoCategories = this.serverService.getVideoCategories()
this.videoLicences = this.serverService.getVideoLicences()
this.videoLanguages = this.serverService.getVideoLanguages()
this.serverService.getVideoCategories()
.subscribe(res => this.videoCategories = res)
this.serverService.getVideoLicences()
.subscribe(res => this.videoLicences = res)
this.serverService.getVideoLanguages()
.subscribe(res => this.videoLanguages = res)
const privacies = this.serverService.getVideoPrivacies()
this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies)
this.serverService.getVideoPrivacies()
.subscribe(privacies => this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies))
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)

View File

@ -3,7 +3,7 @@ import { LoadingBarService } from '@ngx-loading-bar/core'
import { AuthService, Notifier, ServerService } from '@app/core'
import { catchError, switchMap, tap } from 'rxjs/operators'
import { FormReactive } from '@app/shared'
import { VideoConstant, VideoPrivacy } from '../../../../../../shared'
import { ServerConfig, VideoConstant, VideoPrivacy } from '../../../../../../shared'
import { VideoService } from '@app/shared/video/video.service'
import { VideoCaptionEdit } from '@app/shared/video-caption/video-caption-edit.model'
import { VideoCaptionService } from '@app/shared/video-caption'
@ -29,6 +29,7 @@ export abstract class VideoSend extends FormReactive implements OnInit {
protected serverService: ServerService
protected videoService: VideoService
protected videoCaptionService: VideoCaptionService
protected serverConfig: ServerConfig
abstract canDeactivate (): CanComponentDeactivateResult
@ -38,10 +39,14 @@ export abstract class VideoSend extends FormReactive implements OnInit {
populateAsyncUserVideoChannels(this.authService, this.userVideoChannels)
.then(() => this.firstStepChannelId = this.userVideoChannels[ 0 ].id)
this.serverService.videoPrivaciesLoaded
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
this.serverService.getVideoPrivacies()
.subscribe(
() => {
this.videoPrivacies = this.serverService.getVideoPrivacies()
privacies => {
this.videoPrivacies = privacies
this.firstStepPrivacyId = this.DEFAULT_VIDEO_PRIVACY
})

View File

@ -14,6 +14,7 @@ import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.
import { FormValidatorService, UserService } from '@app/shared'
import { VideoCaptionService } from '@app/shared/video-caption'
import { scrollToTop } from '@app/shared/misc/utils'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-video-upload',
@ -70,7 +71,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
}
get videoExtensions () {
return this.serverService.getConfig().video.file.extensions.join(',')
return this.serverConfig.video.file.extensions.join(',')
}
ngOnInit () {
@ -155,7 +156,7 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
}
const privacy = this.firstStepPrivacyId.toString()
const nsfw = this.serverService.getConfig().instance.isNSFW
const nsfw = this.serverConfig.instance.isNSFW
const waitTranscoding = true
const commentsEnabled = true
const downloadEnabled = true

View File

@ -1,28 +1,37 @@
import { Component, HostListener, ViewChild } from '@angular/core'
import { Component, HostListener, OnInit, ViewChild } from '@angular/core'
import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service'
import { VideoImportUrlComponent } from '@app/videos/+video-edit/video-add-components/video-import-url.component'
import { VideoUploadComponent } from '@app/videos/+video-edit/video-add-components/video-upload.component'
import { AuthService, ServerService } from '@app/core'
import { VideoImportTorrentComponent } from '@app/videos/+video-edit/video-add-components/video-import-torrent.component'
import { ServerConfig } from '@shared/models'
@Component({
selector: 'my-videos-add',
templateUrl: './video-add.component.html',
styleUrls: [ './video-add.component.scss' ]
})
export class VideoAddComponent implements CanComponentDeactivate {
export class VideoAddComponent implements OnInit, CanComponentDeactivate {
@ViewChild('videoUpload', { static: false }) videoUpload: VideoUploadComponent
@ViewChild('videoImportUrl', { static: false }) videoImportUrl: VideoImportUrlComponent
@ViewChild('videoImportTorrent', { static: false }) videoImportTorrent: VideoImportTorrentComponent
secondStepType: 'upload' | 'import-url' | 'import-torrent'
videoName: string
serverConfig: ServerConfig
constructor (
private auth: AuthService,
private serverService: ServerService
) {}
ngOnInit () {
this.serverConfig = this.serverService.getTmpConfig()
this.serverService.getConfig()
.subscribe(config => this.serverConfig = config)
}
onFirstStepDone (type: 'upload' | 'import-url' | 'import-torrent', videoName: string) {
this.secondStepType = type
this.videoName = videoName
@ -52,11 +61,11 @@ export class VideoAddComponent implements CanComponentDeactivate {
}
isVideoImportHttpEnabled () {
return this.serverService.getConfig().import.videos.http.enabled
return this.serverConfig.import.videos.http.enabled
}
isVideoImportTorrentEnabled () {
return this.serverService.getConfig().import.videos.torrent.enabled
return this.serverConfig.import.videos.torrent.enabled
}
isInSecondStep () {

View File

@ -8,7 +8,7 @@ import { MetaService } from '@ngx-meta/core'
import { AuthUser, Notifier, ServerService } from '@app/core'
import { forkJoin, Observable, Subscription } from 'rxjs'
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared'
import { ServerConfig, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared'
import { AuthService, ConfirmService } from '../../core'
import { RestExtractor, VideoBlacklistService } from '../../shared'
import { VideoDetails } from '../../shared/video/video-details.model'
@ -84,6 +84,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
private queryParamsSub: Subscription
private configSub: Subscription
private serverConfig: ServerConfig
constructor (
private elementRef: ElementRef,
private changeDetector: ChangeDetectorRef,
@ -120,11 +122,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}
async ngOnInit () {
this.configSub = this.serverService.configLoaded
.subscribe(() => {
this.serverConfig = this.serverService.getTmpConfig()
this.configSub = this.serverService.getConfig()
.subscribe(config => {
this.serverConfig = config
if (
isWebRTCDisabled() ||
this.serverService.getConfig().tracker.enabled === false ||
this.serverConfig.tracker.enabled === false ||
peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
) {
this.hasAlreadyAcceptedPrivacyConcern = true
@ -280,7 +286,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}
isVideoBlur (video: Video) {
return video.isVideoNSFWForUser(this.user, this.serverService.getConfig())
return video.isVideoNSFWForUser(this.user, this.serverConfig)
}
isAutoPlayEnabled () {

View File

@ -40,11 +40,8 @@ export class VideoMostLikedComponent extends AbstractVideoList implements OnInit
this.generateSyndicationList()
this.serverService.configLoaded.subscribe(
() => {
this.titlePage = this.i18n('Most liked videos')
this.titleTooltip = this.i18n('Videos that have the higher number of likes.')
})
this.titlePage = this.i18n('Most liked videos')
this.titleTooltip = this.i18n('Videos that have the higher number of likes.')
}
getVideosObservable (page: number) {

View File

@ -40,9 +40,9 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
this.generateSyndicationList()
this.serverService.configLoaded.subscribe(
() => {
const trendingDays = this.serverService.getConfig().trending.videos.intervalDays
this.serverService.getConfig().subscribe(
config => {
const trendingDays = config.trending.videos.intervalDays
if (trendingDays === 1) {
this.titlePage = this.i18n('Trending for the last 24 hours')

View File

@ -8,6 +8,6 @@ else
clientCommand="npm run build:client"
fi
npm run concurrently -- --raw \
npm run concurrently -- --raw \w
"$clientCommand" \
"npm run build:server"