]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/core/server/server.service.ts
Fix languages alphabetical sort
[github/Chocobozzz/PeerTube.git] / client / src / app / core / server / server.service.ts
CommitLineData
5fb2e288 1import { Observable, of, Subject } from 'rxjs'
ba430d75 2import { first, map, share, shareReplay, switchMap, tap } from 'rxjs/operators'
db7af09b 3import { HttpClient } from '@angular/common/http'
7ce44a74 4import { Inject, Injectable, LOCALE_ID } from '@angular/core'
4504f09f 5import { getDevLocale, isOnDevLocale, sortBy } from '@app/helpers'
42b40636 6import { logger } from '@root-helpers/logger'
bd45d503 7import { getCompleteLocale, isDefaultLocale, peertubeTranslate } from '@shared/core-utils/i18n'
9df52d66 8import { HTMLServerConfig, ServerConfig, ServerStats, VideoConstant } from '@shared/models'
5fb2e288 9import { environment } from '../../../environments/environment'
db7af09b
C
10
11@Injectable()
12export class ServerService {
63c4db6d
C
13 private static BASE_CONFIG_URL = environment.apiUrl + '/api/v1/config/'
14 private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
830b4faf 15 private static BASE_VIDEO_PLAYLIST_URL = environment.apiUrl + '/api/v1/video-playlists/'
7ce44a74 16 private static BASE_LOCALE_URL = environment.apiUrl + '/client/locales/'
b764380a
C
17 private static BASE_STATS_URL = environment.apiUrl + '/api/v1/server/stats'
18
72c33e71 19 configReloaded = new Subject<ServerConfig>()
baeefe22 20
ba430d75
C
21 private localeObservable: Observable<any>
22 private videoLicensesObservable: Observable<VideoConstant<number>[]>
23 private videoCategoriesObservable: Observable<VideoConstant<number>[]>
24 private videoPrivaciesObservable: Observable<VideoConstant<number>[]>
25 private videoPlaylistPrivaciesObservable: Observable<VideoConstant<number>[]>
26 private videoLanguagesObservable: Observable<VideoConstant<string>[]>
27 private configObservable: Observable<ServerConfig>
28
29 private configReset = false
30
31 private configLoaded = false
8e08d415
C
32 private config: ServerConfig
33 private htmlConfig: HTMLServerConfig
db7af09b 34
7ce44a74
C
35 constructor (
36 private http: HttpClient,
37 @Inject(LOCALE_ID) private localeId: string
38 ) {
8e08d415
C
39 }
40
2989628b 41 loadHTMLConfig () {
8e08d415 42 try {
15825ef1 43 this.loadHTMLConfigLocally()
8e08d415
C
44 } catch (err) {
45 // Expected in dev mode since we can't inject the config in the HTML
46 if (environment.production !== false) {
42b40636 47 logger.error('Cannot load config locally. Fallback to API.')
8e08d415
C
48 }
49
50 return this.getConfig()
51 }
36f9424f 52 }
db7af09b 53
ba430d75
C
54 getServerVersionAndCommit () {
55 const serverVersion = this.config.serverVersion
56 const commit = this.config.serverCommit || ''
00b5556c 57
ba430d75
C
58 let result = serverVersion
59 if (commit) result += '...' + commit
db7af09b 60
ba430d75 61 return result
db7af09b
C
62 }
63
ba430d75
C
64 resetConfig () {
65 this.configLoaded = false
66 this.configReset = true
72c33e71
C
67
68 // Notify config update
2539932e 69 return this.getConfig()
db7af09b
C
70 }
71
ba430d75
C
72 getConfig () {
73 if (this.configLoaded) return of(this.config)
db7af09b 74
ba430d75
C
75 if (!this.configObservable) {
76 this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
77 .pipe(
017fbe18
C
78 tap(config => {
79 this.config = config
2989628b 80 this.htmlConfig = config
017fbe18
C
81 this.configLoaded = true
82 }),
72c33e71 83 tap(config => {
ba430d75 84 if (this.configReset) {
72c33e71 85 this.configReloaded.next(config)
ba430d75
C
86 this.configReset = false
87 }
88 }),
89 share()
90 )
91 }
830b4faf 92
ba430d75 93 return this.configObservable
fd45e8f4
C
94 }
95
2989628b
C
96 getHTMLConfig () {
97 return this.htmlConfig
dbdf2d51
C
98 }
99
db7af09b 100 getVideoCategories () {
ba430d75
C
101 if (!this.videoCategoriesObservable) {
102 this.videoCategoriesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'categories', true)
103 }
104
105 return this.videoCategoriesObservable.pipe(first())
db7af09b
C
106 }
107
108 getVideoLicences () {
ba430d75
C
109 if (!this.videoLicensesObservable) {
110 this.videoLicensesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'licences')
111 }
112
113 return this.videoLicensesObservable.pipe(first())
db7af09b
C
114 }
115
116 getVideoLanguages () {
ba430d75
C
117 if (!this.videoLanguagesObservable) {
118 this.videoLanguagesObservable = this.loadAttributeEnum<string>(ServerService.BASE_VIDEO_URL, 'languages', true)
119 }
120
121 return this.videoLanguagesObservable.pipe(first())
db7af09b
C
122 }
123
fd45e8f4 124 getVideoPrivacies () {
ba430d75
C
125 if (!this.videoPrivaciesObservable) {
126 this.videoPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_URL, 'privacies')
127 }
128
129 return this.videoPrivaciesObservable.pipe(first())
fd45e8f4
C
130 }
131
830b4faf 132 getVideoPlaylistPrivacies () {
ba430d75
C
133 if (!this.videoPlaylistPrivaciesObservable) {
134 this.videoPlaylistPrivaciesObservable = this.loadAttributeEnum<number>(ServerService.BASE_VIDEO_PLAYLIST_URL, 'privacies')
135 }
136
137 return this.videoPlaylistPrivaciesObservable.pipe(first())
138 }
139
208c97e1 140 getServerLocale (): Observable<{ [ id: string ]: string }> {
ba430d75
C
141 if (!this.localeObservable) {
142 const completeLocale = isOnDevLocale() ? getDevLocale() : getCompleteLocale(this.localeId)
143
144 // Default locale, nothing to translate
145 if (isDefaultLocale(completeLocale)) {
146 this.localeObservable = of({}).pipe(shareReplay())
147 } else {
148 this.localeObservable = this.http
149 .get(ServerService.BASE_LOCALE_URL + completeLocale + '/server.json')
150 .pipe(shareReplay())
151 }
152 }
153
154 return this.localeObservable.pipe(first())
830b4faf
C
155 }
156
b764380a
C
157 getServerStats () {
158 return this.http.get<ServerStats>(ServerService.BASE_STATS_URL)
159 }
160
ba430d75 161 private loadAttributeEnum <T extends string | number> (
830b4faf 162 baseUrl: string,
fd45e8f4 163 attributeName: 'categories' | 'licences' | 'languages' | 'privacies',
3580fc00 164 sort = false
fd45e8f4 165 ) {
ba430d75
C
166 return this.getServerLocale()
167 .pipe(
168 switchMap(translations => {
169 return this.http.get<{ [ id: string ]: string }>(baseUrl + attributeName)
170 .pipe(map(data => ({ data, translations })))
171 }),
172 map(({ data, translations }) => {
111fdc26
C
173 const hashToPopulate: VideoConstant<T>[] = Object.keys(data)
174 .map(dataKey => {
9df52d66 175 const label = data[dataKey]
111fdc26
C
176
177 const id = attributeName === 'languages'
178 ? dataKey as T
179 : parseInt(dataKey, 10) as T
180
181 return {
182 id,
183 label: peertubeTranslate(label, translations)
184 }
185 })
ba430d75 186
7c77ace9
C
187 if (sort === true) {
188 hashToPopulate.sort((a, b) => a.label.localeCompare(b.label))
189 }
7ce44a74 190
ba430d75
C
191 return hashToPopulate
192 }),
193 shareReplay()
194 )
db7af09b 195 }
36f9424f 196
2989628b 197 private loadHTMLConfigLocally () {
54909304
C
198 // FIXME: typings
199 const configString = (window as any)['PeerTubeServerConfig']
8e08d415
C
200 if (!configString) {
201 throw new Error('Could not find PeerTubeServerConfig in HTML')
36f9424f 202 }
8e08d415 203
2989628b 204 this.htmlConfig = JSON.parse(configString)
36f9424f 205 }
db7af09b 206}