Fetch things in bulk for the homepage
This commit is contained in:
parent
200eaf5152
commit
3da38d6e9f
|
@ -44,13 +44,21 @@ export class RestService {
|
|||
return newParams
|
||||
}
|
||||
|
||||
addArrayParams (params: HttpParams, name: string, values: (string | number)[]) {
|
||||
for (const v of values) {
|
||||
params = params.append(name, v)
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
addObjectParams (params: HttpParams, object: { [ name: string ]: any }) {
|
||||
for (const name of Object.keys(object)) {
|
||||
const value = object[name]
|
||||
if (value === undefined || value === null) continue
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (const v of value) params = params.append(name, v)
|
||||
params = this.addArrayParams(params, name, value)
|
||||
} else {
|
||||
params = params.append(name, value)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export * from './locales'
|
||||
export * from './constants'
|
||||
export * from './i18n-utils'
|
||||
export * from './rxjs'
|
||||
export * from './utils'
|
||||
export * from './zone'
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { uniq } from 'lodash-es'
|
||||
import { asyncScheduler, Observable } from 'rxjs'
|
||||
import { bufferTime, distinctUntilChanged, filter, map, observeOn, share, switchMap } from 'rxjs/operators'
|
||||
import { NgZone } from '@angular/core'
|
||||
import { enterZone, leaveZone } from './zone'
|
||||
|
||||
function buildBulkObservable <T extends number | string, R> (options: {
|
||||
ngZone: NgZone
|
||||
notifierObservable: Observable<T>
|
||||
time: number
|
||||
bulkGet: (params: T[]) => Observable<R>
|
||||
}) {
|
||||
const { ngZone, notifierObservable, time, bulkGet } = options
|
||||
|
||||
return notifierObservable.pipe(
|
||||
distinctUntilChanged(),
|
||||
// We leave Angular zone so Protractor does not get stuck
|
||||
bufferTime(time, leaveZone(ngZone, asyncScheduler)),
|
||||
filter(params => params.length !== 0),
|
||||
map(params => uniq(params)),
|
||||
observeOn(enterZone(ngZone, asyncScheduler)),
|
||||
switchMap(params => bulkGet(params)),
|
||||
share()
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
buildBulkObservable
|
||||
}
|
|
@ -65,15 +65,15 @@ export class CustomMarkupService {
|
|||
|
||||
for (const selector of Object.keys(this.htmlBuilders)) {
|
||||
rootElement.querySelectorAll(selector)
|
||||
.forEach((e: HTMLElement) => {
|
||||
try {
|
||||
const element = this.execHTMLBuilder(selector, e)
|
||||
// Insert as first child
|
||||
e.insertBefore(element, e.firstChild)
|
||||
} catch (err) {
|
||||
console.error('Cannot inject component %s.', selector, err)
|
||||
}
|
||||
})
|
||||
.forEach((e: HTMLElement) => {
|
||||
try {
|
||||
const element = this.execHTMLBuilder(selector, e)
|
||||
// Insert as first child
|
||||
e.insertBefore(element, e.firstChild)
|
||||
} catch (err) {
|
||||
console.error('Cannot inject component %s.', selector, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const loadedPromises: Promise<boolean>[] = []
|
||||
|
|
|
@ -2,8 +2,9 @@ import { from } from 'rxjs'
|
|||
import { finalize, map, switchMap, tap } from 'rxjs/operators'
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
||||
import { MarkdownService, Notifier, UserService } from '@app/core'
|
||||
import { FindInBulkService } from '@app/shared/shared-search'
|
||||
import { Video, VideoSortField } from '@shared/models/videos'
|
||||
import { VideoChannel, VideoChannelService, VideoService } from '../../shared-main'
|
||||
import { VideoChannel, VideoService } from '../../shared-main'
|
||||
import { CustomMarkupComponent } from './shared'
|
||||
|
||||
/*
|
||||
|
@ -29,14 +30,14 @@ export class ChannelMiniatureMarkupComponent implements CustomMarkupComponent, O
|
|||
|
||||
constructor (
|
||||
private markdown: MarkdownService,
|
||||
private channelService: VideoChannelService,
|
||||
private findInBulk: FindInBulkService,
|
||||
private videoService: VideoService,
|
||||
private userService: UserService,
|
||||
private notifier: Notifier
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
this.channelService.getVideoChannel(this.name)
|
||||
this.findInBulk.getChannel(this.name)
|
||||
.pipe(
|
||||
tap(channel => this.channel = channel),
|
||||
switchMap(() => from(this.markdown.textMarkdownToHTML(this.channel.description))),
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { finalize } from 'rxjs/operators'
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { FindInBulkService } from '@app/shared/shared-search'
|
||||
import { MiniatureDisplayOptions } from '../../shared-video-miniature'
|
||||
import { VideoPlaylist, VideoPlaylistService } from '../../shared-video-playlist'
|
||||
import { VideoPlaylist } from '../../shared-video-playlist'
|
||||
import { CustomMarkupComponent } from './shared'
|
||||
|
||||
/*
|
||||
|
@ -33,12 +34,12 @@ export class PlaylistMiniatureMarkupComponent implements CustomMarkupComponent,
|
|||
}
|
||||
|
||||
constructor (
|
||||
private playlistService: VideoPlaylistService,
|
||||
private findInBulkService: FindInBulkService,
|
||||
private notifier: Notifier
|
||||
) { }
|
||||
|
||||
ngOnInit () {
|
||||
this.playlistService.getVideoPlaylist(this.uuid)
|
||||
this.findInBulkService.getPlaylist(this.uuid)
|
||||
.pipe(finalize(() => this.loaded.emit(true)))
|
||||
.subscribe(
|
||||
playlist => this.playlist = playlist,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { AuthService, Notifier } from '@app/core'
|
|||
import { Video, VideoService } from '../../shared-main'
|
||||
import { MiniatureDisplayOptions } from '../../shared-video-miniature'
|
||||
import { CustomMarkupComponent } from './shared'
|
||||
import { FindInBulkService } from '@app/shared/shared-search'
|
||||
|
||||
/*
|
||||
* Markup component that creates a video miniature only
|
||||
|
@ -35,7 +36,7 @@ export class VideoMiniatureMarkupComponent implements CustomMarkupComponent, OnI
|
|||
|
||||
constructor (
|
||||
private auth: AuthService,
|
||||
private videoService: VideoService,
|
||||
private findInBulk: FindInBulkService,
|
||||
private notifier: Notifier
|
||||
) { }
|
||||
|
||||
|
@ -50,7 +51,7 @@ export class VideoMiniatureMarkupComponent implements CustomMarkupComponent, OnI
|
|||
}
|
||||
}
|
||||
|
||||
this.videoService.getVideo({ videoId: this.uuid })
|
||||
this.findInBulk.getVideo(this.uuid)
|
||||
.pipe(finalize(() => this.loaded.emit(true)))
|
||||
.subscribe(
|
||||
video => this.video = video,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'
|
|||
import { SharedActorImageModule } from '../shared-actor-image/shared-actor-image.module'
|
||||
import { SharedGlobalIconModule } from '../shared-icons'
|
||||
import { SharedMainModule } from '../shared-main'
|
||||
import { SharedSearchModule } from '../shared-search'
|
||||
import { SharedVideoMiniatureModule } from '../shared-video-miniature'
|
||||
import { SharedVideoPlaylistModule } from '../shared-video-playlist'
|
||||
import { CustomMarkupContainerComponent } from './custom-markup-container.component'
|
||||
|
@ -26,7 +27,8 @@ import {
|
|||
SharedGlobalIconModule,
|
||||
SharedVideoMiniatureModule,
|
||||
SharedVideoPlaylistModule,
|
||||
SharedActorImageModule
|
||||
SharedActorImageModule,
|
||||
SharedSearchModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
import * as debug from 'debug'
|
||||
import { Observable, Subject } from 'rxjs'
|
||||
import { 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(
|
||||
map(({ data }) => data),
|
||||
map(data => data.find(finder))
|
||||
)
|
||||
.subscribe(result => {
|
||||
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()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from './advanced-search.model'
|
||||
export * from './find-in-bulk.service'
|
||||
export * from './search.service'
|
||||
export * from './shared-search.module'
|
||||
|
|
|
@ -32,11 +32,12 @@ export class SearchService {
|
|||
}
|
||||
|
||||
searchVideos (parameters: {
|
||||
search: string
|
||||
search?: string
|
||||
componentPagination?: ComponentPaginationLight
|
||||
advancedSearch?: AdvancedSearch
|
||||
uuids?: string[]
|
||||
}): Observable<ResultList<Video>> {
|
||||
const { search, componentPagination, advancedSearch } = parameters
|
||||
const { search, uuids, componentPagination, advancedSearch } = parameters
|
||||
|
||||
const url = SearchService.BASE_SEARCH_URL + 'videos'
|
||||
let pagination: RestPagination
|
||||
|
@ -49,6 +50,7 @@ export class SearchService {
|
|||
params = this.restService.addRestGetParams(params, pagination)
|
||||
|
||||
if (search) params = params.append('search', search)
|
||||
if (uuids) params = this.restService.addArrayParams(params, 'uuids', uuids)
|
||||
|
||||
if (advancedSearch) {
|
||||
const advancedSearchObject = advancedSearch.toVideosAPIObject()
|
||||
|
@ -64,11 +66,12 @@ export class SearchService {
|
|||
}
|
||||
|
||||
searchVideoChannels (parameters: {
|
||||
search: string
|
||||
search?: string
|
||||
advancedSearch?: AdvancedSearch
|
||||
componentPagination?: ComponentPaginationLight
|
||||
handles?: string[]
|
||||
}): Observable<ResultList<VideoChannel>> {
|
||||
const { search, advancedSearch, componentPagination } = parameters
|
||||
const { search, advancedSearch, componentPagination, handles } = parameters
|
||||
|
||||
const url = SearchService.BASE_SEARCH_URL + 'video-channels'
|
||||
|
||||
|
@ -81,6 +84,7 @@ export class SearchService {
|
|||
params = this.restService.addRestGetParams(params, pagination)
|
||||
|
||||
if (search) params = params.append('search', search)
|
||||
if (handles) params = this.restService.addArrayParams(params, 'handles', handles)
|
||||
|
||||
if (advancedSearch) {
|
||||
const advancedSearchObject = advancedSearch.toChannelAPIObject()
|
||||
|
@ -96,11 +100,12 @@ export class SearchService {
|
|||
}
|
||||
|
||||
searchVideoPlaylists (parameters: {
|
||||
search: string
|
||||
search?: string
|
||||
advancedSearch?: AdvancedSearch
|
||||
componentPagination?: ComponentPaginationLight
|
||||
uuids?: string[]
|
||||
}): Observable<ResultList<VideoPlaylist>> {
|
||||
const { search, advancedSearch, componentPagination } = parameters
|
||||
const { search, advancedSearch, componentPagination, uuids } = parameters
|
||||
|
||||
const url = SearchService.BASE_SEARCH_URL + 'video-playlists'
|
||||
|
||||
|
@ -113,6 +118,7 @@ export class SearchService {
|
|||
params = this.restService.addRestGetParams(params, pagination)
|
||||
|
||||
if (search) params = params.append('search', search)
|
||||
if (uuids) params = this.restService.addArrayParams(params, 'uuids', uuids)
|
||||
|
||||
if (advancedSearch) {
|
||||
const advancedSearchObject = advancedSearch.toPlaylistAPIObject()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { NgModule } from '@angular/core'
|
||||
import { SharedMainModule } from '../shared-main'
|
||||
import { SharedVideoPlaylistModule } from '../shared-video-playlist'
|
||||
import { FindInBulkService } from './find-in-bulk.service'
|
||||
import { SearchService } from './search.service'
|
||||
|
||||
@NgModule({
|
||||
|
@ -16,6 +17,7 @@ import { SearchService } from './search.service'
|
|||
],
|
||||
|
||||
providers: [
|
||||
FindInBulkService,
|
||||
SearchService
|
||||
]
|
||||
})
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import * as debug from 'debug'
|
||||
import { uniq } from 'lodash-es'
|
||||
import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
|
||||
import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators'
|
||||
import { merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
|
||||
import { catchError, filter, map, switchMap, tap } from 'rxjs/operators'
|
||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { ComponentPaginationLight, RestExtractor, RestService } from '@app/core'
|
||||
import { enterZone, leaveZone } from '@app/helpers'
|
||||
import { buildBulkObservable } from '@app/helpers'
|
||||
import { Video, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||
import { ResultList, VideoChannel as VideoChannelServer, VideoSortField } from '@shared/models'
|
||||
import { environment } from '../../../environments/environment'
|
||||
|
@ -35,15 +34,12 @@ export class UserSubscriptionService {
|
|||
private ngZone: NgZone
|
||||
) {
|
||||
this.existsObservable = merge(
|
||||
this.existsSubject.pipe(
|
||||
// We leave Angular zone so Protractor does not get stuck
|
||||
bufferTime(500, leaveZone(this.ngZone, asyncScheduler)),
|
||||
filter(uris => uris.length !== 0),
|
||||
map(uris => uniq(uris)),
|
||||
observeOn(enterZone(this.ngZone, asyncScheduler)),
|
||||
switchMap(uris => this.doSubscriptionsExist(uris)),
|
||||
share()
|
||||
),
|
||||
buildBulkObservable({
|
||||
time: 500,
|
||||
ngZone: this.ngZone,
|
||||
notifierObservable: this.existsSubject,
|
||||
bulkGet: this.doSubscriptionsExist.bind(this)
|
||||
}),
|
||||
|
||||
this.myAccountSubscriptionCacheSubject
|
||||
)
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import * as debug from 'debug'
|
||||
import { uniq } from 'lodash-es'
|
||||
import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
|
||||
import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap, distinctUntilChanged } from 'rxjs/operators'
|
||||
import { merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
|
||||
import { catchError, filter, map, share, switchMap, tap } from 'rxjs/operators'
|
||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { AuthUser, ComponentPaginationLight, RestExtractor, RestService, ServerService } from '@app/core'
|
||||
import { enterZone, leaveZone, objectToFormData } from '@app/helpers'
|
||||
import { buildBulkObservable, objectToFormData } from '@app/helpers'
|
||||
import { Account, AccountService, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||
import {
|
||||
ResultList,
|
||||
|
@ -52,16 +51,12 @@ export class VideoPlaylistService {
|
|||
private ngZone: NgZone
|
||||
) {
|
||||
this.videoExistsInPlaylistObservable = merge(
|
||||
this.videoExistsInPlaylistNotifier.pipe(
|
||||
distinctUntilChanged(),
|
||||
// We leave Angular zone so Protractor does not get stuck
|
||||
bufferTime(500, leaveZone(this.ngZone, asyncScheduler)),
|
||||
filter(videoIds => videoIds.length !== 0),
|
||||
map(videoIds => uniq(videoIds)),
|
||||
observeOn(enterZone(this.ngZone, asyncScheduler)),
|
||||
switchMap(videoIds => this.doVideosExistInPlaylist(videoIds)),
|
||||
share()
|
||||
),
|
||||
buildBulkObservable({
|
||||
time: 500,
|
||||
ngZone: this.ngZone,
|
||||
bulkGet: this.doVideosExistInPlaylist.bind(this),
|
||||
notifierObservable: this.videoExistsInPlaylistNotifier
|
||||
}),
|
||||
|
||||
this.videoExistsInPlaylistCacheSubject
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue