diff options
-rw-r--r-- | client/package.json | 1 | ||||
-rw-r--r-- | client/src/assets/player/dock/peertube-dock-component.ts | 65 | ||||
-rw-r--r-- | client/src/assets/player/dock/peertube-dock-plugin.ts | 25 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-manager.ts | 1 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-typings.ts | 3 | ||||
-rw-r--r-- | client/src/sass/player/dock.scss | 73 | ||||
-rw-r--r-- | client/src/standalone/videos/embed.scss | 1 | ||||
-rw-r--r-- | client/src/standalone/videos/embed.ts | 15 | ||||
-rw-r--r-- | client/yarn.lock | 10 |
9 files changed, 169 insertions, 25 deletions
diff --git a/client/package.json b/client/package.json index 690e3b982..9e2657a94 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -130,7 +130,6 @@ | |||
130 | "typescript": "~4.4.4", | 130 | "typescript": "~4.4.4", |
131 | "url": "^0.11.0", | 131 | "url": "^0.11.0", |
132 | "video.js": "^7", | 132 | "video.js": "^7", |
133 | "videojs-dock": "^3.0.0", | ||
134 | "videostream": "~3.2.1", | 133 | "videostream": "~3.2.1", |
135 | "wdio-chromedriver-service": "^7.2.0", | 134 | "wdio-chromedriver-service": "^7.2.0", |
136 | "wdio-geckodriver-service": "^2.0.3", | 135 | "wdio-geckodriver-service": "^2.0.3", |
diff --git a/client/src/assets/player/dock/peertube-dock-component.ts b/client/src/assets/player/dock/peertube-dock-component.ts new file mode 100644 index 000000000..183c7a00f --- /dev/null +++ b/client/src/assets/player/dock/peertube-dock-component.ts | |||
@@ -0,0 +1,65 @@ | |||
1 | import videojs from 'video.js' | ||
2 | |||
3 | const Component = videojs.getComponent('Component') | ||
4 | |||
5 | export type PeerTubeDockComponentOptions = { | ||
6 | title?: string | ||
7 | description?: string | ||
8 | avatarUrl?: string | ||
9 | } | ||
10 | |||
11 | class PeerTubeDockComponent extends Component { | ||
12 | |||
13 | createEl () { | ||
14 | const options = this.options_ as PeerTubeDockComponentOptions | ||
15 | |||
16 | const el = super.createEl('div', { | ||
17 | className: 'peertube-dock' | ||
18 | }) | ||
19 | |||
20 | if (options.avatarUrl) { | ||
21 | const avatar = videojs.dom.createEl('img', { | ||
22 | className: 'peertube-dock-avatar', | ||
23 | src: options.avatarUrl | ||
24 | }) | ||
25 | |||
26 | el.appendChild(avatar) | ||
27 | } | ||
28 | |||
29 | const elWrapperTitleDescription = super.createEl('div', { | ||
30 | className: 'peertube-dock-title-description' | ||
31 | }) | ||
32 | |||
33 | if (options.title) { | ||
34 | const title = videojs.dom.createEl('div', { | ||
35 | className: 'peertube-dock-title', | ||
36 | title: options.title, | ||
37 | innerHTML: options.title | ||
38 | }) | ||
39 | |||
40 | elWrapperTitleDescription.appendChild(title) | ||
41 | } | ||
42 | |||
43 | if (options.description) { | ||
44 | const description = videojs.dom.createEl('div', { | ||
45 | className: 'peertube-dock-description', | ||
46 | title: options.description, | ||
47 | innerHTML: options.description | ||
48 | }) | ||
49 | |||
50 | elWrapperTitleDescription.appendChild(description) | ||
51 | } | ||
52 | |||
53 | if (options.title || options.description) { | ||
54 | el.appendChild(elWrapperTitleDescription) | ||
55 | } | ||
56 | |||
57 | return el | ||
58 | } | ||
59 | } | ||
60 | |||
61 | videojs.registerComponent('PeerTubeDockComponent', PeerTubeDockComponent) | ||
62 | |||
63 | export { | ||
64 | PeerTubeDockComponent | ||
65 | } | ||
diff --git a/client/src/assets/player/dock/peertube-dock-plugin.ts b/client/src/assets/player/dock/peertube-dock-plugin.ts new file mode 100644 index 000000000..245981692 --- /dev/null +++ b/client/src/assets/player/dock/peertube-dock-plugin.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import { PeerTubeDockComponent } from './peertube-dock-component' | ||
3 | |||
4 | const Plugin = videojs.getPlugin('plugin') | ||
5 | |||
6 | export type PeerTubeDockPluginOptions = { | ||
7 | title?: string | ||
8 | description?: string | ||
9 | avatarUrl?: string | ||
10 | } | ||
11 | |||
12 | class PeerTubeDockPlugin extends Plugin { | ||
13 | constructor (player: videojs.Player, options: videojs.PlayerOptions & PeerTubeDockPluginOptions) { | ||
14 | super(player, options) | ||
15 | |||
16 | this.player.addClass('peertube-dock') | ||
17 | |||
18 | this.player.ready(() => { | ||
19 | this.player.addChild('PeerTubeDockComponent', options) as PeerTubeDockComponent | ||
20 | }) | ||
21 | } | ||
22 | } | ||
23 | |||
24 | videojs.registerPlugin('peertubeDock', PeerTubeDockPlugin) | ||
25 | export { PeerTubeDockPlugin } | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 2ef42a961..9d2b29811 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | import 'videojs-dock' | ||
2 | import '@peertube/videojs-contextmenu' | 1 | import '@peertube/videojs-contextmenu' |
3 | import './upnext/end-card' | 2 | import './upnext/end-card' |
4 | import './upnext/upnext-plugin' | 3 | import './upnext/upnext-plugin' |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index 246f0d390..09996f75d 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { HlsConfig, Level } from 'hls.js' | 1 | import { HlsConfig, Level } from 'hls.js' |
2 | import videojs from 'video.js' | 2 | import videojs from 'video.js' |
3 | import { VideoFile, VideoPlaylist, VideoPlaylistElement } from '@shared/models' | 3 | import { VideoFile, VideoPlaylist, VideoPlaylistElement } from '@shared/models' |
4 | import { PeerTubeDockPluginOptions } from './dock/peertube-dock-plugin' | ||
4 | import { Html5Hlsjs } from './p2p-media-loader/hls-plugin' | 5 | import { Html5Hlsjs } from './p2p-media-loader/hls-plugin' |
5 | import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin' | 6 | import { P2pMediaLoaderPlugin } from './p2p-media-loader/p2p-media-loader-plugin' |
6 | import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' | 7 | import { RedundancyUrlManager } from './p2p-media-loader/redundancy-url-manager' |
@@ -50,7 +51,7 @@ declare module 'video.js' { | |||
50 | tracks_: (TextTrack & { id: string, label: string, src: string })[] | 51 | tracks_: (TextTrack & { id: string, label: string, src: string })[] |
51 | } | 52 | } |
52 | 53 | ||
53 | dock (options: { title: string, description: string }): void | 54 | peertubeDock (options: PeerTubeDockPluginOptions): void |
54 | 55 | ||
55 | upnext (options: Partial<EndCardOptions>): void | 56 | upnext (options: Partial<EndCardOptions>): void |
56 | 57 | ||
diff --git a/client/src/sass/player/dock.scss b/client/src/sass/player/dock.scss index 4fa1ebd54..4939ea3e5 100644 --- a/client/src/sass/player/dock.scss +++ b/client/src/sass/player/dock.scss | |||
@@ -4,24 +4,62 @@ | |||
4 | @use './_player-variables' as *; | 4 | @use './_player-variables' as *; |
5 | 5 | ||
6 | .video-js.vjs-peertube-skin { | 6 | .video-js.vjs-peertube-skin { |
7 | .vjs-dock-text { | 7 | |
8 | .peertube-dock { | ||
9 | --avatarSize: 48px; | ||
10 | |||
8 | @include padding-right(60px); | 11 | @include padding-right(60px); |
9 | 12 | ||
13 | transition: opacity 0.1s; | ||
14 | |||
15 | display: flex; | ||
16 | align-items: center; | ||
17 | pointer-events: none; | ||
18 | position: absolute; | ||
19 | top: 0; | ||
20 | left: 0; | ||
21 | width: 100%; | ||
22 | |||
23 | font-size: 23px; | ||
10 | padding: $dock-padding; | 24 | padding: $dock-padding; |
11 | background: linear-gradient(to bottom, rgba(20, 20, 20, .7) 0, rgba(20, 20, 20, 0)); | 25 | background: linear-gradient(to bottom, rgba(20, 20, 20, .7) 0, rgba(20, 20, 20, 0)); |
12 | } | 26 | } |
13 | 27 | ||
14 | .vjs-dock-title { | 28 | .peertube-dock-avatar { |
29 | border-radius: 50%; | ||
30 | margin-right: 10px; | ||
31 | min-width: var(--avatarSize); | ||
32 | min-height: var(--avatarSize); | ||
33 | max-height: var(--avatarSize); | ||
34 | max-height: var(--avatarSize); | ||
35 | } | ||
36 | |||
37 | .peertube-dock-title-description { | ||
38 | // For ellipsis | ||
39 | min-width: 0; | ||
40 | } | ||
41 | |||
42 | .peertube-dock-title { | ||
15 | font-weight: $font-semibold; | 43 | font-weight: $font-semibold; |
44 | letter-spacing: 1px; | ||
45 | line-height: normal; | ||
46 | min-width: 0; | ||
16 | } | 47 | } |
17 | 48 | ||
18 | .vjs-dock-title, | 49 | .peertube-dock-title, |
19 | .vjs-dock-description { | 50 | .peertube-dock-description { |
51 | @include ellipsis; | ||
52 | |||
20 | text-shadow: 0 1px 3px rgba(0, 0, 0, .5); | 53 | text-shadow: 0 1px 3px rgba(0, 0, 0, .5); |
21 | } | 54 | } |
22 | 55 | ||
23 | .vjs-dock-description { | 56 | .peertube-dock-title + .peertube-dock-description { |
57 | margin-top: 3px; | ||
58 | } | ||
59 | |||
60 | .peertube-dock-description { | ||
24 | font-size: 11px; | 61 | font-size: 11px; |
62 | line-height: 1.5; | ||
25 | 63 | ||
26 | .text::before { | 64 | .text::before { |
27 | @include margin-right(4px); | 65 | @include margin-right(4px); |
@@ -34,24 +72,41 @@ | |||
34 | } | 72 | } |
35 | 73 | ||
36 | @media screen and (max-width: $screen-width-750) { | 74 | @media screen and (max-width: $screen-width-750) { |
37 | .vjs-dock-text { | 75 | .peertube-dock-avatar { |
76 | --avatarSize: 40px; | ||
77 | } | ||
78 | |||
79 | .peertube-dock { | ||
38 | font-size: 16px; | 80 | font-size: 16px; |
39 | } | 81 | } |
40 | 82 | ||
41 | .vjs-dock-description { | 83 | .peertube-dock-description { |
42 | font-size: 9px; | 84 | font-size: 9px; |
43 | } | 85 | } |
44 | } | 86 | } |
45 | 87 | ||
46 | @media screen and (max-width: $screen-width-570) { | 88 | @media screen and (max-width: $screen-width-570) { |
47 | .vjs-dock-text { | 89 | .peertube-dock-avatar { |
90 | --avatarSize: 35px; | ||
91 | } | ||
92 | |||
93 | .peertube-dock { | ||
48 | font-size: 14px; | 94 | font-size: 14px; |
49 | } | 95 | } |
50 | } | 96 | } |
51 | 97 | ||
52 | @media screen and (max-width: $screen-width-350) { | 98 | @media screen and (max-width: $screen-width-350) { |
53 | .vjs-dock-text { | 99 | .peertube-dock-avatar { |
100 | --avatarSize: 30px; | ||
101 | } | ||
102 | |||
103 | .peertube-dock { | ||
54 | font-size: 13px; | 104 | font-size: 13px; |
55 | } | 105 | } |
56 | } | 106 | } |
107 | |||
108 | &.vjs-playing.vjs-user-inactive { | ||
109 | opacity: 0; | ||
110 | transition: opacity 1s; | ||
111 | } | ||
57 | } | 112 | } |
diff --git a/client/src/standalone/videos/embed.scss b/client/src/standalone/videos/embed.scss index c2ee16ae2..91ab822c8 100644 --- a/client/src/standalone/videos/embed.scss +++ b/client/src/standalone/videos/embed.scss | |||
@@ -1,7 +1,6 @@ | |||
1 | @use '_variables' as *; | 1 | @use '_variables' as *; |
2 | @use '_mixins' as *; | 2 | @use '_mixins' as *; |
3 | @use 'video.js/dist/video-js'; | 3 | @use 'video.js/dist/video-js'; |
4 | @use 'videojs-dock/dist/videojs-dock'; | ||
5 | 4 | ||
6 | $assets-path: '../../assets/'; | 5 | $assets-path: '../../assets/'; |
7 | @use '../../sass/player/index'; | 6 | @use '../../sass/player/index'; |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 054f771ab..38ff39890 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -1,4 +1,6 @@ | |||
1 | import './embed.scss' | 1 | import './embed.scss' |
2 | import '../../assets/player/dock/peertube-dock-component' | ||
3 | import '../../assets/player/dock/peertube-dock-plugin' | ||
2 | import videojs from 'video.js' | 4 | import videojs from 'video.js' |
3 | import { peertubeTranslate } from '../../../../shared/core-utils/i18n' | 5 | import { peertubeTranslate } from '../../../../shared/core-utils/i18n' |
4 | import { | 6 | import { |
@@ -678,15 +680,22 @@ export class PeerTubeEmbed { | |||
678 | if (!this.player.player_) return | 680 | if (!this.player.player_) return |
679 | 681 | ||
680 | const title = this.title ? videoInfo.name : undefined | 682 | const title = this.title ? videoInfo.name : undefined |
681 | |||
682 | const description = this.warningTitle && this.p2pEnabled | 683 | const description = this.warningTitle && this.p2pEnabled |
683 | ? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>' | 684 | ? '<span class="text">' + peertubeTranslate('Watching this video may reveal your IP address to others.') + '</span>' |
684 | : undefined | 685 | : undefined |
685 | 686 | ||
687 | const availableAvatars = videoInfo.channel.avatars.filter(a => a.width < 50) | ||
688 | const avatar = availableAvatars.length !== 0 | ||
689 | ? availableAvatars[0] | ||
690 | : undefined | ||
691 | |||
686 | if (title || description) { | 692 | if (title || description) { |
687 | this.player.dock({ | 693 | this.player.peertubeDock({ |
688 | title, | 694 | title, |
689 | description | 695 | description, |
696 | avatarUrl: title && avatar | ||
697 | ? avatar.path | ||
698 | : undefined | ||
690 | }) | 699 | }) |
691 | } | 700 | } |
692 | } | 701 | } |
diff --git a/client/yarn.lock b/client/yarn.lock index 847fe77d2..278f04942 100644 --- a/client/yarn.lock +++ b/client/yarn.lock | |||
@@ -10941,7 +10941,7 @@ verror@1.10.0: | |||
10941 | core-util-is "1.0.2" | 10941 | core-util-is "1.0.2" |
10942 | extsprintf "^1.2.0" | 10942 | extsprintf "^1.2.0" |
10943 | 10943 | ||
10944 | "video.js@^6 || ^7", video.js@^7, video.js@^7.17.0, video.js@^7.6.0: | 10944 | "video.js@^6 || ^7", video.js@^7, video.js@^7.6.0: |
10945 | version "7.17.0" | 10945 | version "7.17.0" |
10946 | resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.17.0.tgz#35918cc03748a5680f5d5f1da410e06eeea7786e" | 10946 | resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.17.0.tgz#35918cc03748a5680f5d5f1da410e06eeea7786e" |
10947 | integrity sha512-8RbLu9+Pdpep9OTPncUHIvZXFgn/7hKdPnSTE/lGSnlFSucXtTUBp41R7NDwncscMLQ0WgazUbmFlvr4MNWMbA== | 10947 | integrity sha512-8RbLu9+Pdpep9OTPncUHIvZXFgn/7hKdPnSTE/lGSnlFSucXtTUBp41R7NDwncscMLQ0WgazUbmFlvr4MNWMbA== |
@@ -10960,14 +10960,6 @@ verror@1.10.0: | |||
10960 | videojs-font "3.2.0" | 10960 | videojs-font "3.2.0" |
10961 | videojs-vtt.js "^0.15.3" | 10961 | videojs-vtt.js "^0.15.3" |
10962 | 10962 | ||
10963 | videojs-dock@^3.0.0: | ||
10964 | version "3.0.0" | ||
10965 | resolved "https://registry.yarnpkg.com/videojs-dock/-/videojs-dock-3.0.0.tgz#fd343934be410c525cfc6106d6eef8a1b6c21189" | ||
10966 | integrity sha512-v4NCw5mM2BO2pJqJQzjGq9BaEpnqPInNRNXzCBRrDTTxNwPHMG9zSoldpsUMj7lOlboAuB9pSiva/XX1eMWXDA== | ||
10967 | dependencies: | ||
10968 | global "^4.4.0" | ||
10969 | video.js "^7.17.0" | ||
10970 | |||
10971 | videojs-font@3.2.0: | 10963 | videojs-font@3.2.0: |
10972 | version "3.2.0" | 10964 | version "3.2.0" |
10973 | resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" | 10965 | resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" |