]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/helpers/utils.ts
Fix live/upload redirection
[github/Chocobozzz/PeerTube.git] / client / src / app / helpers / utils.ts
CommitLineData
1fa23d6f 1import { first, map } from 'rxjs/operators'
21e493d4 2import { SelectChannelItem } from 'src/types/select-options-item.model'
61bbc727 3import { DatePipe } from '@angular/common'
d4132d3f
RK
4import { HttpErrorResponse } from '@angular/common/http'
5import { Notifier } from '@app/core'
c0e8b12e 6import { HttpStatusCode } from '@shared/models'
67ed6552
C
7import { environment } from '../../environments/environment'
8import { AuthService } from '../core/auth'
15a7387d 9
240458d0 10// Thanks: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
f3aaa9a9
C
11function getParameterByName (name: string, url: string) {
12 if (!url) url = window.location.href
9df52d66 13 name = name.replace(/[[\]]/g, '\\$&')
f3aaa9a9
C
14
15 const regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)')
16 const results = regex.exec(url)
17
18 if (!results) return null
19 if (!results[2]) return ''
20
21 return decodeURIComponent(results[2].replace(/\+/g, ' '))
22}
23
9556ce48
C
24function listUserChannels (authService: AuthService) {
25 return authService.userInformationLoaded
1fa23d6f
C
26 .pipe(
27 first(),
28 map(() => {
29 const user = authService.getUser()
30 if (!user) return undefined
9556ce48 31
1fa23d6f
C
32 const videoChannels = user.videoChannels
33 if (Array.isArray(videoChannels) === false) return undefined
9556ce48 34
1fa23d6f
C
35 return videoChannels
36 .sort((a, b) => {
37 if (a.updatedAt < b.updatedAt) return 1
38 if (a.updatedAt > b.updatedAt) return -1
39 return 0
40 })
41 .map(c => ({
42 id: c.id,
43 label: c.displayName,
44 support: c.support,
45 avatarPath: c.avatar?.path
46 }) as SelectChannelItem)
47 })
48 )
15a7387d
C
49}
50
c5911fd3 51function getAbsoluteAPIUrl () {
94148c90
C
52 let absoluteAPIUrl = environment.hmr === true
53 ? 'http://localhost:9000'
54 : environment.apiUrl
55
c5911fd3
C
56 if (!absoluteAPIUrl) {
57 // The API is on the same domain
58 absoluteAPIUrl = window.location.origin
59 }
60
61 return absoluteAPIUrl
62}
63
72493e44 64function getAbsoluteEmbedUrl () {
5beb89f2 65 let absoluteEmbedUrl = environment.originServerUrl
72493e44
C
66 if (!absoluteEmbedUrl) {
67 // The Embed is on the same domain
68 absoluteEmbedUrl = window.location.origin
69 }
70
71 return absoluteEmbedUrl
72}
73
61bbc727
C
74const datePipe = new DatePipe('en')
75function dateToHuman (date: string) {
76 return datePipe.transform(date, 'medium')
77}
78
11b8762f
C
79function durationToString (duration: number) {
80 const hours = Math.floor(duration / 3600)
81 const minutes = Math.floor((duration % 3600) / 60)
82 const seconds = duration % 60
83
84 const minutesPadding = minutes >= 10 ? '' : '0'
85 const secondsPadding = seconds >= 10 ? '' : '0'
86 const displayedHours = hours > 0 ? hours.toString() + ':' : ''
87
e66883b3
RK
88 return (
89 displayedHours + minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString()
90 ).replace(/^0/, '')
11b8762f
C
91}
92
0cd4344f
C
93function immutableAssign <A, B> (target: A, source: B) {
94 return Object.assign({}, target, source)
95}
96
6de36768
C
97// Thanks: https://gist.github.com/ghinda/8442a57f22099bdb2e34
98function objectToFormData (obj: any, form?: FormData, namespace?: string) {
c4710631 99 const fd = form || new FormData()
6de36768
C
100 let formKey
101
c4710631 102 for (const key of Object.keys(obj)) {
6de36768
C
103 if (namespace) formKey = `${namespace}[${key}]`
104 else formKey = key
105
106 if (obj[key] === undefined) continue
107
2efd32f6
C
108 if (Array.isArray(obj[key]) && obj[key].length === 0) {
109 fd.append(key, null)
110 continue
111 }
112
9df52d66
C
113 if (obj[key] !== null && typeof obj[key] === 'object' && !(obj[key] instanceof File)) {
114 objectToFormData(obj[key], fd, formKey)
6de36768 115 } else {
9df52d66 116 fd.append(formKey, obj[key])
6de36768
C
117 }
118 }
119
120 return fd
121}
122
1506307f 123function objectLineFeedToHtml (obj: any, keyToNormalize: string) {
5de8a55a 124 return immutableAssign(obj, {
1506307f 125 [keyToNormalize]: lineFeedToHtml(obj[keyToNormalize])
5de8a55a
C
126 })
127}
128
1506307f
C
129function lineFeedToHtml (text: string) {
130 if (!text) return text
131
132 return text.replace(/\r?\n|\r/g, '<br />')
133}
134
40e87e9e
C
135function removeElementFromArray <T> (arr: T[], elem: T) {
136 const index = arr.indexOf(elem)
137 if (index !== -1) arr.splice(index, 1)
138}
139
ad774752
C
140function sortBy (obj: any[], key1: string, key2?: string) {
141 return obj.sort((a, b) => {
142 const elem1 = key2 ? a[key1][key2] : a[key1]
143 const elem2 = key2 ? b[key1][key2] : b[key1]
144
145 if (elem1 < elem2) return -1
146 if (elem1 === elem2) return 0
147 return 1
148 })
149}
150
f3081d64
K
151function scrollToTop (behavior: 'auto' | 'smooth' = 'auto') {
152 window.scrollTo({
153 left: 0,
154 top: 0,
155 behavior
156 })
7373507f
C
157}
158
223b24e6
RK
159function isInViewport (el: HTMLElement) {
160 const bounding = el.getBoundingClientRect()
161 return (
9df52d66 162 bounding.top >= 0 &&
223b24e6
RK
163 bounding.left >= 0 &&
164 bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
165 bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
166 )
167}
168
169function isXPercentInViewport (el: HTMLElement, percentVisible: number) {
170 const rect = el.getBoundingClientRect()
171 const windowHeight = (window.innerHeight || document.documentElement.clientHeight)
172
173 return !(
174 Math.floor(100 - (((rect.top >= 0 ? 0 : rect.top) / +-(rect.height / 1)) * 100)) < percentVisible ||
175 Math.floor(100 - ((rect.bottom - windowHeight) / rect.height) * 100) < percentVisible
176 )
177}
178
f6d6e7f8 179function genericUploadErrorHandler (parameters: {
180 err: Pick<HttpErrorResponse, 'message' | 'status' | 'headers'>
d4132d3f
RK
181 name: string
182 notifier: Notifier
183 sticky?: boolean
184}) {
185 const { err, name, notifier, sticky } = { sticky: false, ...parameters }
186 const title = $localize`The upload failed`
187 let message = err.message
188
189 if (err instanceof ErrorEvent) { // network error
190 message = $localize`The connection was interrupted`
191 notifier.error(message, title, null, sticky)
f6d6e7f8 192 } else if (err.status === HttpStatusCode.INTERNAL_SERVER_ERROR_500) {
193 message = $localize`The server encountered an error`
194 notifier.error(message, title, null, sticky)
d4132d3f
RK
195 } else if (err.status === HttpStatusCode.REQUEST_TIMEOUT_408) {
196 message = $localize`Your ${name} file couldn't be transferred before the set timeout (usually 10min)`
197 notifier.error(message, title, null, sticky)
198 } else if (err.status === HttpStatusCode.PAYLOAD_TOO_LARGE_413) {
199 const maxFileSize = err.headers?.get('X-File-Maximum-Size') || '8G'
200 message = $localize`Your ${name} file was too large (max. size: ${maxFileSize})`
201 notifier.error(message, title, null, sticky)
202 } else {
203 notifier.error(err.message, title)
204 }
205
206 return message
207}
208
f3aaa9a9 209export {
ad774752 210 sortBy,
11b8762f 211 durationToString,
1506307f 212 lineFeedToHtml,
15a7387d 213 getParameterByName,
61bbc727
C
214 getAbsoluteAPIUrl,
215 dateToHuman,
6de36768 216 immutableAssign,
5de8a55a 217 objectToFormData,
72493e44 218 getAbsoluteEmbedUrl,
1506307f 219 objectLineFeedToHtml,
7373507f 220 removeElementFromArray,
223b24e6
RK
221 scrollToTop,
222 isInViewport,
d4132d3f 223 isXPercentInViewport,
9556ce48 224 listUserChannels,
f6d6e7f8 225 genericUploadErrorHandler
f3aaa9a9 226}