diff options
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.component.ts | 1 | ||||
-rw-r--r-- | client/src/assets/player/bezels/bezels-plugin.ts | 93 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-manager.ts | 1 | ||||
-rw-r--r-- | client/src/sass/player/bezels.scss | 42 | ||||
-rw-r--r-- | client/src/sass/player/index.scss | 3 | ||||
-rw-r--r-- | client/src/sass/player/upnext.scss | 3 |
6 files changed, 141 insertions, 2 deletions
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 835e9e34a..9eae45fed 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -469,6 +469,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
469 | this.zone.runOutsideAngular(async () => { | 469 | this.zone.runOutsideAngular(async () => { |
470 | this.player = await PeertubePlayerManager.initialize(playerMode, playerOptions, player => this.player = player) | 470 | this.player = await PeertubePlayerManager.initialize(playerMode, playerOptions, player => this.player = player) |
471 | this.player.focus() | 471 | this.player.focus() |
472 | this.player.bezels() | ||
472 | 473 | ||
473 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | 474 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) |
474 | 475 | ||
diff --git a/client/src/assets/player/bezels/bezels-plugin.ts b/client/src/assets/player/bezels/bezels-plugin.ts new file mode 100644 index 000000000..4317d60f9 --- /dev/null +++ b/client/src/assets/player/bezels/bezels-plugin.ts | |||
@@ -0,0 +1,93 @@ | |||
1 | // @ts-ignore | ||
2 | import * as videojs from 'video.js' | ||
3 | import { VideoJSComponentInterface } from '../peertube-videojs-typings' | ||
4 | |||
5 | function getPauseBezel () { | ||
6 | return ` | ||
7 | <div class="vjs-bezels-pause"> | ||
8 | <div class="vjs-bezel" role="status" aria-label="Pause"> | ||
9 | <div class="vjs-bezel-icon"> | ||
10 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
11 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-1"></use> | ||
12 | <path class="vjs-svg-fill" d="M 12,26 16,26 16,10 12,10 z M 21,26 25,26 25,10 21,10 z" id="vjs-id-1"></path> | ||
13 | </svg> | ||
14 | </div> | ||
15 | </div> | ||
16 | </div> | ||
17 | ` | ||
18 | } | ||
19 | |||
20 | function getPlayBezel () { | ||
21 | return ` | ||
22 | <div class="vjs-bezels-play"> | ||
23 | <div class="vjs-bezel" role="status" aria-label="Play"> | ||
24 | <div class="vjs-bezel-icon"> | ||
25 | <svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> | ||
26 | <use class="vjs-svg-shadow" xlink:href="#vjs-id-2"></use> | ||
27 | <path class="vjs-svg-fill" d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" id="ytp-id-2"></path> | ||
28 | </svg> | ||
29 | </div> | ||
30 | </div> | ||
31 | </div> | ||
32 | ` | ||
33 | } | ||
34 | |||
35 | // @ts-ignore-start | ||
36 | const Component = videojs.getComponent('Component') | ||
37 | class PauseBezel extends Component { | ||
38 | options_: any | ||
39 | container: HTMLBodyElement | ||
40 | |||
41 | constructor (player: videojs.Player, options: any) { | ||
42 | super(player, options) | ||
43 | this.options_ = options | ||
44 | |||
45 | player.on('pause', (_: any) => { | ||
46 | if (player.seeking()) return | ||
47 | this.container.innerHTML = getPauseBezel() | ||
48 | this.showBezel() | ||
49 | }) | ||
50 | |||
51 | player.on('play', (_: any) => { | ||
52 | if (player.seeking()) return | ||
53 | this.container.innerHTML = getPlayBezel() | ||
54 | this.showBezel() | ||
55 | }) | ||
56 | } | ||
57 | |||
58 | createEl () { | ||
59 | const container = super.createEl('div', { | ||
60 | className: 'vjs-bezels-content' | ||
61 | }) | ||
62 | this.container = container | ||
63 | container.style.display = 'none' | ||
64 | |||
65 | return container | ||
66 | } | ||
67 | |||
68 | showBezel () { | ||
69 | this.container.style.display = 'inherit' | ||
70 | setTimeout(() => { | ||
71 | this.container.style.display = 'none' | ||
72 | }, 500) // matching the animation duration | ||
73 | } | ||
74 | } | ||
75 | // @ts-ignore-end | ||
76 | |||
77 | videojs.registerComponent('PauseBezel', PauseBezel) | ||
78 | |||
79 | const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin') | ||
80 | class BezelsPlugin extends Plugin { | ||
81 | constructor (player: videojs.Player, options: any = {}) { | ||
82 | super(player, options) | ||
83 | |||
84 | this.player.ready(() => { | ||
85 | player.addClass('vjs-bezels') | ||
86 | }) | ||
87 | |||
88 | player.addChild('PauseBezel', options) | ||
89 | } | ||
90 | } | ||
91 | |||
92 | videojs.registerPlugin('bezels', BezelsPlugin) | ||
93 | export { BezelsPlugin } | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index b1551185a..ac3609c04 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -6,6 +6,7 @@ import 'videojs-dock' | |||
6 | import 'videojs-contextmenu-ui' | 6 | import 'videojs-contextmenu-ui' |
7 | import 'videojs-contrib-quality-levels' | 7 | import 'videojs-contrib-quality-levels' |
8 | import './upnext/upnext-plugin' | 8 | import './upnext/upnext-plugin' |
9 | import './bezels/bezels-plugin' | ||
9 | import './peertube-plugin' | 10 | import './peertube-plugin' |
10 | import './videojs-components/peertube-link-button' | 11 | import './videojs-components/peertube-link-button' |
11 | import './videojs-components/resolution-menu-button' | 12 | import './videojs-components/resolution-menu-button' |
diff --git a/client/src/sass/player/bezels.scss b/client/src/sass/player/bezels.scss new file mode 100644 index 000000000..f1b1dcb4a --- /dev/null +++ b/client/src/sass/player/bezels.scss | |||
@@ -0,0 +1,42 @@ | |||
1 | @keyframes bezels-fadeout { | ||
2 | from { | ||
3 | opacity: 1; | ||
4 | } | ||
5 | to { | ||
6 | opacity: 0; | ||
7 | transform: scale(2); | ||
8 | } | ||
9 | } | ||
10 | |||
11 | .vjs-bezel { | ||
12 | position: absolute; | ||
13 | left: 50%; | ||
14 | top: 50%; | ||
15 | width: 52px; | ||
16 | height: 52px; | ||
17 | z-index: 19; | ||
18 | margin-left: -26px; | ||
19 | margin-top: -26px; | ||
20 | background: rgba(0,0,0,.5); | ||
21 | border-radius: 26px; | ||
22 | animation: bezels-fadeout .5s linear 1 normal forwards; | ||
23 | pointer-events: none; | ||
24 | } | ||
25 | |||
26 | .vjs-bezel-icon { | ||
27 | width: 36px; | ||
28 | height: 36px; | ||
29 | margin: 8px; | ||
30 | |||
31 | svg .vjs-svg-fill { | ||
32 | fill: #fff; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | .video-js { | ||
37 | |||
38 | .vjs-bezel-content { | ||
39 | |||
40 | } | ||
41 | |||
42 | } \ No newline at end of file | ||
diff --git a/client/src/sass/player/index.scss b/client/src/sass/player/index.scss index 886a76536..58ce3ac96 100644 --- a/client/src/sass/player/index.scss +++ b/client/src/sass/player/index.scss | |||
@@ -3,4 +3,5 @@ | |||
3 | @import './context-menu'; | 3 | @import './context-menu'; |
4 | @import './settings-menu'; | 4 | @import './settings-menu'; |
5 | @import './spinner'; | 5 | @import './spinner'; |
6 | @import './upnext'; \ No newline at end of file | 6 | @import './upnext'; |
7 | @import './bezels.scss'; \ No newline at end of file | ||
diff --git a/client/src/sass/player/upnext.scss b/client/src/sass/player/upnext.scss index ecce22aa8..f1f2e0fe2 100644 --- a/client/src/sass/player/upnext.scss +++ b/client/src/sass/player/upnext.scss | |||
@@ -95,8 +95,9 @@ $browser-context: 16; | |||
95 | width: 98px; | 95 | width: 98px; |
96 | height: 98px; | 96 | height: 98px; |
97 | margin: -49px 0 0 -49px; | 97 | margin: -49px 0 0 -49px; |
98 | transition: stroke-dasharray 0.1s cubic-bezier(0.4,0,1,1); | ||
99 | cursor: pointer; | 98 | cursor: pointer; |
99 | |||
100 | @include transition(stroke-dasharray 0.1s cubic-bezier(0.4,0,1,1)); | ||
100 | } | 101 | } |
101 | 102 | ||
102 | } | 103 | } |