From 23ead56781707e4d10a329b8dffd4d0de6effdbb Mon Sep 17 00:00:00 2001 From: nanxun Date: Thu, 23 Apr 2026 23:18:11 +0800 Subject: [PATCH] feat: improve recording automation and task workflows --- .codex_tmp_danmaku/index.js | 7 - .codex_tmp_danmaku/probe.js | 80 -- .codex_tmp_danmaku/xbogus.js | 563 ----------- .dockerignore | 63 ++ .gitignore | 16 + ConsoleApp1/ConsoleApp1.csproj | 14 - ConsoleApp1/Program.cs | 40 - LiveRecorder.sln | 15 - docker-compose.yml | 34 + dycast_repo | 1 - frontend/.dockerignore | 3 + frontend/Dockerfile | 23 + frontend/nginx/default.conf | 39 + frontend/src/api/client.ts | 159 ++- frontend/src/components/layout/MainLayout.vue | 237 ++++- frontend/src/styles/main.css | 46 +- frontend/src/types.ts | 83 +- frontend/src/views/LiveRoomsView.vue | 904 ++++++++++++++--- frontend/src/views/LoginView.vue | 53 +- frontend/src/views/LogsView.vue | 124 ++- frontend/src/views/RecordTaskDetailView.vue | 172 +++- frontend/src/views/RecordTasksView.vue | 445 +++++++-- frontend/src/views/SettingsView.vue | 134 ++- .../Abstractions/Logging/ISystemLogService.cs | 1 + .../Persistence/PersistenceContracts.cs | 1 + .../Platforms/PlatformContracts.cs | 5 +- .../Abstractions/Recording/IFfmpegService.cs | 28 + .../Scripting/IEventScriptService.cs | 20 + .../Storage/IStorageGuardService.cs | 19 + .../Models/LiveRooms/LiveRoomModels.cs | 164 ++++ .../Models/RecordTasks/RecordTaskModels.cs | 6 + .../Models/Settings/SettingsModels.cs | 40 + .../LiveRoomRecordingSettingsResolver.cs | 89 ++ .../Services/LiveRoomService.cs | 366 ++++++- .../Services/LiveRoomStatusService.cs | 24 +- .../Services/RecordModelMapper.cs | 33 +- .../Services/RecordService.cs | 121 ++- .../Services/RecordSessionService.cs | 12 +- .../Services/SystemLogService.cs | 43 +- .../Services/SystemSettingsService.cs | 46 + src/LiveRecorder.Domain/Entities/LiveRoom.cs | 74 +- .../Entities/RecordTask.cs | 8 + .../Enums/RecordTaskStatus.cs | 3 +- .../Persistence/DatabaseInitializer.cs | 27 + .../Persistence/LiveRecorderDbContext.cs | 6 + .../Persistence/Repositories/Repositories.cs | 6 + .../Platforms/Bilibili/BilibiliHttpClient.cs | 800 +++++++++++++++ .../Bilibili/BilibiliLivePlatformAdapter.cs | 60 +- .../Platforms/Bilibili/BilibiliWbiSigner.cs | 136 +++ .../Danmaku/BilibiliDanmakuAdapter.cs | 279 ++++++ .../Danmaku/BilibiliDanmakuProtocol.cs | 395 ++++++++ .../Douyin/Danmaku/DouyinDanmakuAdapter.cs | 369 ++++++- .../Douyin/Danmaku/DouyinDanmakuProtocol.cs | 293 +++++- .../Platforms/Douyin/DouyinHttpClient.cs | 928 ++++++++++++++++-- .../Douyin/DouyinLivePlatformAdapter.cs | 93 +- .../Signing/DouyinLiveWsSignatureSigner.cs | 82 ++ .../Platforms/Douyin/Signing/mssdk.js | 2 + .../Platforms/Douyin/Signing/sign-livews.js | 163 +++ .../Services/EventScriptService.cs | 278 ++++++ .../Services/FfmpegService.Runtime.cs | 911 +++++++++++++++-- .../Services/FfmpegService.Utils.cs | 830 +++++++++++++++- .../Services/FfmpegService.cs | 385 +++++++- .../LiveRoomPollingBackgroundService.cs | 427 ++++++-- .../Services/RecordMediaService.cs | 4 +- .../Services/StorageGuardService.cs | 80 ++ .../Controllers/LiveRoomsController.cs | 37 + .../Controllers/LogsController.cs | 4 +- .../Controllers/RecordSessionsController.cs | 40 + .../Controllers/RecordTasksController.cs | 4 + src/LiveRecorder.WebApi/Dockerfile | 38 + .../ApiTokenAuthenticationMiddleware.cs | 17 + src/LiveRecorder.WebApi/Program.cs | 69 +- src/LiveRecorder.WebApi/live-recorder.db | Bin 352256 -> 0 bytes src/LiveRecorder.WebApi/live-recorder.db-shm | Bin 32768 -> 0 bytes src/LiveRecorder.WebApi/live-recorder.db-wal | Bin 1005312 -> 0 bytes ...五人格赛事_COA9小组赛Day6_24482384478_00001.xml | 3 - .../084002_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml | 3 - .../084717_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml | 3 - .../084924_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml | 3 - .../132847_Wd_Wd正在直播__00001.xml | 3 - .../100501_第五人格赛事_COA9小组赛Day6__00001.xml | 3 - .../061914_第五人格赛事_COA9小组赛Day7__00001.xml | 3 - .../071935_第五人格赛事_COA9小组赛Day7__00001.xml | 3 - .../092236_第五人格赛事_COA9小组赛Day6__00001.xml | 3 - .../092339_第五人格赛事_COA9小组赛Day6__00001.xml | 3 - .../114940_第五人格赛事_COA9小组赛Day6__00001.xml | 3 - .../115804_第五人格赛事_COA9小组赛Day6__00001.xml | 3 - ...浆(S邦邦)_百星S邦邦 娱乐主播!一把__00001.xml | 3 - 88 files changed, 9579 insertions(+), 1581 deletions(-) delete mode 100644 .codex_tmp_danmaku/index.js delete mode 100644 .codex_tmp_danmaku/probe.js delete mode 100644 .codex_tmp_danmaku/xbogus.js create mode 100644 .dockerignore delete mode 100644 ConsoleApp1/ConsoleApp1.csproj delete mode 100644 ConsoleApp1/Program.cs create mode 100644 docker-compose.yml delete mode 160000 dycast_repo create mode 100644 frontend/.dockerignore create mode 100644 frontend/Dockerfile create mode 100644 frontend/nginx/default.conf create mode 100644 src/LiveRecorder.Application/Abstractions/Scripting/IEventScriptService.cs create mode 100644 src/LiveRecorder.Application/Abstractions/Storage/IStorageGuardService.cs create mode 100644 src/LiveRecorder.Application/Services/LiveRoomRecordingSettingsResolver.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Bilibili/BilibiliHttpClient.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Bilibili/BilibiliWbiSigner.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Bilibili/Danmaku/BilibiliDanmakuAdapter.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Bilibili/Danmaku/BilibiliDanmakuProtocol.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Douyin/Signing/DouyinLiveWsSignatureSigner.cs create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Douyin/Signing/mssdk.js create mode 100644 src/LiveRecorder.Infrastructure/Platforms/Douyin/Signing/sign-livews.js create mode 100644 src/LiveRecorder.Infrastructure/Services/EventScriptService.cs create mode 100644 src/LiveRecorder.Infrastructure/Services/StorageGuardService.cs create mode 100644 src/LiveRecorder.WebApi/Dockerfile delete mode 100644 src/LiveRecorder.WebApi/live-recorder.db delete mode 100644 src/LiveRecorder.WebApi/live-recorder.db-shm delete mode 100644 src/LiveRecorder.WebApi/live-recorder.db-wal delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/2026-21-15/第五人格赛事/092132_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/2026-40-15/第五人格赛事/084002_第五人格赛事_COA9小组赛Day6_24482384478/084002_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/2026-47-15/第五人格赛事/084717_第五人格赛事_COA9小组赛Day6_24482384478/084717_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/2026-49-15/第五人格赛事/084924_第五人格赛事_COA9小组赛Day6_24482384478/084924_第五人格赛事_COA9小组赛Day6_24482384478_00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/Wd/2026-28-15/132847_Wd_Wd正在直播__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-05-15/100501_第五人格赛事_COA9小组赛Day6__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-19-16/061914_第五人格赛事_COA9小组赛Day7__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-19-16/071935_第五人格赛事_COA9小组赛Day7__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-22-15/092236_第五人格赛事_COA9小组赛Day6__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-23-15/092339_第五人格赛事_COA9小组赛Day6__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-49-15/114940_第五人格赛事_COA9小组赛Day6__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/第五人格赛事/2026-58-15/115804_第五人格赛事_COA9小组赛Day6__00001.xml delete mode 100644 src/LiveRecorder.WebApi/records/Douyin/豆浆(S邦邦)/2026-00-16/030005_豆浆(S邦邦)_百星S邦邦 娱乐主播!一把__00001.xml diff --git a/.codex_tmp_danmaku/index.js b/.codex_tmp_danmaku/index.js deleted file mode 100644 index d0769c3..0000000 --- a/.codex_tmp_danmaku/index.js +++ /dev/null @@ -1,7 +0,0 @@ -// index.js -const sign = require('./xbogus'); - -module.exports = function (url, userAgent) { - return sign(url.split("?")[1], userAgent); -}; - diff --git a/.codex_tmp_danmaku/probe.js b/.codex_tmp_danmaku/probe.js deleted file mode 100644 index 96fae88..0000000 --- a/.codex_tmp_danmaku/probe.js +++ /dev/null @@ -1,80 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const sqlite3 = require('node:sqlite'); -const https = require('https'); -const sign = require(path.join(process.argv[2], 'index.js')); -const db = new sqlite3.DatabaseSync(process.argv[3]); -const rows = db.prepare("select Key, Value from AppSettings where Key in ('douyin.cookie','douyin.user_agent')").all(); -const settings = Object.fromEntries(rows.map(r => [r.Key, r.Value])); -const webRid = '24482384478'; -function request(url, headers) { - return new Promise((resolve, reject) => { - https.get(url, { headers }, res => { - const chunks = []; - res.on('data', chunk => chunks.push(chunk)); - res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))); - }).on('error', reject); - }); -} -(async () => { - const headers = { - 'user-agent': settings['douyin.user_agent'] || 'Mozilla/5.0', - 'referer': `https://live.douyin.com/${webRid}`, - 'origin': 'https://live.douyin.com', - 'cookie': settings['douyin.cookie'] || '' - }; - const html = await request(`https://live.douyin.com/${webRid}`, headers); - const match = html.match(/self\.__pace_f\.push\(\[1,"[a-z]?:\[\\"\$\\",\\"\$L\d+\\",null,([\s\S]+?state[\s\S]+?)\]\\n"\]\)<\/script>/); - const json = match ? match[1].replace(/\\{1,7}"/g, '"') : ''; - const roomId = (json.match(/\"roomId\":\"(\d+)\"/) || [])[1]; - const uniqueId = '7300000000000000000'; - const msToken = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv'; - const params = new URLSearchParams({ - aid: '6383', - app_name: 'douyin_web', - browser_language: 'zh-CN', - browser_name: 'Mozilla', - browser_online: 'true', - browser_platform: 'Win32', - browser_version: settings['douyin.user_agent'] || 'Mozilla/5.0', - cookie_enabled: 'true', - cursor: '', - device_id: '', - device_platform: 'web', - did_rule: '3', - endpoint: 'live_pc', - fetch_rule: '1', - identity: 'audience', - insert_task_id: '', - internal_ext: '', - last_rtt: '0', - live_id: '1', - live_reason: '', - need_persist_msg_count: '15', - resp_content_type: 'protobuf', - screen_height: '1080', - screen_width: '1920', - support_wrds: '1', - tz_name: 'Asia/Shanghai', - version_code: '180800', - room_id: roomId, - user_unique_id: uniqueId, - live_pc: roomId, - msToken - }); - const rawQuery = params.toString(); - const xb = sign(`https://live.douyin.com/webcast/im/fetch/?${rawQuery}`, headers['user-agent']); - params.set('a_bogus', xb); - const url = `https://live.douyin.com/webcast/im/fetch/?${params.toString()}`; - const body = await new Promise((resolve, reject) => { - https.get(url, { headers: { ...headers, accept: 'application/protobuf, application/octet-stream, */*' } }, res => { - const chunks = []; - res.on('data', chunk => chunks.push(chunk)); - res.on('end', () => resolve(Buffer.concat(chunks))); - }).on('error', reject); - }); - console.log('ROOM_ID', roomId); - console.log('A_BOGUS_LEN', xb.length); - console.log('RESP_LEN', body.length); - console.log('RESP_HEAD', Array.from(body.subarray(0, 48))); -})(); diff --git a/.codex_tmp_danmaku/xbogus.js b/.codex_tmp_danmaku/xbogus.js deleted file mode 100644 index 044cab5..0000000 --- a/.codex_tmp_danmaku/xbogus.js +++ /dev/null @@ -1,563 +0,0 @@ -var window = null; - -function _0x5cd844(e) { - var b = { - exports: {} - }; - return e(b, b.exports), b.exports -} -jsvmp = function(e, b, a) { - function f(e, b, a) { - return (f = function() { - if ("undefined" == typeof Reflect || !Reflect.construct || Reflect.construct.sham) return !1; - if ("function" == typeof Proxy) return !0; - try { - return Date.prototype.toString.call(Reflect.construct(Date, [], function() {})), !0 - } catch (e) { - return !1 - } - }() ? Reflect.construct : function(e, b, a) { - var f = [null]; - f.push.apply(f, b); - var c = new(Function.bind.apply(e, f)); - return a && function(e, b) { - (Object.setPrototypeOf || function(e, b) { - return e.__proto__ = b, e - })(e, b) - }(c, a.prototype), c - }).apply(null, arguments) - } - - function c(e) { - return function(e) { - if (Array.isArray(e)) { - for (var b = 0, a = new Array(e.length); b < e.length; b++) a[b] = e[b]; - return a - } - }(e) || function(e) { - if (Symbol.iterator in Object(e) || "[object Arguments]" === Object.prototype.toString.call(e)) return Array.from(e) - }(e) || function() { - throw new TypeError("Invalid attempt to spread non-iterable instance") - }() - } - for (var r = [], t = 0, d = [], i = 0, n = function(e, b) { - var a = e[b++], - f = e[b], - c = parseInt("" + a + f, 16); - if (c >> 7 == 0) return [1, c]; - if (c >> 6 == 2) { - var r = parseInt("" + e[++b] + e[++b], 16); - return c &= 63, [2, r = (c <<= 8) + r] - } - if (c >> 6 == 3) { - var t = parseInt("" + e[++b] + e[++b], 16), - d = parseInt("" + e[++b] + e[++b], 16); - return c &= 63, [3, d = (c <<= 16) + (t <<= 8) + d] - } - }, s = function(e, b) { - var a = parseInt("" + e[b] + e[b + 1], 16); - return a > 127 ? -256 + a : a - }, o = function(e, b) { - var a = parseInt("" + e[b] + e[b + 1] + e[b + 2] + e[b + 3], 16); - return a > 32767 ? -65536 + a : a - }, l = function(e, b) { - var a = parseInt("" + e[b] + e[b + 1] + e[b + 2] + e[b + 3] + e[b + 4] + e[b + 5] + e[b + 6] + e[b + 7], 16); - return a > 2147483647 ? 0 + a : a - }, _ = function(e, b) { - return parseInt("" + e[b] + e[b + 1], 16) - }, x = function(e, b) { - return parseInt("" + e[b] + e[b + 1] + e[b + 2] + e[b + 3], 16) - }, u = u || this || window, h = (e.length, 0), p = "", y = h; y < h + 16; y++) { - var v = "" + e[y++] + e[y]; - v = parseInt(v, 16), p += String.fromCharCode(v) - } - if ("HNOJ@?RC" != p) throw new Error("error magic number " + p); - parseInt("" + e[h += 16] + e[h + 1], 16), h += 8, t = 0; - for (var g = 0; g < 4; g++) { - var w = h + 2 * g, - A = parseInt("" + e[w++] + e[w], 16); - t += (3 & A) << 2 * g - } - h += 16; - var C = parseInt("" + e[h += 8] + e[h + 1] + e[h + 2] + e[h + 3] + e[h + 4] + e[h + 5] + e[h + 6] + e[h + 7], 16), - m = C, - S = h += 8, - z = x(e, h += C); - z[1], h += 4, r = { - p: [], - q: [] - }; - for (var B = 0; B < z; B++) { - for (var R = n(e, h), q = h += 2 * R[0], I = r.p.length, k = 0; k < R[1]; k++) { - var j = n(e, q); - r.p.push(j[1]), q += 2 * j[0] - } - h = q, r.q.push([I, r.p.length]) - } - var O = { - 5: 1, - 6: 1, - 70: 1, - 22: 1, - 23: 1, - 37: 1, - 73: 1 - }, - U = { - 72: 1 - }, - D = { - 74: 1 - }, - N = { - 11: 1, - 12: 1, - 24: 1, - 26: 1, - 27: 1, - 31: 1 - }, - J = { - 10: 1 - }, - L = { - 2: 1, - 29: 1, - 30: 1, - 20: 1 - }, - T = [], - E = []; - - function M(e, b, a) { - for (var f = b; f < b + a;) { - var c = _(e, f); - T[f] = c, f += 2, U[c] ? (E[f] = s(e, f), f += 2) : O[c] ? (E[f] = o(e, f), f += 4) : D[c] ? (E[f] = l(e, f), f += 8) : N[c] ? (E[f] = _(e, f), f += 2) : J[c] ? (E[f] = x(e, f), f += 4) : L[c] && (E[f] = x(e, f), f += 4) - } - } - return F(e, S, m / 2, [], b, a); - - function P(e, b, a, n, h, p, y, v) { - null == p && (p = this); - var g, w, A, C, m = [], - S = 0; - y && (w = y); - var z, B, R = b, - q = R + 2 * a; - if (!v) - for (; R < q;) { - var I = parseInt("" + e[R] + e[R + 1], 16); - R += 2; - var j = 3 & (z = 13 * I % 241); - if (z >>= 2, j < 1) - if (j = 3 & z, z >>= 2, j < 1) { - if ((j = z) < 1) return [1, m[S--]]; - j < 5 ? (w = m[S--], m[S] = m[S] * w) : j < 7 ? (w = m[S--], m[S] = m[S] != w) : j < 14 ? (A = m[S--], C = m[S--], (j = m[S--]).x === P ? j.y >= 1 ? m[++S] = F(e, j.c, j.l, A, j.z, C, null, 1) : (m[++S] = F(e, j.c, j.l, A, j.z, C, null, 0), j.y++) : m[++S] = j.apply(C, A)) : j < 16 && (B = o(e, R), (g = function b() { - var a = arguments; - return b.y > 0 || b.y++, F(e, b.c, b.l, a, b.z, this, null, 0) - }).c = R + 4, g.l = B - 2, g.x = P, g.y = 0, g.z = h, m[S] = g, R += 2 * B - 2) - } else if (j < 2)(j = z) > 8 ? (w = m[S--], m[S] = typeof w) : j > 4 ? m[S -= 1] = m[S][m[S + 1]] : j > 2 && (A = m[S--], (j = m[S]).x === P ? j.y >= 1 ? m[S] = F(e, j.c, j.l, [A], j.z, C, null, 1) : (m[S] = F(e, j.c, j.l, [A], j.z, C, null, 0), j.y++) : m[S] = j(A)); - else if (j < 3) { - if ((j = z) < 9) { - for (w = m[S--], B = x(e, R), j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - R += 4, m[S--][j] = w - } else if (j < 13) throw m[S--] - } else(j = z) < 1 ? m[++S] = null : j < 3 ? (w = m[S--], m[S] = m[S] >= w) : j < 12 && (m[++S] = void 0); - else if (j < 2) - if (j = 3 & z, z >>= 2, j < 1) - if ((j = z) < 5) { - B = o(e, R); - try { - if (d[i][2] = 1, 1 == (w = P(e, R + 4, B - 3, [], h, p, null, 0))[0]) return w - } catch (b) { - if (d[i] && d[i][1] && 1 == (w = P(e, d[i][1][0], d[i][1][1], [], h, p, b, 0))[0]) return w - } finally { - if (d[i] && d[i][0] && 1 == (w = P(e, d[i][0][0], d[i][0][1], [], h, p, null, 0))[0]) return w; - d[i] = 0, i-- - } - R += 2 * B - 2 - } else j < 7 ? (B = _(e, R), R += 2, m[S -= B] = 0 === B ? new m[S] : f(m[S], c(m.slice(S + 1, S + B + 1)))) : j < 9 && (w = m[S--], m[S] = m[S] & w); - else if (j < 2) - if ((j = z) > 12) m[++S] = s(e, R), R += 2; - else if (j > 10) w = m[S--], m[S] = m[S] << w; - else if (j > 8) { - for (B = x(e, R), j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - R += 4, m[S] = m[S][j] - } else j > 6 && (A = m[S--], w = delete m[S--][A]); - else if (j < 3)(j = z) < 2 ? m[++S] = w : j < 11 ? (w = m[S -= 2][m[S + 1]] = m[S + 2], S--) : j < 13 && (w = m[S], m[++S] = w); - else if ((j = z) > 12) m[++S] = p; - else if (j > 5) w = m[S--], m[S] = m[S] !== w; - else if (j > 3) w = m[S--], m[S] = m[S] / w; - else if (j > 1) { - if ((B = o(e, R)) < 0) { - v = 1, M(e, b, 2 * a), R += 2 * B - 2; - break - } - R += 2 * B - 2 - } else j > -1 && (m[S] = !m[S]); - else if (j < 3) - if (j = 3 & z, z >>= 2, j < 1)(j = z) > 13 ? (m[++S] = o(e, R), R += 4) : j > 11 ? (w = m[S--], m[S] = m[S] >> w) : j > 9 ? (B = _(e, R), R += 2, w = m[S--], h[B] = w) : j > 7 ? (B = x(e, R), R += 4, A = S + 1, m[S -= B - 1] = B ? m.slice(S, A) : []) : j > 0 && (w = m[S--], m[S] = m[S] > w); - else if (j < 2)(j = z) > 12 ? (w = m[S - 1], A = m[S], m[++S] = w, m[++S] = A) : j > 3 ? (w = m[S--], m[S] = m[S] == w) : j > 1 ? (w = m[S--], m[S] = m[S] + w) : j > -1 && (m[++S] = u); - else if (j < 3) { - if ((j = z) > 13) m[++S] = !1; - else if (j > 6) w = m[S--], m[S] = m[S] instanceof w; - else if (j > 4) w = m[S--], m[S] = m[S] % w; - else if (j > 2) - if (m[S--]) R += 4; - else { - if ((B = o(e, R)) < 0) { - v = 1, M(e, b, 2 * a), R += 2 * B - 2; - break - } - R += 2 * B - 2 - } - else if (j > 0) { - for (B = x(e, R), w = "", k = r.q[B][0]; k < r.q[B][1]; k++) w += String.fromCharCode(t ^ r.p[k]); - m[++S] = w, R += 4 - } - } else(j = z) > 7 ? (w = m[S--], m[S] = m[S] | w) : j > 5 ? (B = _(e, R), R += 2, m[++S] = h["$" + B]) : j > 3 && (B = o(e, R), d[i][0] && !d[i][2] ? d[i][1] = [R + 4, B - 3] : d[i++] = [0, [R + 4, B - 3], 0], R += 2 * B - 2); - else if (j = 3 & z, z >>= 2, j > 2)(j = z) > 13 ? (m[++S] = l(e, R), R += 8) : j > 11 ? (w = m[S--], m[S] = m[S] >>> w) : j > 9 ? m[++S] = !0 : j > 7 ? (B = _(e, R), R += 2, m[S] = m[S][B]) : j > 0 && (w = m[S--], m[S] = m[S] < w); - else if (j > 1)(j = z) > 10 ? (B = o(e, R), d[++i] = [ - [R + 4, B - 3], 0, 0 - ], R += 2 * B - 2) : j > 8 ? (w = m[S--], m[S] = m[S] ^ w) : j > 6 && (w = m[S--]); - else if (j > 0) { - if ((j = z) > 7) w = m[S--], m[S] = m[S] in w; - else if (j > 5) m[S] = ++m[S]; - else if (j > 3) B = _(e, R), R += 2, w = h[B], m[++S] = w; - else if (j > 1) { - var O = 0, - U = m[S].length, - D = m[S]; - m[++S] = function() { - var e = O < U; - if (e) { - var b = D[O++]; - m[++S] = b - } - m[++S] = e - } - } - } else if ((j = z) > 13) w = m[S], m[S] = m[S - 1], m[S - 1] = w; - else if (j > 4) w = m[S--], m[S] = m[S] === w; - else if (j > 2) w = m[S--], m[S] = m[S] - w; - else if (j > 0) { - for (B = x(e, R), j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - j = +j, R += 4, m[++S] = j - } - } - if (v) - for (; R < q;) - if (I = T[R], R += 2, j = 3 & (z = 13 * I % 241), z >>= 2, j > 2) - if (j = 3 & z, z >>= 2, j > 2)(j = z) < 2 ? (w = m[S--], m[S] = m[S] < w) : j < 9 ? (B = E[R], R += 2, m[S] = m[S][B]) : j < 11 ? m[++S] = !0 : j < 13 ? (w = m[S--], m[S] = m[S] >>> w) : j < 15 && (m[++S] = E[R], R += 8); - else if (j > 1)(j = z) < 6 || (j < 8 ? w = m[S--] : j < 10 ? (w = m[S--], m[S] = m[S] ^ w) : j < 12 && (B = E[R], d[++i] = [ - [R + 4, B - 3], 0, 0 - ], R += 2 * B - 2)); - else if (j > 0)(j = z) > 7 ? (w = m[S--], m[S] = m[S] in w) : j > 5 ? m[S] = ++m[S] : j > 3 ? (B = E[R], R += 2, w = h[B], m[++S] = w) : j > 1 && (O = 0, U = m[S].length, D = m[S], m[++S] = function() { - var e = O < U; - if (e) { - var b = D[O++]; - m[++S] = b - } - m[++S] = e - }); - else if ((j = z) < 2) { - for (B = E[R], j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - j = +j, R += 4, m[++S] = j - } else j < 4 ? (w = m[S--], m[S] = m[S] - w) : j < 6 ? (w = m[S--], m[S] = m[S] === w) : j < 15 && (w = m[S], m[S] = m[S - 1], m[S - 1] = w); - else if (j > 1) - if (j = 3 & z, z >>= 2, j < 1)(j = z) > 13 ? (m[++S] = E[R], R += 4) : j > 11 ? (w = m[S--], m[S] = m[S] >> w) : j > 9 ? (B = E[R], R += 2, w = m[S--], h[B] = w) : j > 7 ? (B = E[R], R += 4, A = S + 1, m[S -= B - 1] = B ? m.slice(S, A) : []) : j > 0 && (w = m[S--], m[S] = m[S] > w); - else if (j < 2)(j = z) < 1 ? m[++S] = u : j < 3 ? (w = m[S--], m[S] = m[S] + w) : j < 5 ? (w = m[S--], m[S] = m[S] == w) : j < 14 && (w = m[S - 1], A = m[S], m[++S] = w, m[++S] = A); - else if (j < 3) { - if ((j = z) > 13) m[++S] = !1; - else if (j > 6) w = m[S--], m[S] = m[S] instanceof w; - else if (j > 4) w = m[S--], m[S] = m[S] % w; - else if (j > 2) m[S--] ? R += 4 : R += 2 * (B = E[R]) - 2; - else if (j > 0) { - for (B = E[R], w = "", k = r.q[B][0]; k < r.q[B][1]; k++) w += String.fromCharCode(t ^ r.p[k]); - m[++S] = w, R += 4 - } - } else(j = z) > 7 ? (w = m[S--], m[S] = m[S] | w) : j > 5 ? (B = E[R], R += 2, m[++S] = h["$" + B]) : j > 3 && (B = E[R], d[i][0] && !d[i][2] ? d[i][1] = [R + 4, B - 3] : d[i++] = [0, [R + 4, B - 3], 0], R += 2 * B - 2); - else if (j > 0) - if (j = 3 & z, z >>= 2, j < 1) { - if ((j = z) > 9); - else if (j > 7) w = m[S--], m[S] = m[S] & w; - else if (j > 5) B = E[R], R += 2, m[S -= B] = 0 === B ? new m[S] : f(m[S], c(m.slice(S + 1, S + B + 1))); - else if (j > 3) { - B = E[R]; - try { - if (d[i][2] = 1, 1 == (w = P(e, R + 4, B - 3, [], h, p, null, 0))[0]) return w - } catch (b) { - if (d[i] && d[i][1] && 1 == (w = P(e, d[i][1][0], d[i][1][1], [], h, p, b, 0))[0]) return w - } finally { - if (d[i] && d[i][0] && 1 == (w = P(e, d[i][0][0], d[i][0][1], [], h, p, null, 0))[0]) return w; - d[i] = 0, i-- - } - R += 2 * B - 2 - } - } else if (j < 2) - if ((j = z) < 8) A = m[S--], w = delete m[S--][A]; - else if (j < 10) { - for (B = E[R], j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - R += 4, m[S] = m[S][j] - } else j < 12 ? (w = m[S--], m[S] = m[S] << w) : j < 14 && (m[++S] = E[R], R += 2); - else j < 3 ? (j = z) < 2 ? m[++S] = w : j < 11 ? (w = m[S -= 2][m[S + 1]] = m[S + 2], S--) : j < 13 && (w = m[S], m[++S] = w) : (j = z) > 12 ? m[++S] = p : j > 5 ? (w = m[S--], m[S] = m[S] !== w) : j > 3 ? (w = m[S--], m[S] = m[S] / w) : j > 1 ? R += 2 * (B = E[R]) - 2 : j > -1 && (m[S] = !m[S]); - else if (j = 3 & z, z >>= 2, j < 1) { - if ((j = z) < 1) return [1, m[S--]]; - j < 5 ? (w = m[S--], m[S] = m[S] * w) : j < 7 ? (w = m[S--], m[S] = m[S] != w) : j < 14 ? (A = m[S--], C = m[S--], (j = m[S--]).x === P ? j.y >= 1 ? m[++S] = F(e, j.c, j.l, A, j.z, C, null, 1) : (m[++S] = F(e, j.c, j.l, A, j.z, C, null, 0), j.y++) : m[++S] = j.apply(C, A)) : j < 16 && (B = E[R], (g = function b() { - var a = arguments; - return b.y > 0 || b.y++, F(e, b.c, b.l, a, b.z, this, null, 0) - }).c = R + 4, g.l = B - 2, g.x = P, g.y = 0, g.z = h, m[S] = g, R += 2 * B - 2) - } else if (j < 2)(j = z) > 8 ? (w = m[S--], m[S] = typeof w) : j > 4 ? m[S -= 1] = m[S][m[S + 1]] : j > 2 && (A = m[S--], (j = m[S]).x === P ? j.y >= 1 ? m[S] = F(e, j.c, j.l, [A], j.z, C, null, 1) : (m[S] = F(e, j.c, j.l, [A], j.z, C, null, 0), j.y++) : m[S] = j(A)); - else if (j < 3) { - if ((j = z) < 9) { - for (w = m[S--], B = E[R], j = "", k = r.q[B][0]; k < r.q[B][1]; k++) j += String.fromCharCode(t ^ r.p[k]); - R += 4, m[S--][j] = w - } else if (j < 13) throw m[S--] - } else(j = z) < 1 ? m[++S] = null : j < 3 ? (w = m[S--], m[S] = m[S] >= w) : j < 12 && (m[++S] = void 0); - return [0, null] - } - - function F(e, b, a, f, c, r, t, d) { - null == r && (r = this), c && !c.d && (c.d = 0, c.$0 = c, c[1] = {}); - var i, n, s = {}, - o = s.d = c ? c.d + 1 : 0; - for (s["$" + o] = s, n = 0; n < o; n++) s[i = "$" + n] = c[i]; - for (n = 0, o = s.length = f.length; n < o; n++) s[n] = f[n]; - return d && !T[b] && M(e, b, 2 * a), T[b] ? P(e, b, a, 0, s, r, null, 1)[1] : P(e, b, a, 0, s, r, null, 0)[1] - } -}; -var _0x397dc7 = "undefined" != typeof globalThis ? globalThis : void 0 !== window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : {}, - _0x124d1a = _0x5cd844(function(_0x770f81) { - ! function() { - var _0x250d36 = "input is invalid type", - _0x4cfaee = !1, - _0x1702f9 = {}, - _0x5ccbb3 = !_0x4cfaee && "object" == typeof self, - _0x54d876 = !_0x1702f9.JS_MD5_NO_NODE_JS && "object" == typeof process && process.versions && process.versions.node, - _0x185caf; - _0x54d876 ? _0x1702f9 = _0x397dc7 : _0x5ccbb3 && (_0x1702f9 = self); - var _0x17dcbf = !_0x1702f9.JS_MD5_NO_COMMON_JS && _0x770f81.exports, - _0x554fed = !1, - _0x2de28f = !_0x1702f9.JS_MD5_NO_ARRAY_BUFFER && "undefined" != typeof ArrayBuffer, - _0x3a9a1b = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], - _0x465562 = [128, 32768, 8388608, -2147483648], - _0x20b37e = [0, 8, 16, 24], - _0x323604 = ["hex", "array", "digest", "buffer", "arrayBuffer", "base64"], - _0x2c185e = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"], - _0x4b59e0 = []; - if (_0x2de28f) { - var _0x395837 = new ArrayBuffer(68); - _0x185caf = new Uint8Array(_0x395837), _0x4b59e0 = new Uint32Array(_0x395837) - }!_0x1702f9.JS_MD5_NO_NODE_JS && Array.isArray || (Array.isArray = function(e) { - return "[object Array]" === Object.prototype.toString.call(e) - }), _0x2de28f && (_0x1702f9.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView) && (ArrayBuffer.isView = function(e) { - return "object" == typeof e && e.buffer && e.buffer.constructor === ArrayBuffer - }); - var _0x4e9930 = function(e) { - return function(b) { - return new _0x5887c8(!0).update(b)[e]() - } - }, - _0x38ba77 = function() { - var e = _0x4e9930("hex"); - _0x54d876 && (e = _0x474989(e)), e.create = function() { - return new _0x5887c8 - }, e.update = function(b) { - return e.create().update(b) - }; - for (var b = 0; b < _0x323604.length; ++b) { - var a = _0x323604[b]; - e[a] = _0x4e9930(a) - } - return e - }, - _0x474989 = function(_0x57eeaa) { - var _0x114910, _0x226465 = eval("require('crypto');"), - _0x1f6ae0 = eval("require('buffer')['Buffer'];"); - return function(e) { - if ("string" == typeof e) return _0x226465.createHash("md5").update(e, "utf8").digest("hex"); - if (null == e) throw _0x250d36; - return e.constructor === ArrayBuffer && (e = new Uint8Array(e)), Array.isArray(e) || ArrayBuffer.isView(e) || e.constructor === _0x1f6ae0 ? _0x226465.createHash("md5").update(new _0x1f6ae0.from(e)).digest("hex") : _0x57eeaa(e) - } - }; - - function _0x5887c8(e) { - if (e) _0x4b59e0[0] = _0x4b59e0[16] = _0x4b59e0[1] = _0x4b59e0[2] = _0x4b59e0[3] = _0x4b59e0[4] = _0x4b59e0[5] = _0x4b59e0[6] = _0x4b59e0[7] = _0x4b59e0[8] = _0x4b59e0[9] = _0x4b59e0[10] = _0x4b59e0[11] = _0x4b59e0[12] = _0x4b59e0[13] = _0x4b59e0[14] = _0x4b59e0[15] = 0, this.blocks = _0x4b59e0, this.buffer8 = _0x185caf; - else if (_0x2de28f) { - var b = new ArrayBuffer(68); - this.buffer8 = new Uint8Array(b), this.blocks = new Uint32Array(b) - } else this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0, this.finalized = this.hashed = !1, this.first = !0 - } - _0x5887c8.prototype.update = function(e) { - if (!this.finalized) { - var b, a = typeof e; - if ("string" !== a) { - if ("object" !== a || null === e) throw _0x250d36; - if (_0x2de28f && e.constructor === ArrayBuffer) e = new Uint8Array(e); - else if (!(Array.isArray(e) || _0x2de28f && ArrayBuffer.isView(e))) throw _0x250d36; - b = !0 - } - for (var f, c, r = 0, t = e.length, d = this.blocks, i = this.buffer8; r < t;) { - if (this.hashed && (this.hashed = !1, d[0] = d[16], d[16] = d[1] = d[2] = d[3] = d[4] = d[5] = d[6] = d[7] = d[8] = d[9] = d[10] = d[11] = d[12] = d[13] = d[14] = d[15] = 0), b) - if (_0x2de28f) - for (c = this.start; r < t && c < 64; ++r) i[c++] = e[r]; - else - for (c = this.start; r < t && c < 64; ++r) d[c >> 2] |= e[r] << _0x20b37e[3 & c++]; - else if (_0x2de28f) - for (c = this.start; r < t && c < 64; ++r)(f = e.charCodeAt(r)) < 128 ? i[c++] = f : f < 2048 ? (i[c++] = 192 | f >> 6, i[c++] = 128 | 63 & f) : f < 55296 || f >= 57344 ? (i[c++] = 224 | f >> 12, i[c++] = 128 | f >> 6 & 63, i[c++] = 128 | 63 & f) : (f = 65536 + ((1023 & f) << 10 | 1023 & e.charCodeAt(++r)), i[c++] = 240 | f >> 18, i[c++] = 128 | f >> 12 & 63, i[c++] = 128 | f >> 6 & 63, i[c++] = 128 | 63 & f); - else - for (c = this.start; r < t && c < 64; ++r)(f = e.charCodeAt(r)) < 128 ? d[c >> 2] |= f << _0x20b37e[3 & c++] : f < 2048 ? (d[c >> 2] |= (192 | f >> 6) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | 63 & f) << _0x20b37e[3 & c++]) : f < 55296 || f >= 57344 ? (d[c >> 2] |= (224 | f >> 12) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | f >> 6 & 63) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | 63 & f) << _0x20b37e[3 & c++]) : (f = 65536 + ((1023 & f) << 10 | 1023 & e.charCodeAt(++r)), d[c >> 2] |= (240 | f >> 18) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | f >> 12 & 63) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | f >> 6 & 63) << _0x20b37e[3 & c++], d[c >> 2] |= (128 | 63 & f) << _0x20b37e[3 & c++]); - this.lastByteIndex = c, this.bytes += c - this.start, c >= 64 ? (this.start = c - 64, this.hash(), this.hashed = !0) : this.start = c - } - return this.bytes > 4294967295 && (this.hBytes += this.bytes / 4294967296 << 0, this.bytes = this.bytes % 4294967296), this - } - }, _0x5887c8.prototype.finalize = function() { - if (!this.finalized) { - this.finalized = !0; - var e = this.blocks, - b = this.lastByteIndex; - e[b >> 2] |= _0x465562[3 & b], b >= 56 && (this.hashed || this.hash(), e[0] = e[16], e[16] = e[1] = e[2] = e[3] = e[4] = e[5] = e[6] = e[7] = e[8] = e[9] = e[10] = e[11] = e[12] = e[13] = e[14] = e[15] = 0), e[14] = this.bytes << 3, e[15] = this.hBytes << 3 | this.bytes >>> 29, this.hash() - } - }, _0x5887c8.prototype.hash = function() { - var e, b, a, f, c, r, t = this.blocks; - this.first ? b = ((b = ((e = ((e = t[0] - 680876937) << 7 | e >>> 25) - 271733879 << 0) ^ (a = ((a = (-271733879 ^ (f = ((f = (-1732584194 ^ 2004318071 & e) + t[1] - 117830708) << 12 | f >>> 20) + e << 0) & (-271733879 ^ e)) + t[2] - 1126478375) << 17 | a >>> 15) + f << 0) & (f ^ e)) + t[3] - 1316259209) << 22 | b >>> 10) + a << 0 : (e = this.h0, b = this.h1, a = this.h2, b = ((b += ((e = ((e += ((f = this.h3) ^ b & (a ^ f)) + t[0] - 680876936) << 7 | e >>> 25) + b << 0) ^ (a = ((a += (b ^ (f = ((f += (a ^ e & (b ^ a)) + t[1] - 389564586) << 12 | f >>> 20) + e << 0) & (e ^ b)) + t[2] + 606105819) << 17 | a >>> 15) + f << 0) & (f ^ e)) + t[3] - 1044525330) << 22 | b >>> 10) + a << 0), b = ((b += ((e = ((e += (f ^ b & (a ^ f)) + t[4] - 176418897) << 7 | e >>> 25) + b << 0) ^ (a = ((a += (b ^ (f = ((f += (a ^ e & (b ^ a)) + t[5] + 1200080426) << 12 | f >>> 20) + e << 0) & (e ^ b)) + t[6] - 1473231341) << 17 | a >>> 15) + f << 0) & (f ^ e)) + t[7] - 45705983) << 22 | b >>> 10) + a << 0, b = ((b += ((e = ((e += (f ^ b & (a ^ f)) + t[8] + 1770035416) << 7 | e >>> 25) + b << 0) ^ (a = ((a += (b ^ (f = ((f += (a ^ e & (b ^ a)) + t[9] - 1958414417) << 12 | f >>> 20) + e << 0) & (e ^ b)) + t[10] - 42063) << 17 | a >>> 15) + f << 0) & (f ^ e)) + t[11] - 1990404162) << 22 | b >>> 10) + a << 0, b = ((b += ((e = ((e += (f ^ b & (a ^ f)) + t[12] + 1804603682) << 7 | e >>> 25) + b << 0) ^ (a = ((a += (b ^ (f = ((f += (a ^ e & (b ^ a)) + t[13] - 40341101) << 12 | f >>> 20) + e << 0) & (e ^ b)) + t[14] - 1502002290) << 17 | a >>> 15) + f << 0) & (f ^ e)) + t[15] + 1236535329) << 22 | b >>> 10) + a << 0, b = ((b += ((f = ((f += (b ^ a & ((e = ((e += (a ^ f & (b ^ a)) + t[1] - 165796510) << 5 | e >>> 27) + b << 0) ^ b)) + t[6] - 1069501632) << 9 | f >>> 23) + e << 0) ^ e & ((a = ((a += (e ^ b & (f ^ e)) + t[11] + 643717713) << 14 | a >>> 18) + f << 0) ^ f)) + t[0] - 373897302) << 20 | b >>> 12) + a << 0, b = ((b += ((f = ((f += (b ^ a & ((e = ((e += (a ^ f & (b ^ a)) + t[5] - 701558691) << 5 | e >>> 27) + b << 0) ^ b)) + t[10] + 38016083) << 9 | f >>> 23) + e << 0) ^ e & ((a = ((a += (e ^ b & (f ^ e)) + t[15] - 660478335) << 14 | a >>> 18) + f << 0) ^ f)) + t[4] - 405537848) << 20 | b >>> 12) + a << 0, b = ((b += ((f = ((f += (b ^ a & ((e = ((e += (a ^ f & (b ^ a)) + t[9] + 568446438) << 5 | e >>> 27) + b << 0) ^ b)) + t[14] - 1019803690) << 9 | f >>> 23) + e << 0) ^ e & ((a = ((a += (e ^ b & (f ^ e)) + t[3] - 187363961) << 14 | a >>> 18) + f << 0) ^ f)) + t[8] + 1163531501) << 20 | b >>> 12) + a << 0, b = ((b += ((f = ((f += (b ^ a & ((e = ((e += (a ^ f & (b ^ a)) + t[13] - 1444681467) << 5 | e >>> 27) + b << 0) ^ b)) + t[2] - 51403784) << 9 | f >>> 23) + e << 0) ^ e & ((a = ((a += (e ^ b & (f ^ e)) + t[7] + 1735328473) << 14 | a >>> 18) + f << 0) ^ f)) + t[12] - 1926607734) << 20 | b >>> 12) + a << 0, b = ((b += ((r = (f = ((f += ((c = b ^ a) ^ (e = ((e += (c ^ f) + t[5] - 378558) << 4 | e >>> 28) + b << 0)) + t[8] - 2022574463) << 11 | f >>> 21) + e << 0) ^ e) ^ (a = ((a += (r ^ b) + t[11] + 1839030562) << 16 | a >>> 16) + f << 0)) + t[14] - 35309556) << 23 | b >>> 9) + a << 0, b = ((b += ((r = (f = ((f += ((c = b ^ a) ^ (e = ((e += (c ^ f) + t[1] - 1530992060) << 4 | e >>> 28) + b << 0)) + t[4] + 1272893353) << 11 | f >>> 21) + e << 0) ^ e) ^ (a = ((a += (r ^ b) + t[7] - 155497632) << 16 | a >>> 16) + f << 0)) + t[10] - 1094730640) << 23 | b >>> 9) + a << 0, b = ((b += ((r = (f = ((f += ((c = b ^ a) ^ (e = ((e += (c ^ f) + t[13] + 681279174) << 4 | e >>> 28) + b << 0)) + t[0] - 358537222) << 11 | f >>> 21) + e << 0) ^ e) ^ (a = ((a += (r ^ b) + t[3] - 722521979) << 16 | a >>> 16) + f << 0)) + t[6] + 76029189) << 23 | b >>> 9) + a << 0, b = ((b += ((r = (f = ((f += ((c = b ^ a) ^ (e = ((e += (c ^ f) + t[9] - 640364487) << 4 | e >>> 28) + b << 0)) + t[12] - 421815835) << 11 | f >>> 21) + e << 0) ^ e) ^ (a = ((a += (r ^ b) + t[15] + 530742520) << 16 | a >>> 16) + f << 0)) + t[2] - 995338651) << 23 | b >>> 9) + a << 0, b = ((b += ((f = ((f += (b ^ ((e = ((e += (a ^ (b | ~f)) + t[0] - 198630844) << 6 | e >>> 26) + b << 0) | ~a)) + t[7] + 1126891415) << 10 | f >>> 22) + e << 0) ^ ((a = ((a += (e ^ (f | ~b)) + t[14] - 1416354905) << 15 | a >>> 17) + f << 0) | ~e)) + t[5] - 57434055) << 21 | b >>> 11) + a << 0, b = ((b += ((f = ((f += (b ^ ((e = ((e += (a ^ (b | ~f)) + t[12] + 1700485571) << 6 | e >>> 26) + b << 0) | ~a)) + t[3] - 1894986606) << 10 | f >>> 22) + e << 0) ^ ((a = ((a += (e ^ (f | ~b)) + t[10] - 1051523) << 15 | a >>> 17) + f << 0) | ~e)) + t[1] - 2054922799) << 21 | b >>> 11) + a << 0, b = ((b += ((f = ((f += (b ^ ((e = ((e += (a ^ (b | ~f)) + t[8] + 1873313359) << 6 | e >>> 26) + b << 0) | ~a)) + t[15] - 30611744) << 10 | f >>> 22) + e << 0) ^ ((a = ((a += (e ^ (f | ~b)) + t[6] - 1560198380) << 15 | a >>> 17) + f << 0) | ~e)) + t[13] + 1309151649) << 21 | b >>> 11) + a << 0, b = ((b += ((f = ((f += (b ^ ((e = ((e += (a ^ (b | ~f)) + t[4] - 145523070) << 6 | e >>> 26) + b << 0) | ~a)) + t[11] - 1120210379) << 10 | f >>> 22) + e << 0) ^ ((a = ((a += (e ^ (f | ~b)) + t[2] + 718787259) << 15 | a >>> 17) + f << 0) | ~e)) + t[9] - 343485551) << 21 | b >>> 11) + a << 0, this.first ? (this.h0 = e + 1732584193 << 0, this.h1 = b - 271733879 << 0, this.h2 = a - 1732584194 << 0, this.h3 = f + 271733878 << 0, this.first = !1) : (this.h0 = this.h0 + e << 0, this.h1 = this.h1 + b << 0, this.h2 = this.h2 + a << 0, this.h3 = this.h3 + f << 0) - }, _0x5887c8.prototype.hex = function() { - this.finalize(); - var e = this.h0, - b = this.h1, - a = this.h2, - f = this.h3; - return _0x3a9a1b[e >> 4 & 15] + _0x3a9a1b[15 & e] + _0x3a9a1b[e >> 12 & 15] + _0x3a9a1b[e >> 8 & 15] + _0x3a9a1b[e >> 20 & 15] + _0x3a9a1b[e >> 16 & 15] + _0x3a9a1b[e >> 28 & 15] + _0x3a9a1b[e >> 24 & 15] + _0x3a9a1b[b >> 4 & 15] + _0x3a9a1b[15 & b] + _0x3a9a1b[b >> 12 & 15] + _0x3a9a1b[b >> 8 & 15] + _0x3a9a1b[b >> 20 & 15] + _0x3a9a1b[b >> 16 & 15] + _0x3a9a1b[b >> 28 & 15] + _0x3a9a1b[b >> 24 & 15] + _0x3a9a1b[a >> 4 & 15] + _0x3a9a1b[15 & a] + _0x3a9a1b[a >> 12 & 15] + _0x3a9a1b[a >> 8 & 15] + _0x3a9a1b[a >> 20 & 15] + _0x3a9a1b[a >> 16 & 15] + _0x3a9a1b[a >> 28 & 15] + _0x3a9a1b[a >> 24 & 15] + _0x3a9a1b[f >> 4 & 15] + _0x3a9a1b[15 & f] + _0x3a9a1b[f >> 12 & 15] + _0x3a9a1b[f >> 8 & 15] + _0x3a9a1b[f >> 20 & 15] + _0x3a9a1b[f >> 16 & 15] + _0x3a9a1b[f >> 28 & 15] + _0x3a9a1b[f >> 24 & 15] - }, _0x5887c8.prototype.toString = _0x5887c8.prototype.hex, _0x5887c8.prototype.digest = function() { - this.finalize(); - var e = this.h0, - b = this.h1, - a = this.h2, - f = this.h3; - return [255 & e, e >> 8 & 255, e >> 16 & 255, e >> 24 & 255, 255 & b, b >> 8 & 255, b >> 16 & 255, b >> 24 & 255, 255 & a, a >> 8 & 255, a >> 16 & 255, a >> 24 & 255, 255 & f, f >> 8 & 255, f >> 16 & 255, f >> 24 & 255] - }, _0x5887c8.prototype.array = _0x5887c8.prototype.digest, _0x5887c8.prototype.arrayBuffer = function() { - this.finalize(); - var e = new ArrayBuffer(16), - b = new Uint32Array(e); - return b[0] = this.h0, b[1] = this.h1, b[2] = this.h2, b[3] = this.h3, e - }, _0x5887c8.prototype.buffer = _0x5887c8.prototype.arrayBuffer, _0x5887c8.prototype.base64 = function() { - for (var e, b, a, f = "", c = this.array(), r = 0; r < 15;) e = c[r++], b = c[r++], a = c[r++], f += _0x2c185e[e >>> 2] + _0x2c185e[63 & (e << 4 | b >>> 4)] + _0x2c185e[63 & (b << 2 | a >>> 6)] + _0x2c185e[63 & a]; - return f + (_0x2c185e[(e = c[r]) >>> 2] + _0x2c185e[e << 4 & 63] + "==") - }; - var _0x4dd781 = _0x38ba77(); - _0x17dcbf ? _0x770f81.exports = _0x4dd781 : (_0x1702f9.md5 = _0x4dd781, _0x554fed && (void 0)(function() { - return _0x4dd781 - })) - }() - }); - -function _0x178cef(e) { - return jsvmp("484e4f4a403f52430038001eab0015840e8ee21a00000000000000621b000200001d000146000306000e271f001b000200021d00010500121b001b000b021b000b04041d0001071b000b0500000003000126207575757575757575757575757575757575757575757575757575757575757575", [, , void 0 !== _0x124d1a ? _0x124d1a : void 0, _0x178cef, e]) -} -for (var _0xb55f3e = { - boe: !1, - aid: 0, - dfp: !1, - sdi: !1, - enablePathList: [], - _enablePathListRegex: [], - urlRewriteRules: [], - _urlRewriteRules: [], - initialized: !1, - enableTrack: !1, - track: { - unitTime: 0, - unitAmount: 0, - fre: 0 - }, - triggerUnload: !1, - region: "", - regionConf: {}, - umode: 0, - v: !1, - perf: !1, - xxbg: !0 - }, _0x3eaf64 = { - debug: function(e, b) { - let a = !1; - a = !1 - } - }, _0x233455 = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"], _0x2e9f6d = [], _0x511f86 = [], _0x3d35de = 0; _0x3d35de < 256; _0x3d35de++) _0x2e9f6d[_0x3d35de] = _0x233455[_0x3d35de >> 4 & 15] + _0x233455[15 & _0x3d35de], _0x3d35de < 16 && (_0x3d35de < 10 ? _0x511f86[48 + _0x3d35de] = _0x3d35de : _0x511f86[87 + _0x3d35de] = _0x3d35de); -var _0x2ce54d = function(e) { - for (var b = e.length, a = "", f = 0; f < b;) a += _0x2e9f6d[e[f++]]; - return a - }, - _0x5960a2 = function(e) { - for (var b = e.length >> 1, a = b << 1, f = new Uint8Array(b), c = 0, r = 0; r < a;) f[c++] = _0x511f86[e.charCodeAt(r++)] << 4 | _0x511f86[e.charCodeAt(r++)]; - return f - }, - _0x4e46b6 = { - encode: _0x2ce54d, - decode: _0x5960a2 - }; - -function sign(e, b) { - return jsvmp("484e4f4a403f5243001f240fbf2031ccf317480300000000000007181b0002012e1d00921b000b171b000b02402217000a1c1b000b1726402217000c1c1b000b170200004017002646000306000e271f001b000200021d00920500121b001b000b031b000b17041d0092071b000b041e012f17000d1b000b05260a0000101c1b000b06260a0000101c1b001b000b071e01301d00931b001b000b081e00081d00941b0048021d00951b001b000b1b1d00961b0048401d009e1b001b000b031b000b16041d009f1b001b000b09221e0131241b000b031b000b09221e0131241b000b1e0a000110040a0001101d00d51b001b000b09221e0131241b000b031b000b09221e0131241b000b180a000110040a0001101d00d71b001b000b0a1e00101d00d91b001b000b0b261b000b1a1b000b190a0002101d00db1b001b000b0c261b000b221b000b210a0002101d00dc1b001b000b0d261b000b230200200a0002101d00dd1b001b000b09221e0131241b000b031b000b24040a0001101d00df1b001b000b0e1a00221e00de240a0000104903e82b1d00e31b001b000b0f260a0000101d00e41b001b000b1d1d00e71b001b000b1a4901002b1d00e81b001b000b1a4901002c1d00ea1b001b000b191d00f21b001b000b1f480e191d00f81b001b000b1f480f191d00f91b001b000b20480e191d00fb1b001b000b20480f191d00fe1b001b000b25480e191d01001b001b000b25480f191d01011b001b000b264818344900ff2f1d01031b001b000b264810344900ff2f1d01321b001b000b264808344900ff2f1d01331b001b000b264800344900ff2f1d01341b001b000b274818344900ff2f1d01351b001b000b274810344900ff2f1d01361b001b000b274808344900ff2f1d01371b001b000b274800344900ff2f1d01381b001b000b281b000b29311b000b2a311b000b2b311b000b2c311b000b2d311b000b2e311b000b2f311b000b30311b000b31311b000b32311b000b33311b000b34311b000b35311b000b36311b000b37311b000b38311b000b39311d01391b004900ff1d013a1b001b000b10261b000b281b000b2a1b000b2c1b000b2e1b000b301b000b321b000b341b000b361b000b381b000b3a1b000b291b000b2b1b000b2d1b000b2f1b000b311b000b331b000b351b000b371b000b390a0013101d013b1b001b000b0c261b000b111b000b3b041b000b3c0a0002101d013c1b001b000b12261b000b1c1b000b3b1b000b3d0a0003101d013d1b001b000b13261b000b3e0200240a0002101d013e1b000b3f0000013f000126207575757575757575757575757575757575757575757575757575757575757575012b0e7776757a7d7643617c637661676a027a77065c717976706708777671667474766107767d65707c77760374766707707c7d607c7f7607757a61767166740a7c66677661447a77677b0a7a7d7d7661447a77677b0b7c666776615b767a747b670b7a7d7d76615b767a747b6709666076615274767d670b677c5f7c64766150726076077a7d77766b5c7508767f767067617c7d09667d7776757a7d76770963617c677c676a637608677c4067617a7d740470727f7f0763617c7076606010487c71797670673363617c707660604e067c717976706705677a677f76047d7c7776012e0125012402602341525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a383c2e0260224157787763747b2749586042512b233c5e75656420254b5a22412126384446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e0260214157787763747b2749586042512b233c5e75656420254b5a224121263e4446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e02602041525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a3e4c2e012a022222067f767d74677b0a707b7261507c7776526702222306707b726152670f487c717976706733447a7d777c644e08577c70667e767d6712487c7179767067335d72657a7472677c614e057960777c7e10487c7179767067335b7a60677c616a4e07637f66747a7d60084c637b727d677c7e0b70727f7f437b727d677c7e0b4c4c7d7a747b677e726176055266777a7c1850727d65726041767d7776617a7d74507c7d67766b6721570964767177617a657661137476675c647d43617c637661676a5d727e7660097f727d74667274766006707b617c7e760761667d677a7e7607707c7d7d767067144c4c64767177617a6576614c7665727f66726776134c4c60767f767d7a667e4c7665727f667267761b4c4c64767177617a6576614c6070617a63674c75667d70677a7c7d174c4c64767177617a6576614c6070617a63674c75667d70154c4c64767177617a6576614c6070617a63674c757d134c4c756b77617a6576614c7665727f66726776124c4c77617a6576614c667d64617263637677154c4c64767177617a6576614c667d64617263637677114c4c77617a6576614c7665727f66726776144c4c60767f767d7a667e4c667d64617263637677144c4c756b77617a6576614c667d64617263637677094c60767f767d7a667e0c70727f7f40767f767d7a667e164c40767f767d7a667e4c5a57564c4176707c6177766108777c70667e767d670478766a60057e7267707b06417674566b630a4f3748723e694e77704c067072707b764c04607c7e7608707675407b72616308507675407b72616305767c72637a16767c44767151617c64607661577a60637267707b76610f717a7d775c717976706752606a7d700e7a60565c44767151617c646076610120047c63767d0467766067097a7d707c747d7a677c077c7d7661617c6104707c77761242465c47524c564b5056565756574c5641410e607660607a7c7d40677c61727476076076675a67767e10607c7e7658766a5b766176516a6776770a61767e7c65765a67767e097a7d77766b767757510c437c7a7d6776615665767d670e5e40437c7a7d6776615665767d670d706176726776567f767e767d670670727d65726009677c5772677246415f076176637f727076034f603901740a7d72677a6576707c777614487c717976706733437f66747a7d526161726a4e4a4d7b676763602c294f3c4f3c3b48233e2a4e68223f206e3b4f3d48233e2a4e68223f206e3a68206e6f48723e75233e2a4e68223f276e3b2948723e75233e2a4e68223f276e3a68246e3a0127087f7c7072677a7c7d047b61767504757a7f76107b676763293c3c7f7c70727f7b7c606708637f7267757c617e02222102222007647a7d777c646002222703647a7d02222607727d77617c7a77022225057f7a7d666b022224067a637b7c7d7602222b047a63727702222a047a637c77022123037e7270022122097e72707a7d677c607b0c7e72704c637c64766163703a0470617c60036b22220570617a7c6005756b7a7c6004637a787602212102212002212702212602212502212402212b08757a6176757c6b3c067c637661723c05337c63613c05337c63673c07707b617c7e763c0867617a77767d673c047e607a7602212a0220230665767d777c6106547c7c747f760e4c637261727e40647a67707b5c7d0a777a61767067407a747d0a707c7d607a6067767d670660647a67707b03777c7e07637b727d677c7e047b7c7c7840525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a3e3d03727a77017d01750161096067726167477a7e7601670972717a7f7a677a76600a677a7e766067727e6322137b72617764726176507c7d70666161767d706a0c7776657a70765e767e7c616a087f727d74667274760a6176607c7f66677a7c7d0f7265727a7f4176607c7f66677a7c7d0960706176767d477c630a60706176767d5f767567107776657a7076437a6b767f4172677a7c0a63617c77667067406671077172676776616a016309677c66707b5a7d757c08677a7e76697c7d760a677a7e766067727e6321077463665a7d757c0b7960557c7d67605f7a60670b637f66747a7d605f7a60670a677a7e766067727e63200a76657661507c7c787a760767674c60707a77017e0b606a7d67726b5661617c610c7d72677a65765f767d74677b056167705a43097563457661607a7c7d0b4c4c657661607a7c7d4c4c08707f7a767d675a770a677a7e766067727e63270b766b67767d77557a767f77046366607b03727f7f04677b767d097172607625274c707b0c75617c7e507b7261507c7776067125274c2023022022087172607625274c23022021087172607625274c22022020087172607625274c2102202702202602202507747667477a7e760220240b777c7e5d7c6745727f7a77096066716067617a7d740863617c677c707c7f02202b02202a01230e222323232323232322222323232302272302272207757c616176727f02272104717c776a096067617a7d747a756a02686e0b717c776a45727f216067610a717c776a4c7b72607b2e01350366617f02272005626676616a0a72607c7f774c607a747d096372677b7d727e762e0967674c6476717a772e063566667a772e0227270227260e4c716a6776774c6076704c777a770227250a27212a272a2524212a25097576457661607a7c7d0227240e4c232151274925647c232323232202272b02272a05607f7a7076022623074056505a5d555c037d7c6409677a7e766067727e6305757f7c7c610661727d777c7e0f7476674747447671507c7c787a7660056767647a770867674c6476717a770767674476715a770b67674c6476717a774c65210967674476717a7745210761667d7d7a7d7405757f66607b087e7c65765f7a60670660637f7a70760671765e7c657609707f7a70785f7a6067077176507f7a70780c78766a717c7261775f7a60670a717658766a717c7261770b7270677a657640677267760b647a7d777c6440677267760360477e05676172707808667d7a67477a7e76037270700a667d7a67527e7c667d670871767b72657a7c61077e6074476a637603645a5707727a775f7a60670b63617a6572706a5e7c777606706660677c7e067260607a747d0f4456514c5756455a50564c5a5d555c0479607c7d0a6176747a7c7d507c7d75096176637c616746617f04766b7a67094b3e5e403e404746510c4b3e5e403e43524a5f5c525720232323232323232323232323232323232323232323232323232323232323232320772722772b70772a2b75232371212327762a2b23232a2a2b7670752b272124760165066671707c7776067776707c777602262202262102262002262702262602262502262402262b02262a022523022522022521022520", [, , void 0, void 0 !== _0x178cef ? _0x178cef : void 0, { - boe: !1, - aid: 0, - dfp: !1, - sdi: !1, - enablePathList: [], - _enablePathListRegex: [/\/web\/report/], - urlRewriteRules: [], - _urlRewriteRules: [], - initialized: !1, - enableTrack: !1, - track: { - unitTime: 0, - unitAmount: 0, - fre: 0 - }, - triggerUnload: !1, - region: "", - regionConf: {}, - umode: 0, - v: !1, - perf: !1, - xxbg: !0 - }, () => 0, () => "03v", { - ubcode: 0 - }, { - bogusIndex: 0, - msNewTokenList: [], - moveList: [], - clickList: [], - keyboardList: [], - activeState: [], - aidList: [], - envcode: 0, - msToken: "", - msStatus: 0, - __ac_testid: "", - ttwid: "", - tt_webid: "", - tt_webid_v2: "" - }, void 0 !== _0x4e46b6 ? _0x4e46b6 : void 0, { - userAgent: b - }, (e, b) => { - let a = new Uint8Array(3); - return a[0] = e / 256, a[1] = e % 256, a[2] = b % 256, String.fromCharCode.apply(null, a) - }, (e, b) => { - let a, f = [], - c = 0, - r = ""; - for (let e = 0; e < 256; e++) f[e] = e; - for (let b = 0; b < 256; b++) c = (c + f[b] + e.charCodeAt(b % e.length)) % 256, a = f[b], f[b] = f[c], f[c] = a; - let t = 0; - c = 0; - for (let e = 0; e < b.length; e++) c = (c + f[t = (t + 1) % 256]) % 256, a = f[t], f[t] = f[c], f[c] = a, r += String.fromCharCode(b.charCodeAt(e) ^ f[(f[t] + f[c]) % 256]); - return r - }, (e, b) => jsvmp("484e4f4a403f524300281018f7b851f02d296e5b00000000000004a21b0002001d1d001e1b00131e00061a001d001f1b000b070200200200210d1b000b070200220200230d1b000b070200240200250d1b000b070200260200270d1b001b000b071b000b05191d00031b000200001d00281b0048001d00291b000b041e002a1b000b0b4803283b1700f11b001b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f4810331b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f480833301b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f301d002c1b00220b091b000b08221e002d241b000b0a4a00fc00002f4812340a000110281d00281b00220b091b000b08221e002d241b000b0a4a0003f0002f480c340a000110281d00281b00220b091b000b08221e002d241b000b0a490fc02f4806340a000110281d00281b00220b091b000b08221e002d241b000b0a483f2f0a000110281d002816ff031b000b041e002a1b000b0b294800391700e01b001b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f4810331b000b041e002a1b000b0b3917001e1b000b04221e002b241b000b0b0a0001104900ff2f4808331600054800301d002c1b00220b091b000b08221e002d241b000b0a4a00fc00002f4812340a000110281d00281b00220b091b000b08221e002d241b000b0a4a0003f0002f480c340a000110281d00281b00220b091b000b041e002a1b000b0b3917001e1b000b08221e002d241b000b0a490fc02f4806340a0001101600071b000b06281d00281b00220b091b000b06281d00281b000b090000002e000126207575757575757575757575757575757575757575757575757575757575757575012b0e7776757a7d7643617c637661676a027a77065c717976706708777671667474766107767d65707c77760374766707707c7d607c7f7607757a61767166740a7c66677661447a77677b0a7a7d7d7661447a77677b0b7c666776615b767a747b670b7a7d7d76615b767a747b6709666076615274767d670b677c5f7c64766150726076077a7d77766b5c7508767f767067617c7d09667d7776757a7d76770963617c677c676a637608677c4067617a7d740470727f7f0763617c7076606010487c71797670673363617c707660604e067c717976706705677a677f76047d7c7776012e0125012402602341525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a383c2e0260224157787763747b2749586042512b233c5e75656420254b5a22412126384446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e0260214157787763747b2749586042512b233c5e75656420254b5a224121263e4446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e02602041525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a3e4c2e012a022222067f767d74677b0a707b7261507c7776526702222306707b72615267", [, , , , e, b]), "undefined" != typeof Date ? Date : void 0, () => 0, (e, b, a, f, c, r, t, d, i, n, s, o, l, _, x, u, h, p, y) => { - let v = new Uint8Array(19); - return v[0] = e, v[1] = s, v[2] = b, v[3] = o, v[4] = a, v[5] = l, v[6] = f, v[7] = _, v[8] = c, v[9] = x, v[10] = r, v[11] = u, v[12] = t, v[13] = h, v[14] = d, v[15] = p, v[16] = i, v[17] = y, v[18] = n, String.fromCharCode.apply(null, v) - }, e => String.fromCharCode(e), (e, b, a) => String.fromCharCode(e) + String.fromCharCode(b) + a, (e, b) => jsvmp("484e4f4a403f524300281018f7b851f02d296e5b00000000000004a21b0002001d1d001e1b00131e00061a001d001f1b000b070200200200210d1b000b070200220200230d1b000b070200240200250d1b000b070200260200270d1b001b000b071b000b05191d00031b000200001d00281b0048001d00291b000b041e002a1b000b0b4803283b1700f11b001b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f4810331b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f480833301b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f301d002c1b00220b091b000b08221e002d241b000b0a4a00fc00002f4812340a000110281d00281b00220b091b000b08221e002d241b000b0a4a0003f0002f480c340a000110281d00281b00220b091b000b08221e002d241b000b0a490fc02f4806340a000110281d00281b00220b091b000b08221e002d241b000b0a483f2f0a000110281d002816ff031b000b041e002a1b000b0b294800391700e01b001b000b04221e002b241b001e0029222d1b00241d00290a0001104900ff2f4810331b000b041e002a1b000b0b3917001e1b000b04221e002b241b000b0b0a0001104900ff2f4808331600054800301d002c1b00220b091b000b08221e002d241b000b0a4a00fc00002f4812340a000110281d00281b00220b091b000b08221e002d241b000b0a4a0003f0002f480c340a000110281d00281b00220b091b000b041e002a1b000b0b3917001e1b000b08221e002d241b000b0a490fc02f4806340a0001101600071b000b06281d00281b00220b091b000b06281d00281b000b090000002e000126207575757575757575757575757575757575757575757575757575757575757575012b0e7776757a7d7643617c637661676a027a77065c717976706708777671667474766107767d65707c77760374766707707c7d607c7f7607757a61767166740a7c66677661447a77677b0a7a7d7d7661447a77677b0b7c666776615b767a747b670b7a7d7d76615b767a747b6709666076615274767d670b677c5f7c64766150726076077a7d77766b5c7508767f767067617c7d09667d7776757a7d76770963617c677c676a637608677c4067617a7d740470727f7f0763617c7076606010487c71797670673363617c707660604e067c717976706705677a677f76047d7c7776012e0125012402602341525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a383c2e0260224157787763747b2749586042512b233c5e75656420254b5a22412126384446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e0260214157787763747b2749586042512b233c5e75656420254b5a224121263e4446527f567a245d5f717c624a475c4366697e5579597d616a6b2a5b45547072406750762e02602041525150575655545b5a59585f5e5d5c43424140474645444b4a49727170777675747b7a79787f7e7d7c63626160676665646b6a6923222120272625242b2a3e4c2e012a022222067f767d74677b0a707b7261507c7776526702222306707b72615267", [, , , , e, b]), , sign, e, void 0]) -} - -//export text function -module.exports = sign; diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7fa7980 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +.git +.git/ +.gitignore +.vs +.vs/ +.codex-temp +.codex-temp/ +.codex_tmp_danmaku +.codex_tmp_danmaku/ +artifacts +artifacts/ +ConsoleApp1 +ConsoleApp1/ +dycast_repo +dycast_repo/ +tools/**/bin +tools/**/obj + +# Local build logs and exported archives. +*.log +*.zip +build.log +webapi-build.log +webapi-build-no-restore.log + +# .NET build outputs. +bin/ +obj/ +**/bin/ +**/obj/ + +# Frontend is built by the separate frontend image; the API image does not need it. +frontend/ + +# Runtime persistence directories mounted by docker-compose. Never send recordings into build context. +data/ +records/ +docker-data/ +src/LiveRecorder.WebApi/data/ +src/LiveRecorder.WebApi/records/ +src/LiveRecorder.WebApi/live-recorder.db +src/LiveRecorder.WebApi/live-recorder.db-* + +# Generated media and database files if they are placed anywhere else by mistake. +*.db +*.db-* +*.sqlite +*.sqlite3 +*.mp4 +*.ts +*.flv +*.m4s +*.m3u8 +records/**/*.xml +src/LiveRecorder.WebApi/records/**/*.xml + +# Node/Vite outputs in case they are copied outside frontend context. +node_modules/ +dist/ +**/node_modules/ +**/dist/ + +**/.DS_Store diff --git a/.gitignore b/.gitignore index 4fb7f9f..c2c04c1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,19 @@ build.log webapi-build.log webapi-build-no-restore.log artifacts/ +data/ +records/ +docker-data/ +src/LiveRecorder.WebApi/data/ +src/LiveRecorder.WebApi/records/ +src/LiveRecorder.WebApi/live-recorder.db* +*.db +*.db-* +*.sqlite +*.sqlite3 +*.mp4 +*.ts +*.flv +*.m4s +*.m3u8 +*.zip diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj deleted file mode 100644 index 05b303a..0000000 --- a/ConsoleApp1/ConsoleApp1.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - net8.0 - enable - enable - - - - - - - diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs deleted file mode 100644 index f2d9383..0000000 --- a/ConsoleApp1/Program.cs +++ /dev/null @@ -1,40 +0,0 @@ -using WebSocketSharp; -using WebSocketSharp.Server; - -namespace ConsoleApp1 -{ - internal class Program - { - static void Main(string[] args) - { - var wssv = new WebSocketServer("ws://0.0.0.0:8080"); - - wssv.AddWebSocketService("/ws"); - - wssv.Start(); - Console.WriteLine("WebSocket服务器已启动 ws://localhost:8080/ws"); - - Console.ReadKey(); - wssv.Stop(); - } - } - - // 处理连接 - public class WsHandler : WebSocketBehavior - { - protected override void OnOpen() - { - Console.WriteLine("客户端连接"); - } - - protected override void OnMessage(MessageEventArgs e) - { - Console.WriteLine($"收到消息: {e.Data}"); - } - - protected override void OnClose(CloseEventArgs e) - { - Console.WriteLine("客户端断开"); - } - } -} diff --git a/LiveRecorder.sln b/LiveRecorder.sln index 213a278..99c6aca 100644 --- a/LiveRecorder.sln +++ b/LiveRecorder.sln @@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveRecorder.Application", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiveRecorder.Infrastructure", "src\LiveRecorder.Infrastructure\LiveRecorder.Infrastructure.csproj", "{A502FCC8-83F9-402B-A027-D020D34624E1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,18 +71,6 @@ Global {A502FCC8-83F9-402B-A027-D020D34624E1}.Release|x64.Build.0 = Release|Any CPU {A502FCC8-83F9-402B-A027-D020D34624E1}.Release|x86.ActiveCfg = Release|Any CPU {A502FCC8-83F9-402B-A027-D020D34624E1}.Release|x86.Build.0 = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|x64.ActiveCfg = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|x64.Build.0 = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|x86.ActiveCfg = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Debug|x86.Build.0 = Debug|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|Any CPU.Build.0 = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|x64.ActiveCfg = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|x64.Build.0 = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|x86.ActiveCfg = Release|Any CPU - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -94,6 +80,5 @@ Global {CEE984AA-CA08-48B3-B341-BD2C1C68CC1F} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} {3B807934-A995-4F7F-8A4E-878D161F95A1} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} {A502FCC8-83F9-402B-A027-D020D34624E1} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} - {A39485F2-EBFE-451E-B9C0-D60ACFD6D8BE} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} EndGlobalSection EndGlobal diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..26f35b5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +services: + api: + build: + context: . + dockerfile: src/LiveRecorder.WebApi/Dockerfile + network: host + args: + DOTNET_SDK_IMAGE: ${DOTNET_SDK_IMAGE:-mcr.microsoft.com/dotnet/sdk:8.0-bookworm-slim} + DOTNET_RUNTIME_IMAGE: ${DOTNET_RUNTIME_IMAGE:-mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim} + restart: unless-stopped + environment: + ASPNETCORE_ENVIRONMENT: Production + ASPNETCORE_URLS: http://+:8080 + ConnectionStrings__DefaultConnection: Data Source=/app/data/live-recorder.db + volumes: + - ./data:/app/data + - ./records:/app/records + expose: + - "8080" + + nginx: + build: + context: ./frontend + dockerfile: Dockerfile + network: host + args: + NODE_IMAGE: ${NODE_IMAGE:-node:22-alpine} + NGINX_IMAGE: ${NGINX_IMAGE:-nginx:1.27-alpine} + VITE_API_BASE_URL: /api + restart: unless-stopped + depends_on: + - api + ports: + - "${HTTP_PORT:-8080}:80" diff --git a/dycast_repo b/dycast_repo deleted file mode 160000 index dc3ab9a..0000000 --- a/dycast_repo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dc3ab9ad4633b21ec255942e5262bba78750a1c3 diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..b6dddf6 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,3 @@ +node_modules +dist +npm-debug.log diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..275d3e9 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,23 @@ +ARG NODE_IMAGE=node:22-alpine +ARG NGINX_IMAGE=nginx:1.27-alpine + +FROM ${NODE_IMAGE} AS build +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY . . + +ARG VITE_API_BASE_URL=/api +ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} + +RUN npm run build + +FROM ${NGINX_IMAGE} AS runtime +COPY nginx/default.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist /usr/share/nginx/html + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx/default.conf b/frontend/nginx/default.conf new file mode 100644 index 0000000..26d4f11 --- /dev/null +++ b/frontend/nginx/default.conf @@ -0,0 +1,39 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + client_max_body_size 256m; + + location = /api { + return 301 /api/; + } + + location /api/ { + proxy_pass http://api:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /swagger { + return 301 /swagger/; + } + + location /swagger/ { + proxy_pass http://api:8080; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index c04eb9d..8e7334c 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -1,10 +1,153 @@ import axios from "axios"; +import { ElNotification } from "element-plus"; +import { markBackendAvailable, markBackendUnavailable } from "@/composables/useBackendStatus"; + +export const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ?? "/api"; const apiClient = axios.create({ - baseURL: import.meta.env.VITE_API_BASE_URL ?? "/api", + baseURL: apiBaseUrl, timeout: 30000 }); +let lastBackendUnavailableNotificationAt = 0; +const backendUnavailableNotificationIntervalMs = 8000; + +function isDefaultAxiosMessage(message: string) { + return ( + /^Request failed with status code \d+$/i.test(message) || + message === "Network Error" || + message.toLowerCase().includes("timeout") + ); +} + +function joinApiUrl(path: string) { + const normalizedPath = path.startsWith("/") ? path : `/${path}`; + const base = apiBaseUrl.replace(/\/+$/, ""); + return `${base}${normalizedPath}`; +} + +function getStatusFallbackMessage(status?: number) { + switch (status) { + case 400: + return "请求参数有误,请检查后重试。"; + case 401: + return "登录状态已失效,请重新登录。"; + case 403: + return "当前没有权限执行该操作。"; + case 404: + return "请求的接口不存在,请确认前后端版本一致。"; + case 409: + return "请求发生冲突,请刷新后重试。"; + case 422: + return "提交的数据格式不正确,请检查后重试。"; + case 500: + return "后端服务发生内部错误(500),请查看后端日志。"; + case 502: + case 503: + case 504: + return "后端服务暂时不可用,请稍后重试。"; + default: + return status && status >= 500 + ? `后端服务发生异常(${status}),请查看后端日志。` + : "请求失败,请稍后重试。"; + } +} + +export function isBackendUnavailableError(error: unknown) { + if (!axios.isAxiosError(error)) { + return false; + } + + const status = error.response?.status; + return ( + !error.response || + error.code === "ERR_NETWORK" || + error.code === "ECONNABORTED" || + status === 502 || + status === 503 || + status === 504 + ); +} + +export function getBackendUnavailableMessage() { + return "无法连接后端服务,请确认后端已启动后再重试。"; +} + +export function buildApiUrl( + path: string, + query?: Record +) { + const url = new URL(joinApiUrl(path), window.location.origin); + + if (query) { + Object.entries(query).forEach(([key, value]) => { + if (value === null || value === undefined || value === "") { + return; + } + + url.searchParams.set(key, String(value)); + }); + } + + return url.toString(); +} + +export function getApiErrorMessage(error: unknown, fallback = "请求失败,请稍后重试。") { + if (isBackendUnavailableError(error)) { + return getBackendUnavailableMessage(); + } + + if (axios.isAxiosError(error)) { + const status = error.response?.status; + const responseData = error.response?.data as + | { message?: string; title?: string; detail?: string; error?: string } + | string + | undefined; + + if (typeof responseData === "string" && responseData.trim().length > 0 && !isDefaultAxiosMessage(responseData)) { + return responseData; + } + + if (responseData && typeof responseData === "object") { + const candidates = [responseData.message, responseData.title, responseData.detail, responseData.error]; + const responseMessage = candidates.find( + (item): item is string => typeof item === "string" && item.trim().length > 0 && !isDefaultAxiosMessage(item) + ); + + if (responseMessage) { + return responseMessage; + } + } + + if (typeof error.message === "string" && error.message.trim().length > 0 && !isDefaultAxiosMessage(error.message)) { + return error.message; + } + + return getStatusFallbackMessage(status) || fallback; + } + + if (error instanceof Error && error.message.trim().length > 0) { + return error.message; + } + + return fallback; +} + +function notifyBackendUnavailable(message: string) { + const now = Date.now(); + if (now - lastBackendUnavailableNotificationAt < backendUnavailableNotificationIntervalMs) { + return; + } + + lastBackendUnavailableNotificationAt = now; + ElNotification({ + title: "后端连接异常", + message, + type: "error", + duration: 5000 + }); +} + apiClient.interceptors.request.use((config) => { const token = localStorage.getItem("live-recorder-token"); if (token) { @@ -15,9 +158,13 @@ apiClient.interceptors.request.use((config) => { }); apiClient.interceptors.response.use( - (response) => response, + (response) => { + markBackendAvailable(); + return response; + }, (error) => { if (error.response?.status === 401) { + markBackendAvailable(); localStorage.removeItem("live-recorder-token"); localStorage.removeItem("live-recorder-user"); @@ -26,6 +173,14 @@ apiClient.interceptors.response.use( } } + if (isBackendUnavailableError(error)) { + const message = getBackendUnavailableMessage(); + markBackendUnavailable(message); + notifyBackendUnavailable(message); + } else if (error.response) { + markBackendAvailable(); + } + return Promise.reject(error); } ); diff --git a/frontend/src/components/layout/MainLayout.vue b/frontend/src/components/layout/MainLayout.vue index e6d6d0d..940d9ad 100644 --- a/frontend/src/components/layout/MainLayout.vue +++ b/frontend/src/components/layout/MainLayout.vue @@ -1,22 +1,43 @@ @@ -188,16 +453,20 @@ onMounted(loadRooms);

直播间管理

- 直播间长期保留在系统中。临时不想录制时直接停用即可,停用后后台巡检不会再为该直播间自动创建任务。 + 直播间会长期保留在系统里。单房间配置优先于全局配置;未设置的项会自动回退到系统设置。

刷新列表 + 批量导入 + 导出列表 新增直播间 + +
直播间总数
@@ -225,83 +494,111 @@ onMounted(loadRooms);

直播间列表

-

支持手动刷新、直接启动录制、启用/停用自动录制,以及按需删除直播间。

+

支持刷新状态、手动启动录制、单房间配置覆盖,以及按需删除直播间。

+ + 已选 {{ selectedRoomCount }} 个 + 批量启用 + 批量停用 + + 批量删除 + +
- - - - +
+ + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - + + + + + + + + + + + + +
@@ -311,7 +608,7 @@ onMounted(loadRooms); v-model="createForm.url" type="textarea" :rows="5" - placeholder="粘贴抖音分享链接、直播间地址或 roomId" + placeholder="粘贴抖音 / Bilibili / 虎牙直播间链接,或直接输入 roomId" /> @@ -336,20 +633,85 @@ onMounted(loadRooms); + +
+ + + + + + + + + + + + + + +
+
+ 共 {{ importResult.totalCount }} 条,成功 {{ importResult.successCount }} 条,新增 + {{ importResult.createdCount }} 条,更新 {{ importResult.updatedCount }} 条,失败 + {{ importResult.failedCount }} 条 +
+ +
+
+ 第 {{ item.lineNumber }} 行 + {{ item.errorMessage || "导入失败" }} + {{ item.rawLine }} +
+
+
+
+ + +
+
- - - - + @@ -374,33 +736,164 @@ onMounted(loadRooms); + +
+
+ 当前直播间:{{ settingsRoom?.title || settingsRoom?.anchorName || settingsRoom?.roomId || "-" }} + 未设置的项会自动跟随全局配置。 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
- 确认删除直播间 - {{ pendingDeleteRoom?.roomId || "-" }} - 吗?删除后,该直播间的关联记录会按当前后端规则自动清理。 -
- -
-
影响范围
-

只删除当前直播间本身。满足 stopped orphan 规则且没有有效视频文件的空会话会被后端一并清理。

+ {{ + pendingDeleteRoom + ? `确认删除直播间 ${pendingDeleteRoom.roomId} 吗?删除后该直播间的关联记录会按现有后端规则清理。` + : `确认删除选中的 ${pendingDeleteCount} 个直播间吗?删除后相关记录会按现有后端规则清理。` + }}
@@ -424,6 +917,10 @@ onMounted(loadRooms); align-self: center; } +.page-error-alert { + border-radius: 14px; +} + .table-card :deep(.el-card__body) { padding-top: 18px; } @@ -438,31 +935,150 @@ onMounted(loadRooms); border-bottom: 1px solid rgba(82, 74, 63, 0.08); } -.cover-thumb { - width: 56px; - height: 56px; - border-radius: 14px; - box-shadow: 0 10px 22px rgba(31, 24, 18, 0.08); +.batch-actions { + justify-content: flex-end; +} + +.batch-actions__count { + color: var(--text-muted); + font-size: 13px; +} + +.rooms-table-shell { + margin-inline: -4px; + padding-inline: 4px; +} + +.rooms-table { + min-width: 1380px; +} + +.rooms-table :deep(.el-table__cell) { + vertical-align: top; +} + +.rooms-table :deep(.cell) { + overflow: visible; +} + +.room-avatar { + box-shadow: 0 14px 28px rgba(52, 84, 112, 0.14); } .cell-title { + font-size: 15px; font-weight: 700; - letter-spacing: -0.02em; - color: #171614; + color: #17202b; + line-height: 1.5; } .cell-subtitle { margin-top: 6px; - color: #6f675f; + color: #5f6d79; + font-size: 13px; } .cell-mono { margin-top: 8px; - color: #90887d; + color: #7c8690; + font-size: 12px; +} + +.config-summary { + display: flex; + flex-wrap: wrap; + gap: 8px; + color: #5f6d79; + font-size: 12px; +} + +.config-summary span { + display: inline-flex; + align-items: center; + padding: 4px 8px; + border-radius: 999px; + background: rgba(243, 246, 248, 0.9); + border: 1px solid rgba(95, 109, 124, 0.08); +} + +.table-date-text { + white-space: nowrap; + font-variant-numeric: tabular-nums; +} + +.room-actions-cell { + display: flex; + align-items: center; + gap: 8px; + flex-wrap: nowrap; + white-space: nowrap; +} + +.room-actions-cell :deep(.el-button) { + margin: 0; +} + +.settings-note { + display: grid; + gap: 6px; + margin-bottom: 18px; + padding: 14px 16px; + border-radius: 14px; + background: rgba(243, 246, 248, 0.9); + color: #51606c; + line-height: 1.6; +} + +.settings-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0 16px; } .dialog-form { - padding-top: 4px; + display: grid; +} + +.import-dialog-body { + gap: 16px; +} + +.import-result { + display: grid; + gap: 12px; + padding: 14px 16px; + border: 1px solid rgba(62, 95, 124, 0.14); + border-radius: 14px; + background: rgba(246, 248, 250, 0.82); +} + +.import-result__summary { + color: #26323d; + font-size: 14px; + font-weight: 700; + line-height: 1.7; +} + +.import-result__failures { + display: grid; + gap: 8px; + max-height: 180px; + overflow: auto; +} + +.import-result__failure { + display: grid; + gap: 4px; + padding: 10px 12px; + border-radius: 10px; + background: rgba(255, 241, 242, 0.86); + color: #7f1d1d; + font-size: 12px; +} + +.import-result__failure code { + color: #475569; + word-break: break-all; } .delete-dialog__header { @@ -497,27 +1113,6 @@ onMounted(loadRooms); line-height: 1.75; } -.delete-dialog__note { - display: grid; - gap: 8px; - padding: 16px 18px; - border-radius: 14px; - border: 1px solid rgba(183, 80, 70, 0.14); - background: rgba(183, 80, 70, 0.06); -} - -.delete-dialog__note-title { - font-size: 13px; - font-weight: 700; - color: #8f443a; -} - -.delete-dialog__note p { - margin: 0; - color: #6b5d57; - line-height: 1.7; -} - .dialog-footer { display: flex; align-items: center; @@ -528,38 +1123,43 @@ onMounted(loadRooms); justify-content: flex-end; } -:deep(.form-dialog .el-dialog__header) { - padding: 24px 24px 8px; -} - -:deep(.form-dialog .el-dialog__body) { - padding: 12px 24px 10px; -} - -:deep(.form-dialog .el-dialog__footer) { - padding: 12px 24px 24px; -} - -:deep(.delete-room-dialog .el-dialog__header) { - padding: 24px 24px 0; -} - -:deep(.delete-room-dialog .el-dialog__body) { - padding: 18px 24px 10px; -} - -:deep(.delete-room-dialog .el-dialog__footer) { - padding: 12px 24px 24px; -} - -@media (max-width: 768px) { +@media (max-width: 960px) { .toolbar-row { - margin-bottom: 16px; - padding-bottom: 16px; + flex-direction: column; + } + + .batch-actions { + justify-content: flex-start; + } + + .header-actions { + align-self: stretch; + justify-content: stretch; + } + + .header-actions :deep(.el-button) { + flex: 1 1 0; + margin: 0; + } + + .settings-grid { + grid-template-columns: 1fr; + } +} + +@media (max-width: 640px) { + .header-actions :deep(.el-space__item) { + width: 100%; + } + + .header-actions :deep(.el-button) { + width: 100%; + margin: 0; } .dialog-footer { flex-wrap: wrap; + justify-content: stretch; } .dialog-footer :deep(.el-button) { diff --git a/frontend/src/views/LoginView.vue b/frontend/src/views/LoginView.vue index 72557c4..3ed1b15 100644 --- a/frontend/src/views/LoginView.vue +++ b/frontend/src/views/LoginView.vue @@ -3,11 +3,14 @@ import { reactive, ref } from "vue"; import { useRouter } from "vue-router"; import { ElMessage } from "element-plus"; import { Lock, User } from "@element-plus/icons-vue"; +import { getApiErrorMessage, isBackendUnavailableError } from "@/api/client"; +import { useBackendStatus } from "@/composables/useBackendStatus"; import { useAuthStore } from "@/stores/auth"; const router = useRouter(); const authStore = useAuthStore(); const loading = ref(false); +const { backendUnavailable, backendMessage } = useBackendStatus(); const form = reactive({ username: "admin", @@ -22,7 +25,11 @@ async function handleLogin() { ElMessage.success("登录成功"); await router.push({ name: "live-rooms" }); } catch (error) { - ElMessage.error("登录失败,请检查账号密码"); + ElMessage.error( + isBackendUnavailableError(error) + ? getApiErrorMessage(error) + : "登录失败,请检查账号密码" + ); } finally { loading.value = false; } @@ -35,20 +42,30 @@ async function handleLogin() {

把直播录制做成可长期维护的系统,而不是一次性的脚本。

- 平台适配、后台巡检、录制任务、日志和系统设置统一收口。 + 平台适配、后台巡检、录制任务、系统日志和设置统一管理。 默认账号为 admin / Admin@123

+ +
@@ -282,10 +377,23 @@ onMounted(loadDetailAndPreview); gap: 24px; } +.page-error-alert { + border-radius: 14px; +} + .header-actions { align-self: center; } +.detail-logs-shell { + margin-inline: -4px; + padding-inline: 4px; +} + +.detail-logs-table { + min-width: 940px; +} + .detail-card :deep(.el-card__body), .preview-card :deep(.el-card__body), .logs-card :deep(.el-card__body) { @@ -307,6 +415,12 @@ onMounted(loadDetailAndPreview); font-size: 12px; } +.preview-actions { + display: flex; + align-items: center; + gap: 12px; +} + .preview-player { width: 100%; max-height: 560px; @@ -326,15 +440,53 @@ onMounted(loadDetailAndPreview); background: linear-gradient(180deg, rgba(255, 255, 255, 0.76), rgba(246, 243, 238, 0.78)); } +.detail-postprocess { + display: grid; + gap: 8px; +} + +.detail-postprocess__stage { + font-size: 13px; + font-weight: 600; + color: #31465b; +} + +.detail-postprocess__detail { + font-size: 12px; + color: #6c7a86; + line-height: 1.4; +} + .log-detail { font-size: 12px; color: #6d665b; } @media (max-width: 768px) { + .header-actions { + width: 100%; + justify-content: stretch; + } + + .header-actions :deep(.el-button) { + flex: 1 1 0; + margin: 0; + } + .preview-header { + flex-direction: column; + align-items: flex-start; margin-bottom: 16px; padding-bottom: 16px; } + + .preview-actions { + width: 100%; + justify-content: space-between; + } + + .preview-player { + max-height: 360px; + } } diff --git a/frontend/src/views/RecordTasksView.vue b/frontend/src/views/RecordTasksView.vue index 812c933..64222e4 100644 --- a/frontend/src/views/RecordTasksView.vue +++ b/frontend/src/views/RecordTasksView.vue @@ -1,8 +1,14 @@