aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+videos
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+videos')
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts13
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss4
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts13
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts15
-rw-r--r--client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts15
-rw-r--r--client/src/app/+videos/+video-edit/video-add.component.scss4
-rw-r--r--client/src/app/+videos/+video-watch/comment/video-comments.component.html15
-rw-r--r--client/src/app/+videos/+video-watch/comment/video-comments.component.ts1
-rw-r--r--client/src/app/+videos/+video-watch/modal/video-support.component.html15
-rw-r--r--client/src/app/+videos/+video-watch/modal/video-support.component.scss3
-rw-r--r--client/src/app/+videos/+video-watch/modal/video-support.component.ts31
-rw-r--r--client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html4
-rw-r--r--client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss33
-rw-r--r--client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts2
-rw-r--r--client/src/app/+videos/+video-watch/video-avatar-channel.component.html27
-rw-r--r--client/src/app/+videos/+video-watch/video-avatar-channel.component.scss44
-rw-r--r--client/src/app/+videos/+video-watch/video-avatar-channel.component.ts27
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.html5
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.scss59
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts62
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.module.ts9
-rw-r--r--client/src/app/+videos/video-list/overview/video-overview.component.html6
-rw-r--r--client/src/app/+videos/video-list/overview/video-overview.component.scss79
-rw-r--r--client/src/app/+videos/video-list/video-user-subscriptions.component.ts3
24 files changed, 305 insertions, 184 deletions
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
index 8780ca567..8e035b6bb 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-go-live.component.ts
@@ -1,8 +1,8 @@
1 1
2import { forkJoin } from 'rxjs' 2import { forkJoin } from 'rxjs'
3import { Component, EventEmitter, OnInit, Output } from '@angular/core' 3import { AfterViewChecked, AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
4import { Router } from '@angular/router' 4import { Router } from '@angular/router'
5import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' 5import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
6import { scrollToTop } from '@app/helpers' 6import { scrollToTop } from '@app/helpers'
7import { FormValidatorService } from '@app/shared/shared-forms' 7import { FormValidatorService } from '@app/shared/shared-forms'
8import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' 8import { VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
@@ -19,7 +19,7 @@ import { VideoSend } from './video-send'
19 './video-send.scss' 19 './video-send.scss'
20 ] 20 ]
21}) 21})
22export class VideoGoLiveComponent extends VideoSend implements OnInit, CanComponentDeactivate { 22export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {
23 @Output() firstStepDone = new EventEmitter<string>() 23 @Output() firstStepDone = new EventEmitter<string>()
24 @Output() firstStepError = new EventEmitter<void>() 24 @Output() firstStepError = new EventEmitter<void>()
25 25
@@ -41,7 +41,8 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, CanCompon
41 protected videoService: VideoService, 41 protected videoService: VideoService,
42 protected videoCaptionService: VideoCaptionService, 42 protected videoCaptionService: VideoCaptionService,
43 private liveVideoService: LiveVideoService, 43 private liveVideoService: LiveVideoService,
44 private router: Router 44 private router: Router,
45 private hooks: HooksService
45 ) { 46 ) {
46 super() 47 super()
47 } 48 }
@@ -50,6 +51,10 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, CanCompon
50 super.ngOnInit() 51 super.ngOnInit()
51 } 52 }
52 53
54 ngAfterViewInit () {
55 this.hooks.runAction('action:go-live.init', 'video-edit')
56 }
57
53 canDeactivate () { 58 canDeactivate () {
54 return { canDeactivate: true } 59 return { canDeactivate: true }
55 } 60 }
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss
index 1fef74994..dd87641fc 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.scss
@@ -3,8 +3,8 @@
3 3
4.first-step-block { 4.first-step-block {
5 .torrent-or-magnet { 5 .torrent-or-magnet {
6 @include divider($color: pvar(--inputPlaceholderColor), $background: pvar(--submenuColor)); 6 @include divider($color: pvar(--inputPlaceholderColor), $background: pvar(--submenuBackgroundColor));
7 7
8 &[data-content] { 8 &[data-content] {
9 margin: 1.5rem 0; 9 margin: 1.5rem 0;
10 } 10 }
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
index 01087e525..3aae24732 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts
@@ -1,6 +1,6 @@
1import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core' 1import { AfterViewInit, Component, ElementRef, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'
2import { Router } from '@angular/router' 2import { Router } from '@angular/router'
3import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' 3import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
4import { scrollToTop } from '@app/helpers' 4import { scrollToTop } from '@app/helpers'
5import { FormValidatorService } from '@app/shared/shared-forms' 5import { FormValidatorService } from '@app/shared/shared-forms'
6import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' 6import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
@@ -18,7 +18,7 @@ import { VideoSend } from './video-send'
18 './video-send.scss' 18 './video-send.scss'
19 ] 19 ]
20}) 20})
21export class VideoImportTorrentComponent extends VideoSend implements OnInit, CanComponentDeactivate { 21export class VideoImportTorrentComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {
22 @Output() firstStepDone = new EventEmitter<string>() 22 @Output() firstStepDone = new EventEmitter<string>()
23 @Output() firstStepError = new EventEmitter<void>() 23 @Output() firstStepError = new EventEmitter<void>()
24 @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement> 24 @ViewChild('torrentfileInput') torrentfileInput: ElementRef<HTMLInputElement>
@@ -43,7 +43,8 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
43 protected videoService: VideoService, 43 protected videoService: VideoService,
44 protected videoCaptionService: VideoCaptionService, 44 protected videoCaptionService: VideoCaptionService,
45 private router: Router, 45 private router: Router,
46 private videoImportService: VideoImportService 46 private videoImportService: VideoImportService,
47 private hooks: HooksService
47 ) { 48 ) {
48 super() 49 super()
49 } 50 }
@@ -52,6 +53,10 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Ca
52 super.ngOnInit() 53 super.ngOnInit()
53 } 54 }
54 55
56 ngAfterViewInit () {
57 this.hooks.runAction('action:video-torrent-import.init', 'video-edit')
58 }
59
55 canDeactivate () { 60 canDeactivate () {
56 return { canDeactivate: true } 61 return { canDeactivate: true }
57 } 62 }
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
index c447c179d..7a9fe369f 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-url.component.ts
@@ -1,7 +1,7 @@
1import { map, switchMap } from 'rxjs/operators' 1import { map, switchMap } from 'rxjs/operators'
2import { Component, EventEmitter, OnInit, Output } from '@angular/core' 2import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
3import { Router } from '@angular/router' 3import { Router } from '@angular/router'
4import { AuthService, CanComponentDeactivate, Notifier, ServerService } from '@app/core' 4import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService } from '@app/core'
5import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers' 5import { getAbsoluteAPIUrl, scrollToTop } from '@app/helpers'
6import { FormValidatorService } from '@app/shared/shared-forms' 6import { FormValidatorService } from '@app/shared/shared-forms'
7import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' 7import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main'
@@ -18,7 +18,7 @@ import { VideoSend } from './video-send'
18 './video-send.scss' 18 './video-send.scss'
19 ] 19 ]
20}) 20})
21export class VideoImportUrlComponent extends VideoSend implements OnInit, CanComponentDeactivate { 21export class VideoImportUrlComponent extends VideoSend implements OnInit, AfterViewInit, CanComponentDeactivate {
22 @Output() firstStepDone = new EventEmitter<string>() 22 @Output() firstStepDone = new EventEmitter<string>()
23 @Output() firstStepError = new EventEmitter<void>() 23 @Output() firstStepError = new EventEmitter<void>()
24 24
@@ -42,8 +42,9 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
42 protected videoService: VideoService, 42 protected videoService: VideoService,
43 protected videoCaptionService: VideoCaptionService, 43 protected videoCaptionService: VideoCaptionService,
44 private router: Router, 44 private router: Router,
45 private videoImportService: VideoImportService 45 private videoImportService: VideoImportService,
46 ) { 46 private hooks: HooksService
47 ) {
47 super() 48 super()
48 } 49 }
49 50
@@ -51,6 +52,10 @@ export class VideoImportUrlComponent extends VideoSend implements OnInit, CanCom
51 super.ngOnInit() 52 super.ngOnInit()
52 } 53 }
53 54
55 ngAfterViewInit () {
56 this.hooks.runAction('action:video-url-import.init', 'video-edit')
57 }
58
54 canDeactivate () { 59 canDeactivate () {
55 return { canDeactivate: true } 60 return { canDeactivate: true }
56 } 61 }
diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
index ca21b61cd..effb37077 100644
--- a/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
+++ b/client/src/app/+videos/+video-edit/video-add-components/video-upload.component.ts
@@ -1,15 +1,15 @@
1import { Subscription } from 'rxjs' 1import { Subscription } from 'rxjs'
2import { HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http' 2import { HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http'
3import { Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core' 3import { AfterViewInit, Component, ElementRef, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
4import { Router } from '@angular/router' 4import { Router } from '@angular/router'
5import { AuthService, CanComponentDeactivate, Notifier, ServerService, UserService } from '@app/core' 5import { AuthService, CanComponentDeactivate, HooksService, Notifier, ServerService, UserService } from '@app/core'
6import { scrollToTop, uploadErrorHandler } from '@app/helpers' 6import { scrollToTop, uploadErrorHandler } from '@app/helpers'
7import { FormValidatorService } from '@app/shared/shared-forms' 7import { FormValidatorService } from '@app/shared/shared-forms'
8import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main' 8import { BytesPipe, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
9import { LoadingBarService } from '@ngx-loading-bar/core' 9import { LoadingBarService } from '@ngx-loading-bar/core'
10import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
10import { VideoPrivacy } from '@shared/models' 11import { VideoPrivacy } from '@shared/models'
11import { VideoSend } from './video-send' 12import { VideoSend } from './video-send'
12import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
13 13
14@Component({ 14@Component({
15 selector: 'my-video-upload', 15 selector: 'my-video-upload',
@@ -20,7 +20,7 @@ import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
20 './video-send.scss' 20 './video-send.scss'
21 ] 21 ]
22}) 22})
23export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy, CanComponentDeactivate { 23export class VideoUploadComponent extends VideoSend implements OnInit, AfterViewInit, OnDestroy, CanComponentDeactivate {
24 @Output() firstStepDone = new EventEmitter<string>() 24 @Output() firstStepDone = new EventEmitter<string>()
25 @Output() firstStepError = new EventEmitter<void>() 25 @Output() firstStepError = new EventEmitter<void>()
26 @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement> 26 @ViewChild('videofileInput') videofileInput: ElementRef<HTMLInputElement>
@@ -60,7 +60,8 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
60 protected videoService: VideoService, 60 protected videoService: VideoService,
61 protected videoCaptionService: VideoCaptionService, 61 protected videoCaptionService: VideoCaptionService,
62 private userService: UserService, 62 private userService: UserService,
63 private router: Router 63 private router: Router,
64 private hooks: HooksService
64 ) { 65 ) {
65 super() 66 super()
66 } 67 }
@@ -79,6 +80,10 @@ export class VideoUploadComponent extends VideoSend implements OnInit, OnDestroy
79 }) 80 })
80 } 81 }
81 82
83 ngAfterViewInit () {
84 this.hooks.runAction('action:video-upload.init', 'video-edit')
85 }
86
82 ngOnDestroy () { 87 ngOnDestroy () {
83 if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe() 88 if (this.videoUploadObservable) this.videoUploadObservable.unsubscribe()
84 } 89 }
diff --git a/client/src/app/+videos/+video-edit/video-add.component.scss b/client/src/app/+videos/+video-edit/video-add.component.scss
index 5db9e823d..1ebee946b 100644
--- a/client/src/app/+videos/+video-edit/video-add.component.scss
+++ b/client/src/app/+videos/+video-edit/video-add.component.scss
@@ -67,7 +67,7 @@ $nav-link-height: 40px;
67 &.active { 67 &.active {
68 border-color: $border-color; 68 border-color: $border-color;
69 border-bottom-color: transparent; 69 border-bottom-color: transparent;
70 background-color: pvar(--submenuColor) !important; 70 background-color: pvar(--submenuBackgroundColor) !important;
71 71
72 span { 72 span {
73 border-bottom-color: pvar(--mainColor); 73 border-bottom-color: pvar(--mainColor);
@@ -84,7 +84,7 @@ $nav-link-height: 40px;
84 border: $border-width $border-type $border-color; 84 border: $border-width $border-type $border-color;
85 border-top: transparent; 85 border-top: transparent;
86 86
87 background-color: pvar(--submenuColor); 87 background-color: pvar(--submenuBackgroundColor);
88 border-bottom-left-radius: 3px; 88 border-bottom-left-radius: 3px;
89 border-bottom-right-radius: 3px; 89 border-bottom-right-radius: 3px;
90 width: 100%; 90 width: 100%;
diff --git a/client/src/app/+videos/+video-watch/comment/video-comments.component.html b/client/src/app/+videos/+video-watch/comment/video-comments.component.html
index 4a6426d30..9e6fde2e0 100644
--- a/client/src/app/+videos/+video-watch/comment/video-comments.component.html
+++ b/client/src/app/+videos/+video-watch/comment/video-comments.component.html
@@ -1,12 +1,7 @@
1<div> 1<div>
2 <div class="title-block"> 2 <div class="title-block">
3 <h2 class="title-page title-page-single"> 3 <h2 class="title-page title-page-single">
4 <ng-container *ngIf="totalNotDeletedComments > 0; then hasComments; else noComments"></ng-container> 4 {totalNotDeletedComments, plural, =0 {Comments} =1 {1 Comment} other {{{totalNotDeletedComments}} Comments}}
5 <ng-template #hasComments>
6 <ng-container i18n *ngIf="totalNotDeletedComments === 1; else manyComments">1 Comment</ng-container>
7 <ng-template i18n #manyComments>{{ totalNotDeletedComments }} Comments</ng-template>
8 </ng-template>
9 <ng-template i18n #noComments>Comments</ng-template>
10 </h2> 5 </h2>
11 6
12 <my-feed [syndicationItems]="syndicationItems"></my-feed> 7 <my-feed [syndicationItems]="syndicationItems"></my-feed>
@@ -79,15 +74,17 @@
79 <span class="glyphicon glyphicon-menu-down"></span> 74 <span class="glyphicon glyphicon-menu-down"></span>
80 75
81 <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container> 76 <ng-container *ngIf="comment.totalRepliesFromVideoAuthor > 0; then hasAuthorComments; else noAuthorComments"></ng-container>
77
82 <ng-template #hasAuthorComments> 78 <ng-template #hasAuthorComments>
83 <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n> 79 <ng-container *ngIf="comment.totalReplies !== comment.totalRepliesFromVideoAuthor; else onlyAuthorComments" i18n>
84 View {{ comment.totalReplies }} replies from {{ video?.account?.displayName || 'the author' }} and others 80 View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}} from {{ video?.account?.displayName || 'the author' }} and others
85 </ng-container> 81 </ng-container>
86 <ng-template i18n #onlyAuthorComments> 82 <ng-template i18n #onlyAuthorComments>
87 View {{ comment.totalReplies }} replies from {{ video?.account?.displayName || 'the author' }} 83 View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}} from {{ video?.account?.displayName || 'the author' }}
88 </ng-template> 84 </ng-template>
89 </ng-template> 85 </ng-template>
90 <ng-template i18n #noAuthorComments>View {{ comment.totalReplies }} replies</ng-template> 86
87 <ng-template i18n #noAuthorComments>View {comment.totalReplies, plural, =1 {1 reply} other {{{ comment.totalReplies }} replies}}</ng-template>
91 88
92 <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader> 89 <my-small-loader class="comment-thread-loading ml-1" [loading]="threadLoading[comment.id]"></my-small-loader>
93 </div> 90 </div>
diff --git a/client/src/app/+videos/+video-watch/comment/video-comments.component.ts b/client/src/app/+videos/+video-watch/comment/video-comments.component.ts
index d36dd9e34..210236b61 100644
--- a/client/src/app/+videos/+video-watch/comment/video-comments.component.ts
+++ b/client/src/app/+videos/+video-watch/comment/video-comments.component.ts
@@ -5,7 +5,6 @@ import { AuthService, ComponentPagination, ConfirmService, hasMoreItems, Notifie
5import { HooksService } from '@app/core/plugins/hooks.service' 5import { HooksService } from '@app/core/plugins/hooks.service'
6import { Syndication, VideoDetails } from '@app/shared/shared-main' 6import { Syndication, VideoDetails } from '@app/shared/shared-main'
7import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment' 7import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
8import { ThisReceiver } from '@angular/compiler'
9 8
10@Component({ 9@Component({
11 selector: 'my-video-comments', 10 selector: 'my-video-comments',
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.html b/client/src/app/+videos/+video-watch/modal/video-support.component.html
deleted file mode 100644
index 935656d23..000000000
--- a/client/src/app/+videos/+video-watch/modal/video-support.component.html
+++ /dev/null
@@ -1,15 +0,0 @@
1<ng-template #modal let-hide="close">
2 <div class="modal-header">
3 <h4 i18n class="modal-title">Support {{ video.account.displayName }}</h4>
4 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
5 </div>
6
7 <div class="modal-body" [innerHTML]="videoHTMLSupport"></div>
8
9 <div class="modal-footer inputs">
10 <input
11 type="button" role="button" i18n-value value="Maybe later" class="action-button action-button-cancel"
12 (click)="hide()" (key.enter)="hide()"
13 >
14 </div>
15</ng-template>
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.scss b/client/src/app/+videos/+video-watch/modal/video-support.component.scss
deleted file mode 100644
index 184e09027..000000000
--- a/client/src/app/+videos/+video-watch/modal/video-support.component.scss
+++ /dev/null
@@ -1,3 +0,0 @@
1.action-button-cancel {
2 margin-right: 0 !important;
3}
diff --git a/client/src/app/+videos/+video-watch/modal/video-support.component.ts b/client/src/app/+videos/+video-watch/modal/video-support.component.ts
deleted file mode 100644
index bd5290a72..000000000
--- a/client/src/app/+videos/+video-watch/modal/video-support.component.ts
+++ /dev/null
@@ -1,31 +0,0 @@
1import { Component, Input, ViewChild } from '@angular/core'
2import { MarkdownService } from '@app/core'
3import { VideoDetails } from '@app/shared/shared-main'
4import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
5
6@Component({
7 selector: 'my-video-support',
8 templateUrl: './video-support.component.html',
9 styleUrls: [ './video-support.component.scss' ]
10})
11export class VideoSupportComponent {
12 @Input() video: VideoDetails = null
13
14 @ViewChild('modal', { static: true }) modal: NgbModal
15
16 videoHTMLSupport = ''
17
18 constructor (
19 private markdownService: MarkdownService,
20 private modalService: NgbModal
21 ) { }
22
23 show () {
24 const modalRef = this.modalService.open(this.modal, { centered: true })
25
26 this.markdownService.enhancedMarkdownToHTML(this.video.support)
27 .then(r => this.videoHTMLSupport = r)
28
29 return modalRef
30 }
31}
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
index 3c7c679b8..e0e9f92e7 100644
--- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
+++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.html
@@ -1,4 +1,4 @@
1<div class="other-videos"> 1<div class="other-videos" [ngClass]="{ 'display-as-row': displayAsRow }">
2 <ng-container *ngIf="hasVideos$ | async"> 2 <ng-container *ngIf="hasVideos$ | async">
3 <div class="title-page-container"> 3 <div class="title-page-container">
4 <h2 i18n class="title-page title-page-single"> 4 <h2 i18n class="title-page title-page-single">
@@ -14,7 +14,7 @@
14 14
15 <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count"> 15 <ng-container *ngFor="let video of (videos$ | async); let i = index; let length = count">
16 <my-video-miniature 16 <my-video-miniature
17 [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" 17 [displayOptions]="displayOptions" [video]="video" [user]="userMiniature" [displayAsRow]="displayAsRow"
18 (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()"> 18 (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()" (videoAccountMuted)="onVideoRemoved()">
19 </my-video-miniature> 19 </my-video-miniature>
20 20
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss
index b278c9654..c9fae6f27 100644
--- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss
+++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.scss
@@ -1,3 +1,6 @@
1@import '_variables';
2@import '_mixins';
3
1.title-page-container { 4.title-page-container {
2 display: flex; 5 display: flex;
3 justify-content: space-between; 6 justify-content: space-between;
@@ -11,6 +14,10 @@
11 } 14 }
12} 15}
13 16
17.title-page {
18 margin-top: 0;
19}
20
14.title-page-autoplay { 21.title-page-autoplay {
15 display: flex; 22 display: flex;
16 width: max-content; 23 width: max-content;
@@ -29,3 +36,29 @@
29hr { 36hr {
30 margin-top: 0; 37 margin-top: 0;
31} 38}
39
40my-video-miniature {
41 display: block;
42}
43
44.other-videos:not(.display-as-row) my-video-miniature {
45 min-width: $video-thumbnail-medium-width;
46 max-width: $video-thumbnail-medium-width;
47}
48
49.display-as-row {
50 my-video-miniature {
51 margin-bottom: 20px;
52 }
53
54 hr {
55 display: none;
56 }
57
58 @media screen and (max-width: $mobile-view) {
59 my-video-miniature {
60 margin-bottom: 10px;
61 }
62 }
63}
64
diff --git a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts
index a1c8e0661..89b9c01b6 100644
--- a/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts
+++ b/client/src/app/+videos/+video-watch/recommendations/recommended-videos.component.ts
@@ -16,6 +16,8 @@ import { RecommendedVideosStore } from './recommended-videos.store'
16export class RecommendedVideosComponent implements OnInit, OnChanges { 16export class RecommendedVideosComponent implements OnInit, OnChanges {
17 @Input() inputRecommendation: RecommendationInfo 17 @Input() inputRecommendation: RecommendationInfo
18 @Input() playlist: VideoPlaylist 18 @Input() playlist: VideoPlaylist
19 @Input() displayAsRow: boolean
20
19 @Output() gotRecommendations = new EventEmitter<Video[]>() 21 @Output() gotRecommendations = new EventEmitter<Video[]>()
20 22
21 autoPlayNextVideo: boolean 23 autoPlayNextVideo: boolean
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.html b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html
new file mode 100644
index 000000000..5058f05dd
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.html
@@ -0,0 +1,27 @@
1<div class="wrapper" [ngClass]="'avatar-' + size">
2 <ng-container *ngIf="!isChannelAvatarNull() && !genericChannel">
3 <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle">
4 <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" />
5 </a>
6
7 <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle">
8 <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" />
9 </a>
10 </ng-container>
11
12 <ng-container *ngIf="!isChannelAvatarNull() && genericChannel">
13 <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle">
14 <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" />
15 </a>
16
17 <a [routerLink]="[ '/video-channels', video.byVideoChannel ]" [title]="channelLinkTitle">
18 <img [src]="video.videoChannelAvatarUrl" i18n-alt alt="Channel avatar" class="channel-avatar" />
19 </a>
20 </ng-container>
21
22 <ng-container *ngIf="isChannelAvatarNull()">
23 <a [routerLink]="[ '/accounts', video.byAccount ]" [title]="accountLinkTitle">
24 <img [src]="video.accountAvatarUrl" i18n-alt alt="Account avatar" />
25 </a>
26 </ng-container>
27</div>
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss
new file mode 100644
index 000000000..4998e85fa
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.scss
@@ -0,0 +1,44 @@
1@import '_mixins';
2
3.wrapper {
4 $avatar-size: 35px;
5
6 width: $avatar-size;
7 height: $avatar-size;
8 position: relative;
9 margin-right: 5px;
10 margin-bottom: 5px;
11
12 &.avatar-sm {
13 width: 28px;
14 height: 28px;
15 margin-bottom: 3px;
16 }
17
18 a {
19 @include disable-outline;
20 }
21
22 a img {
23 height: 100%;
24 object-fit: cover;
25 position: absolute;
26 top:50%;
27 left:50%;
28 transform: translate(-50%,-50%);
29 border-radius: 5px;
30
31 &:not(.channel-avatar) {
32 border-radius: 50%;
33 }
34 }
35
36 a:nth-of-type(2) img {
37 height: 60%;
38 width: 60%;
39 border: 2px solid pvar(--mainBackgroundColor);
40 transform: translateX(15%);
41 position: relative;
42 background-color: pvar(--mainBackgroundColor);
43 }
44}
diff --git a/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts
new file mode 100644
index 000000000..0b6e796df
--- /dev/null
+++ b/client/src/app/+videos/+video-watch/video-avatar-channel.component.ts
@@ -0,0 +1,27 @@
1import { Component, Input, OnInit } from '@angular/core'
2import { Video } from '@app/shared/shared-main/video'
3
4@Component({
5 selector: 'my-video-avatar-channel',
6 templateUrl: './video-avatar-channel.component.html',
7 styleUrls: [ './video-avatar-channel.component.scss' ]
8})
9export class VideoAvatarChannelComponent implements OnInit {
10 @Input() video: Video
11 @Input() byAccount: string
12
13 @Input() size: 'md' | 'sm' = 'md'
14 @Input() genericChannel: boolean
15
16 channelLinkTitle = ''
17 accountLinkTitle = ''
18
19 ngOnInit () {
20 this.channelLinkTitle = $localize`${this.video.account.name} (channel page)`
21 this.accountLinkTitle = $localize`${this.video.byAccount} (account page)`
22 }
23
24 isChannelAvatarNull () {
25 return this.video.channel.avatar === null
26 }
27}
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.html b/client/src/app/+videos/+video-watch/video-watch.component.html
index b17f898ce..99103c2c3 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.html
+++ b/client/src/app/+videos/+video-watch/video-watch.component.html
@@ -142,7 +142,7 @@
142 <ng-container *ngIf="isUserLoggedIn()"> 142 <ng-container *ngIf="isUserLoggedIn()">
143 <my-video-actions-dropdown 143 <my-video-actions-dropdown
144 placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions" 144 placement="bottom auto" buttonDirection="horizontal" [buttonStyled]="true" [video]="video" [videoCaptions]="videoCaptions"
145 [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()" (modalOpened)="onModalOpened()" 145 [displayOptions]="videoActionsOptions" (videoRemoved)="onVideoRemoved()"
146 ></my-video-actions-dropdown> 146 ></my-video-actions-dropdown>
147 </ng-container> 147 </ng-container>
148 </div> 148 </div>
@@ -289,6 +289,7 @@
289 </div> 289 </div>
290 290
291 <my-recommended-videos 291 <my-recommended-videos
292 [displayAsRow]="displayOtherVideosAsRow()"
292 [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }" 293 [inputRecommendation]="{ uuid: video.uuid, tags: video.tags }"
293 [playlist]="playlist" 294 [playlist]="playlist"
294 (gotRecommendations)="onRecommendations($event)" 295 (gotRecommendations)="onRecommendations($event)"
@@ -313,6 +314,6 @@
313</div> 314</div>
314 315
315<ng-container *ngIf="video !== null"> 316<ng-container *ngIf="video !== null">
316 <my-video-support #videoSupportModal [video]="video"></my-video-support> 317 <my-support-modal #supportModal [video]="video"></my-support-modal>
317 <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share> 318 <my-video-share #videoShareModal [video]="video" [videoCaptions]="videoCaptions" [playlist]="playlist"></my-video-share>
318</ng-container> 319</ng-container>
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.scss b/client/src/app/+videos/+video-watch/video-watch.component.scss
index 555126cbc..2e566e3fb 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.scss
+++ b/client/src/app/+videos/+video-watch/video-watch.component.scss
@@ -3,7 +3,7 @@
3@import '_bootstrap-variables'; 3@import '_bootstrap-variables';
4@import '_miniature'; 4@import '_miniature';
5 5
6$player-factor: 1.7; // 16/9 6$player-factor: #{16/9};
7$video-info-margin-left: 44px; 7$video-info-margin-left: 44px;
8 8
9@function getPlayerHeight($width){ 9@function getPlayerHeight($width){
@@ -179,12 +179,6 @@ $video-info-margin-left: 44px;
179 &:hover { 179 &:hover {
180 opacity: 0.8; 180 opacity: 0.8;
181 } 181 }
182
183 img {
184 @include avatar(18px);
185
186 margin: -2px 5px 0 0;
187 }
188 } 182 }
189 183
190 .video-info-channel-left { 184 .video-info-channel-left {
@@ -413,37 +407,12 @@ $video-info-margin-left: 44px;
413 } 407 }
414 } 408 }
415 } 409 }
410}
416 411
417 ::ng-deep .other-videos { 412my-recommended-videos {
418 padding-left: 15px; 413 display: block;
419 min-width: $video-miniature-width; 414 padding-left: 15px;
420 415 min-width: 250px;
421 @media screen and (min-width: 1800px - (3* $video-miniature-width)) {
422 width: min-content;
423 }
424
425 .title-page {
426 margin: 0 !important;
427 }
428
429 .video-miniature {
430 display: flex;
431 width: max-content;
432 height: 100%;
433 padding-bottom: 20px;
434 flex-wrap: wrap;
435 }
436
437 .video-bottom {
438 @media screen and (max-width: 1800px - (3* $video-miniature-width)) {
439 margin-left: 1rem;
440 }
441 @media screen and (max-width: 500px) {
442 margin-left: 0;
443 margin-top: .5rem;
444 }
445 }
446 }
447} 416}
448 417
449my-video-comments { 418my-video-comments {
@@ -537,6 +506,7 @@ my-video-comments {
537 } 506 }
538} 507}
539 508
509// Use the same breakpoint than in the typescript component to display the other video miniatures as row
540@media screen and (max-width: 1100px) { 510@media screen and (max-width: 1100px) {
541 #video-wrapper { 511 #video-wrapper {
542 flex-direction: column; 512 flex-direction: column;
@@ -549,15 +519,10 @@ my-video-comments {
549 519
550 .video-bottom { 520 .video-bottom {
551 flex-direction: column; 521 flex-direction: column;
522 }
552 523
553 ::ng-deep .other-videos { 524 my-recommended-videos {
554 padding-left: 0 !important; 525 padding-left: 0;
555
556 ::ng-deep .video-miniature {
557 flex-direction: row;
558 width: auto;
559 }
560 }
561 } 526 }
562} 527}
563 528
@@ -579,10 +544,6 @@ my-video-comments {
579 } 544 }
580 } 545 }
581 546
582 ::ng-deep .other-videos .video-miniature {
583 flex-direction: column;
584 }
585
586 .privacy-concerns { 547 .privacy-concerns {
587 width: 100%; 548 width: 100%;
588 } 549 }
diff --git a/client/src/app/+videos/+video-watch/video-watch.component.ts b/client/src/app/+videos/+video-watch/video-watch.component.ts
index 7a98cab3b..de5fb4ed0 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -21,6 +21,7 @@ import { RedirectService } from '@app/core/routing/redirect.service'
21import { isXPercentInViewport, scrollToTop } from '@app/helpers' 21import { isXPercentInViewport, scrollToTop } from '@app/helpers'
22import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' 22import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main'
23import { VideoShareComponent } from '@app/shared/shared-share-modal' 23import { VideoShareComponent } from '@app/shared/shared-share-modal'
24import { SupportModalComponent } from '@app/shared/shared-support-modal'
24import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' 25import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
25import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature' 26import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature'
26import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' 27import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
@@ -28,7 +29,12 @@ import { MetaService } from '@ngx-meta/core'
28import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage' 29import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
29import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes' 30import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
30import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models' 31import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
31import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage' 32import {
33 cleanupVideoWatch,
34 getStoredP2PEnabled,
35 getStoredTheater,
36 getStoredVideoWatchHistory
37} from '../../../assets/player/peertube-player-local-storage'
32import { 38import {
33 CustomizationOptions, 39 CustomizationOptions,
34 P2PMediaLoaderOptions, 40 P2PMediaLoaderOptions,
@@ -39,7 +45,6 @@ import {
39} from '../../../assets/player/peertube-player-manager' 45} from '../../../assets/player/peertube-player-manager'
40import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils' 46import { isWebRTCDisabled, timeToInt } from '../../../assets/player/utils'
41import { environment } from '../../../environments/environment' 47import { environment } from '../../../environments/environment'
42import { VideoSupportComponent } from './modal/video-support.component'
43import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' 48import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
44 49
45type URLOptions = CustomizationOptions & { playerMode: PlayerMode } 50type URLOptions = CustomizationOptions & { playerMode: PlayerMode }
@@ -54,7 +59,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
54 59
55 @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent 60 @ViewChild('videoWatchPlaylist', { static: true }) videoWatchPlaylist: VideoWatchPlaylistComponent
56 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent 61 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
57 @ViewChild('videoSupportModal') videoSupportModal: VideoSupportComponent 62 @ViewChild('supportModal') supportModal: SupportModalComponent
58 @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent 63 @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent
59 @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent 64 @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
60 65
@@ -195,6 +200,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
195 this.theaterEnabled = getStoredTheater() 200 this.theaterEnabled = getStoredTheater()
196 201
197 this.hooks.runAction('action:video-watch.init', 'video-watch') 202 this.hooks.runAction('action:video-watch.init', 'video-watch')
203
204 setTimeout(cleanupVideoWatch, 1500) // Run in timeout to ensure we're not blocking the UI
198 } 205 }
199 206
200 ngOnDestroy () { 207 ngOnDestroy () {
@@ -277,23 +284,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
277 } 284 }
278 285
279 showSupportModal () { 286 showSupportModal () {
280 // Check video was playing before opening support modal 287 this.supportModal.show()
281 const isVideoPlaying = this.isPlaying()
282
283 this.pausePlayer()
284
285 const modalRef = this.videoSupportModal.show()
286
287 modalRef.result.then(() => {
288 if (isVideoPlaying) {
289 this.resumePlayer()
290 }
291 })
292 } 288 }
293 289
294 showShareModal () { 290 showShareModal () {
295 this.pausePlayer()
296
297 this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition) 291 this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition)
298 } 292 }
299 293
@@ -316,10 +310,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
316 } 310 }
317 } 311 }
318 312
319 onModalOpened () {
320 this.pausePlayer()
321 }
322
323 onVideoRemoved () { 313 onVideoRemoved () {
324 this.redirectService.redirectToHomepage() 314 this.redirectService.redirectToHomepage()
325 } 315 }
@@ -396,6 +386,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
396 this.loadVideo(videoId) 386 this.loadVideo(videoId)
397 } 387 }
398 388
389 displayOtherVideosAsRow () {
390 // Use the same value as in the SASS file
391 return this.screenService.getWindowInnerWidth() <= 1100
392 }
393
399 private loadVideo (videoId: string) { 394 private loadVideo (videoId: string) {
400 // Video did not change 395 // Video did not change
401 if (this.video && this.video.uuid === videoId) return 396 if (this.video && this.video.uuid === videoId) return
@@ -768,9 +763,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
768 const getStartTime = () => { 763 const getStartTime = () => {
769 const byUrl = urlOptions.startTime !== undefined 764 const byUrl = urlOptions.startTime !== undefined
770 const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined) 765 const byHistory = video.userHistory && (!this.playlist || urlOptions.resume !== undefined)
766 const byLocalStorage = getStoredVideoWatchHistory(video.uuid)
771 767
772 if (byUrl) return timeToInt(urlOptions.startTime) 768 if (byUrl) return timeToInt(urlOptions.startTime)
773 if (byHistory) return video.userHistory.currentTime 769 if (byHistory) return video.userHistory.currentTime
770 if (byLocalStorage) return byLocalStorage.duration
774 771
775 return 0 772 return 0
776 } 773 }
@@ -815,6 +812,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
815 ? this.videoService.getVideoViewUrl(video.uuid) 812 ? this.videoService.getVideoViewUrl(video.uuid)
816 : null, 813 : null,
817 embedUrl: video.embedUrl, 814 embedUrl: video.embedUrl,
815 embedTitle: video.name,
818 816
819 isLive: video.isLive, 817 isLive: video.isLive,
820 818
@@ -827,7 +825,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
827 825
828 serverUrl: environment.apiUrl, 826 serverUrl: environment.apiUrl,
829 827
830 videoCaptions: playerCaptions 828 videoCaptions: playerCaptions,
829
830 videoUUID: video.uuid
831 }, 831 },
832 832
833 webtorrent: { 833 webtorrent: {
@@ -867,24 +867,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
867 return { playerMode: mode, playerOptions: options } 867 return { playerMode: mode, playerOptions: options }
868 } 868 }
869 869
870 private pausePlayer () {
871 if (!this.player) return
872
873 this.player.pause()
874 }
875
876 private resumePlayer () {
877 if (!this.player) return
878
879 this.player.play()
880 }
881
882 private isPlaying () {
883 if (!this.player) return
884
885 return !this.player.paused()
886 }
887
888 private async subscribeToLiveEventsIfNeeded (oldVideo: VideoDetails, newVideo: VideoDetails) { 870 private async subscribeToLiveEventsIfNeeded (oldVideo: VideoDetails, newVideo: VideoDetails) {
889 if (!this.liveVideosSub) { 871 if (!this.liveVideosSub) {
890 this.liveVideosSub = this.buildLiveEventsSubscription() 872 this.liveVideosSub = this.buildLiveEventsSubscription()
diff --git a/client/src/app/+videos/+video-watch/video-watch.module.ts b/client/src/app/+videos/+video-watch/video-watch.module.ts
index fbda9b9c4..3e9f3822e 100644
--- a/client/src/app/+videos/+video-watch/video-watch.module.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.module.ts
@@ -4,6 +4,7 @@ import { SharedGlobalIconModule } from '@app/shared/shared-icons'
4import { SharedMainModule } from '@app/shared/shared-main' 4import { SharedMainModule } from '@app/shared/shared-main'
5import { SharedModerationModule } from '@app/shared/shared-moderation' 5import { SharedModerationModule } from '@app/shared/shared-moderation'
6import { SharedShareModal } from '@app/shared/shared-share-modal' 6import { SharedShareModal } from '@app/shared/shared-share-modal'
7import { SharedSupportModal } from '@app/shared/shared-support-modal'
7import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription' 8import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription'
8import { SharedVideoModule } from '@app/shared/shared-video' 9import { SharedVideoModule } from '@app/shared/shared-video'
9import { SharedVideoCommentModule } from '@app/shared/shared-video-comment' 10import { SharedVideoCommentModule } from '@app/shared/shared-video-comment'
@@ -13,9 +14,9 @@ import { VideoCommentService } from '../../shared/shared-video-comment/video-com
13import { VideoCommentAddComponent } from './comment/video-comment-add.component' 14import { VideoCommentAddComponent } from './comment/video-comment-add.component'
14import { VideoCommentComponent } from './comment/video-comment.component' 15import { VideoCommentComponent } from './comment/video-comment.component'
15import { VideoCommentsComponent } from './comment/video-comments.component' 16import { VideoCommentsComponent } from './comment/video-comments.component'
16import { VideoSupportComponent } from './modal/video-support.component'
17import { RecommendationsModule } from './recommendations/recommendations.module' 17import { RecommendationsModule } from './recommendations/recommendations.module'
18import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive' 18import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive'
19import { VideoAvatarChannelComponent } from './video-avatar-channel.component'
19import { VideoWatchPlaylistComponent } from './video-watch-playlist.component' 20import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
20import { VideoWatchRoutingModule } from './video-watch-routing.module' 21import { VideoWatchRoutingModule } from './video-watch-routing.module'
21import { VideoWatchComponent } from './video-watch.component' 22import { VideoWatchComponent } from './video-watch.component'
@@ -34,18 +35,20 @@ import { VideoWatchComponent } from './video-watch.component'
34 SharedGlobalIconModule, 35 SharedGlobalIconModule,
35 SharedVideoCommentModule, 36 SharedVideoCommentModule,
36 SharedShareModal, 37 SharedShareModal,
37 SharedVideoModule 38 SharedVideoModule,
39 SharedSupportModal
38 ], 40 ],
39 41
40 declarations: [ 42 declarations: [
41 VideoWatchComponent, 43 VideoWatchComponent,
42 VideoWatchPlaylistComponent, 44 VideoWatchPlaylistComponent,
43 45
44 VideoSupportComponent,
45 VideoCommentsComponent, 46 VideoCommentsComponent,
46 VideoCommentAddComponent, 47 VideoCommentAddComponent,
47 VideoCommentComponent, 48 VideoCommentComponent,
48 49
50 VideoAvatarChannelComponent,
51
49 TimestampRouteTransformerDirective, 52 TimestampRouteTransformerDirective,
50 TimestampRouteTransformerDirective 53 TimestampRouteTransformerDirective
51 ], 54 ],
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.html b/client/src/app/+videos/video-list/overview/video-overview.component.html
index ca986c634..639a96c43 100644
--- a/client/src/app/+videos/video-list/overview/video-overview.component.html
+++ b/client/src/app/+videos/video-list/overview/video-overview.component.html
@@ -14,7 +14,7 @@
14 </h1> 14 </h1>
15 15
16 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> 16 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
17 <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> 17 <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true">
18 </my-video-miniature> 18 </my-video-miniature>
19 </div> 19 </div>
20 </div> 20 </div>
@@ -25,7 +25,7 @@
25 </h2> 25 </h2>
26 26
27 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> 27 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
28 <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> 28 <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true">
29 </my-video-miniature> 29 </my-video-miniature>
30 </div> 30 </div>
31 </div> 31 </div>
@@ -40,7 +40,7 @@
40 </div> 40 </div>
41 41
42 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)"> 42 <div class="video-wrapper" *ngFor="let video of buildVideos(object.videos)">
43 <my-video-miniature [video]="video" [fitWidth]="true" [user]="userMiniature" [displayVideoActions]="true"> 43 <my-video-miniature [video]="video" [user]="userMiniature" [displayVideoActions]="true">
44 </my-video-miniature> 44 </my-video-miniature>
45 </div> 45 </div>
46 </div> 46 </div>
diff --git a/client/src/app/+videos/video-list/overview/video-overview.component.scss b/client/src/app/+videos/video-list/overview/video-overview.component.scss
index c1d10188a..ec73c628c 100644
--- a/client/src/app/+videos/video-list/overview/video-overview.component.scss
+++ b/client/src/app/+videos/video-list/overview/video-overview.component.scss
@@ -8,9 +8,84 @@
8} 8}
9 9
10.margin-content { 10.margin-content {
11 @include fluid-videos-miniature-layout; 11 @include grid-videos-miniature-layout;
12} 12}
13 13
14.section { 14.section {
15 @include miniature-rows; 15 &:first-child {
16 padding-top: 30px;
17
18 .section-title {
19 border-top: none !important;
20 }
21 }
22
23 .section-title {
24 font-size: 24px;
25 font-weight: $font-semibold;
26 padding-top: 15px;
27 margin-bottom: 15px;
28 display: flex;
29 justify-content: space-between;
30
31 &:not(h2) {
32 border-top: 1px solid $separator-border-color;
33 }
34
35 a {
36 &:hover, &:focus:not(.focus-visible), &:active {
37 text-decoration: none;
38 outline: none;
39 }
40
41 color: pvar(--mainForegroundColor);
42 }
43 }
44
45 &.channel {
46 .section-title {
47 a {
48 display: flex;
49 width: fit-content;
50 align-items: center;
51
52 img {
53 @include channel-avatar(28px);
54
55 margin-right: 8px;
56 }
57 }
58
59 .followers {
60 color: pvar(--greyForegroundColor);
61 font-weight: normal;
62 font-size: 14px;
63 margin-left: 10px;
64 position: relative;
65 top: 2px;
66 }
67 }
68 }
69
70 .show-more {
71 position: relative;
72 top: -5px;
73 display: inline-block;
74 font-size: 16px;
75 text-transform: uppercase;
76 color: pvar(--greyForegroundColor);
77 margin-bottom: 10px;
78 font-weight: $font-semibold;
79 text-decoration: none;
80 }
81
82 @media screen and (max-width: $mobile-view) {
83 max-height: initial;
84 overflow: initial;
85
86 .section-title {
87 font-size: 17px;
88 margin-left: 10px;
89 }
90 }
16} 91}
diff --git a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
index e352a2b2c..6aabb93a5 100644
--- a/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
+++ b/client/src/app/+videos/video-list/video-user-subscriptions.component.ts
@@ -7,7 +7,7 @@ import { HooksService } from '@app/core/plugins/hooks.service'
7import { immutableAssign } from '@app/helpers' 7import { immutableAssign } from '@app/helpers'
8import { VideoService } from '@app/shared/shared-main' 8import { VideoService } from '@app/shared/shared-main'
9import { UserSubscriptionService } from '@app/shared/shared-user-subscription' 9import { UserSubscriptionService } from '@app/shared/shared-user-subscription'
10import { AbstractVideoList, OwnerDisplayType } from '@app/shared/shared-video-miniature' 10import { AbstractVideoList } from '@app/shared/shared-video-miniature'
11import { FeedFormat, VideoSortField } from '@shared/models' 11import { FeedFormat, VideoSortField } from '@shared/models'
12import { environment } from '../../../environments/environment' 12import { environment } from '../../../environments/environment'
13import { copyToClipboard } from '../../../root-helpers/utils' 13import { copyToClipboard } from '../../../root-helpers/utils'
@@ -20,7 +20,6 @@ import { copyToClipboard } from '../../../root-helpers/utils'
20export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy { 20export class VideoUserSubscriptionsComponent extends AbstractVideoList implements OnInit, OnDestroy {
21 titlePage: string 21 titlePage: string
22 sort = '-publishedAt' as VideoSortField 22 sort = '-publishedAt' as VideoSortField
23 ownerDisplayType: OwnerDisplayType = 'auto'
24 groupByDate = true 23 groupByDate = true
25 24
26 constructor ( 25 constructor (