]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - client/src/app/shared/shared-main/video/video.service.ts
Add ability to exclude muted accounts
[github/Chocobozzz/PeerTube.git] / client / src / app / shared / shared-main / video / video.service.ts
index 3481b116f132b3d2a455808a1019436ecdd0a7ee..b7c563dca3552f0d7b2faf3ece514a78662f0a8f 100644 (file)
@@ -1,9 +1,11 @@
-import { Observable } from 'rxjs'
-import { catchError, map, switchMap } from 'rxjs/operators'
+import { SortMeta } from 'primeng/api'
+import { from, Observable } from 'rxjs'
+import { catchError, concatMap, map, switchMap, toArray } from 'rxjs/operators'
 import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
 import { Injectable } from '@angular/core'
-import { ComponentPaginationLight, RestExtractor, RestService, ServerService, UserService } from '@app/core'
+import { ComponentPaginationLight, RestExtractor, RestPagination, RestService, ServerService, UserService } from '@app/core'
 import { objectToFormData } from '@app/helpers'
+import { AdvancedInputFilter } from '@app/shared/shared-forms'
 import {
   BooleanBothQuery,
   FeedFormat,
@@ -13,10 +15,11 @@ import {
   UserVideoRateType,
   UserVideoRateUpdate,
   Video as VideoServerModel,
+  VideoChannel as VideoChannelServerModel,
   VideoConstant,
   VideoDetails as VideoDetailsServerModel,
   VideoFileMetadata,
-  VideoFilter,
+  VideoInclude,
   VideoPrivacy,
   VideoSortField,
   VideoUpdate
@@ -30,13 +33,15 @@ import { VideoEdit } from './video-edit.model'
 import { Video } from './video.model'
 
 export type CommonVideoParams = {
-  videoPagination: ComponentPaginationLight
-  sort: VideoSortField
-  filter?: VideoFilter
+  videoPagination?: ComponentPaginationLight
+  sort: VideoSortField | SortMeta
+  include?: VideoInclude
+  isLocal?: boolean
   categoryOneOf?: number[]
   languageOneOf?: string[]
   isLive?: boolean
   skipCount?: boolean
+
   // FIXME: remove?
   nsfwPolicy?: NSFWPolicyType
   nsfw?: BooleanBothQuery
@@ -44,7 +49,7 @@ export type CommonVideoParams = {
 
 @Injectable()
 export class VideoService {
-  static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
+  static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos'
   static BASE_FEEDS_URL = environment.apiUrl + '/feeds/videos.'
   static BASE_SUBSCRIPTION_FEEDS_URL = environment.apiUrl + '/feeds/subscriptions.'
 
@@ -56,18 +61,18 @@ export class VideoService {
   ) {}
 
   getVideoViewUrl (uuid: string) {
-    return VideoService.BASE_VIDEO_URL + uuid + '/views'
+    return `${VideoService.BASE_VIDEO_URL}/${uuid}/views`
   }
 
   getUserWatchingVideoUrl (uuid: string) {
-    return VideoService.BASE_VIDEO_URL + uuid + '/watching'
+    return `${VideoService.BASE_VIDEO_URL}/${uuid}/watching`
   }
 
   getVideo (options: { videoId: string }): Observable<VideoDetails> {
     return this.serverService.getServerLocale()
                .pipe(
                  switchMap(translations => {
-                   return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + options.videoId)
+                   return this.authHttp.get<VideoDetailsServerModel>(`${VideoService.BASE_VIDEO_URL}/${options.videoId}`)
                               .pipe(map(videoHash => ({ videoHash, translations })))
                  }),
                  map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
@@ -107,7 +112,7 @@ export class VideoService {
 
     const data = objectToFormData(body)
 
-    return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data)
+    return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, data)
                .pipe(
                  map(this.restExtractor.extractDataBool),
                  catchError(err => this.restExtractor.handleError(err))
@@ -115,15 +120,22 @@ export class VideoService {
   }
 
   uploadVideo (video: FormData) {
-    const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
+    const req = new HttpRequest('POST', `${VideoService.BASE_VIDEO_URL}/upload`, video, { reportProgress: true })
 
     return this.authHttp
                .request<{ video: { id: number, uuid: string } }>(req)
                .pipe(catchError(err => this.restExtractor.handleError(err)))
   }
 
-  getMyVideos (videoPagination: ComponentPaginationLight, sort: VideoSortField, search?: string): Observable<ResultList<Video>> {
-    const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
+  getMyVideos (options: {
+    videoPagination: ComponentPaginationLight
+    sort: VideoSortField
+    userChannels?: VideoChannelServerModel[]
+    search?: string
+  }): Observable<ResultList<Video>> {
+    const { videoPagination, sort, userChannels = [], search } = options
+
+    const pagination = this.restService.componentToRestPagination(videoPagination)
 
     let params = new HttpParams()
     params = this.restService.addRestGetParams(params, pagination, sort)
@@ -133,6 +145,16 @@ export class VideoService {
         isLive: {
           prefix: 'isLive:',
           isBoolean: true
+        },
+        channelId: {
+          prefix: 'channel:',
+          handler: (name: string) => {
+            const channel = userChannels.find(c => c.name === name)
+
+            if (channel) return channel.id
+
+            return undefined
+          }
         }
       })
 
@@ -182,6 +204,27 @@ export class VideoService {
                )
   }
 
+  getAdminVideos (
+    options: CommonVideoParams & { pagination: RestPagination, search?: string }
+  ): Observable<ResultList<Video>> {
+    const { pagination, search } = options
+
+    let params = new HttpParams()
+    params = this.buildCommonVideosParams({ params, ...options })
+
+    params = params.set('start', pagination.start.toString())
+                   .set('count', pagination.count.toString())
+
+    params = this.buildAdminParamsFromSearch(search, params)
+
+    return this.authHttp
+               .get<ResultList<Video>>(VideoService.BASE_VIDEO_URL, { params })
+               .pipe(
+                 switchMap(res => this.extractVideos(res)),
+                 catchError(err => this.restExtractor.handleError(err))
+               )
+  }
+
   getVideos (parameters: CommonVideoParams): Observable<ResultList<Video>> {
     let params = new HttpParams()
     params = this.buildCommonVideosParams({ params, ...parameters })
@@ -222,10 +265,10 @@ export class VideoService {
     return feeds
   }
 
-  getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter, categoryOneOf?: number[]) {
+  getVideoFeedUrls (sort: VideoSortField, isLocal: boolean, categoryOneOf?: number[]) {
     let params = this.restService.addRestGetParams(new HttpParams(), undefined, sort)
 
-    if (filter) params = params.set('filter', filter)
+    if (isLocal) params = params.set('isLocal', isLocal)
 
     if (categoryOneOf) {
       for (const c of categoryOneOf) {
@@ -266,13 +309,15 @@ export class VideoService {
                )
   }
 
-  removeVideo (id: number) {
-    return this.authHttp
-               .delete(VideoService.BASE_VIDEO_URL + id)
-               .pipe(
-                 map(this.restExtractor.extractDataBool),
-                 catchError(err => this.restExtractor.handleError(err))
-               )
+  removeVideo (idArg: number | number[]) {
+    const ids = Array.isArray(idArg) ? idArg : [ idArg ]
+
+    return from(ids)
+      .pipe(
+        concatMap(id => this.authHttp.delete(`${VideoService.BASE_VIDEO_URL}/${id}`)),
+        toArray(),
+        catchError(err => this.restExtractor.handleError(err))
+      )
   }
 
   loadCompleteDescription (descriptionPath: string) {
@@ -361,7 +406,7 @@ export class VideoService {
   }
 
   private setVideoRate (id: number, rateType: UserVideoRateType) {
-    const url = VideoService.BASE_VIDEO_URL + id + '/rate'
+    const url = `${VideoService.BASE_VIDEO_URL}/${id}/rate`
     const body: UserVideoRateUpdate = {
       rating: rateType
     }
@@ -375,14 +420,30 @@ export class VideoService {
   }
 
   private buildCommonVideosParams (options: CommonVideoParams & { params: HttpParams }) {
-    const { params, videoPagination, sort, filter, categoryOneOf, languageOneOf, skipCount, nsfwPolicy, isLive, nsfw } = options
+    const {
+      params,
+      videoPagination,
+      sort,
+      isLocal,
+      include,
+      categoryOneOf,
+      languageOneOf,
+      skipCount,
+      nsfwPolicy,
+      isLive,
+      nsfw
+    } = options
+
+    const pagination = videoPagination
+      ? this.restService.componentToRestPagination(videoPagination)
+      : undefined
 
-    const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
     let newParams = this.restService.addRestGetParams(params, pagination, sort)
 
-    if (filter) newParams = newParams.set('filter', filter)
     if (skipCount) newParams = newParams.set('skipCount', skipCount + '')
 
+    if (isLocal) newParams = newParams.set('isLocal', isLocal)
+    if (include) newParams = newParams.set('include', include)
     if (isLive) newParams = newParams.set('isLive', isLive)
     if (nsfw) newParams = newParams.set('nsfw', nsfw)
     if (nsfwPolicy) newParams = newParams.set('nsfw', this.nsfwPolicyToParam(nsfwPolicy))
@@ -391,4 +452,61 @@ export class VideoService {
 
     return newParams
   }
+
+  buildAdminInputFilter (): AdvancedInputFilter[] {
+    return [
+      {
+        title: $localize`Videos scope`,
+        children: [
+          {
+            queryParams: { search: 'isLocal:false' },
+            label: $localize`Remote videos`
+          },
+          {
+            queryParams: { search: 'isLocal:true' },
+            label: $localize`Local videos`
+          }
+        ]
+      },
+
+      {
+        title: $localize`Include/Exclude`,
+        children: [
+          {
+            queryParams: { search: 'excludeMuted' },
+            label: $localize`Exclude muted accounts`
+          }
+        ]
+      }
+    ]
+  }
+
+  private buildAdminParamsFromSearch (search: string, params: HttpParams) {
+    let include = VideoInclude.BLACKLISTED |
+      VideoInclude.BLOCKED_OWNER |
+      VideoInclude.HIDDEN_PRIVACY |
+      VideoInclude.NOT_PUBLISHED_STATE |
+      VideoInclude.FILES
+
+    if (!search) return this.restService.addObjectParams(params, { include })
+
+    const filters = this.restService.parseQueryStringFilter(search, {
+      isLocal: {
+        prefix: 'isLocal:',
+        isBoolean: true
+      },
+      excludeMuted: {
+        prefix: 'excludeMuted',
+        handler: () => true
+      }
+    })
+
+    if (filters.excludeMuted) {
+      include &= ~VideoInclude.BLOCKED_OWNER
+
+      filters.excludeMuted = undefined
+    }
+
+    return this.restService.addObjectParams(params, { ...filters, include })
+  }
 }