Skip to content

Commit

Permalink
Add context menu to player
Browse files Browse the repository at this point in the history
  • Loading branch information
Chocobozzz committed May 30, 2018
1 parent e10c7d5 commit 960a11e
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 127 deletions.
2 changes: 1 addition & 1 deletion .sass-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ rules:
space-before-colon: 1
hex-length: 1
hex-notation: 0
indentation: 1
indentation: 2
4 changes: 3 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"license": "GPLv3",
"resolutions": {
"videojs-dock/video.js": "^7",
"video.js": "^7",
"webtorrent/create-torrent/junk": "^1",
"simple-get": "^2.8.1"
},
Expand Down Expand Up @@ -99,6 +99,8 @@
"typescript": "2.7",
"uglifyjs-webpack-plugin": "^1.1.2",
"video.js": "^7.0.3",
"videojs-contextmenu": "^2.0.0",
"videojs-contextmenu-ui": "^4.0.0",
"videojs-dock": "^2.0.2",
"videojs-hotkeys": "^0.2.21",
"webpack": "^4.5.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -28,10 +29,7 @@ export class VideoShareComponent {
}

getVideoIframeCode () {
return '<iframe width="560" height="315" ' +
'src="' + this.video.embedUrl + '" ' +
'frameborder="0" allowfullscreen>' +
'</iframe>'
return buildVideoEmbed(this.video.embedUrl)
}

getVideoUrl () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 7 additions & 13 deletions client/src/assets/player/peertube-link-button.ts
Original file line number Diff line number Diff line change
@@ -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 () {
Expand All @@ -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',
Expand All @@ -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)
27 changes: 27 additions & 0 deletions client/src/assets/player/peertube-player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -16,6 +19,7 @@ function getVideojsOptions (options: {
autoplay: boolean,
playerElement: HTMLVideoElement,
videoViewUrl: string,
videoEmbedUrl: string,
videoDuration: number,
videoFiles: VideoFile[],
enableHotkeys: boolean,
Expand All @@ -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: {
Expand Down
4 changes: 4 additions & 0 deletions client/src/assets/player/peertube-videojs-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ class PeerTubePlugin extends Plugin {
this.trigger('autoResolutionUpdate')
}

getCurrentVideoFile () {
return this.currentVideoFile
}

private tryToPlay (done?: Function) {
if (!done) done = function () { /* empty */ }

Expand Down
34 changes: 34 additions & 0 deletions client/src/assets/player/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 '<iframe width="560" height="315" ' +
'src="' + embedUrl + '" ' +
'frameborder="0" allowfullscreen>' +
'</iframe>'
}

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
}
Expand Down
6 changes: 3 additions & 3 deletions client/src/assets/player/video-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
30 changes: 30 additions & 0 deletions client/src/sass/video-js-custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
1 change: 1 addition & 0 deletions client/src/standalone/videos/embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
15 changes: 15 additions & 0 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10006,6 +10006,21 @@ video.js@^5.19.2, "video.js@^6.8.0 || ^7.0.0", video.js@^7, video.js@^7.0.3:
videojs-vtt.js "0.14.1"
xhr "2.4.0"

videojs-contextmenu-ui@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/videojs-contextmenu-ui/-/videojs-contextmenu-ui-4.0.0.tgz#e7ffceacac95c5d2bc7f80db6f75675404de542a"
dependencies:
global "^4.3.2"
video.js "^5.19.2"
videojs-contextmenu "^2.0.0"

videojs-contextmenu@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/videojs-contextmenu/-/videojs-contextmenu-2.0.0.tgz#7213c8c420ecd2904d26f19c21085f7ebf496e9e"
dependencies:
global "^4.3.2"
video.js "^5.19.2"

videojs-dock@^2.0.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/videojs-dock/-/videojs-dock-2.1.2.tgz#621c27c6f7dd131c541535300ac545377e515a0e"
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"lint-staged": {
"*.{css,md}": "precise-commits",
"*.scss": [
"sass-lint-auto-fix -c .sass-lint.yml --verbose",
"sass-lint -c .sass-lint.yml",
"git add"
]
},
Expand Down Expand Up @@ -156,7 +156,7 @@
"chai-json-schema": "^1.5.0",
"chai-xml": "^0.3.2",
"husky": "^1.0.0-rc.4",
"libxmljs": "^0.18.9-pre0",
"libxmljs": "0.18.8",
"lint-staged": "^7.1.0",
"maildev": "^1.0.0-rc3",
"mocha": "^5.0.0",
Expand All @@ -165,7 +165,6 @@
"prettier": "1.13.2",
"prompt": "^1.0.0",
"sass-lint": "^1.12.1",
"sass-lint-auto-fix": "^0.10.0",
"source-map-support": "^0.5.0",
"spectacle-docs": "^1.0.2",
"supertest": "^3.0.0",
Expand Down
Loading

0 comments on commit 960a11e

Please sign in to comment.