// ==UserScript== // @name b站视频导出markdown文件 // @namespace https://bbs.tampermonkey.net.cn/ // @version 0.2.0 // @description 用于大模型RAG // @author 口吃者 // @match https://www.bilibili.com/video/* // @require https://scriptcat.org/lib/2691/1.0.0/sweetalert2.all.min-11.15.10.js // @require https://scriptcat.org/lib/2724/1.0.0/js%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8E%8B%E7%BC%A9%E5%BA%93-LZString.js // @grant GM.setValue // @grant GM.getValue // @grant GM.deleteValue // @grant unsafeWindow // @grant GM_xmlhttpRequest // @run-at document-body // @license MIT // ==/UserScript== (async function () { 'use strict'; class RequestMonitor { constructor() { // 预编译正则表达式提升匹配性能 this._patterns = new Map(); // Map // 使用WeakMap防止内存泄漏 this.pendingRequests = new WeakMap(); // 缓存已验证的URL this._urlCache = { monitored: new Set(), ignored: new Set() }; // 性能统计 this.stats = { total: 0, processed: 0, errors: 0 }; this._initHooks(); } /* pattern:正则表达式(只要满足其一就会进行监听处理),processor:处理器函数(对满足的每一个pattern进行processor处理,一对多) */ registerHandler(pattern, processor) { const regex = new RegExp(pattern); this._patterns.set(regex, processor); return this; // 支持链式调用 } _initHooks() { // 保存原生方法引用 const nativeFetch = unsafeWindow.fetch; const nativeXHROpen = XMLHttpRequest.prototype.open; const nativeXHRSend = XMLHttpRequest.prototype.send; const self = this; // Hook XHR open方法捕获URL XMLHttpRequest.prototype.open = function (method, url) { this._requestURL = url; return nativeXHROpen.apply(this, arguments); }; // Hook XHR send XMLHttpRequest.prototype.send = function (body) { const xhr = this; const url = xhr._requestURL || ''; // 前置检查 if (!self._shouldMonitor(url)) { return nativeXHRSend.apply(this, arguments); } const requestKey = {}; self.pendingRequests.set(xhr, requestKey); self.stats.total++; // 添加事件监听 xhr.addEventListener('load', () => self._handleXHRResponse(xhr, requestKey)); xhr.addEventListener('error', () => self._cleanup(xhr)); nativeXHRSend.apply(this, arguments); }; // Hook Fetch unsafeWindow.fetch = async (input, init) => { const url = typeof input === 'string' ? input : input.url; if (!self._shouldMonitor(url)) { return nativeFetch(input, init); } const requestKey = {}; self.pendingRequests.set(requestKey, true); self.stats.total++; try { const response = await nativeFetch(input, init); self._handleFetchResponse(url, response.clone(), requestKey); return response; } catch (error) { self.stats.errors++; self._cleanup(requestKey); throw error; } }; } _shouldMonitor(url) { if (this._urlCache.monitored.has(url)) return true; if (this._urlCache.ignored.has(url)) return false; for (const [regex] of this._patterns) { if (regex.test(url)) { this._urlCache.monitored.add(url); return true; } } this._urlCache.ignored.add(url); return false; } async _handleXHRResponse(xhr, requestKey) { try { const data = await this._parseResponse(xhr.response); await this._processData(xhr._requestURL, data); this.stats.processed++; } catch (error) { this.stats.errors++; console.error('XHR处理失败:', error); } finally { this._cleanup(xhr); } } async _handleFetchResponse(url, response, requestKey) { try { const data = await this._parseResponse(await response.text()); await this._processData(url, data); this.stats.processed++; } catch (error) { this.stats.errors++; console.error('Fetch处理失败:', error); } finally { this._cleanup(requestKey); } } async _processData(url, rawData) { for (const [regex, processor] of this._patterns) { if (regex.test(url)) { await processor(rawData); break; // 仅匹配第一个处理器 } } } async _parseResponse(data) { try { return JSON.parse(data); } catch { return data; } } _cleanup(target) { this.pendingRequests.delete(target); // 定期清理缓存防止内存增长 if (this._urlCache.monitored.size > 1000) { this._urlCache.monitored.clear(); } } // 调试方法 printStats() { console.table({ '总请求数': this.stats.total, '已处理请求': this.stats.processed, '当前挂起请求': this.pendingRequests.size, '错误数量': this.stats.errors, '缓存命中率': `${(this.stats.processed / this.stats.total * 100).toFixed(1)}%` }); } } // storage-manager.js class StorageManager { constructor(options = {}) { // 配置参数 this.namespace = options.namespace || 'defaultStorage'; this.chunkSize = options.chunkSize || 500; // 每个分片最大记录数 this.maxChunks = options.maxChunks || 10; // 最大保留分片数 this.autoCleanThreshold = options.autoCleanThreshold || 5 * 1024 * 1024; // 5MB自动清理阈值 this.compression = options.compression !== false; // 默认启用压缩 明确设置为 false 时,this.compression 才会被设置为 false // 状态跟踪 this.currentChunk = 1; this.totalRecords = 0; this.lastCleanTime = 0; } // ======================== 核心接口 ======================== // 静态工厂方法 static async createInstance(options = {}) { const instance = new StorageManager(options); await instance.init(); return instance; } /* 状态跟踪属性赋值 */ async init() { await this._loadIndex(); return this; } async save(data) { // 1. 获取当前分片 let chunk = await this._getCurrentChunk(); // 2. 检查分片容量 if (chunk.length >= this.chunkSize) { // 更新状态跟踪属性 await this._rotateChunk(); chunk = []; } // 3. 添加数据 chunk.push(data); this.totalRecords++; // 4. 保存分片 await this._saveChunk(chunk); // 5. 自动清理检查 // await this._autoCleanCheck(); } async loadAll() { const chunks = []; for (let i = 1; i <= this.maxChunks; i++) { const chunk = await this._getChunk(i); if (chunk) chunks.push(...chunk); } // return this._deduplicate(chunks); return chunks; } async clear() { for (let i = 1; i <= this.maxChunks; i++) { await GM.deleteValue(this._chunkKey(i)); } await this._saveIndex({ currentChunk: 1, totalRecords: 0 }); } // ======================== 内部方法 ======================== async _loadIndex() { const index = await GM.getValue(this._indexKey(), '{}'); const { currentChunk = 1, totalRecords = 0 } = JSON.parse(index); this.currentChunk = currentChunk; this.totalRecords = totalRecords; } async _saveIndex() { const index = JSON.stringify({ currentChunk: this.currentChunk, totalRecords: this.totalRecords, lastCleanTime: this.lastCleanTime }); await GM.setValue(this._indexKey(), index); } async _getCurrentChunk() { return await this._getChunk(this.currentChunk) || []; } async _rotateChunk() { this.currentChunk = (this.currentChunk % this.maxChunks) + 1; await this._saveIndex(); } async _saveChunk(chunk) { const data = this.compression ? LZString.compressToUTF16(JSON.stringify(chunk)) : JSON.stringify(chunk); await GM.setValue( this._chunkKey(this.currentChunk), data ); } async _getChunk(number) { const data = await GM.getValue(this._chunkKey(number)); if (!data) return null; try { return JSON.parse( this.compression ? LZString.decompressFromUTF16(data) : data ); } catch (e) { console.error('分片数据解析失败:', e); return null; } } async _autoCleanCheck() { // 按时间清理(每10分钟) if (Date.now() - this.lastCleanTime > 600_000) { await this.cleanOldChunks(); return; } // 按容量清理 const size = await this._estimateStorageSize(); if (size > this.autoCleanThreshold) { await this.cleanOldChunks(); this.maxChunks = Math.max(3, Math.floor(this.maxChunks * 0.8)); } } async cleanOldChunks() { const oldest = this.currentChunk > this.maxChunks ? this.currentChunk - this.maxChunks : 1; for (let i = 1; i <= oldest; i++) { await GM.deleteValue(this._chunkKey(i)); } this.lastCleanTime = Date.now(); await this._saveIndex(); } async _estimateStorageSize() { let total = 0; for (let i = 1; i <= this.maxChunks; i++) { const data = await GM.getValue(this._chunkKey(i)); total += data ? data.length : 0; } return total; } _deduplicate(data) { const seen = new Set(); return data.filter(item => { const key = item.id || JSON.stringify(item); return seen.has(key) ? false : seen.add(key); }); } // ======================== 工具方法 ======================== _indexKey() { return `${this.namespace}_index`; } _chunkKey(number) { return `${this.namespace}_chunk_${number}`; } // ======================== 调试接口 ======================== async printStats() { const size = await this._estimateStorageSize(); console.log(`[StorageManager 状态报告] 命名空间: ${this.namespace} 当前分片: ${this.currentChunk}/${this.maxChunks} 总记录数: ${this.totalRecords} 预估存储: ${(size / 1024).toFixed(1)}KB 最后清理: ${new Date(this.lastCleanTime).toLocaleTimeString()} 压缩状态: ${this.compression ? '启用' : '关闭'} `); } } class BExportTool { constructor({videoTitle, videoAuthor, videoIntro, videoSubtitle, videoComments}) { this.videoTitle = videoTitle; this.videoAuthor = videoAuthor; this.videoIntro = videoIntro; this.videoSubtitle = videoSubtitle; this.videoComments = videoComments; } // 新增 Markdown 导出方法 exportDsMarkdownData() { // 注意方法名驼峰式命名 if (!this.markdownData) { console.error('No Markdown data to export'); return; } // 创建标准 Markdown Blob(指定 MIME 类型) const blob = new Blob([this.markdownData], { type: 'text/markdown;charset=utf-8' // 或使用 text/plain }); // 生成带时间戳的文件名(示例:chat_history_12345_20230815.md) const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, ''); const filename = `Bilibili_${timestamp}.md`; // 创建并触发下载链接 const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; anchor.style.display = 'none'; document.body.appendChild(anchor); anchor.click(); // 清理资源 document.body.removeChild(anchor); URL.revokeObjectURL(url); } toMarkdown() { // 处理标题和作者 const titleSection = `## ${this.videoTitle}`; const authorSection = `作者 ${this.videoAuthor}`; // 处理视频简介 const introSection = `### 视频简介\n${this.videoIntro}`; // 处理视频文案 const subtitleSection = `### 视频文案\n${this.videoSubtitle}`; // 处理评论部分 const commentItems = this.videoComments.map((comment, index) => { return `${index + 1}. 用户名:${comment.author}\n 点赞数${comment.likes}\n 评论内容:${comment.content}`; }).join('\n'); const commentSection = `### 评论\n${commentItems}`; this.markdownData = [ titleSection, authorSection, introSection, subtitleSection, commentSection ].join('\n'); // 合并所有部分 return this.markdownData; } } const storageComment = await StorageManager.createInstance({ namespace: 'commentData', chunkSize: 1000, maxChunks: 20 }); const monitorTest = new RequestMonitor(); var commentRpId = new Set(); var videoDetails = { videoTitle: '', videoIntroduction: '', upName: '' }; var fetchPageParams; //补环境参数 var ct = "wbi_img_urls"; var e = { "oid": "113402018078283", "type": 1, "mode": 3, "pagination_str": "{\"offset\":\"{\\\"type\\\":1,\\\"direction\\\":1,\\\"data\\\":{\\\"pn\\\":2}}\"}", "plat": 1, "web_location": 1315875 }; monitorTest.registerHandler('x/v2/reply/wbi/main', async data => { try { //是否第一次获取评论 判断StorageManager的totalRecords是否为0 if (storageComment.totalRecords === 0) { let hasMatch = Array.from(monitorTest._urlCache.monitored).filter(element => element.includes('x/v2/reply/wbi/main')); fetchPageParams = getUrlComponent(hasMatch[0]); let pagination_str = { offset: data.data.cursor.pagination_reply.next_offset }; fetchPageParams["pagination_str"] = JSON.stringify(pagination_str); e["pagination_str"] = JSON.stringify(pagination_str); e["oid"] = fetchPageParams["oid"]; e["web_location"] = fetchPageParams['web_location']; var ltFucRes = lt(e); fetchPageParams["w_rid"] = ltFucRes["w_rid"]; fetchPageParams["wts"] = ltFucRes["wts"]; } const replies = data.data.replies; for (let i = 0; i < replies.length; i++) { const reply = replies[i]; const rpId = reply.rpid; const rpContent = reply.content.message; const rpName = reply.member.uname; const rpLike = reply.like; if (commentRpId.has(rpId)) { continue; } await storageComment.save({ "author": rpName, "content": rpContent, "likes": rpLike }); commentRpId.add(rpId); } } catch (e) { console.log(e); } }); monitorTest.registerHandler('x/player/wbi/v2', async data => { try { await GM.deleteValue('subTitleUrl'); await GM.setValue('subTitleUrl', data.data.subtitle.subtitles[0].subtitle_url); } catch (e) { console.log(e); } }); window.addEventListener('load', addPanel); window.addEventListener('load', async () => { // 重置所有值 await storageComment.clear(); videoDetails.videoIntroduction = document.querySelector('#v_desc > div > span')?.textContent; videoDetails.upName = removeSpacesAndNewlines(document.querySelector('div.up-detail-top > a.up-name')?.textContent); videoDetails.videoTitle = document.querySelector('#viewbox_report > div.video-info-title > div > h1')?.textContent; }); function addPanel() { function genButton(text, foo, id, fooParams = {}) { let b = document.createElement('button'); b.textContent = text; b.style.verticalAlign = 'inherit'; // 使用箭头函数创建闭包来保存 fooParams 并传递给 foo b.addEventListener('click', () => { foo.call(b, ...Object.values(fooParams)); // 使用 call 方法确保 this 指向按钮对象 }); if (id) { b.id = id }; return b; } function changeRangeDynamics() { const value = parseInt(this.value, 10); // 只能通过 DOM 方法改变 document.querySelector('#swal-range > output').textContent = value; } async function openPanelFunc() { var swalRangeValue = 20; const { value: formValues } = await Swal.fire({ title: "Select Number", showCancelButton: true, draggable: true, cancelButtonText: 'cancel', confirmButtonText: 'export', confirmButtonColor: "#FFD700", cancelButtonColor: "#8FBC8F", //class="swal2-range" swalalert框架可能会对其有特殊处理,导致其内标签的id声明失效 html: `
${swalRangeValue}
`, focusConfirm: false, didOpen: async () => { const swalRange = document.querySelector('#swal-range input'); const commentsNumber = document.querySelector('#swal2-html-container>ul>li:nth-child(1)>i'); const ifSubtitle = document.querySelector('#swal2-html-container>ul>li:nth-child(2)>i'); const subtitleUrl = await GM.getValue('subTitleUrl', ''); commentsNumber.textContent = storageComment.totalRecords; ifSubtitle.textContent = subtitleUrl ? 'yes' : 'no'; swalRange.addEventListener('input', changeRangeDynamics); }, willClose: () => { // 在关闭前清除事件监听器以防止内存泄漏 const swalRange = document.querySelector('#swal-range input'); swalRange.removeEventListener('input', changeRangeDynamics); }, preConfirm: () => { swalRangeValue = document.querySelector('#swal-range > output').textContent; return [ swalRangeValue ]; } }); if (formValues) { getAllCommentsAndExport(formValues[0]); } } let myButton = genButton('BExport', openPanelFunc, 'BExport'); document.body.appendChild(myButton); var css_text = ` #BExport { position: fixed; color: rgb(211, 67, 235); top: 30%; left: -20px;/* 初始状态下左半部分隐藏 */ transform: translateY(-50%); z-index: 1000; /* 确保按钮在最前面 */ padding: 10px 24px; border-radius: 5px; cursor: pointer; border: 0; background-color: white; box-shadow: rgb(0 0 0 / 5%) 0 0 8px; letter-spacing: 1.5px; text-transform: uppercase; font-size: 9px; transition: all 0.5s ease; } #BExport:hover { left: 0%; /* 鼠标悬停时完整显示 */ letter-spacing: 3px; background-image: linear-gradient(to top, #fad0c4 0%, #fad0c4 1%, #ffd1ff 100%); box-shadow: rgba(211, 67, 235, 0.7) 0px 7px 29px 0px; /* 更柔和的紫色阴影,带透明度 */ } #BExport:active { letter-spacing: 3px; background-image: linear-gradient(to top, #fad0c4 0%, #fad0c4 1%, #ffd1ff 100%); box-shadow: rgba(211, 67, 235, 0.5) 0px 0px 0px 0px; /* 活动状态下的阴影,保持一致性 */ transition: 100ms; } ` GMaddStyle(css_text); } function GMaddStyle(css) { var myStyle = document.createElement('style'); myStyle.textContent = css; var doc = document.head || document.documentElement; doc.appendChild(myStyle); } function removeSpacesAndNewlines(str) { // 使用正则表达式匹配所有空格和换行符,并替换为空字符串 return str.replace(/[\s\r\n]+/g, ''); } async function fetchNextPageData(comment_params) { const finalUrl = getFinalCommentUrl(comment_params); const response = await fetch(finalUrl, { headers: { 'origin': 'https://www.bilibili.com' }, credentials: 'include' // 明确指定携带cookies }); return await response.json(); } async function fetchSubtitle() { const subtitleUrl = await GM.getValue('subTitleUrl', ''); if (subtitleUrl) { const response = await fetch('https://' + subtitleUrl, { headers: { 'origin': 'https://www.bilibili.com' }, credentials: 'include' // 明确指定携带cookies }); return response.json(); } else { return ''; } } function sendGetRequestWithGM(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url: url, headers: { 'Content-Type': 'application/json' }, onload: function (response) { resolve(JSON.parse(response.responseText)); }, onerror: function (error) { reject(error); } }); }); } function getFinalCommentUrl(params) { // 指定参数的顺序 const orderKeys = ["oid", "type", "mode", "plat", "web_location", "pagination_str", "w_rid", "wts"]; // 按照指定顺序构建参数列表 const orderedParams = orderKeys .filter(key => params.hasOwnProperty(key)) .map(key => key === 'pagination_str' ? `${key}=${encodeURIComponent(params[key])}` : `${key}=${params[key]}`); // 构建新的URL const newUrl = 'https://api.bilibili.com/x/v2/reply/wbi/main?' + orderedParams.join('&'); return newUrl; }; function getUrlComponent(targetUrl) { // 提取查询字符串部分 const queryString = targetUrl.split('?')[1]; // 定义正则表达式来匹配参数 const regex = /([^&=]+)=([^&]*)/g; // 创建一个对象来存储参数 const params = {}; let match; while ((match = regex.exec(queryString)) !== null) { const key = decodeURIComponent(match[1]); const value = decodeURIComponent(match[2]); params[key] = value; } return params; }; function extractContentsToString(dataArray) { return dataArray .map(item => item.content || '') // 安全提取content,防止undefined .join(';'); // 默认用空字符串连接,可按需改为换行符\n或其他分隔符 } async function getAllCommentsAndExport(targetAmount) { try { while (storageComment.totalRecords < targetAmount) { const commentData = await fetchNextPageData(fetchPageParams); const replies = commentData.data.replies; if (!replies || replies.length === 0) { break; } for (let i = 0; i < replies.length; i++) { const reply = replies[i]; const rpId = reply.rpid; const rpContent = reply.content.message; const rpName = reply.member.uname; const rpLike = reply.like; if (commentRpId.has(rpId)) { continue; } await storageComment.save({ "author": rpName, "content": rpContent, "likes": rpLike }); commentRpId.add(rpId); } } const subtitleUrl = await GM.getValue('subTitleUrl', ''); let subtitleData; if (subtitleUrl) { let subtitleDataJson = await sendGetRequestWithGM('https://' + subtitleUrl); subtitleData = extractContentsToString(subtitleDataJson.body); } const videoComments = await storageComment.loadAll(); const bExportTool = new BExportTool({ "videoTitle": videoDetails.videoTitle, "videoAuthor": videoDetails.upName, "videoIntro": videoDetails.videoIntroduction, "videoSubtitle": subtitleData, "videoComments": videoComments }); bExportTool.toMarkdown(); bExportTool.exportDsMarkdownData(); } catch (error) { console.error('Error:', error); } } /* 补环境 */ const t_stringToBytes = function (e) { return n_stringToBytes(unescape(encodeURIComponent(e))) }; const n_stringToBytes = function (e) { for (var t = [], r = 0; r < e.length; r++) t.push(255 & e.charCodeAt(r)); return t }; const e_bytesToWords = function (e) { for (var t = [], r = 0, n = 0; r < e.length; r++, n += 8) t[n >>> 5] |= e[r] << 24 - n % 32; return t }; const o_ff = function (e, t, r, n, o, i, a) { var u = e + (t & r | ~t & n) + (o >>> 0) + a; return (u << i | u >>> 32 - i) + t }; const o_gg = function (e, t, r, n, o, i, a) { var u = e + (t & n | r & ~n) + (o >>> 0) + a; return (u << i | u >>> 32 - i) + t }; const o_hh = function (e, t, r, n, o, i, a) { var u = e + (t ^ r ^ n) + (o >>> 0) + a; return (u << i | u >>> 32 - i) + t }; const o_ii = function (e, t, r, n, o, i, a) { var u = e + (r ^ (t | ~n)) + (o >>> 0) + a; return (u << i | u >>> 32 - i) + t }; const t_rotl = function (e, t) { return e << t | e >>> 32 - t }; const e_endian = function (e) { if (e.constructor == Number) return 16711935 & t_rotl(e, 8) | 4278255360 & t_rotl(e, 24); for (var r = 0; r < e.length; r++) e[r] = e_endian(e[r]); return e }; const o = function o(i, a) { i.constructor == String ? i = a && "binary" === a.encoding ? n_stringToBytes(i) : t_stringToBytes(i) : r(i) ? i = Array.prototype.slice.call(i, 0) : Array.isArray(i) || i.constructor === Uint8Array || (i = i.toString()); for (var u = e_bytesToWords(i), s = 8 * i.length, c = 1732584193, l = -271733879, f = -1732584194, d = 271733878, p = 0; p < u.length; p++) u[p] = 16711935 & (u[p] << 8 | u[p] >>> 24) | 4278255360 & (u[p] << 24 | u[p] >>> 8); u[s >>> 5] |= 128 << s % 32, u[14 + (s + 64 >>> 9 << 4)] = s; var h = o_ff , y = o_gg , v = o_hh , b = o_ii; for (p = 0; p < u.length; p += 16) { var m = c , w = l , g = f , x = d; c = h(c, l, f, d, u[p + 0], 7, -680876936), d = h(d, c, l, f, u[p + 1], 12, -389564586), f = h(f, d, c, l, u[p + 2], 17, 606105819), l = h(l, f, d, c, u[p + 3], 22, -1044525330), c = h(c, l, f, d, u[p + 4], 7, -176418897), d = h(d, c, l, f, u[p + 5], 12, 1200080426), f = h(f, d, c, l, u[p + 6], 17, -1473231341), l = h(l, f, d, c, u[p + 7], 22, -45705983), c = h(c, l, f, d, u[p + 8], 7, 1770035416), d = h(d, c, l, f, u[p + 9], 12, -1958414417), f = h(f, d, c, l, u[p + 10], 17, -42063), l = h(l, f, d, c, u[p + 11], 22, -1990404162), c = h(c, l, f, d, u[p + 12], 7, 1804603682), d = h(d, c, l, f, u[p + 13], 12, -40341101), f = h(f, d, c, l, u[p + 14], 17, -1502002290), c = y(c, l = h(l, f, d, c, u[p + 15], 22, 1236535329), f, d, u[p + 1], 5, -165796510), d = y(d, c, l, f, u[p + 6], 9, -1069501632), f = y(f, d, c, l, u[p + 11], 14, 643717713), l = y(l, f, d, c, u[p + 0], 20, -373897302), c = y(c, l, f, d, u[p + 5], 5, -701558691), d = y(d, c, l, f, u[p + 10], 9, 38016083), f = y(f, d, c, l, u[p + 15], 14, -660478335), l = y(l, f, d, c, u[p + 4], 20, -405537848), c = y(c, l, f, d, u[p + 9], 5, 568446438), d = y(d, c, l, f, u[p + 14], 9, -1019803690), f = y(f, d, c, l, u[p + 3], 14, -187363961), l = y(l, f, d, c, u[p + 8], 20, 1163531501), c = y(c, l, f, d, u[p + 13], 5, -1444681467), d = y(d, c, l, f, u[p + 2], 9, -51403784), f = y(f, d, c, l, u[p + 7], 14, 1735328473), c = v(c, l = y(l, f, d, c, u[p + 12], 20, -1926607734), f, d, u[p + 5], 4, -378558), d = v(d, c, l, f, u[p + 8], 11, -2022574463), f = v(f, d, c, l, u[p + 11], 16, 1839030562), l = v(l, f, d, c, u[p + 14], 23, -35309556), c = v(c, l, f, d, u[p + 1], 4, -1530992060), d = v(d, c, l, f, u[p + 4], 11, 1272893353), f = v(f, d, c, l, u[p + 7], 16, -155497632), l = v(l, f, d, c, u[p + 10], 23, -1094730640), c = v(c, l, f, d, u[p + 13], 4, 681279174), d = v(d, c, l, f, u[p + 0], 11, -358537222), f = v(f, d, c, l, u[p + 3], 16, -722521979), l = v(l, f, d, c, u[p + 6], 23, 76029189), c = v(c, l, f, d, u[p + 9], 4, -640364487), d = v(d, c, l, f, u[p + 12], 11, -421815835), f = v(f, d, c, l, u[p + 15], 16, 530742520), c = b(c, l = v(l, f, d, c, u[p + 2], 23, -995338651), f, d, u[p + 0], 6, -198630844), d = b(d, c, l, f, u[p + 7], 10, 1126891415), f = b(f, d, c, l, u[p + 14], 15, -1416354905), l = b(l, f, d, c, u[p + 5], 21, -57434055), c = b(c, l, f, d, u[p + 12], 6, 1700485571), d = b(d, c, l, f, u[p + 3], 10, -1894986606), f = b(f, d, c, l, u[p + 10], 15, -1051523), l = b(l, f, d, c, u[p + 1], 21, -2054922799), c = b(c, l, f, d, u[p + 8], 6, 1873313359), d = b(d, c, l, f, u[p + 15], 10, -30611744), f = b(f, d, c, l, u[p + 6], 15, -1560198380), l = b(l, f, d, c, u[p + 13], 21, 1309151649), c = b(c, l, f, d, u[p + 4], 6, -145523070), d = b(d, c, l, f, u[p + 11], 10, -1120210379), f = b(f, d, c, l, u[p + 2], 15, 718787259), l = b(l, f, d, c, u[p + 9], 21, -343485551), c = c + m >>> 0, l = l + w >>> 0, f = f + g >>> 0, d = d + x >>> 0 } return e_endian([c, l, f, d]) }; function ft(e) { return e.substring(e.lastIndexOf("/") + 1, e.length).split(".")[0] }; const e_wordsToBytes = function (e) { for (var t = [], r = 0; r < 32 * e.length; r += 8) t.push(e[r >>> 5] >>> 24 - r % 32 & 255); return t }; const e_bytesToHex = function (e) { for (var t = [], r = 0; r < e.length; r++) t.push((e[r] >>> 4).toString(16)), t.push((15 & e[r]).toString(16)); return t.join("") }; const at = function (t, r) { if (null == t) throw new Error("Illegal argument " + t); var i = e_wordsToBytes(o(t, r)); return r && r.asBytes ? i : r && r.asString ? n.bytesToString(i) : e_bytesToHex(i) }; function lt(e) { var t, r, n = function (e) { var t; if (e.useAssignKey) return { imgKey: e.wbiImgKey, subKey: e.wbiSubKey }; var r = (null === (t = function (e) { try { return localStorage.getItem(e) } catch (e) { return null } }(ct)) || void 0 === t ? void 0 : t.split("-")) || [] , n = r[0] , o = r[1] , i = n ? ft(n) : e.wbiImgKey , a = o ? ft(o) : e.wbiSubKey; return { imgKey: i, subKey: a } }(arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : { wbiImgKey: "", wbiSubKey: "" }), o = n.imgKey, i = n.subKey; if (o && i) { for (var a = (t = o + i, r = [], [46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52].forEach((function (e) { t.charAt(e) && r.push(t.charAt(e)) } )), r.join("").slice(0, 32)), u = Math.round(Date.now() / 1e3), s = Object.assign({}, e, { wts: u }), c = Object.keys(s).sort(), l = [], f = /[!'()*]/g, d = 0; d < c.length; d++) { var p = c[d] , h = s[p]; h && "string" == typeof h && (h = h.replace(f, "")), null != h && l.push("".concat(encodeURIComponent(p), "=").concat(encodeURIComponent(h))) } var y = l.join("&"); return { w_rid: at(y + a), wts: u.toString() } } return null }; })();