Better label for video privacies
[oweals/peertube.git] / client / src / app / core / server / server.service.ts
1 import { map, shareReplay, switchMap, tap } from 'rxjs/operators'
2 import { HttpClient } from '@angular/common/http'
3 import { Inject, Injectable, LOCALE_ID } from '@angular/core'
4 import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
5 import { Observable, of, ReplaySubject } from 'rxjs'
6 import { getCompleteLocale, ServerConfig } from '../../../../../shared'
7 import { About } from '../../../../../shared/models/server/about.model'
8 import { environment } from '../../../environments/environment'
9 import { VideoConstant, VideoPrivacy } from '../../../../../shared/models/videos'
10 import { isDefaultLocale, peertubeTranslate } from '../../../../../shared/models/i18n'
11 import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
12 import { sortBy } from '@app/shared/misc/utils'
13
14 @Injectable()
15 export class ServerService {
16   private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
17   private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
18   private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
19   private static CONFIG_LOCAL_STORAGE_KEY = 'server-config'
20
21   configLoaded = new ReplaySubject<boolean>(1)
22   videoPrivaciesLoaded = new ReplaySubject<boolean>(1)
23   videoCategoriesLoaded = new ReplaySubject<boolean>(1)
24   videoLicencesLoaded = new ReplaySubject<boolean>(1)
25   videoLanguagesLoaded = new ReplaySubject<boolean>(1)
26   localeObservable: Observable<any>
27
28   private config: ServerConfig = {
29     instance: {
30       name: 'PeerTube',
31       shortDescription: 'PeerTube, a federated (ActivityPub) video streaming platform  ' +
32                         'using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.',
33       defaultClientRoute: '',
34       defaultNSFWPolicy: 'do_not_list' as 'do_not_list',
35       customizations: {
36         javascript: '',
37         css: ''
38       }
39     },
40     serverVersion: 'Unknown',
41     signup: {
42       allowed: false,
43       allowedForCurrentIP: false,
44       requiresEmailVerification: false
45     },
46     transcoding: {
47       enabledResolutions: []
48     },
49     avatar: {
50       file: {
51         size: { max: 0 },
52         extensions: []
53       }
54     },
55     video: {
56       image: {
57         size: { max: 0 },
58         extensions: []
59       },
60       file: {
61         extensions: []
62       }
63     },
64     videoCaption: {
65       file: {
66         size: { max: 0 },
67         extensions: []
68       }
69     },
70     user: {
71       videoQuota: -1,
72       videoQuotaDaily: -1
73     },
74     import: {
75       videos: {
76         http: {
77           enabled: false
78         },
79         torrent: {
80           enabled: false
81         }
82       }
83     }
84   }
85   private videoCategories: Array<VideoConstant<number>> = []
86   private videoLicences: Array<VideoConstant<number>> = []
87   private videoLanguages: Array<VideoConstant<string>> = []
88   private videoPrivacies: Array<VideoConstant<VideoPrivacy>> = []
89
90   constructor (
91     private http: HttpClient,
92     @Inject(LOCALE_ID) private localeId: string
93   ) {
94     this.loadServerLocale()
95     this.loadConfigLocally()
96   }
97
98   loadConfig () {
99     this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
100         .pipe(tap(this.saveConfigLocally))
101         .subscribe(data => {
102           this.config = data
103
104           this.configLoaded.next(true)
105         })
106   }
107
108   loadVideoCategories () {
109     return this.loadVideoAttributeEnum('categories', this.videoCategories, this.videoCategoriesLoaded, true)
110   }
111
112   loadVideoLicences () {
113     return this.loadVideoAttributeEnum('licences', this.videoLicences, this.videoLicencesLoaded)
114   }
115
116   loadVideoLanguages () {
117     return this.loadVideoAttributeEnum('languages', this.videoLanguages, this.videoLanguagesLoaded, true)
118   }
119
120   loadVideoPrivacies () {
121     return this.loadVideoAttributeEnum('privacies', this.videoPrivacies, this.videoPrivaciesLoaded)
122   }
123
124   getConfig () {
125     return this.config
126   }
127
128   getVideoCategories () {
129     return this.videoCategories
130   }
131
132   getVideoLicences () {
133     return this.videoLicences
134   }
135
136   getVideoLanguages () {
137     return this.videoLanguages
138   }
139
140   getVideoPrivacies () {
141     return this.videoPrivacies
142   }
143
144   getAbout () {
145     return this.http.get<About>(ServerService.BASE_CONFIG_URL + '/about')
146   }
147
148   private loadVideoAttributeEnum (
149     attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
150     hashToPopulate: VideoConstant<string | number>[],
151     notifier: ReplaySubject<boolean>,
152     sort = false
153   ) {
154     this.localeObservable
155         .pipe(
156           switchMap(translations => {
157             return this.http.get(ServerService.BASE_VIDEO_URL + attributeName)
158                        .pipe(map(data => ({ data, translations })))
159           })
160         )
161         .subscribe(({ data, translations }) => {
162           Object.keys(data)
163                 .forEach(dataKey => {
164                   const label = data[ dataKey ]
165
166                   hashToPopulate.push({
167                     id: attributeName === 'languages' ? dataKey : parseInt(dataKey, 10),
168                     label: peertubeTranslate(label, translations)
169                   })
170                 })
171
172           if (sort === true) sortBy(hashToPopulate, 'label')
173
174           notifier.next(true)
175         })
176   }
177
178   private loadServerLocale () {
179     const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
180
181     // Default locale, nothing to translate
182     if (isDefaultLocale(completeLocale)) {
183       this.localeObservable = of({}).pipe(shareReplay())
184       return
185     }
186
187     this.localeObservable = this.http
188                                   .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
189                                   .pipe(shareReplay())
190   }
191
192   private saveConfigLocally (config: ServerConfig) {
193     peertubeLocalStorage.setItem(ServerService.CONFIG_LOCAL_STORAGE_KEY, JSON.stringify(config))
194   }
195
196   private loadConfigLocally () {
197     const configString = peertubeLocalStorage.getItem(ServerService.CONFIG_LOCAL_STORAGE_KEY)
198
199     if (configString) {
200       try {
201         const parsed = JSON.parse(configString)
202         Object.assign(this.config, parsed)
203       } catch (err) {
204         console.error('Cannot parse config saved in local storage.', err)
205       }
206     }
207   }
208 }