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',
languages: string[] = []
categories: string[] = []
+ serverConfig: ServerConfig
+
constructor (
private notifier: Notifier,
private serverService: ServerService,
) {}
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
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'))
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',
error: string
private openedModal: NgbModalRef
+ private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
}
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,
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',
languageItems: SelectItem[] = []
categoryItems: SelectItem[] = []
+ private serverConfig: ServerConfig
+
constructor (
protected formValidatorService: FormValidatorService,
private customConfigValidatorsService: CustomConfigValidatorsService,
}
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)
+
const formGroupData: { [key in keyof CustomConfig ]: any } = {
instance: {
name: this.customConfigValidatorsService.INSTANCE_NAME,
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()
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()
-import { Component } from '@angular/core'
+import { Component, OnInit } from '@angular/core'
import { UserRight } from '../../../../../shared'
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 () {
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 = [
{
]
}
- ngOnInit () {
- this.initialize()
- }
-
getVideoUrl (videoBlacklist: VideoBlacklist) {
return Video.buildClientUrl(videoBlacklist.video.uuid)
}
}
ngOnInit () {
+ super.ngOnInit()
+
const defaultValues = {
role: UserRole.USER.toString(),
videoQuota: '-1',
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()
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
}
ngOnInit () {
+ super.ngOnInit()
+
const defaultValues = { videoQuota: '-1', videoQuotaDaily: '-1' }
this.buildForm({
email: this.userValidatorsService.USER_EMAIL,
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'
selectedUsers: User[] = []
bulkUserActions: DropdownAction<User[]>[] = []
+ private serverConfig: ServerConfig
+
constructor (
private notifier: Notifier,
private confirmService: ConfirmService,
}
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 = [
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',
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
- }
+ if (config.signup.requiresEmailVerification) {
+ this.success = this.i18n('Please check your emails to verify your new email.')
+ } else {
+ this.success = this.i18n('Email updated.')
+ }
+ },
- this.error = err.message
+ err => {
+ if (err.status === 401) {
+ this.error = this.i18n('You current password is invalid.')
+ return
}
- )
+
+ this.error = err.message
+ }
+ )
}
}
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'
@Input() user: User = null
@Input() userInformationLoaded: Subject<any>
+ private serverConfig: ServerConfig
+
constructor (
protected formValidatorService: FormValidatorService,
private authService: AuthService,
}
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
})
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)
private serverService: ServerService,
private notifier: Notifier
) {
-
this.labelNotifications = {
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
newCommentOnMyVideo: this.i18n('New comment on your video'),
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())
}
})
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 })))
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',
private paramsSub: Subscription
private oldSupportField: string
+ private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
}
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,
}
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 () {
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 () {
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'
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()
},
-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'),
}
isVideoImportEnabled () {
- const importConfig = this.serverService.getConfig().import.videos
+ const importConfig = this.serverConfig.import.videos
return importConfig.http.enabled || importConfig.torrent.enabled
}
-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) {
}
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(',')
}
}
}
},
resolve: {
- serverConfigLoaded: ServerConfigResolver
+ serverConfig: ServerConfigResolver
}
}
]
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',
formStepUser: FormGroup
formStepChannel: FormGroup
+ private serverConfig: ServerConfig
+
constructor (
+ private route: ActivatedRoute,
private authService: AuthService,
private userValidatorsService: UserValidatorsService,
private notifier: Notifier,
}
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 => {
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',
})
export class VerifyAccountAskSendEmailComponent extends FormReactive implements OnInit {
+ private serverConfig: ServerConfig
constructor (
protected formValidatorService: FormValidatorService,
}
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
})
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'
customCSS: SafeHtml
+ private serverConfig: ServerConfig
+
constructor (
private i18n: I18n,
private viewportScroller: ViewportScroller,
) { }
get instanceName () {
- return this.serverService.getConfig().instance.name
+ return this.serverConfig.instance.name
}
get defaultRoute () {
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()
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
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
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)
}
})
}
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
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 }
}
})
}
}
initializePlugins () {
- this.server.configLoaded
- .subscribe(() => {
- this.plugins = this.server.getConfig().plugin.registered
+ this.server.getConfig()
+ .subscribe(config => {
+ this.plugins = config.plugin.registered
this.buildScopeStruct()
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
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()
}
}
-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',
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
+ getServerVersionAndCommit () {
+ const serverVersion = this.config.serverVersion
+ const commit = this.config.serverCommit || ''
- this.configLoaded.next(true)
- })
- }
+ let result = serverVersion
+ if (commit) result += '...' + commit
- loadVideoCategories () {
- return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'categories', this.videoCategories, this.videoCategoriesLoaded, true)
+ return result
}
- loadVideoLicences () {
- return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'licences', this.videoLicences, this.videoLicencesLoaded)
+ resetConfig () {
+ this.configLoaded = false
+ this.configReset = true
}
- loadVideoLanguages () {
- return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'languages', this.videoLanguages, this.videoLanguagesLoaded, true)
- }
+ getConfig () {
+ if (this.configLoaded) return of(this.config)
- loadVideoPrivacies () {
- return this.loadAttributeEnum(ServerService.BASE_VIDEO_URL, 'privacies', this.videoPrivacies, this.videoPrivaciesLoaded)
- }
+ 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()
+ )
+ }
- loadVideoPlaylistPrivacies () {
- return this.loadAttributeEnum(
- ServerService.BASE_VIDEO_PLAYLIST_URL,
- 'privacies',
- this.videoPlaylistPrivacies,
- this.videoPlaylistPrivaciesLoaded
- )
+ return this.configObservable
}
- getConfig () {
- return cloneDeep(this.config)
- }
-
- getServerVersionAndCommit () {
- const serverVersion = this.config.serverVersion
- const commit = this.config.serverCommit || ''
-
- let result = `v${serverVersion}`
- if (commit) result += '...' + commit
-
- return result
+ 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)
+ if (!this.videoPlaylistPrivaciesObservable) {
+ this.videoPlaylistPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_PLAYLIST_URL, 'privacies')
+ }
+
+ 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 (
+ private loadAttributeEnum <T extends string | number> (
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)
- })
- }
+ 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>[] = []
- private loadServerLocale () {
- const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
+ Object.keys(data)
+ .forEach(dataKey => {
+ const label = data[ dataKey ]
- // Default locale, nothing to translate
- if (isDefaultLocale(completeLocale)) {
- this.localeObservable = of({}).pipe(shareReplay())
- return
- }
+ hashToPopulate.push({
+ id: (attributeName === 'languages' ? dataKey : parseInt(dataKey, 10)) as T,
+ label: peertubeTranslate(label, translations)
+ })
+ })
+
+ if (sort === true) sortBy(hashToPopulate, 'label')
- this.localeObservable = this.http
- .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
- .pipe(shareReplay())
+ return hashToPopulate
+ }),
+ shareReplay()
+ )
}
private saveConfigLocally (config: ServerConfig) {
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'
private themeFromLocalStorage: ServerConfigTheme
private themeDOMLinksFromLocalStorage: HTMLLinkElement[] = []
+ private serverConfig: ServerConfig
+
constructor (
private auth: AuthService,
private pluginService: PluginService,
// 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)
if (theme !== 'instance-default') return theme
}
- return this.server.getConfig().theme.default
+ return this.serverConfig.theme.default
}
private loadTheme (name: string) {
}
},
resolve: {
- serverConfigLoaded: ServerConfigResolver
+ serverConfig: ServerConfigResolver
}
}
]
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',
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,
}
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
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',
userHasAdminAccess = false
helpVisible = false
+ private serverConfig: ServerConfig
private routesPerRight: { [ role in UserRight ]?: string } = {
[UserRight.MANAGE_USERS]: '/admin/users',
[UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
) {}
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()
}
isRegistrationAllowed () {
- return this.serverService.getConfig().signup.allowed &&
- this.serverService.getConfig().signup.allowedForCurrentIP
+ return this.serverConfig.signup.allowed &&
+ this.serverConfig.signup.allowedForCurrentIP
}
getFirstAdminRightAvailable () {
-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',
originallyPublishedStartYear: string
originallyPublishedEndYear: string
+ private serverConfig: ServerConfig
+
constructor (
private i18n: I18n,
private videoValidatorsService: VideoValidatorsService,
}
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()
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',
imageSrc: SafeResourceUrl
allowedExtensionsMessage = ''
+ private serverConfig: ServerConfig
private file: File
constructor (
) {}
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(', ')
}
<div class="feature-table">
- <table class="table" *ngIf="config">
+ <table class="table" *ngIf="serverConfig">
<tr>
<td i18n class="label">PeerTube version</td>
<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>
<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>
<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>
<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>
})
export class InstanceFeaturesTableComponent implements OnInit {
quotaHelpIndication = ''
- config: ServerConfig
+ serverConfig: ServerConfig
constructor (
private i18n: I18n,
}
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 = ''
return this.i18n('~ {{minutes}} {minutes, plural, =1 {minute} other {minutes}}', { minutes })
}
- getServerVersionAndCommit () {
- return this.serverService.getServerVersionAndCommit()
- }
-
private buildQuotaHelpIndication () {
if (this.initialUserVideoQuota === -1) return
-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'
import { MarkdownService } from '@app/shared/renderer'
import { peertubeTranslate } from '@shared/models'
import { ServerService } from '@app/core'
+import { forkJoin } from 'rxjs'
@Injectable()
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()
-
- return about.instance.categories
- .map(c => {
- const categoryObj = categoriesArray.find(ca => ca.id === c)
+ 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 peertubeTranslate(categoryObj.label, translations)
- })
+ return peertubeTranslate(categoryObj.label, translations)
+ })
+ })
+ )
}
}
-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'
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
userActions: DropdownAction<{ user: User, account: Account }>[][] = []
+ private serverConfig: ServerConfig
+
constructor (
private authService: AuthService,
private notifier: Notifier,
) { }
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 () {
.pipe(
// Translate categories
switchMap(() => {
- return this.serverService.localeObservable
+ return this.serverService.getServerLocale()
.pipe(
tap(translations => {
for (const c of videosOverviewResult.categories) {
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 }) => {
}
private extractVideoImports (result: ResultList<VideoImport>): Observable<ResultList<VideoImport>> {
- return this.serverService.localeObservable
+ return this.serverService.getServerLocale()
.pipe(
map(translations => {
result.data.forEach(d =>
-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'
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
stopTimestamp: number
} = {} as any
+ private serverConfig: ServerConfig
+
constructor (
private authService: AuthService,
private serverService: ServerService,
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
}
}
isVideoBlur (video: Video) {
- return video.isVideoNSFWForUser(this.authService.getUser(), this.serverService.getConfig())
+ return video.isVideoNSFWForUser(this.authService.getUser(), this.serverConfig)
}
removeFromPlaylist (playlistElement: VideoPlaylistElement) {
}
extractPlaylists (result: ResultList<VideoPlaylistServerModel>) {
- return this.serverService.localeObservable
+ return this.serverService.getServerLocale()
.pipe(
map(translations => {
const playlistsJSON = result.data
}
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
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,
onDataSubject = new Subject<any[]>()
+ protected serverConfig: ServerConfig
+
protected abstract notifier: Notifier
protected abstract authService: AuthService
protected abstract route: ActivatedRoute
}
ngOnInit () {
+ this.serverConfig = this.serverService.getTmpConfig()
+ this.serverService.getConfig()
+ .subscribe(config => this.serverConfig = config)
+
this.groupedDateLabels = {
[GroupDate.UNKNOWN]: null,
[GroupDate.TODAY]: this.i18n('Today'),
}
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' })
}
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'
report: true
}
showActions = false
+ serverConfig: ServerConfig
private ownerDisplayTypeChosen: 'account' | 'videoChannel'
) { }
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
}
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)
}
extractVideos (result: ResultList<VideoServerModel>) {
- return this.serverService.localeObservable
+ return this.serverService.getServerLocale()
.pipe(
map(translations => {
const videosJson = result.data
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',
export class VideoCaptionAddModalComponent extends FormReactive implements OnInit {
@Input() existingCaptions: string[]
+ @Input() serverConfig: ServerConfig
@Output() captionAdded = new EventEmitter<VideoCaptionEdit>()
}
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,
</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>
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({
calendarTimezone: string
calendarDateFormat: string
+ serverConfig: ServerConfig
+
private schedulerInterval: any
private firstPatchDone = false
private initialVideoCaptions: string[] = []
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)
+
+ this.serverService.getVideoPrivacies()
+ .subscribe(privacies => this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies))
- const privacies = this.serverService.getVideoPrivacies()
- 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)
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'
protected serverService: ServerService
protected videoService: VideoService
protected videoCaptionService: VideoCaptionService
+ protected serverConfig: ServerConfig
abstract canDeactivate (): CanComponentDeactivateResult
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
})
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',
}
get videoExtensions () {
- return this.serverService.getConfig().video.file.extensions.join(',')
+ return this.serverConfig.video.file.extensions.join(',')
}
ngOnInit () {
}
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
-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
}
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 () {
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'
private queryParamsSub: Subscription
private configSub: Subscription
+ private serverConfig: ServerConfig
+
constructor (
private elementRef: ElementRef,
private changeDetector: ChangeDetectorRef,
}
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
}
isVideoBlur (video: Video) {
- return video.isVideoNSFWForUser(this.user, this.serverService.getConfig())
+ return video.isVideoNSFWForUser(this.user, this.serverConfig)
}
isAutoPlayEnabled () {
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) {
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')
clientCommand="npm run build:client"
fi
-npm run concurrently -- --raw \
+npm run concurrently -- --raw \w
"$clientCommand" \
"npm run build:server"