From 960a11e89da4e4a6ad6fbad61c71625f89e267b6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 30 May 2018 17:10:00 +0200 Subject: Add context menu to player --- .../+video-watch/modal/video-share.component.ts | 6 ++-- .../videos/+video-watch/video-watch.component.ts | 1 + client/src/assets/player/peertube-link-button.ts | 20 +++++-------- client/src/assets/player/peertube-player.ts | 27 +++++++++++++++++ .../src/assets/player/peertube-videojs-plugin.ts | 4 +++ client/src/assets/player/utils.ts | 34 ++++++++++++++++++++++ client/src/assets/player/video-renderer.ts | 6 ++-- client/src/sass/video-js-custom.scss | 30 +++++++++++++++++++ client/src/standalone/videos/embed.ts | 1 + 9 files changed, 109 insertions(+), 20 deletions(-) (limited to 'client/src') diff --git a/client/src/app/videos/+video-watch/modal/video-share.component.ts b/client/src/app/videos/+video-watch/modal/video-share.component.ts index 678cccfb5..33998c5d8 100644 --- a/client/src/app/videos/+video-watch/modal/video-share.component.ts +++ b/client/src/app/videos/+video-watch/modal/video-share.component.ts @@ -4,6 +4,7 @@ import { NotificationsService } from 'angular2-notifications' import { ModalDirective } from 'ngx-bootstrap/modal' import { VideoDetails } from '../../../shared/video/video-details.model' +import { buildVideoEmbed } from '../../../../assets/player/utils' @Component({ selector: 'my-video-share', @@ -28,10 +29,7 @@ export class VideoShareComponent { } getVideoIframeCode () { - return '' + return buildVideoEmbed(this.video.embedUrl) } getVideoUrl () { 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 35a7c04cc..c71051649 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts @@ -348,6 +348,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { inactivityTimeout: 2500, videoFiles: this.video.files, playerElement: this.playerElement, + videoEmbedUrl: this.video.embedUrl, videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid), videoDuration: this.video.duration, enableHotkeys: true, 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 @@ import { VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings' +import { buildVideoLink } from './utils' const Button: VideoJSComponentInterface = videojsUntyped.getComponent('Button') class PeerTubeLinkButton extends Button { + constructor (player: videojs.Player, options) { + super(player, options) + } + createEl () { return this.buildElement() } updateHref () { - const currentTime = Math.floor(this.player().currentTime()) - this.el().setAttribute('href', this.buildHref(currentTime)) + this.el().setAttribute('href', buildVideoLink(this.player().currentTime())) } handleClick () { @@ -18,7 +22,7 @@ class PeerTubeLinkButton extends Button { private buildElement () { const el = videojsUntyped.dom.createEl('a', { - href: this.buildHref(), + href: buildVideoLink(), innerHTML: 'PeerTube', title: 'Go to the video page', className: 'vjs-peertube-link', @@ -29,15 +33,5 @@ class PeerTubeLinkButton extends Button { return el } - - private buildHref (time?: number) { - let href = window.location.href.replace('embed', 'watch') - if (time) { - if (window.location.search) href += '&start=' + time - else href += '?start=' + time - } - - return href - } } 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' import 'videojs-hotkeys' import 'videojs-dock' +import 'videojs-contextmenu' +import 'videojs-contextmenu-ui' import './peertube-link-button' import './resolution-menu-button' import './settings-menu-button' import './webtorrent-info-button' import './peertube-videojs-plugin' import { videojsUntyped } from './peertube-videojs-typings' +import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' @@ -16,6 +19,7 @@ function getVideojsOptions (options: { autoplay: boolean, playerElement: HTMLVideoElement, videoViewUrl: string, + videoEmbedUrl: string, videoDuration: number, videoFiles: VideoFile[], enableHotkeys: boolean, @@ -38,6 +42,29 @@ function getVideojsOptions (options: { videoViewUrl: options.videoViewUrl, videoDuration: options.videoDuration, startTime: options.startTime + }, + contextmenuUI: { + content: [ + { + label: 'Copy the video URL', + listener: function () { + copyToClipboard(buildVideoLink()) + } + }, + { + label: 'Copy the video URL at the current time', + listener: function () { + const player = this + copyToClipboard(buildVideoLink(player.currentTime())) + } + }, + { + label: 'Copy embed code', + listener: () => { + copyToClipboard(buildVideoEmbed(options.videoEmbedUrl)) + } + } + ] } }, 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 { this.trigger('autoResolutionUpdate') } + getCurrentVideoFile () { + return this.currentVideoFile + } + private tryToPlay (done?: Function) { if (!done) done = function () { /* empty */ } 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 () { return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) } +function buildVideoLink (time?: number) { + let href = window.location.href.replace('/embed/', '/watch/') + if (time) { + const timeInt = Math.floor(time) + + if (window.location.search) href += '&start=' + timeInt + else href += '?start=' + timeInt + } + + return href +} + +function buildVideoEmbed (embedUrl: string) { + return '' +} + +function copyToClipboard (text: string) { + const el = document.createElement('textarea') + el.value = text + el.setAttribute('readonly', '') + el.style.position = 'absolute' + el.style.left = '-9999px' + document.body.appendChild(el) + el.select() + document.execCommand('copy') + document.body.removeChild(el) +} + export { toTitleCase, + buildVideoLink, getStoredVolume, saveVolumeInStore, saveAverageBandwidth, getAverageBandwidth, saveMuteInStore, + buildVideoEmbed, getStoredMute, + copyToClipboard, isMobile, bytes } 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 return fallbackToMediaSource() }) - preparedElem.addEventListener('canplay', onLoadStart) + preparedElem.addEventListener('loadstart', onLoadStart) return videostream(file, preparedElem) } @@ -66,7 +66,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca return callback(err) }) - preparedElem.addEventListener('canplay', onLoadStart) + preparedElem.addEventListener('loadstart', onLoadStart) const wrapper = new MediaElementWrapper(preparedElem) const writable = wrapper.createWriteStream(codecs) @@ -95,7 +95,7 @@ function renderMedia (file, elem: HTMLVideoElement, opts: RenderMediaOptions, ca } function onLoadStart () { - preparedElem.removeEventListener('canplay', onLoadStart) + preparedElem.removeEventListener('loadstart', onLoadStart) if (opts.autoplay) preparedElem.play() callback(null, renderer) diff --git a/client/src/sass/video-js-custom.scss b/client/src/sass/video-js-custom.scss index 680958a9f..350e7cdd5 100644 --- a/client/src/sass/video-js-custom.scss +++ b/client/src/sass/video-js-custom.scss @@ -21,6 +21,8 @@ $slider-bg-color: lighten($primary-background-color, 33%); $setting-transition-duration: 0.15s; $setting-transition-easing: ease-out; +$context-menu-width: 350px; + .video-js.vjs-peertube-skin { font-size: $font-size; color: $primary-foreground-color; @@ -787,4 +789,32 @@ $setting-transition-easing: ease-out; } } } +} + +/* Sass for videojs-contextmenu-ui */ + +.video-js .vjs-contextmenu-ui-menu { + position: absolute; + background-color: rgba(0, 0, 0, 0.5); + padding: 5px 0; + width: $context-menu-width; + + .vjs-menu-content { + opacity: $primary-foreground-opacity; + color: $primary-foreground-color; + font-size: $font-size !important; + font-weight: $font-semibold; + } + + .vjs-menu-item { + cursor: pointer; + font-size: 1em; + padding: 8px 16px; + text-align: left; + text-transform: none; + + &:hover { + background-color: rgba(255, 255, 255, 0.2); + } + } } \ No newline at end of file diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index ba906cc32..d603690ca 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts @@ -91,6 +91,7 @@ loadVideoInfo(videoId) const videojsOptions = getVideojsOptions({ autoplay, inactivityTimeout: 1500, + videoEmbedUrl: window.location.origin + videoInfo.embedPath, videoViewUrl: getVideoUrl(videoId) + '/views', playerElement: videoElement, videoFiles: videoInfo.files, -- cgit v1.2.3