aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/shared-search/find-in-bulk.service.ts
blob: 962e374a544cf2a96e74392a4959e5c6ea11fdad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import * as debug from 'debug'
import { Observable, Subject } from 'rxjs'
import { first, map } from 'rxjs/operators'
import { Injectable, NgZone } from '@angular/core'
import { buildBulkObservable } from '@app/helpers'
import { ResultList } from '@shared/models/common'
import { Video, VideoChannel } from '../shared-main'
import { VideoPlaylist } from '../shared-video-playlist'
import { SearchService } from './search.service'

const logger = debug('peertube:search:FindInBulkService')

type BulkObservables <P extends number | string, R> = {
  notifier: Subject<P>
  result: Observable<R>
}

@Injectable()
export class FindInBulkService {

  private getVideoInBulk: BulkObservables<string, ResultList<Video>>
  private getChannelInBulk: BulkObservables<string, ResultList<VideoChannel>>
  private getPlaylistInBulk: BulkObservables<string, ResultList<VideoPlaylist>>

  constructor (
    private searchService: SearchService,
    private ngZone: NgZone
  ) {
    this.getVideoInBulk = this.buildBulkObservableObject(this.getVideosInBulk.bind(this))
    this.getChannelInBulk = this.buildBulkObservableObject(this.getChannelsInBulk.bind(this))
    this.getPlaylistInBulk = this.buildBulkObservableObject(this.getPlaylistsInBulk.bind(this))
  }

  getVideo (uuid: string): Observable<Video> {
    logger('Schedule video fetch for uuid %s.', uuid)

    return this.getData({
      observableObject: this.getVideoInBulk,
      finder: v => v.uuid === uuid,
      param: uuid
    })
  }

  getChannel (handle: string): Observable<VideoChannel> {
    logger('Schedule channel fetch for handle %s.', handle)

    return this.getData({
      observableObject: this.getChannelInBulk,
      finder: c => c.nameWithHost === handle || c.nameWithHostForced === handle,
      param: handle
    })
  }

  getPlaylist (uuid: string): Observable<VideoPlaylist> {
    logger('Schedule playlist fetch for uuid %s.', uuid)

    return this.getData({
      observableObject: this.getPlaylistInBulk,
      finder: p => p.uuid === uuid,
      param: uuid
    })
  }

  private getData <P extends number | string, R> (options: {
    observableObject: BulkObservables<P, ResultList<R>>
    param: P
    finder: (d: R) => boolean
  }) {
    const { observableObject, param, finder } = options

    return new Observable<R>(obs => {
      observableObject.result
        .pipe(
          first(),
          map(({ data }) => data),
          map(data => data.find(finder))
        )
        .subscribe(result => {
          if (!result) {
            obs.error(new Error($localize`Element ${param} not found`))
          } else {
            obs.next(result)
            obs.complete()
          }
        })

      observableObject.notifier.next(param)
    })
  }

  private getVideosInBulk (uuids: string[]) {
    logger('Fetching videos %s.', uuids.join(', '))

    return this.searchService.searchVideos({ uuids })
  }

  private getChannelsInBulk (handles: string[]) {
    logger('Fetching channels %s.', handles.join(', '))

    return this.searchService.searchVideoChannels({ handles })
  }

  private getPlaylistsInBulk (uuids: string[]) {
    logger('Fetching playlists %s.', uuids.join(', '))

    return this.searchService.searchVideoPlaylists({ uuids })
  }

  private buildBulkObservableObject <T extends number | string, R> (bulkGet: (params: T[]) => Observable<R>) {
    const notifier = new Subject<T>()

    return {
      notifier,

      result: buildBulkObservable({
        time: 500,
        bulkGet,
        ngZone: this.ngZone,
        notifierObservable: notifier.asObservable()
      })
    }
  }
}