diff options
Diffstat (limited to 'client/src/assets/player')
8 files changed, 19 insertions, 164 deletions
diff --git a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts index f1bd9f0c4..2eb849d2b 100644 --- a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts | |||
@@ -2,8 +2,8 @@ import * as Hlsjs from 'hls.js/dist/hls.light.js' | |||
2 | import { Events, Segment } from 'p2p-media-loader-core' | 2 | import { Events, Segment } from 'p2p-media-loader-core' |
3 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' | 3 | import { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs' |
4 | import videojs from 'video.js' | 4 | import videojs from 'video.js' |
5 | import { timeToInt } from '@shared/core-utils' | ||
5 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' | 6 | import { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../peertube-videojs-typings' |
6 | import { timeToInt } from '../utils' | ||
7 | import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' | 7 | import { registerConfigPlugin, registerSourceHandler } from './hls-plugin' |
8 | 8 | ||
9 | registerConfigPlugin(videojs) | 9 | registerConfigPlugin(videojs) |
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 6f0b804cd..766ad203e 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -23,6 +23,7 @@ import './videojs-components/theater-button' | |||
23 | import './playlist/playlist-plugin' | 23 | import './playlist/playlist-plugin' |
24 | import videojs from 'video.js' | 24 | import videojs from 'video.js' |
25 | import { PluginsManager } from '@root-helpers/plugins-manager' | 25 | import { PluginsManager } from '@root-helpers/plugins-manager' |
26 | import { buildVideoLink, decorateVideoLink } from '@shared/core-utils' | ||
26 | import { isDefaultLocale } from '@shared/core-utils/i18n' | 27 | import { isDefaultLocale } from '@shared/core-utils/i18n' |
27 | import { VideoFile } from '@shared/models' | 28 | import { VideoFile } from '@shared/models' |
28 | import { copyToClipboard } from '../../root-helpers/utils' | 29 | import { copyToClipboard } from '../../root-helpers/utils' |
@@ -40,7 +41,7 @@ import { | |||
40 | VideoJSPluginOptions | 41 | VideoJSPluginOptions |
41 | } from './peertube-videojs-typings' | 42 | } from './peertube-videojs-typings' |
42 | import { TranslationsManager } from './translations-manager' | 43 | import { TranslationsManager } from './translations-manager' |
43 | import { buildVideoLink, buildVideoOrPlaylistEmbed, decorateVideoLink, getRtcConfig, isIOS, isSafari } from './utils' | 44 | import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' |
44 | 45 | ||
45 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) | 46 | // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) |
46 | (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' | 47 | (videojs.getComponent('PlaybackRateMenuButton') as any).prototype.controlText_ = 'Speed' |
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index 07c7e33f6..919b7c239 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts | |||
@@ -1,12 +1,6 @@ | |||
1 | import videojs from 'video.js' | ||
2 | import './videojs-components/settings-menu-button' | 1 | import './videojs-components/settings-menu-button' |
3 | import { | 2 | import videojs from 'video.js' |
4 | PeerTubePluginOptions, | 3 | import { timeToInt } from '@shared/core-utils' |
5 | ResolutionUpdateData, | ||
6 | UserWatching, | ||
7 | VideoJSCaption | ||
8 | } from './peertube-videojs-typings' | ||
9 | import { isMobile, timeToInt } from './utils' | ||
10 | import { | 4 | import { |
11 | getStoredLastSubtitle, | 5 | getStoredLastSubtitle, |
12 | getStoredMute, | 6 | getStoredMute, |
@@ -16,6 +10,8 @@ import { | |||
16 | saveVideoWatchHistory, | 10 | saveVideoWatchHistory, |
17 | saveVolumeInStore | 11 | saveVolumeInStore |
18 | } from './peertube-player-local-storage' | 12 | } from './peertube-player-local-storage' |
13 | import { PeerTubePluginOptions, ResolutionUpdateData, UserWatching, VideoJSCaption } from './peertube-videojs-typings' | ||
14 | import { isMobile } from './utils' | ||
19 | 15 | ||
20 | const Plugin = videojs.getPlugin('plugin') | 16 | const Plugin = videojs.getPlugin('plugin') |
21 | 17 | ||
diff --git a/client/src/assets/player/playlist/playlist-menu-item.ts b/client/src/assets/player/playlist/playlist-menu-item.ts index 87a72b6a3..2519a34c7 100644 --- a/client/src/assets/player/playlist/playlist-menu-item.ts +++ b/client/src/assets/player/playlist/playlist-menu-item.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import videojs from 'video.js' | 1 | import videojs from 'video.js' |
2 | import { secondsToTime } from '@shared/core-utils' | ||
2 | import { VideoPlaylistElement } from '@shared/models' | 3 | import { VideoPlaylistElement } from '@shared/models' |
3 | import { PlaylistItemOptions } from '../peertube-videojs-typings' | 4 | import { PlaylistItemOptions } from '../peertube-videojs-typings' |
4 | import { secondsToTime } from '../utils' | ||
5 | 5 | ||
6 | const Component = videojs.getComponent('Component') | 6 | const Component = videojs.getComponent('Component') |
7 | 7 | ||
diff --git a/client/src/assets/player/stats/stats-card.ts b/client/src/assets/player/stats/stats-card.ts index a93f59506..b271d0526 100644 --- a/client/src/assets/player/stats/stats-card.ts +++ b/client/src/assets/player/stats/stats-card.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import videojs from 'video.js' | 1 | import videojs from 'video.js' |
2 | import { secondsToTime } from '@shared/core-utils' | ||
2 | import { PlayerNetworkInfo as EventPlayerNetworkInfo } from '../peertube-videojs-typings' | 3 | import { PlayerNetworkInfo as EventPlayerNetworkInfo } from '../peertube-videojs-typings' |
3 | import { bytes, secondsToTime } from '../utils' | 4 | import { bytes } from '../utils' |
4 | 5 | ||
5 | interface StatsCardOptions extends videojs.ComponentOptions { | 6 | interface StatsCardOptions extends videojs.ComponentOptions { |
6 | videoUUID: string | 7 | videoUUID: string |
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index eb9302493..f0a1b1aee 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Video, VideoFile, VideoPlaylist } from '@shared/models' | ||
2 | import { escapeHTML } from '@shared/core-utils/renderer' | 1 | import { escapeHTML } from '@shared/core-utils/renderer' |
2 | import { VideoFile } from '@shared/models' | ||
3 | 3 | ||
4 | function toTitleCase (str: string) { | 4 | function toTitleCase (str: string) { |
5 | return str.charAt(0).toUpperCase() + str.slice(1) | 5 | return str.charAt(0).toUpperCase() + str.slice(1) |
@@ -43,144 +43,9 @@ function isMobile () { | |||
43 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) | 43 | return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) |
44 | } | 44 | } |
45 | 45 | ||
46 | function buildPlaylistLink (playlist: Pick<VideoPlaylist, 'shortUUID'>, base?: string) { | ||
47 | return (base ?? window.location.origin) + '/w/p/' + playlist.shortUUID | ||
48 | } | ||
49 | |||
50 | function buildVideoLink (video: Pick<Video, 'shortUUID'>, base?: string) { | ||
51 | return (base ?? window.location.origin) + '/w/' + video.shortUUID | ||
52 | } | ||
53 | |||
54 | function buildPlaylistEmbedLink (playlist: Pick<VideoPlaylist, 'uuid'>, base?: string) { | ||
55 | return (base ?? window.location.origin) + '/video-playlists/embed/' + playlist.uuid | ||
56 | } | ||
57 | |||
58 | function buildVideoEmbedLink (video: Pick<Video, 'uuid'>, base?: string) { | ||
59 | return (base ?? window.location.origin) + '/videos/embed/' + video.uuid | ||
60 | } | ||
61 | |||
62 | function decorateVideoLink (options: { | ||
63 | url: string | ||
64 | |||
65 | startTime?: number | ||
66 | stopTime?: number | ||
67 | |||
68 | subtitle?: string | ||
69 | |||
70 | loop?: boolean | ||
71 | autoplay?: boolean | ||
72 | muted?: boolean | ||
73 | |||
74 | // Embed options | ||
75 | title?: boolean | ||
76 | warningTitle?: boolean | ||
77 | controls?: boolean | ||
78 | peertubeLink?: boolean | ||
79 | }) { | ||
80 | const { url } = options | ||
81 | |||
82 | const params = generateParams(window.location.search) | ||
83 | |||
84 | if (options.startTime !== undefined && options.startTime !== null) { | ||
85 | const startTimeInt = Math.floor(options.startTime) | ||
86 | params.set('start', secondsToTime(startTimeInt)) | ||
87 | } | ||
88 | |||
89 | if (options.stopTime) { | ||
90 | const stopTimeInt = Math.floor(options.stopTime) | ||
91 | params.set('stop', secondsToTime(stopTimeInt)) | ||
92 | } | ||
93 | |||
94 | if (options.subtitle) params.set('subtitle', options.subtitle) | ||
95 | |||
96 | if (options.loop === true) params.set('loop', '1') | ||
97 | if (options.autoplay === true) params.set('autoplay', '1') | ||
98 | if (options.muted === true) params.set('muted', '1') | ||
99 | if (options.title === false) params.set('title', '0') | ||
100 | if (options.warningTitle === false) params.set('warningTitle', '0') | ||
101 | if (options.controls === false) params.set('controls', '0') | ||
102 | if (options.peertubeLink === false) params.set('peertubeLink', '0') | ||
103 | |||
104 | return buildUrl(url, params) | ||
105 | } | ||
106 | |||
107 | function decoratePlaylistLink (options: { | ||
108 | url: string | ||
109 | |||
110 | playlistPosition?: number | ||
111 | }) { | ||
112 | const { url } = options | ||
113 | |||
114 | const params = generateParams(window.location.search) | ||
115 | |||
116 | if (options.playlistPosition) params.set('playlistPosition', '' + options.playlistPosition) | ||
117 | |||
118 | return buildUrl(url, params) | ||
119 | } | ||
120 | |||
121 | function buildUrl (url: string, params: URLSearchParams) { | ||
122 | let hasParams = false | ||
123 | params.forEach(() => hasParams = true) | ||
124 | |||
125 | if (hasParams) return url + '?' + params.toString() | ||
126 | |||
127 | return url | ||
128 | } | ||
129 | |||
130 | function generateParams (url: string) { | ||
131 | const params = new URLSearchParams(window.location.search) | ||
132 | // Unused parameters in embed | ||
133 | params.delete('videoId') | ||
134 | params.delete('resume') | ||
135 | |||
136 | return params | ||
137 | } | ||
138 | |||
139 | function timeToInt (time: number | string) { | ||
140 | if (!time) return 0 | ||
141 | if (typeof time === 'number') return time | ||
142 | |||
143 | const reg = /^((\d+)[h:])?((\d+)[m:])?((\d+)s?)?$/ | ||
144 | const matches = time.match(reg) | ||
145 | |||
146 | if (!matches) return 0 | ||
147 | |||
148 | const hours = parseInt(matches[2] || '0', 10) | ||
149 | const minutes = parseInt(matches[4] || '0', 10) | ||
150 | const seconds = parseInt(matches[6] || '0', 10) | ||
151 | |||
152 | return hours * 3600 + minutes * 60 + seconds | ||
153 | } | ||
154 | |||
155 | function secondsToTime (seconds: number, full = false, symbol?: string) { | ||
156 | let time = '' | ||
157 | |||
158 | if (seconds === 0 && !full) return '0s' | ||
159 | |||
160 | const hourSymbol = (symbol || 'h') | ||
161 | const minuteSymbol = (symbol || 'm') | ||
162 | const secondsSymbol = full ? '' : 's' | ||
163 | |||
164 | const hours = Math.floor(seconds / 3600) | ||
165 | if (hours >= 1) time = hours + hourSymbol | ||
166 | else if (full) time = '0' + hourSymbol | ||
167 | |||
168 | seconds %= 3600 | ||
169 | const minutes = Math.floor(seconds / 60) | ||
170 | if (minutes >= 1 && minutes < 10 && full) time += '0' + minutes + minuteSymbol | ||
171 | else if (minutes >= 1) time += minutes + minuteSymbol | ||
172 | else if (full) time += '00' + minuteSymbol | ||
173 | |||
174 | seconds %= 60 | ||
175 | if (seconds >= 1 && seconds < 10 && full) time += '0' + seconds + secondsSymbol | ||
176 | else if (seconds >= 1) time += seconds + secondsSymbol | ||
177 | else if (full) time += '00' | ||
178 | |||
179 | return time | ||
180 | } | ||
181 | |||
182 | function buildVideoOrPlaylistEmbed (embedUrl: string, embedTitle: string) { | 46 | function buildVideoOrPlaylistEmbed (embedUrl: string, embedTitle: string) { |
183 | const title = escapeHTML(embedTitle) | 47 | const title = escapeHTML(embedTitle) |
48 | |||
184 | return '<iframe width="560" height="315" ' + | 49 | return '<iframe width="560" height="315" ' + |
185 | 'sandbox="allow-same-origin allow-scripts allow-popups" ' + | 50 | 'sandbox="allow-same-origin allow-scripts allow-popups" ' + |
186 | 'title="' + title + '" ' + | 51 | 'title="' + title + '" ' + |
@@ -229,17 +94,8 @@ function getRtcConfig () { | |||
229 | export { | 94 | export { |
230 | getRtcConfig, | 95 | getRtcConfig, |
231 | toTitleCase, | 96 | toTitleCase, |
232 | timeToInt, | ||
233 | secondsToTime, | ||
234 | isWebRTCDisabled, | 97 | isWebRTCDisabled, |
235 | 98 | ||
236 | buildPlaylistLink, | ||
237 | buildVideoLink, | ||
238 | decorateVideoLink, | ||
239 | decoratePlaylistLink, | ||
240 | buildPlaylistEmbedLink, | ||
241 | buildVideoEmbedLink, | ||
242 | |||
243 | buildVideoOrPlaylistEmbed, | 99 | buildVideoOrPlaylistEmbed, |
244 | videoFileMaxByResolution, | 100 | videoFileMaxByResolution, |
245 | videoFileMinByResolution, | 101 | videoFileMinByResolution, |
diff --git a/client/src/assets/player/videojs-components/peertube-link-button.ts b/client/src/assets/player/videojs-components/peertube-link-button.ts index f47c165d9..9267b2ed4 100644 --- a/client/src/assets/player/videojs-components/peertube-link-button.ts +++ b/client/src/assets/player/videojs-components/peertube-link-button.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import videojs from 'video.js' | 1 | import videojs from 'video.js' |
2 | import { buildVideoLink, decorateVideoLink } from '@shared/core-utils' | ||
2 | import { PeerTubeLinkButtonOptions } from '../peertube-videojs-typings' | 3 | import { PeerTubeLinkButtonOptions } from '../peertube-videojs-typings' |
3 | import { buildVideoLink, decorateVideoLink } from '../utils' | ||
4 | 4 | ||
5 | const Button = videojs.getComponent('Button') | 5 | const Button = videojs.getComponent('Button') |
6 | class PeerTubeLinkButton extends Button { | 6 | class PeerTubeLinkButton extends Button { |
diff --git a/client/src/assets/player/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/webtorrent/webtorrent-plugin.ts index b648b29e8..17d369c10 100644 --- a/client/src/assets/player/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/webtorrent/webtorrent-plugin.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | import videojs from 'video.js' | 1 | import videojs from 'video.js' |
2 | import * as WebTorrent from 'webtorrent' | 2 | import * as WebTorrent from 'webtorrent' |
3 | import { renderVideo } from './video-renderer' | 3 | import { timeToInt } from '@shared/core-utils' |
4 | import { LoadedQualityData, PlayerNetworkInfo, WebtorrentPluginOptions } from '../peertube-videojs-typings' | 4 | import { VideoFile } from '@shared/models' |
5 | import { getRtcConfig, timeToInt, videoFileMaxByResolution, videoFileMinByResolution, isIOS, isSafari } from '../utils' | ||
6 | import { PeertubeChunkStore } from './peertube-chunk-store' | ||
7 | import { | 5 | import { |
8 | getAverageBandwidthInStore, | 6 | getAverageBandwidthInStore, |
9 | getStoredMute, | 7 | getStoredMute, |
@@ -11,7 +9,10 @@ import { | |||
11 | getStoredVolume, | 9 | getStoredVolume, |
12 | saveAverageBandwidth | 10 | saveAverageBandwidth |
13 | } from '../peertube-player-local-storage' | 11 | } from '../peertube-player-local-storage' |
14 | import { VideoFile } from '@shared/models' | 12 | import { LoadedQualityData, PlayerNetworkInfo, WebtorrentPluginOptions } from '../peertube-videojs-typings' |
13 | import { getRtcConfig, isIOS, videoFileMaxByResolution, videoFileMinByResolution } from '../utils' | ||
14 | import { PeertubeChunkStore } from './peertube-chunk-store' | ||
15 | import { renderVideo } from './video-renderer' | ||
15 | 16 | ||
16 | const CacheChunkStore = require('cache-chunk-store') | 17 | const CacheChunkStore = require('cache-chunk-store') |
17 | 18 | ||