2019-11-03 19:13:06 +00:00
|
|
|
|
2020-11-24 10:02:14 +00:00
|
|
|
import isNodeJs from 'detect-node'
|
2020-05-18 22:44:45 +00:00
|
|
|
|
2020-11-24 22:35:44 +00:00
|
|
|
export const escapeFilename = (s: string): string => {
|
|
|
|
return s.replace(/[\s<>:{}"/\\|?*~.\0\cA-\cZ]+/g, '_')
|
|
|
|
}
|
|
|
|
|
2020-05-17 22:57:28 +00:00
|
|
|
export const getIndexPath = (id: number): string => {
|
|
|
|
const idStr = String(id)
|
|
|
|
// 获取最后三位,倒序排列
|
|
|
|
// x, y, z are the reversed last digits of the score id. Example: id 123456789, x = 9, y = 8, z = 7
|
|
|
|
// https://developers.musescore.com/#/file-urls
|
|
|
|
// "5449062" -> ["2", "6", "0"]
|
|
|
|
const indexN = idStr.split('').reverse().slice(0, 3)
|
|
|
|
return indexN.join('/')
|
2019-11-03 19:13:06 +00:00
|
|
|
}
|
2019-11-29 23:07:43 +00:00
|
|
|
|
2020-11-29 22:27:29 +00:00
|
|
|
const NODE_FETCH_HEADERS = {
|
|
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0',
|
|
|
|
'Accept-Language': 'en-US,en;q=0.8',
|
|
|
|
}
|
|
|
|
|
2020-11-24 10:02:14 +00:00
|
|
|
export const getFetch = (): typeof fetch => {
|
|
|
|
if (!isNodeJs) {
|
|
|
|
return fetch
|
|
|
|
} else {
|
2020-11-29 22:27:29 +00:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
|
|
const nodeFetch = require('node-fetch')
|
|
|
|
return (input: RequestInfo, init?: RequestInit) => {
|
|
|
|
init = Object.assign({ headers: NODE_FETCH_HEADERS }, init)
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
|
|
return nodeFetch(input, init)
|
|
|
|
}
|
2020-11-24 10:02:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 05:39:38 +00:00
|
|
|
export const fetchData = async (url: string, init?: RequestInit): Promise<Uint8Array> => {
|
|
|
|
const r = await fetch(url, init)
|
|
|
|
const data = await r.arrayBuffer()
|
|
|
|
return new Uint8Array(data)
|
|
|
|
}
|
|
|
|
|
2020-11-21 05:38:10 +00:00
|
|
|
export const assertRes = (r: Response): void => {
|
|
|
|
if (!r.ok) throw new Error(`${r.url} ${r.status} ${r.statusText}`)
|
|
|
|
}
|
|
|
|
|
2020-11-13 05:54:20 +00:00
|
|
|
export const useTimeout = async <T> (promise: T | Promise<T>, ms: number): Promise<T> => {
|
|
|
|
if (!(promise instanceof Promise)) {
|
|
|
|
return promise
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const i = setTimeout(() => {
|
|
|
|
reject(new Error('timeout'))
|
|
|
|
}, ms)
|
|
|
|
promise.then(resolve, reject).finally(() => clearTimeout(i))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-27 17:11:34 +00:00
|
|
|
export const getSandboxWindowAsync = async (targetEl: Element | undefined = undefined): Promise<Window> => {
|
2020-11-26 18:04:04 +00:00
|
|
|
if (typeof document === 'undefined') return {} as any as Window
|
|
|
|
|
2020-11-27 17:11:34 +00:00
|
|
|
if (!targetEl) {
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
// You need ads in your pages, right?
|
|
|
|
const observer = new MutationObserver(() => {
|
|
|
|
for (let i = 0; i < window.frames.length; i++) {
|
|
|
|
// find iframe windows created by ads
|
|
|
|
const frame = frames[i]
|
|
|
|
try {
|
|
|
|
const href = frame.location.href
|
|
|
|
if (href === location.href || href === 'about:blank') {
|
|
|
|
resolve(frame)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
} catch { }
|
|
|
|
}
|
|
|
|
})
|
|
|
|
observer.observe(document.body, { subtree: true, childList: true })
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-26 18:04:04 +00:00
|
|
|
return new Promise((resolve) => {
|
2020-11-26 19:18:41 +00:00
|
|
|
const eventName = 'onmousemove'
|
|
|
|
const id = Math.random().toString()
|
|
|
|
|
2020-11-26 19:21:19 +00:00
|
|
|
targetEl[id] = (iframe: HTMLIFrameElement) => {
|
|
|
|
delete targetEl[id]
|
2020-11-26 19:18:41 +00:00
|
|
|
targetEl.removeAttribute(eventName)
|
|
|
|
|
2020-11-26 18:04:04 +00:00
|
|
|
iframe.style.display = 'none'
|
2020-11-26 19:18:41 +00:00
|
|
|
targetEl.append(iframe)
|
2020-11-26 18:04:04 +00:00
|
|
|
const w = iframe.contentWindow
|
|
|
|
resolve(w as Window)
|
|
|
|
}
|
2020-11-26 19:18:41 +00:00
|
|
|
|
2020-11-26 19:21:19 +00:00
|
|
|
targetEl.setAttribute(eventName, `this['${id}'](document.createElement('iframe'))`)
|
2020-11-26 18:04:04 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-11-26 02:06:35 +00:00
|
|
|
export const getUnsafeWindow = (): Window => {
|
|
|
|
// eslint-disable-next-line no-eval
|
|
|
|
return window.eval('window') as Window
|
2020-11-13 20:55:41 +00:00
|
|
|
}
|
|
|
|
|
2020-11-26 04:57:39 +00:00
|
|
|
export const console: Console = (window || global).console // Object.is(window.console, unsafeWindow.console) == false
|
2020-11-23 19:37:11 +00:00
|
|
|
|
2020-11-27 17:11:34 +00:00
|
|
|
export const windowOpenAsync = (targetEl: Element | undefined, ...args: Parameters<Window['open']>): Promise<Window | null> => {
|
2020-11-27 07:51:23 +00:00
|
|
|
return getSandboxWindowAsync(targetEl).then(w => w.open(...args))
|
2020-11-26 02:06:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export const attachShadow = (el: Element): ShadowRoot => {
|
|
|
|
return Element.prototype.attachShadow.call(el, { mode: 'closed' }) as ShadowRoot
|
2020-11-13 20:55:41 +00:00
|
|
|
}
|
|
|
|
|
2019-11-29 23:07:43 +00:00
|
|
|
export const waitForDocumentLoaded = (): Promise<void> => {
|
2020-05-17 22:57:28 +00:00
|
|
|
if (document.readyState !== 'complete') {
|
|
|
|
return new Promise(resolve => {
|
2020-10-23 14:46:45 +00:00
|
|
|
const cb = () => {
|
2020-05-17 22:57:28 +00:00
|
|
|
if (document.readyState === 'complete') {
|
|
|
|
resolve()
|
2020-10-23 14:46:45 +00:00
|
|
|
document.removeEventListener('readystatechange', cb)
|
2020-05-17 22:57:28 +00:00
|
|
|
}
|
2020-10-23 14:46:45 +00:00
|
|
|
}
|
|
|
|
document.addEventListener('readystatechange', cb)
|
2020-05-17 22:57:28 +00:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
return Promise.resolve()
|
|
|
|
}
|
2019-11-29 23:07:43 +00:00
|
|
|
}
|