이 스크립트는 직접 설치하는 용도가 아닙니다. 다른 스크립트에서 메타 지시문 // @require https://update.greatest.deepsurf.us/scripts/432003/967900/UserscriptAPIWeb.js
을(를) 사용하여 포함하는 라이브러리입니다.
줄 바꿈
/** * UserscriptAPIWeb * * 依赖于 `UserscriptAPI`。 * * 需要通过 `@grant` 引入 `GM_xmlhttpRequest` 或 `GM_download`。 * @version 1.0.0.20210906 * @author Laster2800 * @see {@link https://gitee.com/liangjiancang/userscript/tree/master/lib/UserscriptAPI UserscriptAPI} */ class UserscriptAPIWeb { /** * @param {UserscriptAPI} api `UserscriptAPI` */ constructor ( api ) { this . api = api } /** * @typedef {XMLHttpRequest} GM_XHR GM 定义的类 `XMLHttpRequest` 对象 */ /** * 发起网络请求,获取 `GM_XHR` * @param {Object} details 定义及细节类似于 `GM_xmlhttpRequest` `details` * @param {'GET' | 'HEAD' | 'POST'} [details.method='GET'] `METHOD` * @param {string} [details.url] `URL` * @param {number} [details.timeout] 超时时间 * @param {(xhr: GM_XHR) => void} [details.ontimeout] 超时回调 * @param {(xhr: GM_XHR) => void} [details.onerror] 错误回调 * @param {(xhr: GM_XHR) => void} [details.onload] 加载回调 * @param {string | URLSearchParams | FormData} [details.data] `DATA` * @param {Object} [options] 选项 * @param {(xhr: GM_XHR) => boolean} [options.check] 检查 `GM_XHR` 是否符合条件 * @param {boolean} [options.throwOnFailed = true] 失败时是否抛出异常,否则打印错误信息 * @returns {Promise<GM_XHR>} `GM_XHR` * @throws 等待超时、达成终止条件、等待错误时抛出 * @see {@link https://www.tampermonkey.net/documentation.php#GM_xmlhttpRequest GM_xmlhttpRequest} */ async requestXHR ( details , options ) { if ( details ) { const api = this . api const { check , throwOnFailed = true } = options ?? {} return new Promise (( resolve , reject ) => { if ( details . data && details . data instanceof URLSearchParams ) { details . data = details . data . toString () details . headers = { 'content-type' : 'application/x-www-form-urlencoded' , ... details . headers , } if ( GM_info . scriptHandler == 'Violentmonkey' && ! details . headers . origin ) { details . headers . origin = '' } } details . ontimeout ??= xhr => fail ([ 'TIMEOUT' , 'request' , details , xhr ]) details . onerror ??= xhr => fail ([ 'ERROR' , 'request' , details , xhr ]) details . onload ??= xhr => { if ( check && ! check ( xhr )) { fail ([ 'CHECK-FAIL' , 'request' , details , check , xhr ]) if ( throwOnFailed ) return } resolve ( xhr ) } GM_xmlhttpRequest ( details ) function fail ( msg ) { throwOnFailed ? reject ( msg ) : api . logger . error ( msg ) } }) } } /** * 发起网络请求,获取解析结果 * @param {Object} details 定义及细节类似于 `GM_xmlhttpRequest` `details` * @param {'GET' | 'HEAD' | 'POST'} [details.method='GET'] `METHOD` * @param {string} [details.url] `URL` * @param {number} [details.timeout] 超时时间 * @param {(xhr: GM_XHR) => void} [details.ontimeout] 超时回调 * @param {(xhr: GM_XHR) => void} [details.onerror] 错误回调 * @param {(xhr: GM_XHR) => void} [details.onload] 加载回调 * @param {string | URLSearchParams | FormData} [details.data] `DATA` * @param {Object} [options] 选项 * @param {'json' | 'check' | 'silentCheck'} [options.parser='json'] ```plaintext * json: 返回 JSON.parse(resp) * check: 返回 check(resp, xhr),检查失败时打印信息 * silentCheck: 返回 check(resp, xhr),检查失败时不打印信息 * ``` * @param {(resp: Object, xhr: GM_XHR) => boolean} [options.check] 检查 `GM_XHR` 是否符合条件 * @param {boolean} [options.throwOnFailed=true] 失败时是否抛出异常,否则打印错误信息 * @returns {Promise<Object>} 解析结果 * @see {@link https://www.tampermonkey.net/documentation.php#GM_xmlhttpRequest GM_xmlhttpRequest} */ async request ( details , options ) { const api = this . api const { parser = 'json' , check , throwOnFailed = true } = options ?? {} try { const xhr = await this . requestXHR ( details ) let resp = null try { resp = JSON . parse ( xhr . response ) } catch ( e ) { fail ([ 'PARSE' , 'request' , details , xhr ]) return null } const checkResult = ! check || check ( resp , xhr ) if ( parser == 'silentCheck' ) { return checkResult } else if ( parser == 'check' ) { if (! checkResult ) { api . logger . error ([ 'CHECK-FAIL' , 'request' , details , check , resp , xhr ]) } return checkResult } else { if (! checkResult ) { fail ([ 'CHECK-FAIL' , 'request' , details , check , resp , xhr ]) } return resp } } catch ( e ) { fail ( e ) } function fail ( msg ) { if ( throwOnFailed ) { throw msg } else { api . logger . error ( msg ) } } } /** * 下载资源 * @param {Object} details 定义及细节同 `GM_download` `details` * @returns {() => void} 用于终止下载的方法 * @see {@link https://www.tampermonkey.net/documentation.php#GM_download GM_download} */ download ( details ) { if ( details ) { const api = this . api try { const cfg = { ... details } let name = cfg . name if ( name . indexOf ( '.' ) >= 0 ) { let parts = cfg . url . split ( '/' ) const last = parts [ parts . length - 1 ]. split ( '?' )[ 0 ] if ( last . indexOf ( '.' ) >= 0 ) { parts = last . split ( '.' ) name = ` $ { name }. $ { parts [ parts . length - 1 ]}` } else { name = name . replaceAll ( '.' , '_' ) } cfg . name = name } if (! cfg . onerror ) { cfg . onerror = function ( error , details ) { api . logger . error ( 'DOWNLOAD ERROR' ) api . logger . error ([ error , details ]) } } if (! cfg . ontimeout ) { cfg . ontimeout = function () { api . logger . error ( 'DOWNLOAD TIMEOUT' ) } } GM_download ( cfg ) } catch ( e ) { api . logger . error ( 'DOWNLOAD ERROR' ) api . logger . error ( e ) } } return () => {} } /** * 判断给定 URL 是否匹配 * @param {RegExp | RegExp[]} reg 用于判断是否匹配的正则表达式,或正则表达式数组 * @param {'SINGLE' | 'AND' | 'OR'} [mode='SINGLE'] 匹配模式 * @returns {boolean} 是否匹配 */ urlMatch ( reg , mode = 'SINGLE' ) { let result = false const href = location . href if ( mode == 'SINGLE' ) { if ( reg instanceof Array ) { if ( reg . length > 0 ) { reg = reg [ 0 ] } else { reg = null } } if ( reg ) { result = reg . test ( href ) } } else { if (!( reg instanceof Array )) { reg = [ reg ] } if ( reg . length > 0 ) { if ( mode == 'AND' ) { result = true for ( const r of reg ) { if (! r . test ( href )) { result = false break } } } else if ( mode == 'OR' ) { for ( const r of reg ) { if ( r . test ( href )) { result = true break } } } } } return result } } /* global UserscriptAPI */ { UserscriptAPI . registerModule ( 'web' , UserscriptAPIWeb ) }