diff options
-rw-r--r-- | client/src/app/+videos/+video-watch/video-watch.component.ts | 17 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-manager.ts | 110 | ||||
-rw-r--r-- | client/src/assets/player/peertube-videojs-typings.ts | 9 | ||||
-rw-r--r-- | client/src/assets/player/utils.ts | 6 | ||||
-rw-r--r-- | client/src/standalone/videos/embed.ts | 7 | ||||
-rwxr-xr-x | scripts/i18n/create-custom-files.ts | 8 |
6 files changed, 117 insertions, 40 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 366e9bb57..2216bdd4a 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -795,6 +795,19 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
795 | src: environment.apiUrl + c.captionPath | 795 | src: environment.apiUrl + c.captionPath |
796 | })) | 796 | })) |
797 | 797 | ||
798 | const playlistOptions = this.playlist | ||
799 | ? { | ||
800 | createComponent: false, | ||
801 | |||
802 | playlist: this.playlist, | ||
803 | |||
804 | getCurrentPosition: () => this.playlistPosition, | ||
805 | |||
806 | embedUrl: this.playlist.embedUrl, | ||
807 | embedTitle: this.playlist.displayName | ||
808 | } | ||
809 | : undefined | ||
810 | |||
798 | const options: PeertubePlayerManagerOptions = { | 811 | const options: PeertubePlayerManagerOptions = { |
799 | common: { | 812 | common: { |
800 | autoplay: this.isAutoplay(), | 813 | autoplay: this.isAutoplay(), |
@@ -839,7 +852,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
839 | 852 | ||
840 | videoCaptions: playerCaptions, | 853 | videoCaptions: playerCaptions, |
841 | 854 | ||
842 | videoUUID: video.uuid | 855 | videoUUID: video.uuid, |
856 | |||
857 | playlist: playlistOptions | ||
843 | }, | 858 | }, |
844 | 859 | ||
845 | webtorrent: { | 860 | webtorrent: { |
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index ed82e0496..689e70fb5 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -35,7 +35,7 @@ import { | |||
35 | VideoJSPluginOptions | 35 | VideoJSPluginOptions |
36 | } from './peertube-videojs-typings' | 36 | } from './peertube-videojs-typings' |
37 | import { TranslationsManager } from './translations-manager' | 37 | import { TranslationsManager } from './translations-manager' |
38 | import { buildVideoOrPlaylistEmbed, buildVideoLink, getRtcConfig, isSafari, isIOS } from './utils' | 38 | import { buildVideoOrPlaylistEmbed, buildVideoLink, getRtcConfig, isSafari, isIOS, buildPlaylistLink } from './utils' |
39 | import { copyToClipboard } from '../../root-helpers/utils' | 39 | import { copyToClipboard } from '../../root-helpers/utils' |
40 | 40 | ||
41 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) | 41 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) |
@@ -87,6 +87,8 @@ export interface CommonOptions extends CustomizationOptions { | |||
87 | hasPreviousVideo?: () => boolean | 87 | hasPreviousVideo?: () => boolean |
88 | 88 | ||
89 | playlist?: PlaylistPluginOptions | 89 | playlist?: PlaylistPluginOptions |
90 | playlistEmbedUrl?: string | ||
91 | playlistEmbedTitle?: string | ||
90 | 92 | ||
91 | videoDuration: number | 93 | videoDuration: number |
92 | enableHotkeys: boolean | 94 | enableHotkeys: boolean |
@@ -167,7 +169,13 @@ export class PeertubePlayerManager { | |||
167 | PeertubePlayerManager.alreadyPlayed = true | 169 | PeertubePlayerManager.alreadyPlayed = true |
168 | }) | 170 | }) |
169 | 171 | ||
170 | self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) | 172 | self.addContextMenu({ |
173 | mode, | ||
174 | player, | ||
175 | videoEmbedUrl: options.common.embedUrl, | ||
176 | videoEmbedTitle: options.common.embedTitle, | ||
177 | playlist: options.common.playlist | ||
178 | }) | ||
171 | 179 | ||
172 | player.bezels() | 180 | player.bezels() |
173 | 181 | ||
@@ -205,7 +213,13 @@ export class PeertubePlayerManager { | |||
205 | videojs(newVideoElement, videojsOptions, function (this: videojs.Player) { | 213 | videojs(newVideoElement, videojsOptions, function (this: videojs.Player) { |
206 | const player = this | 214 | const player = this |
207 | 215 | ||
208 | self.addContextMenu(mode, player, options.common.embedUrl, options.common.embedTitle) | 216 | self.addContextMenu({ |
217 | mode, | ||
218 | player, | ||
219 | videoEmbedUrl: options.common.embedUrl, | ||
220 | videoEmbedTitle: options.common.embedTitle, | ||
221 | playlist: options.common.playlist | ||
222 | }) | ||
209 | 223 | ||
210 | PeertubePlayerManager.onPlayerChange(player) | 224 | PeertubePlayerManager.onPlayerChange(player) |
211 | }) | 225 | }) |
@@ -239,7 +253,7 @@ export class PeertubePlayerManager { | |||
239 | } | 253 | } |
240 | } | 254 | } |
241 | 255 | ||
242 | if (commonOptions.playlist) { | 256 | if (commonOptions.playlist?.createComponent === true) { |
243 | plugins.playlist = commonOptions.playlist | 257 | plugins.playlist = commonOptions.playlist |
244 | } | 258 | } |
245 | 259 | ||
@@ -497,37 +511,71 @@ export class PeertubePlayerManager { | |||
497 | return children | 511 | return children |
498 | } | 512 | } |
499 | 513 | ||
500 | private static addContextMenu (mode: PlayerMode, player: videojs.Player, videoEmbedUrl: string, videoEmbedTitle: string) { | 514 | private static addContextMenu (options: { |
515 | mode: PlayerMode | ||
516 | player: videojs.Player | ||
517 | videoEmbedUrl: string | ||
518 | videoEmbedTitle: string | ||
519 | playlist?: PlaylistPluginOptions | ||
520 | }) { | ||
521 | const { mode, player, videoEmbedUrl, videoEmbedTitle, playlist } = options | ||
522 | |||
501 | const content = () => { | 523 | const content = () => { |
502 | const isLoopEnabled = player.options_['loop'] | 524 | let items: { icon?: string, label: string, listener: Function }[] = [] |
503 | const items = [ | 525 | |
504 | { | 526 | if (!playlist) { |
505 | icon: 'repeat', | 527 | const isLoopEnabled = player.options_['loop'] |
506 | label: player.localize('Play in loop') + (isLoopEnabled ? '<span class="vjs-icon-tick-white"></span>' : ''), | 528 | items = items.concat([ |
507 | listener: function () { | 529 | { |
508 | player.options_['loop'] = !isLoopEnabled | 530 | icon: 'repeat', |
509 | } | 531 | label: player.localize('Play in loop') + (isLoopEnabled ? '<span class="vjs-icon-tick-white"></span>' : ''), |
510 | }, | 532 | listener: function () { |
511 | { | 533 | player.options_['loop'] = !isLoopEnabled |
512 | label: player.localize('Copy the video URL'), | 534 | } |
513 | listener: function () { | 535 | }, |
514 | copyToClipboard(buildVideoLink()) | 536 | { |
515 | } | 537 | label: player.localize('Copy the video URL'), |
516 | }, | 538 | listener: function () { |
517 | { | 539 | copyToClipboard(buildVideoLink()) |
518 | label: player.localize('Copy the video URL at the current time'), | 540 | } |
519 | listener: function (this: videojs.Player) { | 541 | }, |
520 | copyToClipboard(buildVideoLink({ startTime: this.currentTime() })) | 542 | { |
543 | label: player.localize('Copy the video URL at the current time'), | ||
544 | listener: function (this: videojs.Player) { | ||
545 | copyToClipboard(buildVideoLink({ startTime: this.currentTime() })) | ||
546 | } | ||
521 | } | 547 | } |
522 | }, | 548 | ]) |
523 | { | 549 | } else { |
524 | icon: 'code', | 550 | items = items.concat([ |
525 | label: player.localize('Copy embed code'), | 551 | { |
526 | listener: () => { | 552 | label: player.localize('Copy the playlist URL'), |
527 | copyToClipboard(buildVideoOrPlaylistEmbed(videoEmbedUrl, videoEmbedTitle)) | 553 | listener: function () { |
554 | copyToClipboard(buildPlaylistLink()) | ||
555 | } | ||
556 | }, | ||
557 | { | ||
558 | label: player.localize('Copy the playlist URL at current video position'), | ||
559 | listener: function (this: videojs.Player) { | ||
560 | copyToClipboard(buildPlaylistLink({ playlistPosition: playlist.getCurrentPosition() })) | ||
561 | } | ||
562 | }, | ||
563 | { | ||
564 | label: player.localize('Copy the playlist embed code'), | ||
565 | listener: function (this: videojs.Player) { | ||
566 | copyToClipboard(buildVideoOrPlaylistEmbed(playlist.embedUrl, playlist.embedTitle)) | ||
567 | } | ||
528 | } | 568 | } |
569 | ]) | ||
570 | } | ||
571 | |||
572 | items = items.concat({ | ||
573 | icon: 'code', | ||
574 | label: player.localize('Copy video embed code'), | ||
575 | listener: () => { | ||
576 | copyToClipboard(buildVideoOrPlaylistEmbed(videoEmbedUrl, videoEmbedTitle)) | ||
529 | } | 577 | } |
530 | ] | 578 | }) |
531 | 579 | ||
532 | if (mode === 'webtorrent') { | 580 | if (mode === 'webtorrent') { |
533 | items.push({ | 581 | items.push({ |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index 4a6c80247..a48ff2cd0 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -113,13 +113,18 @@ type PeerTubePluginOptions = { | |||
113 | } | 113 | } |
114 | 114 | ||
115 | type PlaylistPluginOptions = { | 115 | type PlaylistPluginOptions = { |
116 | elements: VideoPlaylistElement[] | 116 | createComponent: boolean |
117 | |||
118 | elements?: VideoPlaylistElement[] | ||
117 | 119 | ||
118 | playlist: VideoPlaylist | 120 | playlist: VideoPlaylist |
119 | 121 | ||
120 | getCurrentPosition: () => number | 122 | getCurrentPosition: () => number |
121 | 123 | ||
122 | onItemClicked: (element: VideoPlaylistElement) => void | 124 | embedUrl: string |
125 | embedTitle: string | ||
126 | |||
127 | onItemClicked?: (element: VideoPlaylistElement) => void | ||
123 | } | 128 | } |
124 | 129 | ||
125 | type NextPreviousVideoButtonOptions = { | 130 | type NextPreviousVideoButtonOptions = { |
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index d7451fa1d..136b69b4f 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -94,9 +94,8 @@ function buildVideoLink (options: { | |||
94 | 94 | ||
95 | function buildPlaylistLink (options: { | 95 | function buildPlaylistLink (options: { |
96 | baseUrl?: string | 96 | baseUrl?: string |
97 | 97 | playlistPosition?: number | |
98 | playlistPosition: number | 98 | } = {}) { |
99 | }) { | ||
100 | const { baseUrl } = options | 99 | const { baseUrl } = options |
101 | 100 | ||
102 | const url = baseUrl | 101 | const url = baseUrl |
@@ -106,6 +105,7 @@ function buildPlaylistLink (options: { | |||
106 | const params = generateParams(window.location.search) | 105 | const params = generateParams(window.location.search) |
107 | 106 | ||
108 | if (options.playlistPosition) params.set('playlistPosition', '' + options.playlistPosition) | 107 | if (options.playlistPosition) params.set('playlistPosition', '' + options.playlistPosition) |
108 | else params.delete('playlistPosition') | ||
109 | 109 | ||
110 | return buildUrl(url, params) | 110 | return buildUrl(url, params) |
111 | } | 111 | } |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 103014bb0..9e5b2a655 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -492,6 +492,8 @@ export class PeerTubeEmbed { | |||
492 | 492 | ||
493 | const playlistPlugin = this.currentPlaylistElement | 493 | const playlistPlugin = this.currentPlaylistElement |
494 | ? { | 494 | ? { |
495 | createComponent: true, | ||
496 | |||
495 | elements: this.playlistElements, | 497 | elements: this.playlistElements, |
496 | playlist: this.playlist, | 498 | playlist: this.playlist, |
497 | 499 | ||
@@ -502,7 +504,10 @@ export class PeerTubeEmbed { | |||
502 | 504 | ||
503 | this.loadVideoAndBuildPlayer(this.currentPlaylistElement.video.uuid) | 505 | this.loadVideoAndBuildPlayer(this.currentPlaylistElement.video.uuid) |
504 | .catch(err => console.error(err)) | 506 | .catch(err => console.error(err)) |
505 | } | 507 | }, |
508 | |||
509 | embedTitle: this.playlist.displayName, | ||
510 | embedUrl: window.location.origin + this.playlist.embedPath | ||
506 | } | 511 | } |
507 | : undefined | 512 | : undefined |
508 | 513 | ||
diff --git a/scripts/i18n/create-custom-files.ts b/scripts/i18n/create-custom-files.ts index d4d5b44f0..111bcbf4c 100755 --- a/scripts/i18n/create-custom-files.ts +++ b/scripts/i18n/create-custom-files.ts | |||
@@ -29,14 +29,18 @@ const playerKeys = { | |||
29 | 'Watching this video may reveal your IP address to others.': 'Watching this video may reveal your IP address to others.', | 29 | 'Watching this video may reveal your IP address to others.': 'Watching this video may reveal your IP address to others.', |
30 | 'Copy the video URL': 'Copy the video URL', | 30 | 'Copy the video URL': 'Copy the video URL', |
31 | 'Copy the video URL at the current time': 'Copy the video URL at the current time', | 31 | 'Copy the video URL at the current time': 'Copy the video URL at the current time', |
32 | 'Copy embed code': 'Copy embed code', | 32 | 'Copy video embed code': 'Copy video embed code', |
33 | 'Copy magnet URI': 'Copy magnet URI', | 33 | 'Copy magnet URI': 'Copy magnet URI', |
34 | 'Total downloaded: ': 'Total downloaded: ', | 34 | 'Total downloaded: ': 'Total downloaded: ', |
35 | 'Total uploaded: ': 'Total uploaded: ', | 35 | 'Total uploaded: ': 'Total uploaded: ', |
36 | 'From servers: ': 'From servers: ', | 36 | 'From servers: ': 'From servers: ', |
37 | 'From peers: ': 'From peers: ', | 37 | 'From peers: ': 'From peers: ', |
38 | 'Normal mode': 'Normal mode', | 38 | 'Normal mode': 'Normal mode', |
39 | 'Theater mode': 'Theater mode' | 39 | 'Play in loop': 'Play in loop', |
40 | 'Theater mode': 'Theater mode', | ||
41 | 'Copy the playlist URL': 'Copy the playlist URL', | ||
42 | 'Copy the playlist URL at current video position': 'Copy the playlist URL at current video position', | ||
43 | 'Copy the playlist embed code': 'Copy the playlist embed code' | ||
40 | } | 44 | } |
41 | Object.assign(playerKeys, videojs) | 45 | Object.assign(playerKeys, videojs) |
42 | 46 | ||