aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts2
-rw-r--r--client/src/app/+manage/video-channel-edit/video-channel-create.component.ts13
-rw-r--r--client/src/app/+manage/video-channel-edit/video-channel-update.component.ts18
-rw-r--r--client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts36
-rw-r--r--client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.html2
-rw-r--r--client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts21
-rw-r--r--client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts2
-rw-r--r--client/src/app/core/plugins/hooks.service.ts5
-rw-r--r--client/src/app/shared/shared-video-miniature/videos-list.component.ts2
-rw-r--r--client/src/root-helpers/plugins-manager.ts3
-rw-r--r--shared/models/plugins/client/client-hook.model.ts17
-rw-r--r--shared/models/plugins/client/plugin-client-scope.type.ts3
12 files changed, 91 insertions, 33 deletions
diff --git a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
index 1a40f6c65..ec02cfcd9 100644
--- a/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
+++ b/client/src/app/+admin/plugins/plugin-show-installed/plugin-show-installed.component.ts
@@ -111,7 +111,7 @@ export class PluginShowInstalledComponent extends FormReactive implements OnInit
111 111
112 this.form.patchValue(settingsValues) 112 this.form.patchValue(settingsValues)
113 113
114 setTimeout(() => this.hooks.runAction('action:admin-plugin-settings.init', 'admin-plugin', { npmName: this.npmName })) 114 this.hooks.runAction('action:admin-plugin-settings.init', 'admin-plugin', { npmName: this.npmName })
115 } 115 }
116 116
117 private getSetting (name: string) { 117 private getSetting (name: string) {
diff --git a/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts b/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts
index 5f8e0278e..8211451a4 100644
--- a/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts
+++ b/client/src/app/+manage/video-channel-edit/video-channel-create.component.ts
@@ -1,8 +1,8 @@
1import { of } from 'rxjs' 1import { of } from 'rxjs'
2import { switchMap } from 'rxjs/operators' 2import { switchMap } from 'rxjs/operators'
3import { Component, OnInit } from '@angular/core' 3import { AfterViewInit, Component, OnInit } from '@angular/core'
4import { Router } from '@angular/router' 4import { Router } from '@angular/router'
5import { AuthService, Notifier } from '@app/core' 5import { AuthService, HooksService, Notifier } from '@app/core'
6import { 6import {
7 VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, 7 VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
8 VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR, 8 VIDEO_CHANNEL_DISPLAY_NAME_VALIDATOR,
@@ -18,7 +18,7 @@ import { VideoChannelEdit } from './video-channel-edit'
18 templateUrl: './video-channel-edit.component.html', 18 templateUrl: './video-channel-edit.component.html',
19 styleUrls: [ './video-channel-edit.component.scss' ] 19 styleUrls: [ './video-channel-edit.component.scss' ]
20}) 20})
21export class VideoChannelCreateComponent extends VideoChannelEdit implements OnInit { 21export class VideoChannelCreateComponent extends VideoChannelEdit implements OnInit, AfterViewInit {
22 error: string 22 error: string
23 videoChannel = new VideoChannel({}) 23 videoChannel = new VideoChannel({})
24 24
@@ -30,7 +30,8 @@ export class VideoChannelCreateComponent extends VideoChannelEdit implements OnI
30 private authService: AuthService, 30 private authService: AuthService,
31 private notifier: Notifier, 31 private notifier: Notifier,
32 private router: Router, 32 private router: Router,
33 private videoChannelService: VideoChannelService 33 private videoChannelService: VideoChannelService,
34 private hooks: HooksService
34 ) { 35 ) {
35 super() 36 super()
36 } 37 }
@@ -44,6 +45,10 @@ export class VideoChannelCreateComponent extends VideoChannelEdit implements OnI
44 }) 45 })
45 } 46 }
46 47
48 ngAfterViewInit () {
49 this.hooks.runAction('action:video-channel-create.init', 'video-channel')
50 }
51
47 formValidated () { 52 formValidated () {
48 this.error = undefined 53 this.error = undefined
49 54
diff --git a/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts b/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts
index 6b4947912..7e8d6ffe6 100644
--- a/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts
+++ b/client/src/app/+manage/video-channel-edit/video-channel-update.component.ts
@@ -1,8 +1,8 @@
1import { Subscription } from 'rxjs' 1import { Subscription } from 'rxjs'
2import { HttpErrorResponse } from '@angular/common/http' 2import { HttpErrorResponse } from '@angular/common/http'
3import { Component, OnDestroy, OnInit } from '@angular/core' 3import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'
4import { ActivatedRoute, Router } from '@angular/router' 4import { ActivatedRoute } from '@angular/router'
5import { AuthService, Notifier, RedirectService, ServerService } from '@app/core' 5import { AuthService, HooksService, Notifier, RedirectService, ServerService } from '@app/core'
6import { genericUploadErrorHandler } from '@app/helpers' 6import { genericUploadErrorHandler } from '@app/helpers'
7import { 7import {
8 VIDEO_CHANNEL_DESCRIPTION_VALIDATOR, 8 VIDEO_CHANNEL_DESCRIPTION_VALIDATOR,
@@ -19,7 +19,7 @@ import { VideoChannelEdit } from './video-channel-edit'
19 templateUrl: './video-channel-edit.component.html', 19 templateUrl: './video-channel-edit.component.html',
20 styleUrls: [ './video-channel-edit.component.scss' ] 20 styleUrls: [ './video-channel-edit.component.scss' ]
21}) 21})
22export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnInit, OnDestroy { 22export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnInit, AfterViewInit, OnDestroy {
23 error: string 23 error: string
24 videoChannel: VideoChannel 24 videoChannel: VideoChannel
25 25
@@ -31,11 +31,11 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
31 protected formValidatorService: FormValidatorService, 31 protected formValidatorService: FormValidatorService,
32 private authService: AuthService, 32 private authService: AuthService,
33 private notifier: Notifier, 33 private notifier: Notifier,
34 private router: Router,
35 private route: ActivatedRoute, 34 private route: ActivatedRoute,
36 private videoChannelService: VideoChannelService, 35 private videoChannelService: VideoChannelService,
37 private serverService: ServerService, 36 private serverService: ServerService,
38 private redirectService: RedirectService 37 private redirectService: RedirectService,
38 private hooks: HooksService
39 ) { 39 ) {
40 super() 40 super()
41 } 41 }
@@ -58,6 +58,8 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
58 next: videoChannelToUpdate => { 58 next: videoChannelToUpdate => {
59 this.videoChannel = videoChannelToUpdate 59 this.videoChannel = videoChannelToUpdate
60 60
61 this.hooks.runAction('action:video-channel-update.video-channel.loaded', 'video-channel', { videoChannel: this.videoChannel })
62
61 this.oldSupportField = videoChannelToUpdate.support 63 this.oldSupportField = videoChannelToUpdate.support
62 64
63 this.form.patchValue({ 65 this.form.patchValue({
@@ -74,6 +76,10 @@ export class VideoChannelUpdateComponent extends VideoChannelEdit implements OnI
74 }) 76 })
75 } 77 }
76 78
79 ngAfterViewInit () {
80 this.hooks.runAction('action:video-channel-update.init', 'video-channel')
81 }
82
77 ngOnDestroy () { 83 ngOnDestroy () {
78 if (this.paramsSub) this.paramsSub.unsubscribe() 84 if (this.paramsSub) this.paramsSub.unsubscribe()
79 } 85 }
diff --git a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
index 14465bb8d..82af65026 100644
--- a/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
+++ b/client/src/app/+video-channels/video-channel-playlists/video-channel-playlists.component.ts
@@ -1,6 +1,6 @@
1import { Subject, Subscription } from 'rxjs' 1import { Subject, Subscription } from 'rxjs'
2import { Component, OnDestroy, OnInit } from '@angular/core' 2import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'
3import { ComponentPagination, hasMoreItems, ScreenService } from '@app/core' 3import { ComponentPagination, hasMoreItems, HooksService, ScreenService } from '@app/core'
4import { VideoChannel, VideoChannelService } from '@app/shared/shared-main' 4import { VideoChannel, VideoChannelService } from '@app/shared/shared-main'
5import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' 5import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
6 6
@@ -9,7 +9,7 @@ import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-pl
9 templateUrl: './video-channel-playlists.component.html', 9 templateUrl: './video-channel-playlists.component.html',
10 styleUrls: [ './video-channel-playlists.component.scss' ] 10 styleUrls: [ './video-channel-playlists.component.scss' ]
11}) 11})
12export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy { 12export class VideoChannelPlaylistsComponent implements OnInit, AfterViewInit, OnDestroy {
13 videoPlaylists: VideoPlaylist[] = [] 13 videoPlaylists: VideoPlaylist[] = []
14 14
15 pagination: ComponentPagination = { 15 pagination: ComponentPagination = {
@@ -26,16 +26,24 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy {
26 constructor ( 26 constructor (
27 private videoPlaylistService: VideoPlaylistService, 27 private videoPlaylistService: VideoPlaylistService,
28 private videoChannelService: VideoChannelService, 28 private videoChannelService: VideoChannelService,
29 private screenService: ScreenService 29 private screenService: ScreenService,
30 private hooks: HooksService
30 ) {} 31 ) {}
31 32
32 ngOnInit () { 33 ngOnInit () {
33 // Parent get the video channel for us 34 // Parent get the video channel for us
34 this.videoChannelSub = this.videoChannelService.videoChannelLoaded 35 this.videoChannelSub = this.videoChannelService.videoChannelLoaded
35 .subscribe(videoChannel => { 36 .subscribe(videoChannel => {
36 this.videoChannel = videoChannel 37 this.videoChannel = videoChannel
37 this.loadVideoPlaylists() 38
38 }) 39 this.hooks.runAction('action:video-channel-playlists.video-channel.loaded', 'video-channel', { videoChannel })
40
41 this.loadVideoPlaylists()
42 })
43 }
44
45 ngAfterViewInit () {
46 this.hooks.runAction('action:video-channel-playlists.init', 'video-channel')
39 } 47 }
40 48
41 ngOnDestroy () { 49 ngOnDestroy () {
@@ -55,11 +63,13 @@ export class VideoChannelPlaylistsComponent implements OnInit, OnDestroy {
55 63
56 private loadVideoPlaylists () { 64 private loadVideoPlaylists () {
57 this.videoPlaylistService.listChannelPlaylists(this.videoChannel, this.pagination) 65 this.videoPlaylistService.listChannelPlaylists(this.videoChannel, this.pagination)
58 .subscribe(res => { 66 .subscribe(res => {
59 this.videoPlaylists = this.videoPlaylists.concat(res.data) 67 this.videoPlaylists = this.videoPlaylists.concat(res.data)
60 this.pagination.totalItems = res.total 68 this.pagination.totalItems = res.total
69
70 this.hooks.runAction('action:video-channel-playlists.playlists.loaded', 'video-channel', { playlists: this.videoPlaylists })
61 71
62 this.onDataSubject.next(res.data) 72 this.onDataSubject.next(res.data)
63 }) 73 })
64 } 74 }
65} 75}
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.html b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.html
index 0a6c5fcb2..9e9e98c99 100644
--- a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.html
+++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.html
@@ -19,5 +19,7 @@
19 [loadUserVideoPreferences]="true" 19 [loadUserVideoPreferences]="true"
20 20
21 [disabled]="disabled" 21 [disabled]="disabled"
22
23 (videosLoaded)="onVideosLoaded($event)"
22> 24>
23</my-videos-list> 25</my-videos-list>
diff --git a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
index 43fce475d..5e3946bf5 100644
--- a/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
+++ b/client/src/app/+video-channels/video-channel-videos/video-channel-videos.component.ts
@@ -1,16 +1,16 @@
1import { Subscription } from 'rxjs' 1import { Subscription } from 'rxjs'
2import { first } from 'rxjs/operators' 2import { first } from 'rxjs/operators'
3import { Component, OnDestroy, OnInit } from '@angular/core' 3import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core'
4import { ComponentPaginationLight, DisableForReuseHook, ScreenService } from '@app/core' 4import { ComponentPaginationLight, DisableForReuseHook, HooksService, ScreenService } from '@app/core'
5import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main' 5import { VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
6import { MiniatureDisplayOptions, VideoFilters } from '@app/shared/shared-video-miniature' 6import { MiniatureDisplayOptions, VideoFilters } from '@app/shared/shared-video-miniature'
7import { VideoSortField } from '@shared/models/videos' 7import { Video, VideoSortField } from '@shared/models'
8 8
9@Component({ 9@Component({
10 selector: 'my-video-channel-videos', 10 selector: 'my-video-channel-videos',
11 templateUrl: './video-channel-videos.component.html' 11 templateUrl: './video-channel-videos.component.html'
12}) 12})
13export class VideoChannelVideosComponent implements OnInit, OnDestroy, DisableForReuseHook { 13export class VideoChannelVideosComponent implements OnInit, AfterViewInit, OnDestroy, DisableForReuseHook {
14 getVideosObservableFunction = this.getVideosObservable.bind(this) 14 getVideosObservableFunction = this.getVideosObservable.bind(this)
15 getSyndicationItemsFunction = this.getSyndicationItems.bind(this) 15 getSyndicationItemsFunction = this.getSyndicationItems.bind(this)
16 16
@@ -36,7 +36,8 @@ export class VideoChannelVideosComponent implements OnInit, OnDestroy, DisableFo
36 constructor ( 36 constructor (
37 private screenService: ScreenService, 37 private screenService: ScreenService,
38 private videoChannelService: VideoChannelService, 38 private videoChannelService: VideoChannelService,
39 private videoService: VideoService 39 private videoService: VideoService,
40 private hooks: HooksService
40 ) { 41 ) {
41 } 42 }
42 43
@@ -45,9 +46,15 @@ export class VideoChannelVideosComponent implements OnInit, OnDestroy, DisableFo
45 this.videoChannelService.videoChannelLoaded.pipe(first()) 46 this.videoChannelService.videoChannelLoaded.pipe(first())
46 .subscribe(videoChannel => { 47 .subscribe(videoChannel => {
47 this.videoChannel = videoChannel 48 this.videoChannel = videoChannel
49
50 this.hooks.runAction('action:video-channel-videos.video-channel.loaded', 'video-channel', { videoChannel })
48 }) 51 })
49 } 52 }
50 53
54 ngAfterViewInit () {
55 this.hooks.runAction('action:video-channel-videos.init', 'video-channel')
56 }
57
51 ngOnDestroy () { 58 ngOnDestroy () {
52 if (this.videoChannelSub) this.videoChannelSub.unsubscribe() 59 if (this.videoChannelSub) this.videoChannelSub.unsubscribe()
53 } 60 }
@@ -79,4 +86,8 @@ export class VideoChannelVideosComponent implements OnInit, OnDestroy, DisableFo
79 enabledForReuse () { 86 enabledForReuse () {
80 this.disabled = false 87 this.disabled = false
81 } 88 }
89
90 onVideosLoaded (videos: Video[]) {
91 this.hooks.runAction('action:video-channel-videos.videos.loaded', 'video-channel', { videos })
92 }
82} 93}
diff --git a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
index 108ad63e3..28edcfdcb 100644
--- a/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
+++ b/client/src/app/+videos/+video-watch/shared/comment/video-comments.component.ts
@@ -139,7 +139,7 @@ export class VideoCommentsComponent implements OnInit, OnChanges, OnDestroy {
139 139
140 this.onDataSubject.next(res.data) 140 this.onDataSubject.next(res.data)
141 141
142 setTimeout(() => this.hooks.runAction('action:video-watch.video-threads.loaded', 'video-watch', { data: this.componentPagination })) 142 this.hooks.runAction('action:video-watch.video-threads.loaded', 'video-watch', { data: this.componentPagination })
143 }, 143 },
144 144
145 error: err => this.notifier.error(err.message) 145 error: err => this.notifier.error(err.message)
diff --git a/client/src/app/core/plugins/hooks.service.ts b/client/src/app/core/plugins/hooks.service.ts
index 7fd56d92e..29db75d89 100644
--- a/client/src/app/core/plugins/hooks.service.ts
+++ b/client/src/app/core/plugins/hooks.service.ts
@@ -49,9 +49,12 @@ export class HooksService {
49 } 49 }
50 50
51 runAction<T, U extends ClientActionHookName> (hookName: U, scope: PluginClientScope, params?: T) { 51 runAction<T, U extends ClientActionHookName> (hookName: U, scope: PluginClientScope, params?: T) {
52 this.pluginService.ensurePluginsAreLoaded(scope) 52 // Use setTimeout to give priority to Angular change detector
53 setTimeout(() => {
54 this.pluginService.ensurePluginsAreLoaded(scope)
53 .then(() => this.pluginService.runHook(hookName, undefined, params)) 55 .then(() => this.pluginService.runHook(hookName, undefined, params))
54 .catch((err: any) => logger.error('Fatal hook error.', err)) 56 .catch((err: any) => logger.error('Fatal hook error.', err))
57 })
55 } 58 }
56 59
57 async wrapObject<T, U extends ClientFilterHookName> (result: T, scope: PluginClientScope, hookName: U) { 60 async wrapObject<T, U extends ClientFilterHookName> (result: T, scope: PluginClientScope, hookName: U) {
diff --git a/client/src/app/shared/shared-video-miniature/videos-list.component.ts b/client/src/app/shared/shared-video-miniature/videos-list.component.ts
index 508a189fd..d5cdd958e 100644
--- a/client/src/app/shared/shared-video-miniature/videos-list.component.ts
+++ b/client/src/app/shared/shared-video-miniature/videos-list.component.ts
@@ -76,6 +76,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
76 @Input() disabled = false 76 @Input() disabled = false
77 77
78 @Output() filtersChanged = new EventEmitter<VideoFilters>() 78 @Output() filtersChanged = new EventEmitter<VideoFilters>()
79 @Output() videosLoaded = new EventEmitter<Video[]>()
79 80
80 videos: Video[] = [] 81 videos: Video[] = []
81 filters: VideoFilters 82 filters: VideoFilters
@@ -241,6 +242,7 @@ export class VideosListComponent implements OnInit, OnChanges, OnDestroy {
241 if (this.groupByDate) this.buildGroupedDateLabels() 242 if (this.groupByDate) this.buildGroupedDateLabels()
242 243
243 this.onDataSubject.next(data) 244 this.onDataSubject.next(data)
245 this.videosLoaded.emit(this.videos)
244 }, 246 },
245 247
246 error: err => { 248 error: err => {
diff --git a/client/src/root-helpers/plugins-manager.ts b/client/src/root-helpers/plugins-manager.ts
index 300f174b4..6c64e2b01 100644
--- a/client/src/root-helpers/plugins-manager.ts
+++ b/client/src/root-helpers/plugins-manager.ts
@@ -69,7 +69,8 @@ class PluginsManager {
69 login: new ReplaySubject<boolean>(1), 69 login: new ReplaySubject<boolean>(1),
70 'video-edit': new ReplaySubject<boolean>(1), 70 'video-edit': new ReplaySubject<boolean>(1),
71 embed: new ReplaySubject<boolean>(1), 71 embed: new ReplaySubject<boolean>(1),
72 'my-library': new ReplaySubject<boolean>(1) 72 'my-library': new ReplaySubject<boolean>(1),
73 'video-channel': new ReplaySubject<boolean>(1)
73 } 74 }
74 75
75 private readonly peertubeHelpersFactory: PeertubeHelpersFactory 76 private readonly peertubeHelpersFactory: PeertubeHelpersFactory
diff --git a/shared/models/plugins/client/client-hook.model.ts b/shared/models/plugins/client/client-hook.model.ts
index 466be8946..dda03124d 100644
--- a/shared/models/plugins/client/client-hook.model.ts
+++ b/shared/models/plugins/client/client-hook.model.ts
@@ -93,6 +93,23 @@ export const clientActionHookObject = {
93 // Fired when a user click on 'View x replies' and they're loaded 93 // Fired when a user click on 'View x replies' and they're loaded
94 'action:video-watch.video-thread-replies.loaded': true, 94 'action:video-watch.video-thread-replies.loaded': true,
95 95
96 // Fired when the video channel creation page is being initialized
97 'action:video-channel-create.init': true,
98
99 // Fired when the video channel update page is being initialized
100 'action:video-channel-update.init': true,
101 'action:video-channel-update.video-channel.loaded': true,
102
103 // Fired when the page that list video channel videos is being initialized
104 'action:video-channel-videos.init': true,
105 'action:video-channel-videos.video-channel.loaded': true,
106 'action:video-channel-videos.videos.loaded': true,
107
108 // Fired when the page that list video channel playlists is being initialized
109 'action:video-channel-playlists.init': true,
110 'action:video-channel-playlists.video-channel.loaded': true,
111 'action:video-channel-playlists.playlists.loaded': true,
112
96 // Fired when the video edit page (upload, URL/torrent import, update) is being initialized 113 // Fired when the video edit page (upload, URL/torrent import, update) is being initialized
97 'action:video-edit.init': true, 114 'action:video-edit.init': true,
98 115
diff --git a/shared/models/plugins/client/plugin-client-scope.type.ts b/shared/models/plugins/client/plugin-client-scope.type.ts
index 92734533d..c09a453b8 100644
--- a/shared/models/plugins/client/plugin-client-scope.type.ts
+++ b/shared/models/plugins/client/plugin-client-scope.type.ts
@@ -7,4 +7,5 @@ export type PluginClientScope =
7 'embed' | 7 'embed' |
8 'video-edit' | 8 'video-edit' |
9 'admin-plugin' | 9 'admin-plugin' |
10 'my-library' 10 'my-library' |
11 'video-channel'