diff options
Diffstat (limited to 'client/src/app/shared')
-rw-r--r-- | client/src/app/shared/users/user.service.ts | 51 | ||||
-rw-r--r-- | client/src/app/shared/video/abstract-video-list.html | 2 | ||||
-rw-r--r-- | client/src/app/shared/video/abstract-video-list.ts | 69 | ||||
-rw-r--r-- | client/src/app/shared/video/video.service.ts | 50 |
4 files changed, 102 insertions, 70 deletions
diff --git a/client/src/app/shared/users/user.service.ts b/client/src/app/shared/users/user.service.ts index 7c1ae5799..de1c8ec94 100644 --- a/client/src/app/shared/users/user.service.ts +++ b/client/src/app/shared/users/user.service.ts | |||
@@ -1,19 +1,20 @@ | |||
1 | import { from, Observable } from 'rxjs' | 1 | import { has } from 'lodash-es' |
2 | import { catchError, concatMap, map, shareReplay, toArray } from 'rxjs/operators' | 2 | import { BytesPipe } from 'ngx-pipes' |
3 | import { SortMeta } from 'primeng/api' | ||
4 | import { from, Observable, of } from 'rxjs' | ||
5 | import { catchError, concatMap, first, map, shareReplay, toArray, throttleTime, filter } from 'rxjs/operators' | ||
3 | import { HttpClient, HttpParams } from '@angular/common/http' | 6 | import { HttpClient, HttpParams } from '@angular/common/http' |
4 | import { Injectable } from '@angular/core' | 7 | import { Injectable } from '@angular/core' |
5 | import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared' | 8 | import { AuthService } from '@app/core/auth' |
6 | import { environment } from '../../../environments/environment' | ||
7 | import { RestExtractor, RestPagination, RestService } from '../rest' | ||
8 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' | ||
9 | import { SortMeta } from 'primeng/api' | ||
10 | import { BytesPipe } from 'ngx-pipes' | ||
11 | import { I18n } from '@ngx-translate/i18n-polyfill' | 9 | import { I18n } from '@ngx-translate/i18n-polyfill' |
12 | import { UserRegister } from '@shared/models/users/user-register.model' | 10 | import { UserRegister } from '@shared/models/users/user-register.model' |
13 | import { User } from './user.model' | ||
14 | import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' | 11 | import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' |
15 | import { has } from 'lodash-es' | 12 | import { ResultList, User as UserServerModel, UserCreate, UserRole, UserUpdate, UserUpdateMe, UserVideoQuota } from '../../../../../shared' |
13 | import { Avatar } from '../../../../../shared/models/avatars/avatar.model' | ||
14 | import { environment } from '../../../environments/environment' | ||
16 | import { LocalStorageService, SessionStorageService } from '../misc/storage.service' | 15 | import { LocalStorageService, SessionStorageService } from '../misc/storage.service' |
16 | import { RestExtractor, RestPagination, RestService } from '../rest' | ||
17 | import { User } from './user.model' | ||
17 | 18 | ||
18 | @Injectable() | 19 | @Injectable() |
19 | export class UserService { | 20 | export class UserService { |
@@ -25,6 +26,7 @@ export class UserService { | |||
25 | 26 | ||
26 | constructor ( | 27 | constructor ( |
27 | private authHttp: HttpClient, | 28 | private authHttp: HttpClient, |
29 | private authService: AuthService, | ||
28 | private restExtractor: RestExtractor, | 30 | private restExtractor: RestExtractor, |
29 | private restService: RestService, | 31 | private restService: RestService, |
30 | private localStorageService: LocalStorageService, | 32 | private localStorageService: LocalStorageService, |
@@ -94,6 +96,21 @@ export class UserService { | |||
94 | } | 96 | } |
95 | } | 97 | } |
96 | 98 | ||
99 | listenAnonymousUpdate () { | ||
100 | return this.localStorageService.watch([ | ||
101 | User.KEYS.NSFW_POLICY, | ||
102 | User.KEYS.WEBTORRENT_ENABLED, | ||
103 | User.KEYS.AUTO_PLAY_VIDEO, | ||
104 | User.KEYS.AUTO_PLAY_VIDEO_PLAYLIST, | ||
105 | User.KEYS.THEME, | ||
106 | User.KEYS.VIDEO_LANGUAGES | ||
107 | ]).pipe( | ||
108 | throttleTime(200), | ||
109 | filter(() => this.authService.isLoggedIn() !== true), | ||
110 | map(() => this.getAnonymousUser()) | ||
111 | ) | ||
112 | } | ||
113 | |||
97 | deleteMe () { | 114 | deleteMe () { |
98 | const url = UserService.BASE_USERS_URL + 'me' | 115 | const url = UserService.BASE_USERS_URL + 'me' |
99 | 116 | ||
@@ -241,7 +258,7 @@ export class UserService { | |||
241 | } | 258 | } |
242 | 259 | ||
243 | getAnonymousUser () { | 260 | getAnonymousUser () { |
244 | let videoLanguages | 261 | let videoLanguages: string[] |
245 | 262 | ||
246 | try { | 263 | try { |
247 | videoLanguages = JSON.parse(this.localStorageService.getItem(User.KEYS.VIDEO_LANGUAGES)) | 264 | videoLanguages = JSON.parse(this.localStorageService.getItem(User.KEYS.VIDEO_LANGUAGES)) |
@@ -313,6 +330,18 @@ export class UserService { | |||
313 | ) | 330 | ) |
314 | } | 331 | } |
315 | 332 | ||
333 | getAnonymousOrLoggedUser () { | ||
334 | if (!this.authService.isLoggedIn()) { | ||
335 | return of(this.getAnonymousUser()) | ||
336 | } | ||
337 | |||
338 | return this.authService.userInformationLoaded | ||
339 | .pipe( | ||
340 | first(), | ||
341 | map(() => this.authService.getUser()) | ||
342 | ) | ||
343 | } | ||
344 | |||
316 | private formatUser (user: UserServerModel) { | 345 | private formatUser (user: UserServerModel) { |
317 | let videoQuota | 346 | let videoQuota |
318 | if (user.videoQuota === -1) { | 347 | if (user.videoQuota === -1) { |
diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index 548370843..1e919ee72 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html | |||
@@ -38,7 +38,7 @@ | |||
38 | <div class="video-wrapper"> | 38 | <div class="video-wrapper"> |
39 | <my-video-miniature | 39 | <my-video-miniature |
40 | [fitWidth]="true" | 40 | [fitWidth]="true" |
41 | [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" | 41 | [video]="video" [user]="userMiniature" [ownerDisplayType]="ownerDisplayType" |
42 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" | 42 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" |
43 | (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" | 43 | (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" |
44 | > | 44 | > |
diff --git a/client/src/app/shared/video/abstract-video-list.ts b/client/src/app/shared/video/abstract-video-list.ts index 76aa683fc..0bc339ff6 100644 --- a/client/src/app/shared/video/abstract-video-list.ts +++ b/client/src/app/shared/video/abstract-video-list.ts | |||
@@ -1,22 +1,23 @@ | |||
1 | import { debounceTime, first, tap, throttleTime } from 'rxjs/operators' | 1 | import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs' |
2 | import { debounceTime, tap, throttleTime, switchMap } from 'rxjs/operators' | ||
2 | import { OnDestroy, OnInit } from '@angular/core' | 3 | import { OnDestroy, OnInit } from '@angular/core' |
3 | import { ActivatedRoute, Router } from '@angular/router' | 4 | import { ActivatedRoute, Router } from '@angular/router' |
4 | import { fromEvent, Observable, of, Subject, Subscription } from 'rxjs' | ||
5 | import { AuthService } from '../../core/auth' | ||
6 | import { ComponentPaginationLight } from '../rest/component-pagination.model' | ||
7 | import { VideoSortField } from './sort-field.type' | ||
8 | import { Video } from './video.model' | ||
9 | import { ScreenService } from '@app/shared/misc/screen.service' | ||
10 | import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/video-miniature.component' | ||
11 | import { Syndication } from '@app/shared/video/syndication.model' | ||
12 | import { Notifier, ServerService } from '@app/core' | 5 | import { Notifier, ServerService } from '@app/core' |
13 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' | 6 | import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook' |
7 | import { GlobalIconName } from '@app/shared/images/global-icon.component' | ||
8 | import { ScreenService } from '@app/shared/misc/screen.service' | ||
9 | import { Syndication } from '@app/shared/video/syndication.model' | ||
10 | import { MiniatureDisplayOptions, OwnerDisplayType } from '@app/shared/video/video-miniature.component' | ||
14 | import { I18n } from '@ngx-translate/i18n-polyfill' | 11 | import { I18n } from '@ngx-translate/i18n-polyfill' |
15 | import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date' | 12 | import { isLastMonth, isLastWeek, isToday, isYesterday } from '@shared/core-utils/miscs/date' |
16 | import { ServerConfig } from '@shared/models' | 13 | import { ServerConfig } from '@shared/models' |
17 | import { GlobalIconName } from '@app/shared/images/global-icon.component' | 14 | import { NSFWPolicyType } from '@shared/models/videos/nsfw-policy.type' |
18 | import { UserService, User } from '../users' | 15 | import { AuthService } from '../../core/auth' |
19 | import { LocalStorageService } from '../misc/storage.service' | 16 | import { LocalStorageService } from '../misc/storage.service' |
17 | import { ComponentPaginationLight } from '../rest/component-pagination.model' | ||
18 | import { User, UserService } from '../users' | ||
19 | import { VideoSortField } from './sort-field.type' | ||
20 | import { Video } from './video.model' | ||
20 | 21 | ||
21 | enum GroupDate { | 22 | enum GroupDate { |
22 | UNKNOWN = 0, | 23 | UNKNOWN = 0, |
@@ -34,14 +35,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
34 | } | 35 | } |
35 | sort: VideoSortField = '-publishedAt' | 36 | sort: VideoSortField = '-publishedAt' |
36 | 37 | ||
37 | categoryOneOf?: number | 38 | categoryOneOf?: number[] |
38 | languageOneOf?: string[] | 39 | languageOneOf?: string[] |
40 | nsfwPolicy?: NSFWPolicyType | ||
39 | defaultSort: VideoSortField = '-publishedAt' | 41 | defaultSort: VideoSortField = '-publishedAt' |
40 | 42 | ||
41 | syndicationItems: Syndication[] = [] | 43 | syndicationItems: Syndication[] = [] |
42 | 44 | ||
43 | loadOnInit = true | 45 | loadOnInit = true |
44 | useUserVideoLanguagePreferences = false | 46 | useUserVideoPreferences = false |
45 | ownerDisplayType: OwnerDisplayType = 'account' | 47 | ownerDisplayType: OwnerDisplayType = 'account' |
46 | displayModerationBlock = false | 48 | displayModerationBlock = false |
47 | titleTooltip: string | 49 | titleTooltip: string |
@@ -71,6 +73,8 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
71 | 73 | ||
72 | onDataSubject = new Subject<any[]>() | 74 | onDataSubject = new Subject<any[]>() |
73 | 75 | ||
76 | userMiniature: User | ||
77 | |||
74 | protected serverConfig: ServerConfig | 78 | protected serverConfig: ServerConfig |
75 | 79 | ||
76 | protected abstract notifier: Notifier | 80 | protected abstract notifier: Notifier |
@@ -96,10 +100,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
96 | 100 | ||
97 | abstract generateSyndicationList (): void | 101 | abstract generateSyndicationList (): void |
98 | 102 | ||
99 | get user () { | ||
100 | return this.authService.getUser() | ||
101 | } | ||
102 | |||
103 | ngOnInit () { | 103 | ngOnInit () { |
104 | this.serverConfig = this.serverService.getTmpConfig() | 104 | this.serverConfig = this.serverService.getTmpConfig() |
105 | this.serverService.getConfig() | 105 | this.serverService.getConfig() |
@@ -124,21 +124,17 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
124 | 124 | ||
125 | this.calcPageSizes() | 125 | this.calcPageSizes() |
126 | 126 | ||
127 | const loadUserObservable = this.loadUserVideoLanguagesIfNeeded() | 127 | const loadUserObservable = this.loadUserAndSettings() |
128 | 128 | ||
129 | if (this.loadOnInit === true) { | 129 | if (this.loadOnInit === true) { |
130 | loadUserObservable.subscribe(() => this.loadMoreVideos()) | 130 | loadUserObservable.subscribe(() => this.loadMoreVideos()) |
131 | } | 131 | } |
132 | 132 | ||
133 | this.storageService.watch([ | 133 | this.userService.listenAnonymousUpdate() |
134 | User.KEYS.NSFW_POLICY, | 134 | .pipe(switchMap(() => this.loadUserAndSettings())) |
135 | User.KEYS.VIDEO_LANGUAGES | 135 | .subscribe(() => { |
136 | ]).pipe(throttleTime(200)).subscribe( | ||
137 | () => { | ||
138 | this.loadUserVideoLanguagesIfNeeded() | ||
139 | if (this.hasDoneFirstQuery) this.reloadVideos() | 136 | if (this.hasDoneFirstQuery) this.reloadVideos() |
140 | } | 137 | }) |
141 | ) | ||
142 | 138 | ||
143 | // Display avatar in mobile view | 139 | // Display avatar in mobile view |
144 | if (this.screenService.isInMobileView()) { | 140 | if (this.screenService.isInMobileView()) { |
@@ -298,20 +294,15 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, DisableFor | |||
298 | this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' }) | 294 | this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' }) |
299 | } | 295 | } |
300 | 296 | ||
301 | private loadUserVideoLanguagesIfNeeded () { | 297 | private loadUserAndSettings () { |
302 | if (!this.useUserVideoLanguagePreferences) { | 298 | return this.userService.getAnonymousOrLoggedUser() |
303 | return of(true) | 299 | .pipe(tap(user => { |
304 | } | 300 | this.userMiniature = user |
305 | 301 | ||
306 | if (!this.authService.isLoggedIn()) { | 302 | if (!this.useUserVideoPreferences) return |
307 | this.languageOneOf = this.userService.getAnonymousUser().videoLanguages | ||
308 | return of(true) | ||
309 | } | ||
310 | 303 | ||
311 | return this.authService.userInformationLoaded | 304 | this.languageOneOf = user.videoLanguages |
312 | .pipe( | 305 | this.nsfwPolicy = user.nsfwPolicy |
313 | first(), | 306 | })) |
314 | tap(() => this.languageOneOf = this.user.videoLanguages) | ||
315 | ) | ||
316 | } | 307 | } |
317 | } | 308 | } |
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts index 3aaf14990..d66a1f809 100644 --- a/client/src/app/shared/video/video.service.ts +++ b/client/src/app/shared/video/video.service.ts | |||
@@ -39,8 +39,9 @@ export interface VideosProvider { | |||
39 | videoPagination: ComponentPaginationLight, | 39 | videoPagination: ComponentPaginationLight, |
40 | sort: VideoSortField, | 40 | sort: VideoSortField, |
41 | filter?: VideoFilter, | 41 | filter?: VideoFilter, |
42 | categoryOneOf?: number, | 42 | categoryOneOf?: number[], |
43 | languageOneOf?: string[] | 43 | languageOneOf?: string[] |
44 | nsfwPolicy: NSFWPolicyType | ||
44 | }): Observable<ResultList<Video>> | 45 | }): Observable<ResultList<Video>> |
45 | } | 46 | } |
46 | 47 | ||
@@ -161,13 +162,18 @@ export class VideoService implements VideosProvider { | |||
161 | getVideoChannelVideos ( | 162 | getVideoChannelVideos ( |
162 | videoChannel: VideoChannel, | 163 | videoChannel: VideoChannel, |
163 | videoPagination: ComponentPaginationLight, | 164 | videoPagination: ComponentPaginationLight, |
164 | sort: VideoSortField | 165 | sort: VideoSortField, |
166 | nsfwPolicy?: NSFWPolicyType | ||
165 | ): Observable<ResultList<Video>> { | 167 | ): Observable<ResultList<Video>> { |
166 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) | 168 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) |
167 | 169 | ||
168 | let params = new HttpParams() | 170 | let params = new HttpParams() |
169 | params = this.restService.addRestGetParams(params, pagination, sort) | 171 | params = this.restService.addRestGetParams(params, pagination, sort) |
170 | 172 | ||
173 | if (nsfwPolicy) { | ||
174 | params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy)) | ||
175 | } | ||
176 | |||
171 | return this.authHttp | 177 | return this.authHttp |
172 | .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params }) | 178 | .get<ResultList<Video>>(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.nameWithHost + '/videos', { params }) |
173 | .pipe( | 179 | .pipe( |
@@ -201,12 +207,12 @@ export class VideoService implements VideosProvider { | |||
201 | videoPagination: ComponentPaginationLight, | 207 | videoPagination: ComponentPaginationLight, |
202 | sort: VideoSortField, | 208 | sort: VideoSortField, |
203 | filter?: VideoFilter, | 209 | filter?: VideoFilter, |
204 | categoryOneOf?: number, | 210 | categoryOneOf?: number[], |
205 | languageOneOf?: string[], | 211 | languageOneOf?: string[], |
206 | skipCount?: boolean, | 212 | skipCount?: boolean, |
207 | nsfw?: boolean | 213 | nsfwPolicy?: NSFWPolicyType |
208 | }): Observable<ResultList<Video>> { | 214 | }): Observable<ResultList<Video>> { |
209 | const { videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfw } = parameters | 215 | const { videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfwPolicy } = parameters |
210 | 216 | ||
211 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) | 217 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) |
212 | 218 | ||
@@ -214,16 +220,10 @@ export class VideoService implements VideosProvider { | |||
214 | params = this.restService.addRestGetParams(params, pagination, sort) | 220 | params = this.restService.addRestGetParams(params, pagination, sort) |
215 | 221 | ||
216 | if (filter) params = params.set('filter', filter) | 222 | if (filter) params = params.set('filter', filter) |
217 | if (categoryOneOf) params = params.set('categoryOneOf', categoryOneOf + '') | ||
218 | if (skipCount) params = params.set('skipCount', skipCount + '') | 223 | if (skipCount) params = params.set('skipCount', skipCount + '') |
219 | 224 | ||
220 | if (nsfw) { | 225 | if (nsfwPolicy) { |
221 | params = params.set('nsfw', nsfw + '') | 226 | params = params.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy)) |
222 | } else { | ||
223 | const nsfwPolicy = this.authService.isLoggedIn() | ||
224 | ? this.authService.getUser().nsfwPolicy | ||
225 | : this.userService.getAnonymousUser().nsfwPolicy | ||
226 | if (this.nsfwPolicyToFilter(nsfwPolicy)) params.set('nsfw', 'false') | ||
227 | } | 227 | } |
228 | 228 | ||
229 | if (languageOneOf) { | 229 | if (languageOneOf) { |
@@ -232,6 +232,12 @@ export class VideoService implements VideosProvider { | |||
232 | } | 232 | } |
233 | } | 233 | } |
234 | 234 | ||
235 | if (categoryOneOf) { | ||
236 | for (const c of categoryOneOf) { | ||
237 | params = params.append('categoryOneOf[]', c + '') | ||
238 | } | ||
239 | } | ||
240 | |||
235 | return this.authHttp | 241 | return this.authHttp |
236 | .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params }) | 242 | .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params }) |
237 | .pipe( | 243 | .pipe( |
@@ -268,12 +274,16 @@ export class VideoService implements VideosProvider { | |||
268 | return feeds | 274 | return feeds |
269 | } | 275 | } |
270 | 276 | ||
271 | getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter, categoryOneOf?: number) { | 277 | getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter, categoryOneOf?: number[]) { |
272 | let params = this.restService.addRestGetParams(new HttpParams(), undefined, sort) | 278 | let params = this.restService.addRestGetParams(new HttpParams(), undefined, sort) |
273 | 279 | ||
274 | if (filter) params = params.set('filter', filter) | 280 | if (filter) params = params.set('filter', filter) |
275 | 281 | ||
276 | if (categoryOneOf) params = params.set('categoryOneOf', categoryOneOf + '') | 282 | if (categoryOneOf) { |
283 | for (const c of categoryOneOf) { | ||
284 | params = params.append('categoryOneOf[]', c + '') | ||
285 | } | ||
286 | } | ||
277 | 287 | ||
278 | return this.buildBaseFeedUrls(params) | 288 | return this.buildBaseFeedUrls(params) |
279 | } | 289 | } |
@@ -377,6 +387,12 @@ export class VideoService implements VideosProvider { | |||
377 | return base.filter(o => !!privacies.find(p => p.id === o.id)) | 387 | return base.filter(o => !!privacies.find(p => p.id === o.id)) |
378 | } | 388 | } |
379 | 389 | ||
390 | nsfwPolicyToParam (nsfwPolicy: NSFWPolicyType) { | ||
391 | return nsfwPolicy === 'do_not_list' | ||
392 | ? 'false' | ||
393 | : 'both' | ||
394 | } | ||
395 | |||
380 | private setVideoRate (id: number, rateType: UserVideoRateType) { | 396 | private setVideoRate (id: number, rateType: UserVideoRateType) { |
381 | const url = VideoService.BASE_VIDEO_URL + id + '/rate' | 397 | const url = VideoService.BASE_VIDEO_URL + id + '/rate' |
382 | const body: UserVideoRateUpdate = { | 398 | const body: UserVideoRateUpdate = { |
@@ -390,8 +406,4 @@ export class VideoService implements VideosProvider { | |||
390 | catchError(err => this.restExtractor.handleError(err)) | 406 | catchError(err => this.restExtractor.handleError(err)) |
391 | ) | 407 | ) |
392 | } | 408 | } |
393 | |||
394 | private nsfwPolicyToFilter (policy: NSFWPolicyType) { | ||
395 | return policy === 'do_not_list' | ||
396 | } | ||
397 | } | 409 | } |