most-box 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -26
- package/electron/main.js +366 -30
- package/electron/preload.js +16 -1
- package/electron/updateChecker.js +18 -11
- package/electron/updateChecker.test.js +23 -7
- package/out/admin/index.html +0 -0
- package/out/app/index.html +0 -0
- package/out/assets/AppShell-gILTcRs-.js +1 -0
- package/out/assets/FilePreviewOverlay-CM-fcIaD.js +1 -0
- package/out/assets/LanguageToggle-B99eQcTE.js +1 -0
- package/out/assets/MarketingHeader-Q2cpkqAM.js +1 -0
- package/out/assets/MarketingLayout-X3Nj2JvA.js +1 -0
- package/out/assets/{MarketingThemeToggle-C6fggkl7.js → MarketingThemeToggle-z4jr4-vt.js} +1 -1
- package/out/assets/{MilkdownEditor-Cfze75zl.js → MilkdownEditor-Bv2VA3bu.js} +1 -1
- package/out/assets/{OpenSidebarButton-DDuALgJ2.js → OpenSidebarButton-CaQJk5LD.js} +1 -1
- package/out/assets/{SidebarAccount-bo1ypzrJ.js → SidebarAccount-CpNVqNva.js} +1 -1
- package/out/assets/arrow-right-mNO53HQi.js +1 -0
- package/out/assets/{circle-alert-BQoSDxUe.js → circle-alert-CofRTRHr.js} +1 -1
- package/out/assets/cloud-DAGFCFIp.js +1 -0
- package/out/assets/{copy-BtJHJnqH.js → copy-5aEv78Eq.js} +1 -1
- package/out/assets/{download-Bg-OdoxM.js → download-Bhqn6hL1.js} +1 -1
- package/out/assets/{downloadValidation-CUvbvj9f.js → downloadValidation-xzpa5rap.js} +1 -1
- package/out/assets/{external-link-m8ZIQe4p.js → external-link-CNR21yFA.js} +1 -1
- package/out/assets/{file-text-DG1orIkZ.js → file-text-CFfvvCnM.js} +1 -1
- package/out/assets/folder-BGJCjyba.js +1 -0
- package/out/assets/{hard-drive-BB-sllXA.js → hard-drive-4vHpA5kz.js} +1 -1
- package/out/assets/index-CgErXULe.css +1 -0
- package/out/assets/index-DN0kD5zr.js +31 -0
- package/out/assets/{index.lazy-BTndBeBF.js → index.lazy-0DsJzEoI.js} +1 -1
- package/out/assets/{index.lazy-DfsgyiMN.js → index.lazy-CJBRtbWA.js} +1 -1
- package/out/assets/{index.lazy-DejOniAm.js → index.lazy-CPV-dZxo.js} +1 -1
- package/out/assets/{index.lazy-DVOcrcEB.js → index.lazy-CQavt0-9.js} +2 -2
- package/out/assets/index.lazy-CUq9lbK_.js +1 -0
- package/out/assets/index.lazy-CxpNXlwa.js +1 -0
- package/out/assets/index.lazy-DOgKxDuF.js +1 -0
- package/out/assets/index.lazy-Dzf-q-Vf.js +1 -0
- package/out/assets/index.lazy-GtegOPkJ.js +2 -0
- package/out/assets/index.lazy-H7NATHUs.js +1 -0
- package/out/assets/index.lazy-b_N8nrYw.js +1 -0
- package/out/assets/index.lazy-erexqght.js +3 -0
- package/out/assets/index.lazy-s3nUpCQ1.js +1 -0
- package/out/assets/{key-round-DIQ3Xt5F.js → key-round-BpSdpOHi.js} +1 -1
- package/out/assets/loader-ByMmV2_4.js +1 -0
- package/out/assets/{lock-tf1t2yuy.js → lock-C0pdaery.js} +1 -1
- package/out/assets/{message-square-DaQH7q-P.js → message-square-Eu86zZup.js} +1 -1
- package/out/assets/{mp-DvFTsIL9.js → mp-DjXDNjls.js} +1 -1
- package/out/assets/{music-DaFvU2DL.js → music-Btrhub6z.js} +1 -1
- package/out/assets/{notebook-pen-CqEFOHKx.js → notebook-pen-CfdFgaDE.js} +1 -1
- package/out/assets/play-D5r9Yvbq.js +1 -0
- package/out/assets/plus-Mlh7r_bm.js +1 -0
- package/out/assets/{refresh-cw-roxAhABl.js → refresh-cw--JB8k6mH.js} +1 -1
- package/out/assets/{save-DR0O9ReR.js → save-DN4eprSt.js} +1 -1
- package/out/assets/search-CbzMyENy.js +1 -0
- package/out/assets/{send-m1XCcuPn.js → send-D8p6f8OD.js} +1 -1
- package/out/assets/{shield-check-BwcvTU4U.js → shield-check-c0labdRH.js} +1 -1
- package/out/assets/{trash-2-CNpsqYc1.js → trash-2-zdhWec_U.js} +1 -1
- package/out/assets/{triangle-alert-DP9EP7IM.js → triangle-alert-D-qigSSn.js} +1 -1
- package/out/assets/upload-BD23c5Pz.js +1 -0
- package/out/assets/{useChannelMessages-46C52EyL.js → useChannelMessages-DS1ntAKN.js} +2 -2
- package/out/assets/useGameRoom-BSPkCY3n.js +1 -0
- package/out/assets/userProfile-BmzBA_Bk.js +1 -0
- package/out/assets/{userStore-C4vdYsQp.js → userStore-q0BBZsIV.js} +1 -1
- package/out/assets/{wallet-CozFU6yK.js → wallet-DmZMdK9A.js} +1 -1
- package/out/assets/{wifi-DIR3g_8A.js → wifi-CVqaPDcv.js} +1 -1
- package/out/chat/index.html +0 -0
- package/out/chat/join/index.html +0 -0
- package/out/download/index.html +2 -2
- package/out/game/gandengyan/index.html +0 -0
- package/out/game/index.html +0 -0
- package/out/game/zhajinhua/index.html +0 -0
- package/out/index.html +2 -2
- package/out/note/index.html +0 -0
- package/out/ping/index.html +2 -2
- package/out/profile/index.html +0 -0
- package/out/web3/index.html +0 -0
- package/package.json +8 -1
- package/server/index.js +2 -2
- package/server/src/core/syncTimestamp.js +10 -0
- package/server/src/http/nodeStatus.js +16 -16
- package/server/src/http/routePolicy.js +2 -2
- package/server/src/http/routes/nodeRoutes.js +21 -19
- package/server/src/index.js +578 -960
- package/server/src/utils/accountBackup.js +134 -0
- package/server/src/utils/api.js +27 -1
- package/out/assets/AppShell-BOtfY12t.js +0 -1
- package/out/assets/FilePreviewOverlay-C5qK9HAE.js +0 -1
- package/out/assets/LanguageToggle-Di5b88mK.js +0 -1
- package/out/assets/MarketingHeader-BOytKcCc.js +0 -1
- package/out/assets/MarketingLayout-B8m1Q7Pa.js +0 -1
- package/out/assets/arrow-right-RldN7Rwi.js +0 -1
- package/out/assets/cloud-DHoTMeZY.js +0 -1
- package/out/assets/index-C0xqKeu-.css +0 -1
- package/out/assets/index-CrAXrmfP.js +0 -31
- package/out/assets/index.lazy-0Njp0U6I.js +0 -1
- package/out/assets/index.lazy-Bq39jYTl.js +0 -1
- package/out/assets/index.lazy-Bu93oGzJ.js +0 -2
- package/out/assets/index.lazy-BvdBwgHx.js +0 -1
- package/out/assets/index.lazy-CIx8ist6.js +0 -3
- package/out/assets/index.lazy-DK7R297q.js +0 -1
- package/out/assets/index.lazy-DpNIiSXF.js +0 -1
- package/out/assets/index.lazy-Vnvz-t7T.js +0 -1
- package/out/assets/index.lazy-v7nBJ-sF.js +0 -1
- package/out/assets/play-B7q6F75-.js +0 -1
- package/out/assets/plus-H2i2mspM.js +0 -1
- package/out/assets/search-ncblG-zw.js +0 -1
- package/out/assets/upload-V--8p13l.js +0 -1
- package/out/assets/useGameRoom-BtxPpfck.js +0 -1
- package/server/src/core/userSyncKeys.js +0 -36
- package/server/src/utils/noteBackup.js +0 -116
package/README.md
CHANGED
|
@@ -251,29 +251,6 @@ npx most-box@latest
|
|
|
251
251
|
|
|
252
252
|
在线 Web 入口只能连接已有节点;它本身不提供本机发布、下载校验或持续做种能力。
|
|
253
253
|
|
|
254
|
-
## 路线图
|
|
255
|
-
|
|
256
|
-
### v0.2.1(当前版本)
|
|
257
|
-
|
|
258
|
-
- ✅ P2P 文件上传与下载
|
|
259
|
-
- ✅ 确定性 CID 生成
|
|
260
|
-
- ✅ 大文件流式传输
|
|
261
|
-
- ✅ most:// 链接分享
|
|
262
|
-
- ✅ Web UI 界面
|
|
263
|
-
- ✅ P2P 频道聊天
|
|
264
|
-
- ✅ 网络连通性测试
|
|
265
|
-
- ✅ Electron 桌面客户端
|
|
266
|
-
|
|
267
|
-
### 长期规划
|
|
268
|
-
|
|
269
|
-
- [ ] 下载体验优化 - 检测是否可下载
|
|
270
|
-
- [ ] P2P 多人视频/语音通话
|
|
271
|
-
- 基于 WebRTC 的端到端加密通话
|
|
272
|
-
- 频道内一键发起通话
|
|
273
|
-
- 屏幕共享与文字聊天
|
|
274
|
-
- [ ] 浏览器扩展
|
|
275
|
-
- [ ] 移动端支持(iOS/Android)
|
|
276
|
-
|
|
277
254
|
## 技术栈
|
|
278
255
|
|
|
279
256
|
- **前端**: React 19, Vite, TanStack Start static prerender, TanStack Router, TypeScript, Zustand, Lucide React
|
|
@@ -287,15 +264,15 @@ npx most-box@latest
|
|
|
287
264
|
发布新版本时,推送 tag 即可自动构建:
|
|
288
265
|
|
|
289
266
|
```bash
|
|
290
|
-
git tag
|
|
291
|
-
git push origin
|
|
267
|
+
git tag vx.x.x
|
|
268
|
+
git push origin vx.x.x
|
|
292
269
|
```
|
|
293
270
|
|
|
294
271
|
触发后自动执行:
|
|
295
272
|
|
|
296
273
|
1. **npm 包发布** — 发布 `most-box` 到 npm registry
|
|
297
274
|
2. **Windows 打包** — 分别构建 `.exe` 安装包(x64 / arm64)并上传 Release
|
|
298
|
-
3. **macOS 打包** — 构建 `.dmg`
|
|
275
|
+
3. **macOS 打包** — 构建 `.dmg` 安装包和 `.zip` 更新包(x64 + arm64)并上传 Release
|
|
299
276
|
4. **Linux 打包** — 构建 `.AppImage` 安装包(x64 + arm64)并上传 Release
|
|
300
277
|
5. **下载镜像** — 将 Release 资产同步到 Cloudflare R2,并生成 `releases/latest.json`
|
|
301
278
|
|
package/electron/main.js
CHANGED
|
@@ -3,16 +3,17 @@ import {
|
|
|
3
3
|
BrowserWindow,
|
|
4
4
|
Menu,
|
|
5
5
|
Tray,
|
|
6
|
-
|
|
6
|
+
ipcMain,
|
|
7
7
|
nativeImage,
|
|
8
8
|
shell,
|
|
9
9
|
} from 'electron'
|
|
10
|
+
import { spawn } from 'node:child_process'
|
|
10
11
|
import fs from 'node:fs'
|
|
11
12
|
import path from 'node:path'
|
|
13
|
+
import { Readable } from 'node:stream'
|
|
12
14
|
import { fileURLToPath } from 'node:url'
|
|
13
15
|
|
|
14
16
|
import {
|
|
15
|
-
formatBytes,
|
|
16
17
|
getAvailableUpdate,
|
|
17
18
|
getCurrentArch,
|
|
18
19
|
getCurrentPlatform,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
createMostDeepLinkTarget,
|
|
23
24
|
findMostDeepLinkArg,
|
|
24
25
|
} from './deepLink.js'
|
|
26
|
+
import { calculateCid } from '../server/src/core/cid.js'
|
|
25
27
|
|
|
26
28
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
27
29
|
const PORT = 1976
|
|
@@ -32,6 +34,16 @@ let tray = null
|
|
|
32
34
|
let isQuitting = false
|
|
33
35
|
let hasCheckedForUpdates = false
|
|
34
36
|
let pendingDeepLinkUrl = ''
|
|
37
|
+
let updateState = {
|
|
38
|
+
status: 'idle',
|
|
39
|
+
version: '',
|
|
40
|
+
filename: '',
|
|
41
|
+
source: '',
|
|
42
|
+
progress: 0,
|
|
43
|
+
error: '',
|
|
44
|
+
path: '',
|
|
45
|
+
cid: '',
|
|
46
|
+
}
|
|
35
47
|
|
|
36
48
|
const gotSingleInstanceLock = app.requestSingleInstanceLock()
|
|
37
49
|
|
|
@@ -89,6 +101,57 @@ function getInitialWindowUrl() {
|
|
|
89
101
|
return initialUrl
|
|
90
102
|
}
|
|
91
103
|
|
|
104
|
+
function getPublicUpdateState() {
|
|
105
|
+
return {
|
|
106
|
+
status: updateState.status,
|
|
107
|
+
version: updateState.version,
|
|
108
|
+
filename: updateState.filename,
|
|
109
|
+
source: updateState.source,
|
|
110
|
+
progress: updateState.progress,
|
|
111
|
+
error: updateState.error,
|
|
112
|
+
cid: updateState.cid,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function setUpdateState(patch) {
|
|
117
|
+
updateState = {
|
|
118
|
+
...updateState,
|
|
119
|
+
...patch,
|
|
120
|
+
}
|
|
121
|
+
mainWindow?.webContents.send('updates:state', getPublicUpdateState())
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function getUpdateAssetFilename(update) {
|
|
125
|
+
return path.basename(
|
|
126
|
+
update.asset.filename ||
|
|
127
|
+
`MostBox-${update.version}-${getCurrentPlatform()}-${getCurrentArch()}`
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function getSafeVersionDir(version) {
|
|
132
|
+
return String(version || 'unknown').replace(/[^a-zA-Z0-9._-]/g, '_')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getUpdateCachePath(update) {
|
|
136
|
+
const filename = getUpdateAssetFilename(update)
|
|
137
|
+
return path.join(
|
|
138
|
+
app.getPath('userData'),
|
|
139
|
+
'updates',
|
|
140
|
+
getSafeVersionDir(update.version),
|
|
141
|
+
filename
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function verifyFileCid(filePath, expectedCid) {
|
|
146
|
+
const { cid } = await calculateCid(filePath)
|
|
147
|
+
const actualCid = cid.toString()
|
|
148
|
+
if (actualCid !== expectedCid) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Update CID mismatch. Expected ${expectedCid}, got ${actualCid}.`
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
92
155
|
function registerMostProtocolClient() {
|
|
93
156
|
if (process.defaultApp && process.argv.length >= 2) {
|
|
94
157
|
app.setAsDefaultProtocolClient('most', process.execPath, [
|
|
@@ -100,6 +163,14 @@ function registerMostProtocolClient() {
|
|
|
100
163
|
app.setAsDefaultProtocolClient('most')
|
|
101
164
|
}
|
|
102
165
|
|
|
166
|
+
function registerUpdateIpc() {
|
|
167
|
+
ipcMain.handle('updates:get-state', () => getPublicUpdateState())
|
|
168
|
+
ipcMain.handle('updates:install-and-restart', async () => {
|
|
169
|
+
await installDownloadedUpdate()
|
|
170
|
+
return getPublicUpdateState()
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
103
174
|
function openMostDeepLink(link) {
|
|
104
175
|
const targetUrl = createMostDeepLinkTarget(
|
|
105
176
|
link,
|
|
@@ -201,14 +272,294 @@ async function fetchReleaseManifest(manifestUrl) {
|
|
|
201
272
|
}
|
|
202
273
|
}
|
|
203
274
|
|
|
275
|
+
async function downloadUpdateFromHttp(update, targetPath) {
|
|
276
|
+
if (!update.downloadUrl) {
|
|
277
|
+
throw new Error('No HTTP fallback URL is available for this update')
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const tempPath = `${targetPath}.http.part`
|
|
281
|
+
fs.rmSync(tempPath, { force: true })
|
|
282
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true })
|
|
283
|
+
|
|
284
|
+
const response = await fetch(update.downloadUrl, { cache: 'no-store' })
|
|
285
|
+
if (!response.ok || !response.body) {
|
|
286
|
+
throw new Error(`HTTP update download failed: ${response.status}`)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const total = Number(response.headers.get('content-length')) || 0
|
|
290
|
+
let loaded = 0
|
|
291
|
+
|
|
292
|
+
await new Promise((resolve, reject) => {
|
|
293
|
+
const rs = Readable.fromWeb(response.body)
|
|
294
|
+
const ws = fs.createWriteStream(tempPath)
|
|
295
|
+
|
|
296
|
+
const cleanup = err => {
|
|
297
|
+
rs.destroy(err)
|
|
298
|
+
ws.destroy()
|
|
299
|
+
fs.unlink(tempPath, () => {})
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
rs.on('data', chunk => {
|
|
303
|
+
loaded += chunk.length
|
|
304
|
+
if (total > 0) {
|
|
305
|
+
setUpdateState({
|
|
306
|
+
status: 'downloading',
|
|
307
|
+
source: 'http',
|
|
308
|
+
progress: Math.min(99, Math.round((loaded / total) * 100)),
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
rs.on('error', err => {
|
|
314
|
+
cleanup(err)
|
|
315
|
+
reject(err)
|
|
316
|
+
})
|
|
317
|
+
ws.on('error', err => {
|
|
318
|
+
cleanup(err)
|
|
319
|
+
reject(err)
|
|
320
|
+
})
|
|
321
|
+
ws.on('finish', resolve)
|
|
322
|
+
rs.pipe(ws)
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
await verifyFileCid(tempPath, update.cid)
|
|
327
|
+
fs.rmSync(targetPath, { force: true })
|
|
328
|
+
fs.renameSync(tempPath, targetPath)
|
|
329
|
+
} catch (error) {
|
|
330
|
+
fs.rmSync(tempPath, { force: true })
|
|
331
|
+
throw error
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
try {
|
|
335
|
+
await engine?.seedCidFileFromPath(update.cid, targetPath, {
|
|
336
|
+
fileName: getUpdateAssetFilename(update),
|
|
337
|
+
source: 'update',
|
|
338
|
+
})
|
|
339
|
+
} catch (error) {
|
|
340
|
+
console.warn('[Electron] Update downloaded but seeding failed:', error)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function downloadUpdateByCid(update, targetPath) {
|
|
345
|
+
if (!engine?.downloadCidToPath) {
|
|
346
|
+
throw new Error('MostBox engine update download API is unavailable')
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const taskId = `update_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
|
|
350
|
+
const filename = getUpdateAssetFilename(update)
|
|
351
|
+
|
|
352
|
+
const onProgress = data => {
|
|
353
|
+
if (data?.taskId !== taskId) return
|
|
354
|
+
setUpdateState({
|
|
355
|
+
status: 'downloading',
|
|
356
|
+
source: 'cid',
|
|
357
|
+
progress: Math.min(99, Number(data.percent) || 0),
|
|
358
|
+
})
|
|
359
|
+
}
|
|
360
|
+
const onStatus = data => {
|
|
361
|
+
if (data?.taskId !== taskId) return
|
|
362
|
+
setUpdateState({
|
|
363
|
+
status: 'downloading',
|
|
364
|
+
source: 'cid',
|
|
365
|
+
filename,
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
engine.on('download:progress', onProgress)
|
|
370
|
+
engine.on('download:status', onStatus)
|
|
371
|
+
try {
|
|
372
|
+
await engine.downloadCidToPath({
|
|
373
|
+
cid: update.cid,
|
|
374
|
+
fileName: filename,
|
|
375
|
+
targetPath,
|
|
376
|
+
taskId,
|
|
377
|
+
timeout: 30000,
|
|
378
|
+
overwrite: true,
|
|
379
|
+
source: 'update',
|
|
380
|
+
})
|
|
381
|
+
} finally {
|
|
382
|
+
engine.off('download:progress', onProgress)
|
|
383
|
+
engine.off('download:status', onStatus)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async function downloadUpdate(update) {
|
|
388
|
+
const targetPath = getUpdateCachePath(update)
|
|
389
|
+
const filename = getUpdateAssetFilename(update)
|
|
390
|
+
|
|
391
|
+
setUpdateState({
|
|
392
|
+
status: 'downloading',
|
|
393
|
+
version: update.version,
|
|
394
|
+
filename,
|
|
395
|
+
source: 'cid',
|
|
396
|
+
progress: 0,
|
|
397
|
+
error: '',
|
|
398
|
+
path: '',
|
|
399
|
+
cid: update.cid,
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
try {
|
|
403
|
+
await downloadUpdateByCid(update, targetPath)
|
|
404
|
+
} catch (cidError) {
|
|
405
|
+
console.warn('[Electron] CID update download failed, trying fallback:', cidError)
|
|
406
|
+
setUpdateState({
|
|
407
|
+
status: 'downloading',
|
|
408
|
+
source: 'http',
|
|
409
|
+
progress: 0,
|
|
410
|
+
error: '',
|
|
411
|
+
})
|
|
412
|
+
await downloadUpdateFromHttp(update, targetPath)
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
await verifyFileCid(targetPath, update.cid)
|
|
416
|
+
setUpdateState({
|
|
417
|
+
status: 'downloaded',
|
|
418
|
+
version: update.version,
|
|
419
|
+
filename,
|
|
420
|
+
source: updateState.source || 'cid',
|
|
421
|
+
progress: 100,
|
|
422
|
+
error: '',
|
|
423
|
+
path: targetPath,
|
|
424
|
+
cid: update.cid,
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function quitForUpdate() {
|
|
429
|
+
isQuitting = true
|
|
430
|
+
if (tray) {
|
|
431
|
+
tray.destroy()
|
|
432
|
+
tray = null
|
|
433
|
+
}
|
|
434
|
+
app.quit()
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function installWindowsUpdate(updatePath) {
|
|
438
|
+
const child = spawn(updatePath, ['/S'], {
|
|
439
|
+
detached: true,
|
|
440
|
+
stdio: 'ignore',
|
|
441
|
+
})
|
|
442
|
+
child.unref()
|
|
443
|
+
quitForUpdate()
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function getMacAppBundlePath() {
|
|
447
|
+
return path.resolve(app.getPath('exe'), '../../..')
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function installMacUpdate(updatePath) {
|
|
451
|
+
const scriptPath = path.join(app.getPath('userData'), 'updates', 'install-mac.sh')
|
|
452
|
+
const appBundlePath = getMacAppBundlePath()
|
|
453
|
+
const script = `#!/bin/bash
|
|
454
|
+
set -e
|
|
455
|
+
APP_PATH="$1"
|
|
456
|
+
ZIP_PATH="$2"
|
|
457
|
+
TMP_DIR="$(mktemp -d)"
|
|
458
|
+
cleanup() {
|
|
459
|
+
rm -rf "$TMP_DIR"
|
|
460
|
+
}
|
|
461
|
+
trap cleanup EXIT
|
|
462
|
+
while pgrep -f "$APP_PATH/Contents/MacOS" >/dev/null 2>&1; do
|
|
463
|
+
sleep 1
|
|
464
|
+
done
|
|
465
|
+
ditto -x -k "$ZIP_PATH" "$TMP_DIR"
|
|
466
|
+
NEW_APP="$(find "$TMP_DIR" -maxdepth 1 -name "*.app" -type d | head -n 1)"
|
|
467
|
+
if [ -z "$NEW_APP" ]; then
|
|
468
|
+
exit 1
|
|
469
|
+
fi
|
|
470
|
+
rm -rf "$APP_PATH"
|
|
471
|
+
ditto "$NEW_APP" "$APP_PATH"
|
|
472
|
+
open "$APP_PATH"
|
|
473
|
+
`
|
|
474
|
+
|
|
475
|
+
fs.mkdirSync(path.dirname(scriptPath), { recursive: true })
|
|
476
|
+
fs.writeFileSync(scriptPath, script, { mode: 0o755 })
|
|
477
|
+
const child = spawn('/bin/bash', [scriptPath, appBundlePath, updatePath], {
|
|
478
|
+
detached: true,
|
|
479
|
+
stdio: 'ignore',
|
|
480
|
+
})
|
|
481
|
+
child.unref()
|
|
482
|
+
quitForUpdate()
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function installLinuxUpdate(updatePath) {
|
|
486
|
+
const currentAppImage = process.env.APPIMAGE
|
|
487
|
+
if (!currentAppImage) {
|
|
488
|
+
shell.openPath(updatePath).catch(() => {})
|
|
489
|
+
throw new Error('当前 Linux 运行方式不支持自动替换 AppImage')
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const scriptPath = path.join(app.getPath('userData'), 'updates', 'install-linux.sh')
|
|
493
|
+
const script = `#!/bin/sh
|
|
494
|
+
set -e
|
|
495
|
+
APPIMAGE_PATH="$1"
|
|
496
|
+
UPDATE_PATH="$2"
|
|
497
|
+
APP_PID="$3"
|
|
498
|
+
while kill -0 "$APP_PID" >/dev/null 2>&1; do
|
|
499
|
+
sleep 1
|
|
500
|
+
done
|
|
501
|
+
cp "$UPDATE_PATH" "$APPIMAGE_PATH"
|
|
502
|
+
chmod +x "$APPIMAGE_PATH"
|
|
503
|
+
nohup "$APPIMAGE_PATH" >/dev/null 2>&1 &
|
|
504
|
+
`
|
|
505
|
+
|
|
506
|
+
fs.mkdirSync(path.dirname(scriptPath), { recursive: true })
|
|
507
|
+
fs.writeFileSync(scriptPath, script, { mode: 0o755 })
|
|
508
|
+
const child = spawn('/bin/sh', [scriptPath, currentAppImage, updatePath, String(process.pid)], {
|
|
509
|
+
detached: true,
|
|
510
|
+
stdio: 'ignore',
|
|
511
|
+
})
|
|
512
|
+
child.unref()
|
|
513
|
+
quitForUpdate()
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async function installDownloadedUpdate() {
|
|
517
|
+
if (updateState.status !== 'downloaded' || !updateState.path) {
|
|
518
|
+
throw new Error('No downloaded update is ready to install')
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
setUpdateState({ status: 'installing', error: '' })
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
if (process.platform === 'win32') {
|
|
525
|
+
installWindowsUpdate(updateState.path)
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
if (process.platform === 'darwin') {
|
|
529
|
+
installMacUpdate(updateState.path)
|
|
530
|
+
return
|
|
531
|
+
}
|
|
532
|
+
if (process.platform === 'linux') {
|
|
533
|
+
installLinuxUpdate(updateState.path)
|
|
534
|
+
return
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
throw new Error('当前平台不支持自动安装更新')
|
|
538
|
+
} catch (error) {
|
|
539
|
+
setUpdateState({
|
|
540
|
+
status: 'error',
|
|
541
|
+
error: error?.message || 'Update install failed',
|
|
542
|
+
})
|
|
543
|
+
throw error
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
204
547
|
async function checkForUpdates() {
|
|
205
548
|
if (hasCheckedForUpdates) return
|
|
206
549
|
hasCheckedForUpdates = true
|
|
207
550
|
|
|
208
551
|
try {
|
|
552
|
+
setUpdateState({
|
|
553
|
+
status: 'checking',
|
|
554
|
+
progress: 0,
|
|
555
|
+
error: '',
|
|
556
|
+
})
|
|
209
557
|
const platform = getCurrentPlatform()
|
|
210
558
|
const arch = getCurrentArch()
|
|
211
|
-
if (!platform || !arch)
|
|
559
|
+
if (!platform || !arch) {
|
|
560
|
+
setUpdateState({ status: 'idle' })
|
|
561
|
+
return
|
|
562
|
+
}
|
|
212
563
|
|
|
213
564
|
const manifest = await fetchReleaseManifest(getReleaseManifestUrl())
|
|
214
565
|
const update = getAvailableUpdate(manifest, {
|
|
@@ -217,35 +568,19 @@ async function checkForUpdates() {
|
|
|
217
568
|
arch,
|
|
218
569
|
})
|
|
219
570
|
|
|
220
|
-
if (!update)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const detail = [
|
|
224
|
-
`当前版本:${app.getVersion()}`,
|
|
225
|
-
`最新版本:${update.version}`,
|
|
226
|
-
sizeText ? `安装包大小:${sizeText}` : null,
|
|
227
|
-
'',
|
|
228
|
-
'是否现在打开浏览器下载更新?',
|
|
229
|
-
]
|
|
230
|
-
.filter(line => line !== null)
|
|
231
|
-
.join('\n')
|
|
232
|
-
|
|
233
|
-
const result = await dialog.showMessageBox(mainWindow, {
|
|
234
|
-
type: 'info',
|
|
235
|
-
buttons: ['立即下载', '稍后'],
|
|
236
|
-
defaultId: 0,
|
|
237
|
-
cancelId: 1,
|
|
238
|
-
title: '发现 MostBox 新版本',
|
|
239
|
-
message: `MostBox ${update.version} 已可下载`,
|
|
240
|
-
detail,
|
|
241
|
-
noLink: true,
|
|
242
|
-
})
|
|
243
|
-
|
|
244
|
-
if (result.response === 0) {
|
|
245
|
-
await shell.openExternal(update.downloadUrl)
|
|
571
|
+
if (!update) {
|
|
572
|
+
setUpdateState({ status: 'idle' })
|
|
573
|
+
return
|
|
246
574
|
}
|
|
575
|
+
|
|
576
|
+
await downloadUpdate(update)
|
|
247
577
|
} catch (error) {
|
|
248
|
-
console.warn('[Electron] Update check
|
|
578
|
+
console.warn('[Electron] Update check failed:', error)
|
|
579
|
+
setUpdateState({
|
|
580
|
+
status: 'error',
|
|
581
|
+
error: error?.message || 'Update check failed',
|
|
582
|
+
progress: 0,
|
|
583
|
+
})
|
|
249
584
|
}
|
|
250
585
|
}
|
|
251
586
|
|
|
@@ -254,6 +589,7 @@ if (!gotSingleInstanceLock) {
|
|
|
254
589
|
app.quit()
|
|
255
590
|
} else {
|
|
256
591
|
registerMostProtocolClient()
|
|
592
|
+
registerUpdateIpc()
|
|
257
593
|
openMostDeepLink(findMostDeepLinkArg(process.argv))
|
|
258
594
|
|
|
259
595
|
app.on('second-instance', (_event, commandLine) => {
|
package/electron/preload.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
import { contextBridge } from 'electron'
|
|
1
|
+
import { contextBridge, ipcRenderer } from 'electron'
|
|
2
2
|
|
|
3
3
|
contextBridge.exposeInMainWorld('electronAPI', {
|
|
4
4
|
platform: process.platform,
|
|
5
5
|
isElectron: true,
|
|
6
|
+
updates: {
|
|
7
|
+
getState: () => ipcRenderer.invoke('updates:get-state'),
|
|
8
|
+
installAndRestart: () => ipcRenderer.invoke('updates:install-and-restart'),
|
|
9
|
+
onStateChange: callback => {
|
|
10
|
+
if (typeof callback !== 'function') return () => {}
|
|
11
|
+
|
|
12
|
+
const listener = (_event, state) => {
|
|
13
|
+
callback(state)
|
|
14
|
+
}
|
|
15
|
+
ipcRenderer.on('updates:state', listener)
|
|
16
|
+
return () => {
|
|
17
|
+
ipcRenderer.off('updates:state', listener)
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
},
|
|
6
21
|
})
|
|
@@ -50,16 +50,23 @@ function isRecord(value) {
|
|
|
50
50
|
export function findUpdateAsset(manifest, platform, arch) {
|
|
51
51
|
if (!isRecord(manifest) || !Array.isArray(manifest.assets)) return null
|
|
52
52
|
|
|
53
|
+
const compatibleAssets = manifest.assets.filter(
|
|
54
|
+
asset =>
|
|
55
|
+
isRecord(asset) &&
|
|
56
|
+
asset.platform === platform &&
|
|
57
|
+
asset.arch === arch &&
|
|
58
|
+
(asset.kind === 'updater' || asset.kind === 'installer') &&
|
|
59
|
+
typeof asset.cid === 'string' &&
|
|
60
|
+
(typeof asset.githubUrl === 'string' ||
|
|
61
|
+
typeof asset.r2Url === 'string' ||
|
|
62
|
+
typeof asset.githubUrl === 'undefined') &&
|
|
63
|
+
(typeof asset.r2Url === 'string' || typeof asset.r2Url === 'undefined')
|
|
64
|
+
)
|
|
65
|
+
|
|
53
66
|
return (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
asset.platform === platform &&
|
|
58
|
-
asset.arch === arch &&
|
|
59
|
-
asset.kind === 'installer' &&
|
|
60
|
-
typeof asset.githubUrl === 'string' &&
|
|
61
|
-
(typeof asset.r2Url === 'string' || typeof asset.r2Url === 'undefined')
|
|
62
|
-
) || null
|
|
67
|
+
compatibleAssets.find(asset => asset.kind === 'updater') ||
|
|
68
|
+
compatibleAssets.find(asset => asset.kind === 'installer') ||
|
|
69
|
+
null
|
|
63
70
|
)
|
|
64
71
|
}
|
|
65
72
|
|
|
@@ -86,12 +93,12 @@ export function getAvailableUpdate(manifest, options = {}) {
|
|
|
86
93
|
const asset = findUpdateAsset(manifest, platform, arch)
|
|
87
94
|
if (!asset) return null
|
|
88
95
|
|
|
89
|
-
const downloadUrl = asset.r2Url || asset.githubUrl
|
|
90
|
-
if (!downloadUrl) return null
|
|
96
|
+
const downloadUrl = asset.r2Url || asset.githubUrl || ''
|
|
91
97
|
|
|
92
98
|
return {
|
|
93
99
|
version: manifest.version,
|
|
94
100
|
asset,
|
|
101
|
+
cid: asset.cid,
|
|
95
102
|
downloadUrl,
|
|
96
103
|
}
|
|
97
104
|
}
|
|
@@ -21,7 +21,19 @@ const manifest = {
|
|
|
21
21
|
kind: 'installer',
|
|
22
22
|
filename: 'MostBox-0.1.3-win-x64-setup.exe',
|
|
23
23
|
size: 112197632,
|
|
24
|
-
|
|
24
|
+
cid: 'bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e',
|
|
25
|
+
r2Url:
|
|
26
|
+
'https://download.most.box/releases/v0.1.3/MostBox-0.1.3-win-x64-setup.exe',
|
|
27
|
+
githubUrl:
|
|
28
|
+
'https://github.com/most-people/most/releases/download/v0.1.3/MostBox-0.1.3-win-x64-setup.exe',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
platform: 'windows',
|
|
32
|
+
arch: 'x64',
|
|
33
|
+
kind: 'updater',
|
|
34
|
+
filename: 'MostBox-0.1.3-win-x64-setup.exe',
|
|
35
|
+
size: 112197632,
|
|
36
|
+
cid: 'bafkreifzjut3te2nhyekklss27nh3k72ysco7y32koao5eei66wof36n5e',
|
|
25
37
|
r2Url:
|
|
26
38
|
'https://download.most.box/releases/v0.1.3/MostBox-0.1.3-win-x64-setup.exe',
|
|
27
39
|
githubUrl:
|
|
@@ -30,18 +42,20 @@ const manifest = {
|
|
|
30
42
|
{
|
|
31
43
|
platform: 'windows',
|
|
32
44
|
arch: 'arm64',
|
|
33
|
-
kind: '
|
|
45
|
+
kind: 'updater',
|
|
34
46
|
filename: 'MostBox-0.1.3-win-arm64-setup.exe',
|
|
47
|
+
cid: 'bafkreidsxk7x7eekhalvskbqtqnucird2p4eq3riz6ijmrswzm4miwq74m',
|
|
35
48
|
githubUrl:
|
|
36
49
|
'https://github.com/most-people/most/releases/download/v0.1.3/MostBox-0.1.3-win-arm64-setup.exe',
|
|
37
50
|
},
|
|
38
51
|
{
|
|
39
52
|
platform: 'macos',
|
|
40
53
|
arch: 'arm64',
|
|
41
|
-
kind: '
|
|
42
|
-
filename: 'MostBox-0.1.3-mac-arm64.
|
|
54
|
+
kind: 'updater',
|
|
55
|
+
filename: 'MostBox-0.1.3-mac-arm64.zip',
|
|
56
|
+
cid: 'bafkreicjs6qwdk7xuclzrkch7gx4vy3zc7y5dxrg4i764py54nk5kekbsm',
|
|
43
57
|
githubUrl:
|
|
44
|
-
'https://github.com/most-people/most/releases/download/v0.1.3/MostBox-0.1.3-mac-arm64.
|
|
58
|
+
'https://github.com/most-people/most/releases/download/v0.1.3/MostBox-0.1.3-mac-arm64.zip',
|
|
45
59
|
},
|
|
46
60
|
],
|
|
47
61
|
}
|
|
@@ -86,6 +100,7 @@ describe('desktop update checker', () => {
|
|
|
86
100
|
findUpdateAsset(manifest, 'windows', 'x64')?.filename,
|
|
87
101
|
'MostBox-0.1.3-win-x64-setup.exe'
|
|
88
102
|
)
|
|
103
|
+
assert.equal(findUpdateAsset(manifest, 'windows', 'x64')?.kind, 'updater')
|
|
89
104
|
assert.equal(
|
|
90
105
|
findUpdateAsset(manifest, 'windows', 'arm64')?.filename,
|
|
91
106
|
'MostBox-0.1.3-win-arm64-setup.exe'
|
|
@@ -101,7 +116,8 @@ describe('desktop update checker', () => {
|
|
|
101
116
|
})
|
|
102
117
|
|
|
103
118
|
assert.equal(update?.version, '0.1.3')
|
|
104
|
-
assert.equal(update?.
|
|
119
|
+
assert.equal(update?.cid, manifest.assets[1].cid)
|
|
120
|
+
assert.equal(update?.downloadUrl, manifest.assets[1].r2Url)
|
|
105
121
|
|
|
106
122
|
assert.equal(
|
|
107
123
|
getAvailableUpdate(manifest, {
|
|
@@ -136,7 +152,7 @@ describe('desktop update checker', () => {
|
|
|
136
152
|
arch: 'arm64',
|
|
137
153
|
})
|
|
138
154
|
|
|
139
|
-
assert.equal(update?.downloadUrl, manifest.assets[
|
|
155
|
+
assert.equal(update?.downloadUrl, manifest.assets[2].githubUrl)
|
|
140
156
|
})
|
|
141
157
|
|
|
142
158
|
it('formats installer sizes for update prompts', () => {
|
package/out/admin/index.html
CHANGED
|
Binary file
|
package/out/app/index.html
CHANGED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{g as r}from"./userStore-q0BBZsIV.js";import{n as i,t as a}from"./LanguageToggle-B99eQcTE.js";import{I as o}from"./index-DN0kD5zr.js";var s=r(`menu`,[[`path`,{d:`M4 5h16`,key:`1tepv9`}],[`path`,{d:`M4 12h16`,key:`1lakjw`}],[`path`,{d:`M4 19h16`,key:`1djgab`}]]),c=t(e(),1);function l(e,t){return typeof t==`boolean`?t:typeof window<`u`&&`matchMedia`in window?window.matchMedia(e).matches:!1}function u(e,t,{getInitialValueInEffect:n}={getInitialValueInEffect:!0}){let[r,i]=(0,c.useState)(n?t:l(e));return(0,c.useEffect)(()=>{try{if(`matchMedia`in window){let t=window.matchMedia(e);i(t.matches);let n=e=>i(e.matches);return t.addEventListener(`change`,n),()=>{t.removeEventListener(`change`,n)}}}catch{return}},[e]),r||!1}function d(e=!1,t={}){let[n,r]=(0,c.useState)(e),i=(0,c.useCallback)(()=>{r(e=>e||(t.onOpen?.(),!0))},[t.onOpen]),a=(0,c.useCallback)(()=>{r(e=>e&&(t.onClose?.(),!1))},[t.onClose]);return[n,{open:i,close:a,toggle:(0,c.useCallback)(()=>{n?a():i()},[a,i,n]),set:r}]}var f=n(),p=(0,c.createContext)(null);function m(){let e=(0,c.useContext)(p);if(!e)throw Error(`useAppShell must be used within AppShell`);return e}function h({sidebar:e,className:t=``,headerTitle:n,headerRight:r,sidebarToggleReplacement:l,defaultHide:m=!1,children:h}){let[g,_]=d(!1),[v,y]=(0,c.useState)(m),b=(0,c.useRef)(m),x=u(`(max-width: 768px)`),{t:S}=o(),C=(0,c.useCallback)((e={})=>{_.close(),e.collapse&&y(!0)},[_]);(0,c.useEffect)(()=>{m!==b.current&&(m?C({collapse:!0}):y(!1),b.current=m)},[m,C]);let w=()=>{x?_.toggle():y(!v)},T=()=>{x?_.open():y(!1)},E=x?g:!v;return(0,f.jsx)(p.Provider,{value:{closeSidebar:C,openSidebar:T,isSidebarVisible:E},children:(0,f.jsxs)(`div`,{className:[`app-layout`,t].filter(Boolean).join(` `),children:[(0,f.jsx)(`div`,{className:`sidebar-overlay ${g?`visible`:``}`,onClick:()=>C()}),(0,f.jsx)(`div`,{className:`sidebar ${g?`open`:``} ${v?`collapsed`:``}`,children:e({closeSidebar:C,openSidebar:T})}),(0,f.jsxs)(`div`,{className:`main-content`,children:[(0,f.jsxs)(`header`,{className:`app-header`,children:[(0,f.jsxs)(`div`,{className:`header-left`,children:[l??(0,f.jsx)(`button`,{onClick:w,className:`btn btn-icon sidebar-toggle-btn`,"aria-label":S(x?`appShell.openMenu`:v?`appShell.expandSidebar`:`appShell.collapseSidebar`),children:(0,f.jsx)(s,{size:16})}),n]}),(0,f.jsxs)(`div`,{className:`header-right`,children:[(0,f.jsx)(i,{}),(0,f.jsx)(a,{className:`btn btn-icon app-language-toggle`}),r]})]}),h]})]})})}export{m as n,d as r,h as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,o as t,t as n}from"./jsx-runtime-Bt-cYkS5.js";import{g as r}from"./userStore-q0BBZsIV.js";import{t as i}from"./file-text-CFfvvCnM.js";import{t as a}from"./loader-ByMmV2_4.js";import{t as o}from"./music-Btrhub6z.js";import{I as s,b as c,k as l}from"./index-DN0kD5zr.js";var u=r(`film`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M3 7.5h4`,key:`zfgn84`}],[`path`,{d:`M3 12h18`,key:`1i2n21`}],[`path`,{d:`M3 16.5h4`,key:`1230mu`}],[`path`,{d:`M17 3v18`,key:`in4fa5`}],[`path`,{d:`M17 7.5h4`,key:`myr1c1`}],[`path`,{d:`M17 16.5h4`,key:`go4c1d`}]]),d=r(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]),f=r(`pen`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]]);function p(e){let t=String(e||``).split(`.`).pop()?.toLowerCase()||``,n=[`jpg`,`jpeg`,`png`,`gif`,`webp`,`svg`,`bmp`,`ico`,`tiff`,`heic`,`heif`],r=[`mp4`,`webm`,`mov`,`avi`,`mkv`,`flv`,`wmv`,`m4v`,`mpeg`,`3gp`],i=[`mp3`,`wav`,`ogg`,`flac`,`aac`,`m4a`,`wma`,`opus`],a=`txt.md.js.ts.jsx.tsx.css.scss.less.json.xml.html.htm.yaml.yml.toml.ini.cfg.conf.log.sh.bash.py.rb.go.rs.java.c.cpp.h.hpp.cs.php.sql.graphql.env.gitignore.dockerfile.readme`.split(`.`);return n.includes(t)?`image`:r.includes(t)?`video`:i.includes(t)?`audio`:a.includes(t)?`text`:`file`}var m=t(e(),1),h=n();function g(e){return e===`image`||e===`video`||e===`audio`}function _({item:e,isBackendReady:t,getFileDownloadUrl:n,onClose:r}){let{t:u}=s(),[d,f]=(0,m.useState)(``),[p,_]=(0,m.useState)(!1),[v,y]=(0,m.useState)(``),[b,x]=(0,m.useState)(``);return(0,m.useEffect)(()=>{if(e.subtype!==`text`)return;let r=!1;if(f(``),x(``),!t){f(u(`preview.loadFailed`));return}return _(!0),(async()=>{try{let t=await fetch(n(e.cid),{headers:{...await c(`GET`,`/api/files/${e.cid}/download`),Range:`bytes=0-9999`}});if(!t.ok)throw Error(u(`preview.loadFailed`));let i=await t.text();r||f(i||u(`preview.emptyFile`))}catch{r||f(u(`preview.loadFailed`))}finally{r||_(!1)}})(),()=>{r=!0}},[n,t,e.cid,e.subtype]),(0,m.useEffect)(()=>{if(!g(e.subtype)){y(``);return}if(y(``),x(``),!t){x(u(`preview.loadFailed`));return}let r=``,i=!1;return(async()=>{try{let t=await fetch(n(e.cid),{headers:await c(`GET`,`/api/files/${e.cid}/download`)});if(!t.ok)throw Error(u(`preview.loadFailed`));let a=URL.createObjectURL(await t.blob());r=a,i||y(a)}catch{i||x(u(`preview.loadFailed`))}})(),()=>{i=!0,r&&URL.revokeObjectURL(r)}},[n,t,e.cid,e.subtype]),(0,h.jsxs)(`div`,{className:`preview-overlay`,onClick:r,children:[(0,h.jsx)(`button`,{type:`button`,className:`preview-close`,onClick:r,"aria-label":u(`preview.close`),children:(0,h.jsx)(l,{size:20})}),(0,h.jsxs)(`div`,{onClick:e=>e.stopPropagation(),children:[e.subtype===`image`&&(0,h.jsx)(`div`,{className:`preview-media-wrapper`,children:v?(0,h.jsx)(`img`,{src:v,alt:e.fileName,translate:`no`}):b?(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(i,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:b})]}):(0,h.jsx)(`div`,{className:`preview-loading`,children:(0,h.jsx)(`div`,{className:`preview-loading-spinner`})})}),e.subtype===`video`&&(0,h.jsx)(`div`,{className:`preview-media-wrapper`,children:v?(0,h.jsx)(`video`,{src:v,controls:!0}):b?(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(i,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:b})]}):(0,h.jsx)(`div`,{className:`preview-loading`,children:(0,h.jsx)(`div`,{className:`preview-loading-spinner`})})}),e.subtype===`audio`&&(0,h.jsxs)(`div`,{className:`preview-audio`,children:[(0,h.jsx)(`div`,{className:`preview-audio-icon`,children:(0,h.jsx)(o,{size:36,color:`var(--accent)`})}),(0,h.jsx)(`p`,{className:`preview-audio-filename`,translate:`no`,children:e.fileName}),v?(0,h.jsx)(`audio`,{className:`preview-audio-player`,src:v,controls:!0}):(0,h.jsx)(`div`,{className:`preview-text-loading`,children:b?(0,h.jsx)(`p`,{children:b}):(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(a,{size:24,className:`preview-text-spinner`}),(0,h.jsx)(`p`,{children:u(`preview.audioLoading`)})]})})]}),e.subtype===`file`&&(0,h.jsxs)(`div`,{className:`preview-unsupported`,children:[(0,h.jsx)(i,{size:48,className:`preview-file-icon`}),(0,h.jsx)(`p`,{translate:`no`,children:e.fileName}),(0,h.jsx)(`p`,{className:`preview-unsupported-hint`,children:u(`preview.unsupported`)})]}),e.subtype===`text`&&(0,h.jsxs)(`div`,{className:`preview-text-container`,children:[(0,h.jsx)(`div`,{className:`preview-text-header`,children:(0,h.jsx)(`span`,{translate:`no`,children:e.fileName})}),p?(0,h.jsxs)(`div`,{className:`preview-text-loading`,children:[(0,h.jsx)(a,{size:24,className:`preview-text-spinner`}),(0,h.jsx)(`p`,{children:u(`preview.textLoading`)}),(0,h.jsx)(`p`,{className:`preview-text-loading-hint`,children:u(`preview.firstSyncHint`)})]}):(0,h.jsx)(`pre`,{className:`preview-text`,translate:`no`,children:d||u(`preview.emptyFile`)})]})]})]})}export{u as a,d as i,p as n,f as r,_ as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{g as t}from"./userStore-q0BBZsIV.js";import{t as n}from"./refresh-cw--JB8k6mH.js";import{I as r,L as i,R as a,c as o,p as s}from"./index-DN0kD5zr.js";var c=t(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),l=t(`languages`,[[`path`,{d:`m5 8 6 6`,key:`1wu5hv`}],[`path`,{d:`m4 14 6-6 2-3`,key:`1k1g8d`}],[`path`,{d:`M2 5h12`,key:`or177f`}],[`path`,{d:`M7 2h1`,key:`1t2jsx`}],[`path`,{d:`m22 22-5-10-5 10`,key:`don7ne`}],[`path`,{d:`M14 18h6`,key:`1m8k6r`}]]),u=t(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),d=t(`sun`,[[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}],[`path`,{d:`M12 2v2`,key:`tus03m`}],[`path`,{d:`M12 20v2`,key:`1lh1kg`}],[`path`,{d:`m4.93 4.93 1.41 1.41`,key:`149t6j`}],[`path`,{d:`m17.66 17.66 1.41 1.41`,key:`ptbguv`}],[`path`,{d:`M2 12h2`,key:`1t8f8n`}],[`path`,{d:`M20 12h2`,key:`1q8mjw`}],[`path`,{d:`m6.34 17.66-1.41 1.41`,key:`1m8zz5`}],[`path`,{d:`m19.07 4.93-1.41 1.41`,key:`1shlcs`}]]),f=e();function p(){let{t:e}=r(),{state:t,installAndRestart:i}=s(),a=t.status===`installing`;return t.status!==`downloaded`&&!a?null:(0,f.jsxs)(`button`,{type:`button`,className:`btn btn-primary desktop-update-button`,disabled:a,title:e(`desktopUpdate.readyTitle`,{version:t.version||t.filename}),onClick:()=>{i()},children:[(0,f.jsx)(n,{size:16}),e(a?`desktopUpdate.installing`:`desktopUpdate.install`)]})}function m({className:e=``}){let{locale:t,localeName:n,setLocale:s,t:u}=r(),d=u(`common.locale.choose`),p=`${d} (${u(`common.locale.current`)}: ${n})`;return(0,f.jsx)(o,{ariaLabel:d,placement:`bottom-end`,items:i.map(e=>({key:e,label:a[e],icon:e===t?(0,f.jsx)(c,{size:16}):(0,f.jsx)(`span`,{"aria-hidden":`true`}),onSelect:()=>{e!==t&&s(e)}})),renderTrigger:t=>(0,f.jsx)(`button`,{...t,className:[`language-toggle`,e].filter(Boolean).join(` `),"aria-label":d,title:p,children:(0,f.jsx)(l,{size:16})})})}export{c as a,u as i,p as n,d as r,m as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./jsx-runtime-Bt-cYkS5.js";import{n as t,t as n}from"./LanguageToggle-B99eQcTE.js";import{N as r,O as i}from"./index-DN0kD5zr.js";import{t as a}from"./MarketingThemeToggle-z4jr4-vt.js";var o=e();function s(){return(0,o.jsx)(`nav`,{className:`mkt-nav`,children:(0,o.jsxs)(`div`,{className:`mkt-nav-inner`,children:[(0,o.jsxs)(`button`,{type:`button`,className:`mkt-nav-logo`,onClick:i(),children:[(0,o.jsx)(r,{size:18}),(0,o.jsx)(`span`,{children:`MOST PEOPLE`})]}),(0,o.jsxs)(`div`,{className:`mkt-nav-cta`,children:[(0,o.jsx)(a,{}),(0,o.jsx)(n,{className:`mkt-theme-toggle`}),(0,o.jsx)(t,{})]})]})})}export{s as t};
|