diff options
author | Chocobozzz <me@florianbigard.com> | 2019-02-11 14:09:23 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-02-11 14:09:23 +0100 |
commit | b718fd22374d64534bcfe69932cf562894abed6a (patch) | |
tree | 311d3c67e2a4d1f33ebdd1dc163527de9d33d0f7 /client/src/app/videos/+video-watch | |
parent | adb115f5522bea4d52456a9fc5eb4140bb064476 (diff) | |
parent | 501e961199578129629cf0567033d13efced9904 (diff) | |
download | PeerTube-b718fd22374d64534bcfe69932cf562894abed6a.tar.gz PeerTube-b718fd22374d64534bcfe69932cf562894abed6a.tar.zst PeerTube-b718fd22374d64534bcfe69932cf562894abed6a.zip |
Merge branch 'develop' into pr/1285
Diffstat (limited to 'client/src/app/videos/+video-watch')
15 files changed, 135 insertions, 287 deletions
diff --git a/client/src/app/videos/+video-watch/comment/linkifier.service.ts b/client/src/app/videos/+video-watch/comment/linkifier.service.ts deleted file mode 100644 index 2529c9eaf..000000000 --- a/client/src/app/videos/+video-watch/comment/linkifier.service.ts +++ /dev/null | |||
@@ -1,115 +0,0 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' | ||
3 | // FIXME: use @types/linkify when https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29682/files is merged? | ||
4 | const linkify = require('linkifyjs') | ||
5 | const linkifyHtml = require('linkifyjs/html') | ||
6 | |||
7 | @Injectable() | ||
8 | export class LinkifierService { | ||
9 | |||
10 | static CLASSNAME = 'linkified' | ||
11 | |||
12 | private linkifyOptions = { | ||
13 | className: { | ||
14 | mention: LinkifierService.CLASSNAME + '-mention', | ||
15 | url: LinkifierService.CLASSNAME + '-url' | ||
16 | } | ||
17 | } | ||
18 | |||
19 | constructor () { | ||
20 | // Apply plugin | ||
21 | this.mentionWithDomainPlugin(linkify) | ||
22 | } | ||
23 | |||
24 | linkify (text: string) { | ||
25 | return linkifyHtml(text, this.linkifyOptions) | ||
26 | } | ||
27 | |||
28 | private mentionWithDomainPlugin (linkify: any) { | ||
29 | const TT = linkify.scanner.TOKENS // Text tokens | ||
30 | const { TOKENS: MT, State } = linkify.parser // Multi tokens, state | ||
31 | const MultiToken = MT.Base | ||
32 | const S_START = linkify.parser.start | ||
33 | |||
34 | const TT_AT = TT.AT | ||
35 | const TT_DOMAIN = TT.DOMAIN | ||
36 | const TT_LOCALHOST = TT.LOCALHOST | ||
37 | const TT_NUM = TT.NUM | ||
38 | const TT_COLON = TT.COLON | ||
39 | const TT_SLASH = TT.SLASH | ||
40 | const TT_TLD = TT.TLD | ||
41 | const TT_UNDERSCORE = TT.UNDERSCORE | ||
42 | const TT_DOT = TT.DOT | ||
43 | |||
44 | function MENTION (this: any, value: any) { | ||
45 | this.v = value | ||
46 | } | ||
47 | |||
48 | linkify.inherits(MultiToken, MENTION, { | ||
49 | type: 'mentionWithDomain', | ||
50 | isLink: true, | ||
51 | toHref () { | ||
52 | return getAbsoluteAPIUrl() + '/services/redirect/accounts/' + this.toString().substr(1) | ||
53 | } | ||
54 | }) | ||
55 | |||
56 | const S_AT = S_START.jump(TT_AT) // @ | ||
57 | const S_AT_SYMS = new State() | ||
58 | const S_MENTION = new State(MENTION) | ||
59 | const S_MENTION_DIVIDER = new State() | ||
60 | const S_MENTION_DIVIDER_SYMS = new State() | ||
61 | |||
62 | // @_, | ||
63 | S_AT.on(TT_UNDERSCORE, S_AT_SYMS) | ||
64 | |||
65 | // @_* | ||
66 | S_AT_SYMS | ||
67 | .on(TT_UNDERSCORE, S_AT_SYMS) | ||
68 | .on(TT_DOT, S_AT_SYMS) | ||
69 | |||
70 | // Valid mention (not made up entirely of symbols) | ||
71 | S_AT | ||
72 | .on(TT_DOMAIN, S_MENTION) | ||
73 | .on(TT_LOCALHOST, S_MENTION) | ||
74 | .on(TT_TLD, S_MENTION) | ||
75 | .on(TT_NUM, S_MENTION) | ||
76 | |||
77 | S_AT_SYMS | ||
78 | .on(TT_DOMAIN, S_MENTION) | ||
79 | .on(TT_LOCALHOST, S_MENTION) | ||
80 | .on(TT_TLD, S_MENTION) | ||
81 | .on(TT_NUM, S_MENTION) | ||
82 | |||
83 | // More valid mentions | ||
84 | S_MENTION | ||
85 | .on(TT_DOMAIN, S_MENTION) | ||
86 | .on(TT_LOCALHOST, S_MENTION) | ||
87 | .on(TT_TLD, S_MENTION) | ||
88 | .on(TT_COLON, S_MENTION) | ||
89 | .on(TT_NUM, S_MENTION) | ||
90 | .on(TT_UNDERSCORE, S_MENTION) | ||
91 | |||
92 | // Mention with a divider | ||
93 | S_MENTION | ||
94 | .on(TT_AT, S_MENTION_DIVIDER) | ||
95 | .on(TT_SLASH, S_MENTION_DIVIDER) | ||
96 | .on(TT_DOT, S_MENTION_DIVIDER) | ||
97 | |||
98 | // Mention _ trailing stash plus syms | ||
99 | S_MENTION_DIVIDER.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) | ||
100 | S_MENTION_DIVIDER_SYMS.on(TT_UNDERSCORE, S_MENTION_DIVIDER_SYMS) | ||
101 | |||
102 | // Once we get a word token, mentions can start up again | ||
103 | S_MENTION_DIVIDER | ||
104 | .on(TT_DOMAIN, S_MENTION) | ||
105 | .on(TT_LOCALHOST, S_MENTION) | ||
106 | .on(TT_TLD, S_MENTION) | ||
107 | .on(TT_NUM, S_MENTION) | ||
108 | |||
109 | S_MENTION_DIVIDER_SYMS | ||
110 | .on(TT_DOMAIN, S_MENTION) | ||
111 | .on(TT_LOCALHOST, S_MENTION) | ||
112 | .on(TT_TLD, S_MENTION) | ||
113 | .on(TT_NUM, S_MENTION) | ||
114 | } | ||
115 | } | ||
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.scss b/client/src/app/videos/+video-watch/comment/video-comment.component.scss index 84da5727e..731ecbf8f 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment.component.scss +++ b/client/src/app/videos/+video-watch/comment/video-comment.component.scss | |||
@@ -41,7 +41,7 @@ | |||
41 | } | 41 | } |
42 | 42 | ||
43 | .comment-date { | 43 | .comment-date { |
44 | color: #585858; | 44 | color: $grey-foreground-color; |
45 | margin-left: 10px; | 45 | margin-left: 10px; |
46 | } | 46 | } |
47 | } | 47 | } |
@@ -69,7 +69,7 @@ | |||
69 | 69 | ||
70 | .comment-action-reply, | 70 | .comment-action-reply, |
71 | .comment-action-delete { | 71 | .comment-action-delete { |
72 | color: #585858; | 72 | color: $grey-foreground-color; |
73 | cursor: pointer; | 73 | cursor: pointer; |
74 | margin-right: 10px; | 74 | margin-right: 10px; |
75 | 75 | ||
@@ -108,4 +108,4 @@ | |||
108 | .root-comment { | 108 | .root-comment { |
109 | font-size: 14px; | 109 | font-size: 14px; |
110 | } | 110 | } |
111 | } \ No newline at end of file | 111 | } |
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.component.ts b/client/src/app/videos/+video-watch/comment/video-comment.component.ts index 00f0460a1..aba7f9d1c 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment.component.ts +++ b/client/src/app/videos/+video-watch/comment/video-comment.component.ts | |||
@@ -1,11 +1,10 @@ | |||
1 | import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core' | 1 | import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core' |
2 | import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service' | ||
3 | import * as sanitizeHtml from 'sanitize-html' | ||
4 | import { UserRight } from '../../../../../../shared/models/users' | 2 | import { UserRight } from '../../../../../../shared/models/users' |
5 | import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' | 3 | import { VideoCommentThreadTree } from '../../../../../../shared/models/videos/video-comment.model' |
6 | import { AuthService } from '../../../core/auth' | 4 | import { AuthService } from '../../../core/auth' |
7 | import { Video } from '../../../shared/video/video.model' | 5 | import { Video } from '../../../shared/video/video.model' |
8 | import { VideoComment } from './video-comment.model' | 6 | import { VideoComment } from './video-comment.model' |
7 | import { HtmlRendererService } from '@app/shared/renderer' | ||
9 | 8 | ||
10 | @Component({ | 9 | @Component({ |
11 | selector: 'my-video-comment', | 10 | selector: 'my-video-comment', |
@@ -29,7 +28,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { | |||
29 | newParentComments: VideoComment[] = [] | 28 | newParentComments: VideoComment[] = [] |
30 | 29 | ||
31 | constructor ( | 30 | constructor ( |
32 | private linkifierService: LinkifierService, | 31 | private htmlRenderer: HtmlRendererService, |
33 | private authService: AuthService | 32 | private authService: AuthService |
34 | ) {} | 33 | ) {} |
35 | 34 | ||
@@ -87,27 +86,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { | |||
87 | } | 86 | } |
88 | 87 | ||
89 | private init () { | 88 | private init () { |
90 | // Convert possible markdown to html | 89 | this.sanitizedCommentHTML = this.htmlRenderer.toSafeHtml(this.comment.text) |
91 | const html = this.linkifierService.linkify(this.comment.text) | ||
92 | |||
93 | this.sanitizedCommentHTML = sanitizeHtml(html, { | ||
94 | allowedTags: [ 'a', 'p', 'span', 'br' ], | ||
95 | allowedSchemes: [ 'http', 'https' ], | ||
96 | allowedAttributes: { | ||
97 | 'a': [ 'href', 'class', 'target' ] | ||
98 | }, | ||
99 | transformTags: { | ||
100 | a: (tagName, attribs) => { | ||
101 | return { | ||
102 | tagName, | ||
103 | attribs: Object.assign(attribs, { | ||
104 | target: '_blank', | ||
105 | rel: 'noopener noreferrer' | ||
106 | }) | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | }) | ||
111 | 90 | ||
112 | this.newParentComments = this.parentComments.concat([ this.comment ]) | 91 | this.newParentComments = this.parentComments.concat([ this.comment ]) |
113 | } | 92 | } |
diff --git a/client/src/app/videos/+video-watch/comment/video-comment.service.ts b/client/src/app/videos/+video-watch/comment/video-comment.service.ts index 921447d5b..b8e5878c5 100644 --- a/client/src/app/videos/+video-watch/comment/video-comment.service.ts +++ b/client/src/app/videos/+video-watch/comment/video-comment.service.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { catchError, map } from 'rxjs/operators' | 1 | import { catchError, map } from 'rxjs/operators' |
2 | import { HttpClient, HttpParams } from '@angular/common/http' | 2 | import { HttpClient, HttpParams } from '@angular/common/http' |
3 | import { Injectable } from '@angular/core' | 3 | import { Injectable } from '@angular/core' |
4 | import { lineFeedToHtml } from '@app/shared/misc/utils' | 4 | import { objectLineFeedToHtml } from '@app/shared/misc/utils' |
5 | import { Observable } from 'rxjs' | 5 | import { Observable } from 'rxjs' |
6 | import { ResultList, FeedFormat } from '../../../../../../shared/models' | 6 | import { ResultList, FeedFormat } from '../../../../../../shared/models' |
7 | import { | 7 | import { |
@@ -28,7 +28,7 @@ export class VideoCommentService { | |||
28 | 28 | ||
29 | addCommentThread (videoId: number | string, comment: VideoCommentCreate) { | 29 | addCommentThread (videoId: number | string, comment: VideoCommentCreate) { |
30 | const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads' | 30 | const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comment-threads' |
31 | const normalizedComment = lineFeedToHtml(comment, 'text') | 31 | const normalizedComment = objectLineFeedToHtml(comment, 'text') |
32 | 32 | ||
33 | return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) | 33 | return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) |
34 | .pipe( | 34 | .pipe( |
@@ -39,7 +39,7 @@ export class VideoCommentService { | |||
39 | 39 | ||
40 | addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) { | 40 | addCommentReply (videoId: number | string, inReplyToCommentId: number, comment: VideoCommentCreate) { |
41 | const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comments/' + inReplyToCommentId | 41 | const url = VideoCommentService.BASE_VIDEO_URL + videoId + '/comments/' + inReplyToCommentId |
42 | const normalizedComment = lineFeedToHtml(comment, 'text') | 42 | const normalizedComment = objectLineFeedToHtml(comment, 'text') |
43 | 43 | ||
44 | return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) | 44 | return this.authHttp.post<{ comment: VideoCommentServerModel }>(url, normalizedComment) |
45 | .pipe( | 45 | .pipe( |
diff --git a/client/src/app/videos/+video-watch/modal/video-blacklist.component.html b/client/src/app/videos/+video-watch/modal/video-blacklist.component.html index c436501b4..1a87bdcd4 100644 --- a/client/src/app/videos/+video-watch/modal/video-blacklist.component.html +++ b/client/src/app/videos/+video-watch/modal/video-blacklist.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <ng-template #modal> | 1 | <ng-template #modal> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Blacklist video</h4> | 3 | <h4 i18n class="modal-title">Blacklist video</h4> |
4 | <span class="close" aria-label="Close" role="button" (click)="hide()"></span> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
@@ -15,6 +15,13 @@ | |||
15 | </div> | 15 | </div> |
16 | </div> | 16 | </div> |
17 | 17 | ||
18 | <div class="form-group" *ngIf="video.isLocal"> | ||
19 | <my-peertube-checkbox | ||
20 | inputName="unfederate" formControlName="unfederate" | ||
21 | i18n-labelText labelText="Unfederate the video (ask for its deletion from the remote instances)" | ||
22 | ></my-peertube-checkbox> | ||
23 | </div> | ||
24 | |||
18 | <div class="form-group inputs"> | 25 | <div class="form-group inputs"> |
19 | <span i18n class="action-button action-button-cancel" (click)="hide()"> | 26 | <span i18n class="action-button action-button-cancel" (click)="hide()"> |
20 | Cancel | 27 | Cancel |
diff --git a/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts b/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts index 357ce39ce..50a7cadd1 100644 --- a/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-blacklist.component.ts | |||
@@ -34,9 +34,12 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | ngOnInit () { | 36 | ngOnInit () { |
37 | const defaultValues = { unfederate: 'true' } | ||
38 | |||
37 | this.buildForm({ | 39 | this.buildForm({ |
38 | reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON | 40 | reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON, |
39 | }) | 41 | unfederate: null |
42 | }, defaultValues) | ||
40 | } | 43 | } |
41 | 44 | ||
42 | show () { | 45 | show () { |
@@ -50,8 +53,9 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { | |||
50 | 53 | ||
51 | blacklist () { | 54 | blacklist () { |
52 | const reason = this.form.value[ 'reason' ] || undefined | 55 | const reason = this.form.value[ 'reason' ] || undefined |
56 | const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined | ||
53 | 57 | ||
54 | this.videoBlacklistService.blacklistVideo(this.video.id, reason) | 58 | this.videoBlacklistService.blacklistVideo(this.video.id, reason, unfederate) |
55 | .subscribe( | 59 | .subscribe( |
56 | () => { | 60 | () => { |
57 | this.notifier.success(this.i18n('Video blacklisted.')) | 61 | this.notifier.success(this.i18n('Video blacklisted.')) |
diff --git a/client/src/app/videos/+video-watch/modal/video-download.component.html b/client/src/app/videos/+video-watch/modal/video-download.component.html index f46f92a17..2bb5d6d37 100644 --- a/client/src/app/videos/+video-watch/modal/video-download.component.html +++ b/client/src/app/videos/+video-watch/modal/video-download.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <ng-template #modal let-hide="close"> | 1 | <ng-template #modal let-hide="close"> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Download video</h4> | 3 | <h4 i18n class="modal-title">Download video</h4> |
4 | <span class="close" aria-hidden="true" (click)="hide()"></span> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
diff --git a/client/src/app/videos/+video-watch/modal/video-report.component.html b/client/src/app/videos/+video-watch/modal/video-report.component.html index 733c01be0..b9434da26 100644 --- a/client/src/app/videos/+video-watch/modal/video-report.component.html +++ b/client/src/app/videos/+video-watch/modal/video-report.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <ng-template #modal> | 1 | <ng-template #modal> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Report video</h4> | 3 | <h4 i18n class="modal-title">Report video</h4> |
4 | <span class="close" aria-label="Close" role="button" (click)="hide()"></span> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.html b/client/src/app/videos/+video-watch/modal/video-share.component.html index 301f67f2d..9f3c37fe8 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.html +++ b/client/src/app/videos/+video-watch/modal/video-share.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <ng-template #modal let-hide="close"> | 1 | <ng-template #modal let-hide="close"> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Share</h4> | 3 | <h4 i18n class="modal-title">Share</h4> |
4 | <span class="close" aria-hidden="true" (click)="hide()"></span> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
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 index 00c304709..2a05224a8 100644 --- a/client/src/app/videos/+video-watch/modal/video-support.component.html +++ b/client/src/app/videos/+video-watch/modal/video-support.component.html | |||
@@ -1,7 +1,7 @@ | |||
1 | <ng-template #modal let-hide="close"> | 1 | <ng-template #modal let-hide="close"> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Support</h4> | 3 | <h4 i18n class="modal-title">Support</h4> |
4 | <span class="close" aria-label="Close" role="button" (click)="hide()"></span> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body" [innerHTML]="videoHTMLSupport"></div> | 7 | <div class="modal-body" [innerHTML]="videoHTMLSupport"></div> |
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 index 154002120..deb8fbc67 100644 --- a/client/src/app/videos/+video-watch/modal/video-support.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-support.component.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core' | 1 | import { Component, Input, ViewChild } from '@angular/core' |
2 | import { MarkdownService } from '@app/videos/shared' | ||
3 | |||
4 | import { VideoDetails } from '../../../shared/video/video-details.model' | 2 | import { VideoDetails } from '../../../shared/video/video-details.model' |
5 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
4 | import { MarkdownService } from '@app/shared/renderer' | ||
6 | 5 | ||
7 | @Component({ | 6 | @Component({ |
8 | selector: 'my-video-support', | 7 | selector: 'my-video-support', |
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 2cdbc7aa6..6e18ab6a6 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -52,55 +52,57 @@ | |||
52 | <div | 52 | <div |
53 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()" | 53 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'like' }" (click)="setLike()" |
54 | class="action-button action-button-like" role="button" [attr.aria-pressed]="userRating === 'like'" | 54 | class="action-button action-button-like" role="button" [attr.aria-pressed]="userRating === 'like'" |
55 | i18n-title title="Like this video" | ||
55 | > | 56 | > |
56 | <span class="icon icon-like" i18n-title title="Like this video" ></span> | 57 | <my-global-icon iconName="like"></my-global-icon> |
57 | </div> | 58 | </div> |
58 | 59 | ||
59 | <div | 60 | <div |
60 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()" | 61 | *ngIf="isUserLoggedIn()" [ngClass]="{ 'activated': userRating === 'dislike' }" (click)="setDislike()" |
61 | class="action-button action-button-dislike" role="button" [attr.aria-pressed]="userRating === 'dislike'" | 62 | class="action-button action-button-dislike" role="button" [attr.aria-pressed]="userRating === 'dislike'" |
63 | i18n-title title="Dislike this video" | ||
62 | > | 64 | > |
63 | <span class="icon icon-dislike" i18n-title title="Dislike this video"></span> | 65 | <my-global-icon iconName="dislike"></my-global-icon> |
64 | </div> | 66 | </div> |
65 | 67 | ||
66 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button action-button-support"> | 68 | <div *ngIf="video.support" (click)="showSupportModal()" class="action-button action-button-support"> |
67 | <span class="icon icon-support"></span> | 69 | <my-global-icon iconName="heart"></my-global-icon> |
68 | <span class="icon-text" i18n>Support</span> | 70 | <span class="icon-text" i18n>Support</span> |
69 | </div> | 71 | </div> |
70 | 72 | ||
71 | <div (click)="showShareModal()" class="action-button action-button-share" role="button"> | 73 | <div (click)="showShareModal()" class="action-button action-button-share" role="button"> |
72 | <span class="icon icon-share"></span> | 74 | <my-global-icon iconName="share"></my-global-icon> |
73 | <span class="icon-text" i18n>Share</span> | 75 | <span class="icon-text" i18n>Share</span> |
74 | </div> | 76 | </div> |
75 | 77 | ||
76 | <div class="action-more" ngbDropdown placement="top" role="button"> | 78 | <div class="action-more" ngbDropdown placement="top" role="button"> |
77 | <div class="action-button" ngbDropdownToggle role="button"> | 79 | <div class="action-button" ngbDropdownToggle role="button"> |
78 | <span class="icon icon-more"></span> | 80 | <my-global-icon class="more-icon" iconName="more"></my-global-icon> |
79 | </div> | 81 | </div> |
80 | 82 | ||
81 | <div ngbDropdownMenu> | 83 | <div ngbDropdownMenu> |
82 | <a class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)"> | 84 | <a *ngIf="isVideoDownloadable()" class="dropdown-item" i18n-title title="Download the video" href="#" (click)="showDownloadModal($event)"> |
83 | <span class="icon icon-download"></span> <ng-container i18n>Download</ng-container> | 85 | <my-global-icon iconName="download"></my-global-icon> <ng-container i18n>Download</ng-container> |
84 | </a> | 86 | </a> |
85 | 87 | ||
86 | <a *ngIf="isUserLoggedIn()" class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)"> | 88 | <a *ngIf="isUserLoggedIn()" class="dropdown-item" i18n-title title="Report this video" href="#" (click)="showReportModal($event)"> |
87 | <span class="icon icon-alert"></span> <ng-container i18n>Report</ng-container> | 89 | <my-global-icon iconName="alert"></my-global-icon> <ng-container i18n>Report</ng-container> |
88 | </a> | 90 | </a> |
89 | 91 | ||
90 | <a *ngIf="isVideoUpdatable()" class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]"> | 92 | <a *ngIf="isVideoUpdatable()" class="dropdown-item" i18n-title title="Update this video" href="#" [routerLink]="[ '/videos/update', video.uuid ]"> |
91 | <span class="icon icon-edit"></span> <ng-container i18n>Update</ng-container> | 93 | <my-global-icon iconName="edit"></my-global-icon> <ng-container i18n>Update</ng-container> |
92 | </a> | 94 | </a> |
93 | 95 | ||
94 | <a *ngIf="isVideoBlacklistable()" class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="showBlacklistModal($event)"> | 96 | <a *ngIf="isVideoBlacklistable()" class="dropdown-item" i18n-title title="Blacklist this video" href="#" (click)="showBlacklistModal($event)"> |
95 | <span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container> | 97 | <my-global-icon iconName="no"></my-global-icon> <ng-container i18n>Blacklist</ng-container> |
96 | </a> | 98 | </a> |
97 | 99 | ||
98 | <a *ngIf="isVideoUnblacklistable()" class="dropdown-item" i18n-title title="Unblacklist this video" href="#" (click)="unblacklistVideo($event)"> | 100 | <a *ngIf="isVideoUnblacklistable()" class="dropdown-item" i18n-title title="Unblacklist this video" href="#" (click)="unblacklistVideo($event)"> |
99 | <span class="icon icon-unblacklist"></span> <ng-container i18n>Unblacklist</ng-container> | 101 | <my-global-icon iconName="undo"></my-global-icon> <ng-container i18n>Unblacklist</ng-container> |
100 | </a> | 102 | </a> |
101 | 103 | ||
102 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> | 104 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> |
103 | <span class="icon icon-delete"></span> <ng-container i18n>Delete</ng-container> | 105 | <my-global-icon iconName="delete"></my-global-icon> <ng-container i18n>Delete</ng-container> |
104 | </a> | 106 | </a> |
105 | </div> | 107 | </div> |
106 | </div> | 108 | </div> |
@@ -159,12 +161,9 @@ | |||
159 | <span class="video-attribute-value">{{ video.privacy.label }}</span> | 161 | <span class="video-attribute-value">{{ video.privacy.label }}</span> |
160 | </div> | 162 | </div> |
161 | 163 | ||
162 | <div class="video-attribute"> | 164 | <div *ngIf="!!video.originallyPublishedAt" class="video-attribute"> |
163 | <span i18n class="video-attribute-label">Originally published on</span> | 165 | <span i18n class="video-attribute-label">Originally published</span> |
164 | <span *ngIf="!video.originallyPublishedAt" class="video-attribute-value">Unknown</span> | 166 | <span class="video-attribute-value">{{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }}</span> |
165 | <span *ngIf="video.originallyPublishedAt" class="video-attribute-value"> | ||
166 | {{ video.originallyPublishedAt | date: 'dd MMMM yyyy' }} | ||
167 | </span> | ||
168 | </div> | 167 | </div> |
169 | 168 | ||
170 | <div class="video-attribute"> | 169 | <div class="video-attribute"> |
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 f96ce8b8f..cfe3533b6 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss | |||
@@ -183,6 +183,8 @@ $other-videos-width: 260px; | |||
183 | .action-button { | 183 | .action-button { |
184 | @include peertube-button; | 184 | @include peertube-button; |
185 | @include grey-button; | 185 | @include grey-button; |
186 | @include button-with-icon(21px, 0, -1px); | ||
187 | @include apply-svg-color($grey-foreground-color); | ||
186 | 188 | ||
187 | font-size: 15px; | 189 | font-size: 15px; |
188 | font-weight: $font-semibold; | 190 | font-weight: $font-semibold; |
@@ -194,53 +196,25 @@ $other-videos-width: 260px; | |||
194 | display: none; | 196 | display: none; |
195 | } | 197 | } |
196 | 198 | ||
197 | .icon { | ||
198 | @include icon(21px); | ||
199 | |||
200 | position: relative; | ||
201 | top: -2px; | ||
202 | |||
203 | &.icon-like { | ||
204 | background-image: url('../../../assets/images/video/like-grey.svg'); | ||
205 | } | ||
206 | |||
207 | &.icon-dislike { | ||
208 | background-image: url('../../../assets/images/video/dislike-grey.svg'); | ||
209 | } | ||
210 | |||
211 | &.icon-support { | ||
212 | background-image: url('../../../assets/images/video/heart.svg'); | ||
213 | } | ||
214 | |||
215 | &.icon-share { | ||
216 | background-image: url('../../../assets/images/video/share.svg'); | ||
217 | } | ||
218 | |||
219 | &.icon-more { | ||
220 | background-image: url('../../../assets/images/video/more.svg'); | ||
221 | top: -1px; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | .icon-text { | ||
226 | margin-left: 3px; | ||
227 | } | ||
228 | |||
229 | &.action-button-like.activated { | 199 | &.action-button-like.activated { |
230 | background-color: $green; | 200 | background-color: $green; |
231 | 201 | ||
232 | .icon-like { | 202 | my-global-icon { |
233 | background-image: url('../../../assets/images/video/like-white.svg'); | 203 | @include apply-svg-color(#fff); |
234 | } | 204 | } |
235 | } | 205 | } |
236 | 206 | ||
237 | &.action-button-dislike.activated { | 207 | &.action-button-dislike.activated { |
238 | background-color: $red; | 208 | background-color: $red; |
239 | 209 | ||
240 | .icon-dislike { | 210 | my-global-icon { |
241 | background-image: url('../../../assets/images/video/dislike-white.svg'); | 211 | @include apply-svg-color(#fff); |
242 | } | 212 | } |
243 | } | 213 | } |
214 | |||
215 | .icon-text { | ||
216 | margin-left: 3px; | ||
217 | } | ||
244 | } | 218 | } |
245 | 219 | ||
246 | .action-more { | 220 | .action-more { |
@@ -249,36 +223,12 @@ $other-videos-width: 260px; | |||
249 | .dropdown-menu .dropdown-item { | 223 | .dropdown-menu .dropdown-item { |
250 | padding: 6px 24px; | 224 | padding: 6px 24px; |
251 | 225 | ||
252 | .icon { | 226 | my-global-icon { |
253 | @include icon(24px); | 227 | width: 24px; |
254 | 228 | ||
255 | margin-right: 10px; | 229 | margin-right: 10px; |
256 | position: relative; | 230 | position: relative; |
257 | top: -1px; | 231 | top: -2px; |
258 | |||
259 | &.icon-download { | ||
260 | background-image: url('../../../assets/images/video/download-black.svg'); | ||
261 | } | ||
262 | |||
263 | &.icon-edit { | ||
264 | background-image: url('../../../assets/images/global/edit-black.svg'); | ||
265 | } | ||
266 | |||
267 | &.icon-alert { | ||
268 | background-image: url('../../../assets/images/video/alert.svg'); | ||
269 | } | ||
270 | |||
271 | &.icon-blacklist { | ||
272 | background-image: url('../../../assets/images/video/blacklist.svg'); | ||
273 | } | ||
274 | |||
275 | &.icon-unblacklist { | ||
276 | background-image: url('../../../assets/images/global/undo.svg'); | ||
277 | } | ||
278 | |||
279 | &.icon-delete { | ||
280 | background-image: url('../../../assets/images/global/delete-black.svg'); | ||
281 | } | ||
282 | } | 232 | } |
283 | } | 233 | } |
284 | } | 234 | } |
@@ -320,7 +270,7 @@ $other-videos-width: 260px; | |||
320 | .video-info-description-more { | 270 | .video-info-description-more { |
321 | cursor: pointer; | 271 | cursor: pointer; |
322 | font-weight: $font-semibold; | 272 | font-weight: $font-semibold; |
323 | color: #585858; | 273 | color: $grey-foreground-color; |
324 | font-size: 14px; | 274 | font-size: 14px; |
325 | 275 | ||
326 | .glyphicon { | 276 | .glyphicon { |
@@ -339,7 +289,7 @@ $other-videos-width: 260px; | |||
339 | min-width: 142px; | 289 | min-width: 142px; |
340 | padding-right: 5px; | 290 | padding-right: 5px; |
341 | display: inline-block; | 291 | display: inline-block; |
342 | color: #585858; | 292 | color: $grey-foreground-color; |
343 | font-weight: $font-bold; | 293 | font-weight: $font-bold; |
344 | } | 294 | } |
345 | 295 | ||
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 67c5254b3..4dbfa41e5 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -7,29 +7,27 @@ import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-supp | |||
7 | import { MetaService } from '@ngx-meta/core' | 7 | import { MetaService } from '@ngx-meta/core' |
8 | import { Notifier, ServerService } from '@app/core' | 8 | import { Notifier, ServerService } from '@app/core' |
9 | import { forkJoin, Subscription } from 'rxjs' | 9 | import { forkJoin, Subscription } from 'rxjs' |
10 | // FIXME: something weird with our path definition in tsconfig and typings | ||
11 | // @ts-ignore | ||
12 | import videojs from 'video.js' | ||
13 | import 'videojs-hotkeys' | ||
14 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' | 10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' |
15 | import * as WebTorrent from 'webtorrent' | ||
16 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' | 11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' |
17 | import '../../../assets/player/peertube-videojs-plugin' | ||
18 | import { AuthService, ConfirmService } from '../../core' | 12 | import { AuthService, ConfirmService } from '../../core' |
19 | import { RestExtractor, VideoBlacklistService } from '../../shared' | 13 | import { RestExtractor, VideoBlacklistService } from '../../shared' |
20 | import { VideoDetails } from '../../shared/video/video-details.model' | 14 | import { VideoDetails } from '../../shared/video/video-details.model' |
21 | import { VideoService } from '../../shared/video/video.service' | 15 | import { VideoService } from '../../shared/video/video.service' |
22 | import { MarkdownService } from '../shared' | ||
23 | import { VideoDownloadComponent } from './modal/video-download.component' | 16 | import { VideoDownloadComponent } from './modal/video-download.component' |
24 | import { VideoReportComponent } from './modal/video-report.component' | 17 | import { VideoReportComponent } from './modal/video-report.component' |
25 | import { VideoShareComponent } from './modal/video-share.component' | 18 | import { VideoShareComponent } from './modal/video-share.component' |
26 | import { VideoBlacklistComponent } from './modal/video-blacklist.component' | 19 | import { VideoBlacklistComponent } from './modal/video-blacklist.component' |
27 | import { SubscribeButtonComponent } from '@app/shared/user-subscription/subscribe-button.component' | 20 | import { SubscribeButtonComponent } from '@app/shared/user-subscription/subscribe-button.component' |
28 | import { addContextMenu, getVideojsOptions, loadLocaleInVideoJS } from '../../../assets/player/peertube-player' | ||
29 | import { I18n } from '@ngx-translate/i18n-polyfill' | 21 | import { I18n } from '@ngx-translate/i18n-polyfill' |
30 | import { environment } from '../../../environments/environment' | 22 | import { environment } from '../../../environments/environment' |
31 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' | ||
32 | import { VideoCaptionService } from '@app/shared/video-caption' | 23 | import { VideoCaptionService } from '@app/shared/video-caption' |
24 | import { MarkdownService } from '@app/shared/renderer' | ||
25 | import { | ||
26 | P2PMediaLoaderOptions, | ||
27 | PeertubePlayerManager, | ||
28 | PeertubePlayerManagerOptions, | ||
29 | PlayerMode | ||
30 | } from '../../../assets/player/peertube-player-manager' | ||
33 | 31 | ||
34 | @Component({ | 32 | @Component({ |
35 | selector: 'my-video-watch', | 33 | selector: 'my-video-watch', |
@@ -46,7 +44,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
46 | @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent | 44 | @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent |
47 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent | 45 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent |
48 | 46 | ||
49 | player: videojs.Player | 47 | player: any |
50 | playerElement: HTMLVideoElement | 48 | playerElement: HTMLVideoElement |
51 | userRating: UserVideoRateType = null | 49 | userRating: UserVideoRateType = null |
52 | video: VideoDetails = null | 50 | video: VideoDetails = null |
@@ -61,7 +59,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
61 | remoteServerDown = false | 59 | remoteServerDown = false |
62 | hotkeys: Hotkey[] | 60 | hotkeys: Hotkey[] |
63 | 61 | ||
64 | private videojsLocaleLoaded = false | ||
65 | private paramsSub: Subscription | 62 | private paramsSub: Subscription |
66 | 63 | ||
67 | constructor ( | 64 | constructor ( |
@@ -92,7 +89,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
92 | 89 | ||
93 | ngOnInit () { | 90 | ngOnInit () { |
94 | if ( | 91 | if ( |
95 | WebTorrent.WEBRTC_SUPPORT === false || | 92 | !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false || |
96 | peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' | 93 | peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' |
97 | ) { | 94 | ) { |
98 | this.hasAlreadyAcceptedPrivacyConcern = true | 95 | this.hasAlreadyAcceptedPrivacyConcern = true |
@@ -118,8 +115,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
118 | .subscribe(([ video, captionsResult ]) => { | 115 | .subscribe(([ video, captionsResult ]) => { |
119 | const startTime = this.route.snapshot.queryParams.start | 116 | const startTime = this.route.snapshot.queryParams.start |
120 | const subtitle = this.route.snapshot.queryParams.subtitle | 117 | const subtitle = this.route.snapshot.queryParams.subtitle |
118 | const playerMode = this.route.snapshot.queryParams.mode | ||
121 | 119 | ||
122 | this.onVideoFetched(video, captionsResult.data, { startTime, subtitle }) | 120 | this.onVideoFetched(video, captionsResult.data, { startTime, subtitle, playerMode }) |
123 | .catch(err => this.handleError(err)) | 121 | .catch(err => this.handleError(err)) |
124 | }) | 122 | }) |
125 | }) | 123 | }) |
@@ -310,6 +308,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
310 | return this.video && this.video.state.id === VideoState.TO_TRANSCODE | 308 | return this.video && this.video.state.id === VideoState.TO_TRANSCODE |
311 | } | 309 | } |
312 | 310 | ||
311 | isVideoDownloadable () { | ||
312 | return this.video && this.video.downloadEnabled | ||
313 | } | ||
314 | |||
313 | isVideoToImport () { | 315 | isVideoToImport () { |
314 | return this.video && this.video.state.id === VideoState.TO_IMPORT | 316 | return this.video && this.video.state.id === VideoState.TO_IMPORT |
315 | } | 317 | } |
@@ -366,7 +368,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
366 | ) | 368 | ) |
367 | } | 369 | } |
368 | 370 | ||
369 | private async onVideoFetched (video: VideoDetails, videoCaptions: VideoCaption[], urlOptions: { startTime: number, subtitle: string }) { | 371 | private async onVideoFetched ( |
372 | video: VideoDetails, | ||
373 | videoCaptions: VideoCaption[], | ||
374 | urlOptions: { startTime?: number, subtitle?: string, playerMode?: string } | ||
375 | ) { | ||
370 | this.video = video | 376 | this.video = video |
371 | 377 | ||
372 | // Re init attributes | 378 | // Re init attributes |
@@ -402,41 +408,64 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
402 | src: environment.apiUrl + c.captionPath | 408 | src: environment.apiUrl + c.captionPath |
403 | })) | 409 | })) |
404 | 410 | ||
405 | const videojsOptions = getVideojsOptions({ | 411 | const options: PeertubePlayerManagerOptions = { |
406 | autoplay: this.isAutoplay(), | 412 | common: { |
407 | inactivityTimeout: 2500, | 413 | autoplay: this.isAutoplay(), |
408 | videoFiles: this.video.files, | 414 | |
409 | videoCaptions: playerCaptions, | 415 | playerElement: this.playerElement, |
410 | playerElement: this.playerElement, | 416 | onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element, |
411 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, | 417 | |
412 | videoDuration: this.video.duration, | 418 | videoDuration: this.video.duration, |
413 | enableHotkeys: true, | 419 | enableHotkeys: true, |
414 | peertubeLink: false, | 420 | inactivityTimeout: 2500, |
415 | poster: this.video.previewUrl, | 421 | poster: this.video.previewUrl, |
416 | startTime, | 422 | startTime, |
417 | subtitle: urlOptions.subtitle, | 423 | |
418 | theaterMode: true, | 424 | theaterMode: true, |
419 | language: this.localeId, | 425 | captions: videoCaptions.length !== 0, |
420 | 426 | peertubeLink: false, | |
421 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | 427 | |
422 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | 428 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, |
423 | authorizationHeader: this.authService.getRequestHeaderValue() | 429 | embedUrl: this.video.embedUrl, |
424 | } : undefined | 430 | |
425 | }) | 431 | language: this.localeId, |
432 | |||
433 | subtitle: urlOptions.subtitle, | ||
434 | |||
435 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | ||
436 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | ||
437 | authorizationHeader: this.authService.getRequestHeaderValue() | ||
438 | } : undefined, | ||
426 | 439 | ||
427 | if (this.videojsLocaleLoaded === false) { | 440 | serverUrl: environment.apiUrl, |
428 | await loadLocaleInVideoJS(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId) | 441 | |
429 | this.videojsLocaleLoaded = true | 442 | videoCaptions: playerCaptions |
443 | }, | ||
444 | |||
445 | webtorrent: { | ||
446 | videoFiles: this.video.files | ||
447 | } | ||
430 | } | 448 | } |
431 | 449 | ||
432 | const self = this | 450 | const mode: PlayerMode = urlOptions.playerMode === 'p2p-media-loader' ? 'p2p-media-loader' : 'webtorrent' |
433 | this.zone.runOutsideAngular(async () => { | 451 | |
434 | videojs(this.playerElement, videojsOptions, function (this: videojs.Player) { | 452 | if (mode === 'p2p-media-loader') { |
435 | self.player = this | 453 | const hlsPlaylist = this.video.getHlsPlaylist() |
436 | this.on('customError', ({ err }: { err: any }) => self.handleError(err)) | ||
437 | 454 | ||
438 | addContextMenu(self.player, self.video.embedUrl) | 455 | const p2pMediaLoader = { |
439 | }) | 456 | playlistUrl: hlsPlaylist.playlistUrl, |
457 | segmentsSha256Url: hlsPlaylist.segmentsSha256Url, | ||
458 | redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl), | ||
459 | trackerAnnounce: this.video.trackerUrls, | ||
460 | videoFiles: this.video.files | ||
461 | } as P2PMediaLoaderOptions | ||
462 | |||
463 | Object.assign(options, { p2pMediaLoader }) | ||
464 | } | ||
465 | |||
466 | this.zone.runOutsideAngular(async () => { | ||
467 | this.player = await PeertubePlayerManager.initialize(mode, options) | ||
468 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | ||
440 | }) | 469 | }) |
441 | 470 | ||
442 | this.setVideoDescriptionHTML() | 471 | this.setVideoDescriptionHTML() |
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 54a12c126..2f448db78 100644 --- a/client/src/app/videos/+video-watch/video-watch.module.ts +++ b/client/src/app/videos/+video-watch/video-watch.module.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | import { NgModule } from '@angular/core' | 1 | import { NgModule } from '@angular/core' |
2 | import { LinkifierService } from '@app/videos/+video-watch/comment/linkifier.service' | ||
3 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' | 2 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' |
4 | import { ClipboardModule } from 'ngx-clipboard' | 3 | import { ClipboardModule } from 'ngx-clipboard' |
5 | import { SharedModule } from '../../shared' | 4 | import { SharedModule } from '../../shared' |
6 | import { MarkdownService } from '../shared' | ||
7 | import { VideoCommentAddComponent } from './comment/video-comment-add.component' | 5 | import { VideoCommentAddComponent } from './comment/video-comment-add.component' |
8 | import { VideoCommentComponent } from './comment/video-comment.component' | 6 | import { VideoCommentComponent } from './comment/video-comment.component' |
9 | import { VideoCommentService } from './comment/video-comment.service' | 7 | import { VideoCommentService } from './comment/video-comment.service' |
@@ -46,8 +44,6 @@ import { RecommendationsModule } from '@app/videos/recommendations/recommendatio | |||
46 | ], | 44 | ], |
47 | 45 | ||
48 | providers: [ | 46 | providers: [ |
49 | MarkdownService, | ||
50 | LinkifierService, | ||
51 | VideoCommentService | 47 | VideoCommentService |
52 | ] | 48 | ] |
53 | }) | 49 | }) |