diff options
author | Chocobozzz <me@florianbigard.com> | 2018-05-30 17:10:00 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-05-30 17:10:00 +0200 |
commit | 960a11e89da4e4a6ad6fbad61c71625f89e267b6 (patch) | |
tree | 0cd370970c3166dd3715e46a5503a3da78f25e37 /client/src/assets/player | |
parent | e10c7d5125c47830bd23ecfed2f1b2d1048e6639 (diff) | |
download | PeerTube-960a11e89da4e4a6ad6fbad61c71625f89e267b6.tar.gz PeerTube-960a11e89da4e4a6ad6fbad61c71625f89e267b6.tar.zst PeerTube-960a11e89da4e4a6ad6fbad61c71625f89e267b6.zip |
Add context menu to player
Diffstat (limited to 'client/src/assets/player')
-rw-r--r-- | client/src/assets/player/peertube-link-button.ts | 20 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player.ts | 27 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-plugin.ts | 4 | ||||
-rw-r--r-- | client/src/assets/player/utils.ts | 34 | ||||
-rw-r--r-- | client/src/assets/player/video-renderer.ts | 6 |
5 files changed, 75 insertions, 16 deletions
diff --git a/client/src/assets/player/peertube-link-button.ts b/client/src/assets/player/peertube-link-button.ts index 54d802732..a13815d61 100644 --- a/client/src/assets/player/peertube-link-button.ts +++ b/client/src/assets/player/peertube-link-button.ts | |||
@@ -1,15 +1,19 @@ | |||
1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' | 1 | import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' |
2 | import { buildVideoLink } from './utils' | ||
2 | 3 | ||
3 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') | 4 | const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') |
4 | class PeerTubeLinkButton extends Button { | 5 | class PeerTubeLinkButton extends Button { |
5 | 6 | ||
7 | constructor (player: videojs.Player, options) { | ||
8 | super(player, options) | ||
9 | } | ||
10 | |||
6 | createEl () { | 11 | createEl () { |
7 | return this.buildElement() | 12 | return this.buildElement() |
8 | } | 13 | } |
9 | 14 | ||
10 | updateHref () { | 15 | updateHref () { |
11 | const currentTime = Math.floor(this.player().currentTime()) | 16 | this.el().setAttribute('href', buildVideoLink(this.player().currentTime())) |
12 | this.el().setAttribute('href', this.buildHref(currentTime)) | ||
13 | } | 17 | } |
14 | 18 | ||
15 | handleClick () { | 19 | handleClick () { |
@@ -18,7 +22,7 @@ class PeerTubeLinkButton extends Button { | |||
18 | 22 | ||
19 | private buildElement () { | 23 | private buildElement () { |
20 | const el = videojsUntyped.dom.createEl('a', { | 24 | const el = videojsUntyped.dom.createEl('a', { |
21 | href: this.buildHref(), | 25 | href: buildVideoLink(), |
22 | innerHTML: 'PeerTube', | 26 | innerHTML: 'PeerTube', |
23 | title: 'Go to the video page', | 27 | title: 'Go to the video page', |
24 | className: 'vjs-peertube-link', | 28 | className: 'vjs-peertube-link', |
@@ -29,15 +33,5 @@ class PeerTubeLinkButton extends Button { | |||
29 | 33 | ||
30 | return el | 34 | return el |
31 | } | 35 | } |
32 | |||
33 | private buildHref (time?: number) { | ||
34 | let href = window.location.href.replace('embed', 'watch') | ||
35 | if (time) { | ||
36 | if (window.location.search) href += '&start=' + time | ||
37 | else href += '?start=' + time | ||
38 | } | ||
39 | |||
40 | return href | ||
41 | } | ||
42 | } | 36 | } |
43 | Button.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton) | 37 | Button.registerComponent('PeerTubeLinkButton', PeerTubeLinkButton) |
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts index f419d58fc..9fe5af569 100644 --- a/client/src/assets/player/peertube-player.ts +++ b/client/src/assets/player/peertube-player.ts | |||
@@ -2,12 +2,15 @@ import { VideoFile } from '../../../../shared/models/videos' | |||
2 | 2 | ||
3 | import 'videojs-hotkeys' | 3 | import 'videojs-hotkeys' |
4 | import 'videojs-dock' | 4 | import 'videojs-dock' |
5 | import 'videojs-contextmenu' | ||
6 | import 'videojs-contextmenu-ui' | ||
5 | import './peertube-link-button' | 7 | import './peertube-link-button' |
6 | import './resolution-menu-button' | 8 | import './resolution-menu-button' |
7 | import './settings-menu-button' | 9 | import './settings-menu-button' |
8 | import './webtorrent-info-button' | 10 | import './webtorrent-info-button' |
9 | import './peertube-videojs-plugin' | 11 | import './peertube-videojs-plugin' |
10 | import { videojsUntyped } from './peertube-videojs-typings' | 12 | import { videojsUntyped } from './peertube-videojs-typings' |
13 | import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' | ||
11 | 14 | ||
12 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) | 15 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) |
13 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' | 16 | videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' |
@@ -16,6 +19,7 @@ function getVideojsOptions (options: { | |||
16 | autoplay: boolean, | 19 | autoplay: boolean, |
17 | playerElement: HTMLVideoElement, | 20 | playerElement: HTMLVideoElement, |
18 | videoViewUrl: string, | 21 | videoViewUrl: string, |
22 | videoEmbedUrl: string, | ||
19 | videoDuration: number, | 23 | videoDuration: number, |
20 | videoFiles: VideoFile[], | 24 | videoFiles: VideoFile[], |
21 | enableHotkeys: boolean, | 25 | enableHotkeys: boolean, |
@@ -38,6 +42,29 @@ function getVideojsOptions (options: { | |||
38 | videoViewUrl: options.videoViewUrl, | 42 | videoViewUrl: options.videoViewUrl, |
39 | videoDuration: options.videoDuration, | 43 | videoDuration: options.videoDuration, |
40 | startTime: options.startTime | 44 | startTime: options.startTime |
45 | }, | ||
46 | contextmenuUI: { | ||
47 | content: [ | ||
48 | { | ||
49 | label: 'Copy the video URL', | ||
50 | listener: function () { | ||
51 | copyToClipboard(buildVideoLink()) | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | label: 'Copy the video URL at the current time', | ||
56 | listener: function () { | ||
57 | const player = this | ||
58 | copyToClipboard(buildVideoLink(player.currentTime())) | ||
59 | } | ||
60 | }, | ||
61 | { | ||
62 | label: 'Copy embed code', | ||
63 | listener: () => { | ||
64 | copyToClipboard(buildVideoEmbed(options.videoEmbedUrl)) | ||
65 | } | ||
66 | } | ||
67 | ] | ||
41 | } | 68 | } |
42 | }, | 69 | }, |
43 | controlBar: { | 70 | controlBar: { |
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts index d9ded7a7e..65103f3ab 100644 --- a/client/src/assets/player/peertube-videojs-plugin.ts +++ b/client/src/assets/player/peertube-videojs-plugin.ts | |||
@@ -268,6 +268,10 @@ class PeerTubePlugin extends Plugin { | |||
268 | this.trigger('autoResolutionUpdate') | 268 | this.trigger('autoResolutionUpdate') |
269 | } | 269 | } |
270 | 270 | ||
271 | getCurrentVideoFile () { | ||
272 | return this.currentVideoFile | ||
273 | } | ||
274 | |||
271 | private tryToPlay (done?: Function) { | 275 | private tryToPlay (done?: Function) { |
272 | if (!done) done = function () { /* empty */ } | 276 | if (!done) done = function () { /* empty */ } |
273 | 277 | ||
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index 1df39d4e4..487b3a1be 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -64,14 +64,48 @@ function isMobile () { | |||
64 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) | 64 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) |
65 | } | 65 | } |
66 | 66 | ||
67 | function buildVideoLink (time?: number) { | ||
68 | let href = window.location.href.replace('/embed/', '/watch/') | ||
69 | if (time) { | ||
70 | const timeInt = Math.floor(time) | ||
71 | |||
72 | if (window.location.search) href += '&start=' + timeInt | ||
73 | else href += '?start=' + timeInt | ||
74 | } | ||
75 | |||
76 | return href | ||
77 | } | ||
78 | |||
79 | function buildVideoEmbed (embedUrl: string) { | ||
80 | return '<iframe width="560" height="315" ' + | ||
81 | 'src="' + embedUrl + '" ' + | ||
82 | 'frameborder="0" allowfullscreen>' + | ||
83 | '</iframe>' | ||
84 | } | ||
85 | |||
86 | function copyToClipboard (text: string) { | ||
87 | const el = document.createElement('textarea') | ||
88 | el.value = text | ||
89 | el.setAttribute('readonly', '') | ||
90 | el.style.position = 'absolute' | ||
91 | el.style.left = '-9999px' | ||
92 | document.body.appendChild(el) | ||
93 | el.select() | ||
94 | document.execCommand('copy') | ||
95 | document.body.removeChild(el) | ||
96 | } | ||
97 | |||
67 | export { | 98 | export { |
68 | toTitleCase, | 99 | toTitleCase, |
100 | buildVideoLink, | ||
69 | getStoredVolume, | 101 | getStoredVolume, |
70 | saveVolumeInStore, | 102 | saveVolumeInStore, |
71 | saveAverageBandwidth, | 103 | saveAverageBandwidth, |
72 | getAverageBandwidth, | 104 | getAverageBandwidth, |
73 | saveMuteInStore, | 105 | saveMuteInStore, |
106 | buildVideoEmbed, | ||
74 | getStoredMute, | 107 | getStoredMute, |
108 | copyToClipboard, | ||
75 | isMobile, | 109 | isMobile, |
76 | bytes | 110 | bytes |
77 | } | 111 | } |
diff --git a/client/src/assets/player/video-renderer.ts b/client/src/assets/player/video-renderer.ts index 4b54b661a..4affb43cf 100644 --- a/client/src/assets/player/video-renderer.ts +++ b/client/src/assets/player/video-renderer.ts | |||
@@ -50,7 +50,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca | |||
50 | 50 | ||
51 | return fallbackToMediaSource() | 51 | return fallbackToMediaSource() |
52 | }) | 52 | }) |
53 | preparedElem.addEventListener('canplay', onLoadStart) | 53 | preparedElem.addEventListener('loadstart', onLoadStart) |
54 | return videostream(file, preparedElem) | 54 | return videostream(file, preparedElem) |
55 | } | 55 | } |
56 | 56 | ||
@@ -66,7 +66,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca | |||
66 | 66 | ||
67 | return callback(err) | 67 | return callback(err) |
68 | }) | 68 | }) |
69 | preparedElem.addEventListener('canplay', onLoadStart) | 69 | preparedElem.addEventListener('loadstart', onLoadStart) |
70 | 70 | ||
71 | const wrapper = new MediaElementWrapper(preparedElem) | 71 | const wrapper = new MediaElementWrapper(preparedElem) |
72 | const writable = wrapper.createWriteStream(codecs) | 72 | const writable = wrapper.createWriteStream(codecs) |
@@ -95,7 +95,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca | |||
95 | } | 95 | } |
96 | 96 | ||
97 | function onLoadStart () { | 97 | function onLoadStart () { |
98 | preparedElem.removeEventListener('canplay', onLoadStart) | 98 | preparedElem.removeEventListener('loadstart', onLoadStart) |
99 | if (opts.autoplay) preparedElem.play() | 99 | if (opts.autoplay) preparedElem.play() |
100 | 100 | ||
101 | callback(null, renderer) | 101 | callback(null, renderer) |