diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-06-15 13:18:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-15 13:18:22 +0200 |
commit | 228393302d98136d4dc35c5f197edc8cebd5d64f (patch) | |
tree | f92b3ad80bcc9c89088ff1d4de5ebff76a3f46ed /client/src/app/+admin | |
parent | 7dfe35288613967f5ac69cd46901ec60c5050b93 (diff) | |
download | PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.tar.gz PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.tar.zst PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.zip |
factorize account/server blocklists for users and instance (#2875)
Diffstat (limited to 'client/src/app/+admin')
13 files changed, 19 insertions, 238 deletions
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index eb073f709..eccec8a49 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -27,7 +27,6 @@ import { SelectButtonModule } from 'primeng/selectbutton' | |||
27 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' | 27 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' |
28 | import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component' | 28 | import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component' |
29 | import { ChartModule } from 'primeng/chart' | 29 | import { ChartModule } from 'primeng/chart' |
30 | import { BatchDomainsModalComponent } from './config/shared/batch-domains-modal.component' | ||
31 | import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-abuse-details.component' | 30 | import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-abuse-details.component' |
32 | 31 | ||
33 | @NgModule({ | 32 | @NgModule({ |
@@ -76,9 +75,7 @@ import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video- | |||
76 | DebugComponent, | 75 | DebugComponent, |
77 | 76 | ||
78 | ConfigComponent, | 77 | ConfigComponent, |
79 | EditCustomConfigComponent, | 78 | EditCustomConfigComponent |
80 | |||
81 | BatchDomainsModalComponent | ||
82 | ], | 79 | ], |
83 | 80 | ||
84 | exports: [ | 81 | exports: [ |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index 298871fce..48b5681f4 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -56,7 +56,7 @@ | |||
56 | <ng-template pTemplate="emptymessage"> | 56 | <ng-template pTemplate="emptymessage"> |
57 | <tr> | 57 | <tr> |
58 | <td colspan="6"> | 58 | <td colspan="6"> |
59 | <div class="empty-table-message"> | 59 | <div class="no-results"> |
60 | <ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container> | 60 | <ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container> |
61 | <ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container> | 61 | <ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container> |
62 | </div> | 62 | </div> |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index ed521d650..a8fbf65d4 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -58,7 +58,7 @@ | |||
58 | <ng-template pTemplate="emptymessage"> | 58 | <ng-template pTemplate="emptymessage"> |
59 | <tr> | 59 | <tr> |
60 | <td colspan="6"> | 60 | <td colspan="6"> |
61 | <div class="empty-table-message"> | 61 | <div class="no-results"> |
62 | <ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container> | 62 | <ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container> |
63 | <ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container> | 63 | <ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container> |
64 | </div> | 64 | </div> |
diff --git a/client/src/app/+admin/follows/follows.component.scss b/client/src/app/+admin/follows/follows.component.scss index 32394f698..0cffcb555 100644 --- a/client/src/app/+admin/follows/follows.component.scss +++ b/client/src/app/+admin/follows/follows.component.scss | |||
@@ -4,7 +4,3 @@ | |||
4 | flex-grow: 0; | 4 | flex-grow: 0; |
5 | margin-right: 30px; | 5 | margin-right: 30px; |
6 | } | 6 | } |
7 | |||
8 | .empty-table-message { | ||
9 | @include empty-state; | ||
10 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html index c08154bcd..44586cb67 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html | |||
@@ -73,7 +73,7 @@ | |||
73 | <ng-template pTemplate="emptymessage"> | 73 | <ng-template pTemplate="emptymessage"> |
74 | <tr> | 74 | <tr> |
75 | <td colspan="6"> | 75 | <td colspan="6"> |
76 | <div class="empty-table-message"> | 76 | <div class="no-results"> |
77 | <ng-container *ngIf="isDisplayingRemoteVideos()" i18n>Your instance doesn't mirror any video.</ng-container> | 77 | <ng-container *ngIf="isDisplayingRemoteVideos()" i18n>Your instance doesn't mirror any video.</ng-container> |
78 | <ng-container *ngIf="!isDisplayingRemoteVideos()" i18n>Your instance has no mirrored videos.</ng-container> | 78 | <ng-container *ngIf="!isDisplayingRemoteVideos()" i18n>Your instance has no mirrored videos.</ng-container> |
79 | </div> | 79 | </div> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index b7d40be60..486785f35 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -54,7 +54,7 @@ | |||
54 | <ng-template pTemplate="emptymessage"> | 54 | <ng-template pTemplate="emptymessage"> |
55 | <tr> | 55 | <tr> |
56 | <td colspan="6"> | 56 | <td colspan="6"> |
57 | <div class="empty-table-message"> | 57 | <div class="no-results"> |
58 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> | 58 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> |
59 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> | 59 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> |
60 | </div> | 60 | </div> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts index 73a9ae75d..90a176194 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts | |||
@@ -1,70 +1,15 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { AccountBlock, BlocklistService } from '@app/shared/blocklist' | ||
7 | import { Actor } from '@app/shared/actor/actor.model' | ||
8 | 3 | ||
9 | @Component({ | 4 | @Component({ |
10 | selector: 'my-instance-account-blocklist', | 5 | selector: 'my-instance-account-blocklist', |
11 | styleUrls: [ '../moderation.component.scss', './instance-account-blocklist.component.scss' ], | 6 | styleUrls: [ '../moderation.component.scss', '../../../shared/blocklist/account-blocklist.component.scss' ], |
12 | templateUrl: './instance-account-blocklist.component.html' | 7 | templateUrl: '../../../shared/blocklist/account-blocklist.component.html' |
13 | }) | 8 | }) |
14 | export class InstanceAccountBlocklistComponent extends RestTable implements OnInit { | 9 | export class InstanceAccountBlocklistComponent extends GenericAccountBlocklistComponent { |
15 | blockedAccounts: AccountBlock[] = [] | 10 | mode = BlocklistComponentType.Instance |
16 | totalRecords = 0 | ||
17 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
18 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
19 | |||
20 | constructor ( | ||
21 | private notifier: Notifier, | ||
22 | private blocklistService: BlocklistService, | ||
23 | private i18n: I18n | ||
24 | ) { | ||
25 | super() | ||
26 | } | ||
27 | |||
28 | ngOnInit () { | ||
29 | this.initialize() | ||
30 | } | ||
31 | 11 | ||
32 | getIdentifier () { | 12 | getIdentifier () { |
33 | return 'InstanceAccountBlocklistComponent' | 13 | return 'InstanceAccountBlocklistComponent' |
34 | } | 14 | } |
35 | |||
36 | switchToDefaultAvatar ($event: Event) { | ||
37 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | ||
38 | } | ||
39 | |||
40 | unblockAccount (accountBlock: AccountBlock) { | ||
41 | const blockedAccount = accountBlock.blockedAccount | ||
42 | |||
43 | this.blocklistService.unblockAccountByInstance(blockedAccount) | ||
44 | .subscribe( | ||
45 | () => { | ||
46 | this.notifier.success( | ||
47 | this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost }) | ||
48 | ) | ||
49 | |||
50 | this.loadData() | ||
51 | } | ||
52 | ) | ||
53 | } | ||
54 | |||
55 | protected loadData () { | ||
56 | return this.blocklistService.getInstanceAccountBlocklist({ | ||
57 | pagination: this.pagination, | ||
58 | sort: this.sort, | ||
59 | search: this.search | ||
60 | }) | ||
61 | .subscribe( | ||
62 | resultList => { | ||
63 | this.blockedAccounts = resultList.data | ||
64 | this.totalRecords = resultList.total | ||
65 | }, | ||
66 | |||
67 | err => this.notifier.error(err.message) | ||
68 | ) | ||
69 | } | ||
70 | } | 15 | } |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html deleted file mode 100644 index 7a77b8842..000000000 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | <p-table | ||
2 | [value]="blockedServers" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted instances" | ||
6 | > | ||
7 | <ng-template pTemplate="caption"> | ||
8 | <div class="caption"> | ||
9 | <div class="ml-auto has-feedback has-clear"> | ||
10 | <input | ||
11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
12 | (keyup)="onSearch($event)" | ||
13 | > | ||
14 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
15 | <span class="sr-only" i18n>Clear filters</span> | ||
16 | </div> | ||
17 | <a class="ml-2 block-button" (click)="addServersToBlock()" (key.enter)="addServersToBlock()"> | ||
18 | <my-global-icon iconName="add" aria-hidden="true"></my-global-icon> | ||
19 | <ng-container i18n>Mute domain</ng-container> | ||
20 | </a> | ||
21 | </div> | ||
22 | </ng-template> | ||
23 | |||
24 | <ng-template pTemplate="header"> | ||
25 | <tr> | ||
26 | <th style="width: 100%;" i18n>Instance</th> | ||
27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
28 | <th style="width: 150px;"></th> <!-- column for action buttons --> | ||
29 | </tr> | ||
30 | </ng-template> | ||
31 | |||
32 | <ng-template pTemplate="body" let-serverBlock> | ||
33 | <tr> | ||
34 | <td> | ||
35 | <a [href]="'https://' + serverBlock.blockedServer.host" i18n-title title="Open instance in a new tab" target="_blank" rel="noopener noreferrer"> | ||
36 | {{ serverBlock.blockedServer.host }} | ||
37 | <span class="glyphicon glyphicon-new-window"></span> | ||
38 | </a> | ||
39 | </td> | ||
40 | <td>{{ serverBlock.createdAt | date: 'short' }}</td> | ||
41 | <td class="action-cell"> | ||
42 | <button class="unblock-button" (click)="unblockServer(serverBlock)" i18n>Unmute</button> | ||
43 | </td> | ||
44 | </tr> | ||
45 | </ng-template> | ||
46 | |||
47 | <ng-template pTemplate="emptymessage"> | ||
48 | <tr> | ||
49 | <td colspan="6"> | ||
50 | <div class="empty-table-message"> | ||
51 | <ng-container *ngIf="search" i18n>No server found matching current filters.</ng-container> | ||
52 | <ng-container *ngIf="!search" i18n>No server found.</ng-container> | ||
53 | </div> | ||
54 | </td> | ||
55 | </tr> | ||
56 | </ng-template> | ||
57 | </p-table> | ||
58 | |||
59 | <my-batch-domains-modal #batchDomainsModal i18n-action action="Mute domains" (domains)="onDomainsToBlock($event)"></my-batch-domains-modal> | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.scss b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.scss deleted file mode 100644 index c1f66116b..000000000 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.scss +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | a { | ||
5 | @include disable-default-a-behaviour; | ||
6 | display: inline-block; | ||
7 | |||
8 | &, &:hover { | ||
9 | color: pvar(--mainForegroundColor); | ||
10 | } | ||
11 | |||
12 | span { | ||
13 | font-size: 80%; | ||
14 | color: pvar(--inputPlaceholderColor); | ||
15 | } | ||
16 | } | ||
17 | |||
18 | .unblock-button { | ||
19 | @include peertube-button; | ||
20 | @include grey-button; | ||
21 | } | ||
22 | |||
23 | .block-button { | ||
24 | @include create-button; | ||
25 | } | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts index 559c9c0b0..9d4ec174a 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts | |||
@@ -1,84 +1,15 @@ | |||
1 | import { Component, OnInit, ViewChild } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { BlocklistService } from '@app/shared/blocklist' | ||
7 | import { ServerBlock } from '../../../../../../shared' | ||
8 | import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component' | ||
9 | 3 | ||
10 | @Component({ | 4 | @Component({ |
11 | selector: 'my-instance-server-blocklist', | 5 | selector: 'my-instance-server-blocklist', |
12 | styleUrls: [ '../moderation.component.scss', './instance-server-blocklist.component.scss' ], | 6 | styleUrls: [ '../../../shared/blocklist/server-blocklist.component.scss' ], |
13 | templateUrl: './instance-server-blocklist.component.html' | 7 | templateUrl: '../../../shared/blocklist/server-blocklist.component.html' |
14 | }) | 8 | }) |
15 | export class InstanceServerBlocklistComponent extends RestTable implements OnInit { | 9 | export class InstanceServerBlocklistComponent extends GenericServerBlocklistComponent { |
16 | @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent | 10 | mode = BlocklistComponentType.Instance |
17 | |||
18 | blockedServers: ServerBlock[] = [] | ||
19 | totalRecords = 0 | ||
20 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | |||
23 | constructor ( | ||
24 | private notifier: Notifier, | ||
25 | private blocklistService: BlocklistService, | ||
26 | private i18n: I18n | ||
27 | ) { | ||
28 | super() | ||
29 | } | ||
30 | |||
31 | ngOnInit () { | ||
32 | this.initialize() | ||
33 | } | ||
34 | 11 | ||
35 | getIdentifier () { | 12 | getIdentifier () { |
36 | return 'InstanceServerBlocklistComponent' | 13 | return 'InstanceServerBlocklistComponent' |
37 | } | 14 | } |
38 | |||
39 | unblockServer (serverBlock: ServerBlock) { | ||
40 | const host = serverBlock.blockedServer.host | ||
41 | |||
42 | this.blocklistService.unblockServerByInstance(host) | ||
43 | .subscribe( | ||
44 | () => { | ||
45 | this.notifier.success(this.i18n('Instance {{host}} unmuted by your instance.', { host })) | ||
46 | |||
47 | this.loadData() | ||
48 | } | ||
49 | ) | ||
50 | } | ||
51 | |||
52 | addServersToBlock () { | ||
53 | this.batchDomainsModal.openModal() | ||
54 | } | ||
55 | |||
56 | onDomainsToBlock (domains: string[]) { | ||
57 | domains.forEach(domain => { | ||
58 | this.blocklistService.blockServerByInstance(domain) | ||
59 | .subscribe( | ||
60 | () => { | ||
61 | this.notifier.success(this.i18n('Instance {{domain}} muted by your instance.', { domain })) | ||
62 | |||
63 | this.loadData() | ||
64 | } | ||
65 | ) | ||
66 | }) | ||
67 | } | ||
68 | |||
69 | protected loadData () { | ||
70 | return this.blocklistService.getInstanceServerBlocklist({ | ||
71 | pagination: this.pagination, | ||
72 | sort: this.sort, | ||
73 | search: this.search | ||
74 | }) | ||
75 | .subscribe( | ||
76 | resultList => { | ||
77 | this.blockedServers = resultList.data | ||
78 | this.totalRecords = resultList.total | ||
79 | }, | ||
80 | |||
81 | err => this.notifier.error(err.message) | ||
82 | ) | ||
83 | } | ||
84 | } | 15 | } |
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 404eb0504..ba68cf6f6 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -16,10 +16,6 @@ | |||
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
19 | .empty-table-message { | ||
20 | @include empty-state; | ||
21 | } | ||
22 | |||
23 | .moderation-expanded { | 19 | .moderation-expanded { |
24 | font-size: 90%; | 20 | font-size: 90%; |
25 | 21 | ||
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index a2ed51559..64641b28a 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -137,7 +137,7 @@ | |||
137 | <ng-template pTemplate="emptymessage"> | 137 | <ng-template pTemplate="emptymessage"> |
138 | <tr> | 138 | <tr> |
139 | <td colspan="6"> | 139 | <td colspan="6"> |
140 | <div class="empty-table-message"> | 140 | <div class="no-results"> |
141 | <ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container> | 141 | <ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container> |
142 | <ng-container *ngIf="!search" i18n>No video abuses found.</ng-container> | 142 | <ng-container *ngIf="!search" i18n>No video abuses found.</ng-container> |
143 | </div> | 143 | </div> |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html index a01a2566d..ec20e46f1 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html | |||
@@ -102,7 +102,7 @@ | |||
102 | <ng-template pTemplate="emptymessage"> | 102 | <ng-template pTemplate="emptymessage"> |
103 | <tr> | 103 | <tr> |
104 | <td colspan="6"> | 104 | <td colspan="6"> |
105 | <div class="empty-table-message"> | 105 | <div class="no-results"> |
106 | <ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container> | 106 | <ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container> |
107 | <ng-container *ngIf="!search" i18n>No blocked video found.</ng-container> | 107 | <ng-container *ngIf="!search" i18n>No blocked video found.</ng-container> |
108 | </div> | 108 | </div> |