]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/assets/player/utils.ts
Add ability to share playlists in modal
[github/Chocobozzz/PeerTube.git] / client / src / assets / player / utils.ts
1 import { VideoFile } from '@shared/models'
2
3 function toTitleCase (str: string) {
4 return str.charAt(0).toUpperCase() + str.slice(1)
5 }
6
7 function isWebRTCDisabled () {
8 return !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false
9 }
10
11 function isIOS () {
12 if (/iPad|iPhone|iPod/.test(navigator.platform)) {
13 return true
14 }
15
16 // Detect iPad Desktop mode
17 return !!(navigator.maxTouchPoints &&
18 navigator.maxTouchPoints > 2 &&
19 /MacIntel/.test(navigator.platform))
20 }
21
22 function isSafari () {
23 return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
24 }
25
26 // https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
27 // Don't import all Angular stuff, just copy the code with shame
28 const dictionaryBytes: Array<{max: number, type: string}> = [
29 { max: 1024, type: 'B' },
30 { max: 1048576, type: 'KB' },
31 { max: 1073741824, type: 'MB' },
32 { max: 1.0995116e12, type: 'GB' }
33 ]
34 function bytes (value: number) {
35 const format = dictionaryBytes.find(d => value < d.max) || dictionaryBytes[dictionaryBytes.length - 1]
36 const calc = Math.floor(value / (format.max / 1024)).toString()
37
38 return [ calc, format.type ]
39 }
40
41 function isMobile () {
42 return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
43 }
44
45 function buildVideoLink (options: {
46 baseUrl?: string
47
48 startTime?: number
49 stopTime?: number
50
51 subtitle?: string
52
53 loop?: boolean
54 autoplay?: boolean
55 muted?: boolean
56
57 // Embed options
58 title?: boolean
59 warningTitle?: boolean
60 controls?: boolean
61 peertubeLink?: boolean
62 } = {}) {
63 const { baseUrl } = options
64
65 const url = baseUrl
66 ? baseUrl
67 : window.location.origin + window.location.pathname.replace('/embed/', '/watch/')
68
69 const params = generateParams(window.location.search)
70
71 if (options.startTime) {
72 const startTimeInt = Math.floor(options.startTime)
73 params.set('start', secondsToTime(startTimeInt))
74 }
75
76 if (options.stopTime) {
77 const stopTimeInt = Math.floor(options.stopTime)
78 params.set('stop', secondsToTime(stopTimeInt))
79 }
80
81 if (options.subtitle) params.set('subtitle', options.subtitle)
82
83 if (options.loop === true) params.set('loop', '1')
84 if (options.autoplay === true) params.set('autoplay', '1')
85 if (options.muted === true) params.set('muted', '1')
86 if (options.title === false) params.set('title', '0')
87 if (options.warningTitle === false) params.set('warningTitle', '0')
88 if (options.controls === false) params.set('controls', '0')
89 if (options.peertubeLink === false) params.set('peertubeLink', '0')
90
91 return buildUrl(url, params)
92 }
93
94 function buildPlaylistLink (options: {
95 baseUrl?: string
96
97 playlistPosition: number
98 }) {
99 const { baseUrl } = options
100
101 const url = baseUrl
102 ? baseUrl
103 : window.location.origin + window.location.pathname.replace('/video-playlists/embed/', '/videos/watch/playlist/')
104
105 const params = generateParams(window.location.search)
106
107 if (options.playlistPosition) params.set('playlistPosition', '' + options.playlistPosition)
108
109 return buildUrl(url, params)
110 }
111
112 function buildUrl (url: string, params: URLSearchParams) {
113 let hasParams = false
114 params.forEach(() => hasParams = true)
115
116 if (hasParams) return url + '?' + params.toString()
117
118 return url
119 }
120
121 function generateParams (url: string) {
122 const params = new URLSearchParams(window.location.search)
123 // Unused parameters in embed
124 params.delete('videoId')
125 params.delete('resume')
126
127 return params
128 }
129
130 function timeToInt (time: number | string) {
131 if (!time) return 0
132 if (typeof time === 'number') return time
133
134 const reg = /^((\d+)[h:])?((\d+)[m:])?((\d+)s?)?$/
135 const matches = time.match(reg)
136
137 if (!matches) return 0
138
139 const hours = parseInt(matches[2] || '0', 10)
140 const minutes = parseInt(matches[4] || '0', 10)
141 const seconds = parseInt(matches[6] || '0', 10)
142
143 return hours * 3600 + minutes * 60 + seconds
144 }
145
146 function secondsToTime (seconds: number, full = false, symbol?: string) {
147 let time = ''
148
149 const hourSymbol = (symbol || 'h')
150 const minuteSymbol = (symbol || 'm')
151 const secondsSymbol = full ? '' : 's'
152
153 const hours = Math.floor(seconds / 3600)
154 if (hours >= 1) time = hours + hourSymbol
155 else if (full) time = '0' + hourSymbol
156
157 seconds %= 3600
158 const minutes = Math.floor(seconds / 60)
159 if (minutes >= 1 && minutes < 10 && full) time += '0' + minutes + minuteSymbol
160 else if (minutes >= 1) time += minutes + minuteSymbol
161 else if (full) time += '00' + minuteSymbol
162
163 seconds %= 60
164 if (seconds >= 1 && seconds < 10 && full) time += '0' + seconds + secondsSymbol
165 else if (seconds >= 1) time += seconds + secondsSymbol
166 else if (full) time += '00'
167
168 return time
169 }
170
171 function buildVideoOrPlaylistEmbed (embedUrl: string) {
172 return '<iframe width="560" height="315" ' +
173 'sandbox="allow-same-origin allow-scripts allow-popups" ' +
174 'src="' + embedUrl + '" ' +
175 'frameborder="0" allowfullscreen>' +
176 '</iframe>'
177 }
178
179 function copyToClipboard (text: string) {
180 const el = document.createElement('textarea')
181 el.value = text
182 el.setAttribute('readonly', '')
183 el.style.position = 'absolute'
184 el.style.left = '-9999px'
185 document.body.appendChild(el)
186 el.select()
187 document.execCommand('copy')
188 document.body.removeChild(el)
189 }
190
191 function videoFileMaxByResolution (files: VideoFile[]) {
192 let max = files[0]
193
194 for (let i = 1; i < files.length; i++) {
195 const file = files[i]
196 if (max.resolution.id < file.resolution.id) max = file
197 }
198
199 return max
200 }
201
202 function videoFileMinByResolution (files: VideoFile[]) {
203 let min = files[0]
204
205 for (let i = 1; i < files.length; i++) {
206 const file = files[i]
207 if (min.resolution.id > file.resolution.id) min = file
208 }
209
210 return min
211 }
212
213 function getRtcConfig () {
214 return {
215 iceServers: [
216 {
217 urls: 'stun:stun.stunprotocol.org'
218 },
219 {
220 urls: 'stun:stun.framasoft.org'
221 }
222 ]
223 }
224 }
225
226 // ---------------------------------------------------------------------------
227
228 export {
229 getRtcConfig,
230 toTitleCase,
231 timeToInt,
232 secondsToTime,
233 isWebRTCDisabled,
234 buildPlaylistLink,
235 buildVideoLink,
236 buildVideoOrPlaylistEmbed,
237 videoFileMaxByResolution,
238 videoFileMinByResolution,
239 copyToClipboard,
240 isMobile,
241 bytes,
242 isIOS,
243 isSafari
244 }