mirror of
https://git.um-react.app/um/um-react.git
synced 2025-11-28 19:43:02 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fe6efec1f | ||
|
|
c4fe9ce938 | ||
|
|
045bea8084 | ||
|
|
c68195eb9a | ||
|
|
b986a2ef99 | ||
|
|
b48d9b0079 | ||
|
|
62e49804a5 | ||
|
|
c41e5ae531 | ||
|
|
27c33a7d20 | ||
|
|
bbb557eafd | ||
|
|
befe35e5bc | ||
|
|
1fb6526cdb | ||
|
|
d122eaecf5 | ||
|
|
2da766168c | ||
|
|
17200150dd | ||
|
|
2c461df5fc | ||
|
|
b493391371 | ||
|
|
13b67f40aa | ||
|
|
fbe8ef8ba1 | ||
|
|
54f784d778 |
@@ -20,8 +20,13 @@ body:
|
|||||||
|
|
||||||
目前 Mac 客户端仅支持 v8.8.0 或更低版本下载的歌曲文件。
|
目前 Mac 客户端仅支持 v8.8.0 或更低版本下载的歌曲文件。
|
||||||
|
|
||||||
|
* [web.archive.org 镜像](https://web.archive.org/web/20230903/https://dldir1.qq.com/music/clntupate/mac/QQMusicMac_Mgr.dmg)
|
||||||
* [通过 Telegram 下载](https://t.me/um_lsr_ch/21)
|
* [通过 Telegram 下载](https://t.me/um_lsr_ch/21)
|
||||||
|
|
||||||
|
安装好客户端后可以加装更新屏蔽更新:
|
||||||
|
|
||||||
|
* [屏蔽更新](https://t.me/um_lsr_ch/29)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
如果你确定你的客户端版本符合上述描述,并遇到了问题,请继续填写下面的表单。
|
如果你确定你的客户端版本符合上述描述,并遇到了问题,请继续填写下面的表单。
|
||||||
|
|||||||
4
.npmrc
4
.npmrc
@@ -1,3 +1,3 @@
|
|||||||
use-node-version=22.12.0
|
use-node-version=24.7.0
|
||||||
engine-strict=true
|
engine-strict=true
|
||||||
@unlock-music:registry=https://git.unlock-music.dev/api/packages/um/npm/
|
@unlock-music:registry=https://git.um-react.app/api/packages/um/npm/
|
||||||
|
|||||||
30
README.MD
30
README.MD
@@ -1,6 +1,6 @@
|
|||||||
# Unlock Music 音乐解锁 (React)
|
# Unlock Music 音乐解锁 (React)
|
||||||
|
|
||||||
[][um-react-actions]
|
[][um-react-actions]
|
||||||
|
|
||||||
- 在浏览器中解锁加密的音乐文件。 Unlock encrypted music file in the browser.
|
- 在浏览器中解锁加密的音乐文件。 Unlock encrypted music file in the browser.
|
||||||
- 查看[原基于 Vue 的 Unlock Music 项目][um-vue]
|
- 查看[原基于 Vue 的 Unlock Music 项目][um-vue]
|
||||||
@@ -13,11 +13,11 @@
|
|||||||
> **WARNING**
|
> **WARNING**
|
||||||
> 在本站 fork 不会起到备份的作用,只会浪费服务器储存空间。如无必要请勿 fork 该仓库。
|
> 在本站 fork 不会起到备份的作用,只会浪费服务器储存空间。如无必要请勿 fork 该仓库。
|
||||||
|
|
||||||
[授权协议]: https://git.unlock-music.dev/um/um-react/src/branch/main/LICENSE
|
[授权协议]: https://git.um-react.app/um/um-react/src/branch/main/LICENSE
|
||||||
[um-vue]: https://git.unlock-music.dev/um/web
|
[um-vue]: https://git.um-react.app/um/web
|
||||||
[unlock-music/cli]: https://git.unlock-music.dev/um/cli
|
[unlock-music/cli]: https://git.um-react.app/um/cli
|
||||||
[`@unlock_music_chat`]: https://t.me/unlock_music_chat
|
[`@unlock_music_chat`]: https://t.me/unlock_music_chat
|
||||||
[um-react-actions]: https://git.unlock-music.dev/um/um-react/actions?workflow=build.yaml
|
[um-react-actions]: https://git.um-react.app/um/um-react/actions?workflow=build.yaml
|
||||||
|
|
||||||
⚠️ 手机端浏览器支持有限,请使用最新版本的 Chrome 或 Firefox 官方浏览器。
|
⚠️ 手机端浏览器支持有限,请使用最新版本的 Chrome 或 Firefox 官方浏览器。
|
||||||
|
|
||||||
@@ -55,16 +55,16 @@
|
|||||||
|
|
||||||
遇到解密出错的情况,请一并携带错误信息(诊断信息)并简单描述错误的重现过程。
|
遇到解密出错的情况,请一并携带错误信息(诊断信息)并简单描述错误的重现过程。
|
||||||
|
|
||||||
待实现的算法支持可[追踪 `crypto` 标签](https://git.unlock-music.dev/um/um-react/issues?labels=67)。
|
待实现的算法支持可[追踪 `crypto` 标签](https://git.um-react.app/um/um-react/issues?labels=67)。
|
||||||
|
|
||||||
[project-issues]: https://git.unlock-music.dev/um/um-react/issues/new
|
[project-issues]: https://git.um-react.app/um/um-react/issues/new
|
||||||
|
|
||||||
## 使用 Docker 构建、部署 (Linux)
|
## 使用 Docker 构建、部署 (Linux)
|
||||||
|
|
||||||
首先克隆仓库并进入目录:
|
首先克隆仓库并进入目录:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone https://git.unlock-music.dev/um/um-react.git
|
git clone https://git.um-react.app/um/um-react.git
|
||||||
cd um-react
|
cd um-react
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -115,15 +115,15 @@ docker run -d -p 8080:80 --name um-react um-react
|
|||||||
|
|
||||||
## 相关项目
|
## 相关项目
|
||||||
|
|
||||||
- [Unlock Music (Web)](https://git.unlock-music.dev/um/web) - 原始项目
|
- [Unlock Music (Web)](https://git.um-react.app/um/web) - 原始项目
|
||||||
- [Unlock Music (Cli)](https://git.unlock-music.dev/um/cli) - 命令行批量处理版
|
- [Unlock Music (Cli)](https://git.um-react.app/um/cli) - 命令行批量处理版
|
||||||
- [lib_um_crypto_rust](https://git.unlock-music.dev/um/lib_um_crypto_rust) - 项目引入的解密算法实现
|
- [lib_um_crypto_rust](https://git.um-react.app/um/lib_um_crypto_rust) - 项目引入的解密算法实现
|
||||||
- [NPM 包](https://git.unlock-music.dev/um/-/packages/npm/@unlock-music%2Fcrypto)
|
- [NPM 包](https://git.um-react.app/um/-/packages/npm/@unlock-music%2Fcrypto)
|
||||||
- [um-react (Electron 前端)](https://github.com/CarlGao4/um-react-electron) - 使用 Electron 框架封装的本地可执行文件。
|
- [um-react (Electron 前端)](https://github.com/CarlGao4/um-react-electron) - 使用 Electron 框架封装的本地可执行文件。
|
||||||
- [GitHub 下载](https://github.com/CarlGao4/um-react-electron/releases/latest) | [仓库镜像](https://git.unlock-music.dev/CarlGao4/um-react-electron)
|
- [GitHub 下载](https://github.com/CarlGao4/um-react-electron/releases/latest)
|
||||||
- [um-react-wry](https://git.unlock-music.dev/um/um-react-wry) - 使用 WRY 框架封装的 Win64 单文件 (
|
- [um-react-wry](https://git.um-react.app/um/um-react-wry) - 使用 WRY 框架封装的 Win64 单文件 (
|
||||||
需要[安装 Edge WebView2 运行时][webview2_redist],Win10+ 操作系统自带)
|
需要[安装 Edge WebView2 运行时][webview2_redist],Win10+ 操作系统自带)
|
||||||
- [本地下载](https://git.unlock-music.dev/um/um-react/releases/latest) | 寻找文件名为 `um-react-win64-` 开头的附件
|
- [本地下载](https://git.um-react.app/um/um-react/releases/latest) | 寻找文件名为 `um-react-win64-` 开头的附件
|
||||||
|
|
||||||
[webview2_redist]: https://go.microsoft.com/fwlink/p/?LinkId=2124703
|
[webview2_redist]: https://go.microsoft.com/fwlink/p/?LinkId=2124703
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
- 进入上层目录:`cd ..`
|
- 进入上层目录:`cd ..`
|
||||||
- 克隆 `lib_um_crypto_rust` 仓库
|
- 克隆 `lib_um_crypto_rust` 仓库
|
||||||
- `git clone https://git.unlock-music.dev/um/lib_um_crypto_rust.git`
|
- `git clone https://git.um-react.app/um/lib_um_crypto_rust.git`
|
||||||
- 进入 SDK 目录:`cd lib_um_crypto_rust ; cd um_wasm_loader`
|
- 进入 SDK 目录:`cd lib_um_crypto_rust ; cd um_wasm_loader`
|
||||||
- 安装所有 Node 以来:`pnpm i`
|
- 安装所有 Node 以来:`pnpm i`
|
||||||
- 构建:`pnpm build`
|
- 构建:`pnpm build`
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
|
|
||||||
- WSA 可以参考 [MagiskOnWSALocal](https://github.com/LSPosed/MagiskOnWSALocal) 的说明操作。
|
- WSA 可以参考 [MagiskOnWSALocal](https://github.com/LSPosed/MagiskOnWSALocal) 的说明操作。
|
||||||
- 雷电模拟器可以在「模拟器设置」 → 「其他设置」中启用 root 特权。
|
- 雷电模拟器可以在「模拟器设置」 → 「其他设置」中启用 root 特权。
|
||||||

|

|
||||||
|
|
||||||
### Via 等浏览器无法正常解密/下载
|
### Via 等浏览器无法正常解密/下载
|
||||||
|
|
||||||
@@ -87,10 +87,6 @@
|
|||||||
- 无法下载解密后内容
|
- 无法下载解密后内容
|
||||||
- 下载的文件名错误
|
- 下载的文件名错误
|
||||||
|
|
||||||
### 新版解锁网站没有批量下载
|
|
||||||
|
|
||||||
目前没有做。抱歉。
|
|
||||||
|
|
||||||
## 仍有问题?
|
## 仍有问题?
|
||||||
|
|
||||||
欢迎进入[Telegram 交流群](https://t.me/unlock_music_chat),一起探讨。
|
欢迎进入[Telegram 交流群](https://t.me/unlock_music_chat),一起探讨。
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "um-react",
|
"name": "um-react",
|
||||||
"version": "0.5.0",
|
"version": "0.5.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "um-react",
|
"name": "um-react",
|
||||||
"version": "0.5.0",
|
"version": "0.5.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.8.2",
|
||||||
"@unlock-music/crypto": "0.1.10",
|
"@unlock-music/crypto": "0.1.10",
|
||||||
|
|||||||
74
package.json
74
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "um-react",
|
"name": "um-react",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.5.0",
|
"version": "0.5.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
@@ -17,60 +17,60 @@
|
|||||||
"prepare": "simple-git-hooks"
|
"prepare": "simple-git-hooks"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reduxjs/toolkit": "^2.8.2",
|
"@reduxjs/toolkit": "^2.9.0",
|
||||||
"@unlock-music/crypto": "0.1.10",
|
"@unlock-music/crypto": "^0.1.12",
|
||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"nanoid": "^5.1.5",
|
"nanoid": "^5.1.5",
|
||||||
"radash": "^12.1.1",
|
"radash": "^12.1.1",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.1",
|
||||||
"react-dropzone": "^14.3.8",
|
"react-dropzone": "^14.3.8",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router": "^7.6.3",
|
"react-router": "^7.8.2",
|
||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.6",
|
||||||
"react-toastify": "^11.0.5",
|
"react-toastify": "^11.0.5",
|
||||||
"sql.js": "^1.13.0"
|
"sql.js": "^1.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.30.1",
|
"@eslint/js": "^9.35.0",
|
||||||
"@rollup/plugin-replace": "^6.0.2",
|
"@rollup/plugin-replace": "^6.0.2",
|
||||||
"@tailwindcss/vite": "^4.1.11",
|
"@tailwindcss/vite": "^4.1.13",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.8.0",
|
||||||
"@testing-library/react": "^16.3.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@testing-library/user-event": "^14.6.1",
|
"@testing-library/user-event": "^14.6.1",
|
||||||
"@types/node": "^24.0.10",
|
"@types/node": "^24.3.1",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.12",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.9",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@types/sql.js": "^1.4.9",
|
"@types/sql.js": "^1.4.9",
|
||||||
"@types/wicg-file-system-access": "^2023.10.6",
|
"@types/wicg-file-system-access": "^2023.10.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.35.1",
|
"@typescript-eslint/eslint-plugin": "^8.42.0",
|
||||||
"@typescript-eslint/parser": "^8.35.1",
|
"@typescript-eslint/parser": "^8.42.0",
|
||||||
"@vitejs/plugin-react": "^4.6.0",
|
"@vitejs/plugin-react": "^5.0.2",
|
||||||
"@vitest/coverage-v8": "^3.2.4",
|
"@vitest/coverage-v8": "^3.2.4",
|
||||||
"@vitest/ui": "^3.2.4",
|
"@vitest/ui": "^3.2.4",
|
||||||
"daisyui": "^5.0.43",
|
"daisyui": "^5.1.8",
|
||||||
"eslint": "^9.30.1",
|
"eslint": "^9.35.0",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^26.1.0",
|
"jsdom": "^26.1.0",
|
||||||
"lint-staged": "^16.1.2",
|
"lint-staged": "^16.1.6",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
"rollup": "^4.44.2",
|
"rollup": "^4.50.1",
|
||||||
"sass": "^1.89.2",
|
"sass": "^1.92.1",
|
||||||
"simple-git-hooks": "^2.13.0",
|
"simple-git-hooks": "^2.13.1",
|
||||||
"tailwindcss": "^4.1.11",
|
"tailwindcss": "^4.1.13",
|
||||||
"terser": "^5.43.1",
|
"terser": "^5.44.0",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.9.2",
|
||||||
"typescript-eslint": "^8.35.1",
|
"typescript-eslint": "^8.42.0",
|
||||||
"vite": "^6.3.5",
|
"vite": "^7.1.5",
|
||||||
"vite-plugin-pwa": "^1.0.1",
|
"vite-plugin-pwa": "^1.0.3",
|
||||||
"vite-plugin-top-level-await": "^1.5.0",
|
"vite-plugin-top-level-await": "^1.6.0",
|
||||||
"vite-plugin-wasm": "^3.4.1",
|
"vite-plugin-wasm": "^3.5.0",
|
||||||
"vitest": "^3.2.4",
|
"vitest": "^3.2.4",
|
||||||
"workbox-build": "^7.3.0",
|
"workbox-build": "^7.3.0",
|
||||||
"workbox-window": "^7.3.0"
|
"workbox-window": "^7.3.0"
|
||||||
@@ -90,13 +90,17 @@
|
|||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"@rollup/plugin-terser": "patches/@rollup__plugin-terser.patch",
|
|
||||||
"sql.js": "patches/sql.js.patch"
|
"sql.js": "patches/sql.js.patch"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"rollup-plugin-terser": "npm:@rollup/plugin-terser@0.4.3",
|
|
||||||
"sourcemap-codec": "npm:@jridgewell/sourcemap-codec@1.4.15"
|
"sourcemap-codec": "npm:@jridgewell/sourcemap-codec@1.4.15"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4"
|
"onlyBuiltDependencies": [
|
||||||
|
"@swc/core",
|
||||||
|
"@tailwindcss/oxide",
|
||||||
|
"esbuild",
|
||||||
|
"simple-git-hooks"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.15.1"
|
||||||
}
|
}
|
||||||
|
|||||||
2497
pnpm-lock.yaml
generated
2497
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
pushd "$(dirname "${BASH_SOURCE[0]}")/../"
|
pushd "$(dirname "${BASH_SOURCE[0]}")/../"
|
||||||
|
|
||||||
WRY_VER="0.1.1"
|
WRY_VER="0.1.2"
|
||||||
|
|
||||||
mkdir -p win64/{deps,dist}
|
mkdir -p win64/{deps,dist}
|
||||||
dl_file() {
|
dl_file() {
|
||||||
|
|||||||
@@ -65,3 +65,12 @@ h6 {
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#downloadAll {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.5em;
|
||||||
|
bottom: 72px;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
|
import { CodeHighlight } from '../CodeHighlight';
|
||||||
import hljsStyleGitHub from 'react-syntax-highlighter/dist/esm/styles/hljs/github';
|
|
||||||
import { ExtLink } from '../ExtLink';
|
import { ExtLink } from '../ExtLink';
|
||||||
import PowerShellAdbDumpCommandTemplate from './adb_dump.ps1?raw';
|
import PowerShellAdbDumpCommandTemplate from './adb_dump.ps1?raw';
|
||||||
import ShellAdbDumpCommandTemplate from './adb_dump.sh?raw';
|
import ShellAdbDumpCommandTemplate from './adb_dump.sh?raw';
|
||||||
@@ -45,9 +44,7 @@ export function AdbInstructionTemplate({ dir, file, platform }: AdbInstructionTe
|
|||||||
<li>将安卓设备连接到电脑。</li>
|
<li>将安卓设备连接到电脑。</li>
|
||||||
<li>
|
<li>
|
||||||
<p>粘贴执行下述代码执行。若设备提示「是否允许 USB 调试」或「超级用户请求」,选择允许:</p>
|
<p>粘贴执行下述代码执行。若设备提示「是否允许 USB 调试」或「超级用户请求」,选择允许:</p>
|
||||||
<SyntaxHighlighter language={language} style={hljsStyleGitHub}>
|
<CodeHighlight language={language}>{command}</CodeHighlight>
|
||||||
{command}
|
|
||||||
</SyntaxHighlighter>
|
|
||||||
<br />※ 安卓模拟器可能需要额外操作,如
|
<br />※ 安卓模拟器可能需要额外操作,如
|
||||||
<ExtLink className="text-nowrap" href="https://g.126.fm/04jewvw">
|
<ExtLink className="text-nowrap" href="https://g.126.fm/04jewvw">
|
||||||
网易 MuMu 模拟器
|
网易 MuMu 模拟器
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { Bounce, ToastContainer } from 'react-toastify';
|
|||||||
import { SettingsHome } from '~/features/settings/SettingsHome';
|
import { SettingsHome } from '~/features/settings/SettingsHome';
|
||||||
import { FAQ_PAGES } from '~/faq/FAQPages';
|
import { FAQ_PAGES } from '~/faq/FAQPages';
|
||||||
import { FaqHome } from '~/faq/FaqHome';
|
import { FaqHome } from '~/faq/FaqHome';
|
||||||
import { DownloadAll } from '~/components/DownloadAll.tsx';
|
|
||||||
|
|
||||||
// Private to this file only.
|
// Private to this file only.
|
||||||
const store = setupStore();
|
const store = setupStore();
|
||||||
@@ -72,7 +71,6 @@ export function AppRoot() {
|
|||||||
transition={Bounce}
|
transition={Bounce}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DownloadAll />
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</Provider>
|
</Provider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
10
src/components/CodeHighlight.tsx
Normal file
10
src/components/CodeHighlight.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { Light as SyntaxHighlighter, type SyntaxHighlighterProps } from 'react-syntax-highlighter';
|
||||||
|
import hljsStyleGitHub from 'react-syntax-highlighter/dist/esm/styles/hljs/github';
|
||||||
|
|
||||||
|
export function CodeHighlight({ children, ...props }: SyntaxHighlighterProps) {
|
||||||
|
return (
|
||||||
|
<SyntaxHighlighter style={hljsStyleGitHub} {...props}>
|
||||||
|
{children}
|
||||||
|
</SyntaxHighlighter>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,49 +1,68 @@
|
|||||||
import { DecryptedAudioFile, selectFiles } from '~/features/file-listing/fileListingSlice';
|
import { DecryptedAudioFile, ProcessState, selectFiles } from '~/features/file-listing/fileListingSlice';
|
||||||
import { FaDownload } from 'react-icons/fa';
|
import { FaDownload } from 'react-icons/fa';
|
||||||
import { useAppSelector } from '~/hooks';
|
import { useAppSelector } from '~/hooks';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
export function DownloadAll() {
|
export function DownloadAll() {
|
||||||
const files = useAppSelector(selectFiles);
|
const files = useAppSelector(selectFiles);
|
||||||
const filesLength = Object.keys(files).length;
|
|
||||||
const onClickDownloadAll = async () => {
|
const onClickDownloadAll = async () => {
|
||||||
|
console.time('DownloadAll'); //开始计时
|
||||||
|
const fileCount = Object.keys(files).length;
|
||||||
|
if (fileCount === 0) {
|
||||||
|
toast.warning('未添加文件');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断所有文件是否处理完成
|
||||||
|
const allComplete = Object.values(files).every((file) => file.state !== ProcessState.PROCESSING);
|
||||||
|
if (!allComplete) {
|
||||||
|
toast.warning('请等待所有文件解密完成');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//过滤处理失败的文件
|
||||||
|
const completeFiles = Object.values(files).filter((file) => file.state === ProcessState.COMPLETE);
|
||||||
|
|
||||||
|
//开始下载
|
||||||
let dir: FileSystemDirectoryHandle | undefined;
|
let dir: FileSystemDirectoryHandle | undefined;
|
||||||
let success = 0;
|
|
||||||
try {
|
try {
|
||||||
dir = await window.showDirectoryPicker();
|
dir = await window.showDirectoryPicker({ mode: 'readwrite' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
if (e instanceof Error && e.name === 'AbortError') {
|
if (e instanceof Error && e.name === 'AbortError') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const [_, file] of Object.entries(files)) {
|
toast.warning('开始下载,请稍候');
|
||||||
|
|
||||||
|
const promises = Object.values(completeFiles).map(async (file) => {
|
||||||
|
console.log(`开始下载: ${file.fileName}`);
|
||||||
try {
|
try {
|
||||||
if (dir) {
|
if (dir) {
|
||||||
await DownloadNew(dir, file);
|
await DownloadNew(dir, file);
|
||||||
} else {
|
} else {
|
||||||
await DownloadOld(file);
|
await DownloadOld(file);
|
||||||
}
|
}
|
||||||
success++;
|
console.log(`成功下载: ${file.fileName}`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`下载失败: ${file.fileName}`, e);
|
console.error(`下载失败: ${file.fileName}`, e);
|
||||||
toast.error(`出现错误: ${e}`);
|
toast.error(`出现错误: ${e}`);
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
if (success === filesLength) {
|
await Promise.allSettled(promises).then((f) => {
|
||||||
toast.success(`成功下载: ${success}/${filesLength}首`);
|
const success = f.filter((result) => result.status === 'fulfilled').length;
|
||||||
|
if (success === fileCount) {
|
||||||
|
toast.success(`成功下载: ${success}/${fileCount}首`);
|
||||||
} else {
|
} else {
|
||||||
toast.error(`成功下载: ${success}/${filesLength}首`);
|
toast.warning(`成功下载: ${success}/${fileCount}首`);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
console.timeEnd('DownloadAll'); //停止计时
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button className="btn btn-primary" id="downloadAll" onClick={onClickDownloadAll} title="下载全部">
|
||||||
style={{ width: '48px', height: '48px', paddingInline: '0px', margin: '10px', marginLeft: 'auto' }}
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={onClickDownloadAll}
|
|
||||||
title="下载全部"
|
|
||||||
>
|
|
||||||
<FaDownload />
|
<FaDownload />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ export function Footer() {
|
|||||||
return (
|
return (
|
||||||
<footer className="flex flex-col text-center p-4 bg-base-200">
|
<footer className="flex flex-col text-center p-4 bg-base-200">
|
||||||
<p className="flex flex-row justify-center items-center h-[1em]">
|
<p className="flex flex-row justify-center items-center h-[1em]">
|
||||||
<a className="link link-info mr-1" href="https://git.unlock-music.dev/um/um-react">
|
<a className="link link-info mr-1" href="https://git.um-react.app/um/um-react">
|
||||||
音乐解锁
|
音乐解锁
|
||||||
</a>
|
</a>
|
||||||
(
|
(
|
||||||
<a
|
<a
|
||||||
title="使用 MIT 授权协议"
|
title="使用 MIT 授权协议"
|
||||||
className="link link-info"
|
className="link link-info"
|
||||||
href="https://git.unlock-music.dev/um/um-react/src/branch/main/LICENSE"
|
href="https://git.um-react.app/um/um-react/src/branch/main/LICENSE"
|
||||||
>
|
>
|
||||||
MIT
|
MIT
|
||||||
</a>
|
</a>
|
||||||
@@ -23,7 +23,7 @@ export function Footer() {
|
|||||||
<p>
|
<p>
|
||||||
{'© 2019 - '}
|
{'© 2019 - '}
|
||||||
<CurrentYear />
|
<CurrentYear />
|
||||||
<a className="ml-1 link link-info" href="https://git.unlock-music.dev/um">
|
<a className="ml-1 link link-info" href="https://git.um-react.app/um">
|
||||||
Unlock Music
|
Unlock Music
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export interface ProjectIssueProps {
|
|||||||
|
|
||||||
export function ProjectIssue({ id, title }: ProjectIssueProps) {
|
export function ProjectIssue({ id, title }: ProjectIssueProps) {
|
||||||
return (
|
return (
|
||||||
<ExtLink target="_blank" href={`https://git.unlock-music.dev/um/um-react/issues/${id}`}>
|
<ExtLink target="_blank" href={`https://git.um-react.app/um/um-react/issues/${id}`}>
|
||||||
{`#${id}`}
|
{`#${id}`}
|
||||||
{title && ` - ${title}`}
|
{title && ` - ${title}`}
|
||||||
</ExtLink>
|
</ExtLink>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export interface DecipherNotOK {
|
|||||||
export interface DecipherOK {
|
export interface DecipherOK {
|
||||||
status: Status.OK;
|
status: Status.OK;
|
||||||
message?: string;
|
message?: string;
|
||||||
data: Uint8Array;
|
data: Uint8Array<ArrayBuffer>;
|
||||||
overrideExtension?: string;
|
overrideExtension?: string;
|
||||||
cipherName: string;
|
cipherName: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { DecipherInstance, DecipherOK, DecipherResult, Status } from '~/decrypt-
|
|||||||
export class TransparentDecipher implements DecipherInstance {
|
export class TransparentDecipher implements DecipherInstance {
|
||||||
cipherName = 'none';
|
cipherName = 'none';
|
||||||
|
|
||||||
async decrypt(buffer: Uint8Array): Promise<DecipherResult | DecipherOK> {
|
async decrypt(buffer: Uint8Array<ArrayBuffer>): Promise<DecipherResult | DecipherOK> {
|
||||||
return {
|
return {
|
||||||
cipherName: 'None',
|
cipherName: 'None',
|
||||||
status: Status.OK,
|
status: Status.OK,
|
||||||
|
|||||||
@@ -24,3 +24,17 @@ export function isDataLooksLikeAudio(buffer: Uint8Array): boolean {
|
|||||||
detectResult.free();
|
detectResult.free();
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AudioMimeType: Record<string, string> = {
|
||||||
|
mp3: 'audio/mpeg',
|
||||||
|
flac: 'audio/flac',
|
||||||
|
m4a: 'audio/mp4',
|
||||||
|
ogg: 'audio/ogg',
|
||||||
|
wma: 'audio/x-ms-wma',
|
||||||
|
wav: 'audio/x-wav',
|
||||||
|
dff: 'audio/x-dff',
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getMimeTypeFromExt(ext: string) {
|
||||||
|
return AudioMimeType[ext] || 'application/octet-stream';
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
export const toArrayBuffer = async (src: Blob | ArrayBuffer | Uint8Array<ArrayBufferLike>) =>
|
export const toArrayBuffer = async (src: Blob | BlobPart) => (src instanceof Blob ? await src.arrayBuffer() : src);
|
||||||
src instanceof Blob ? await src.arrayBuffer() : src;
|
export const toBlob = (src: Blob | BlobPart, mimeType?: string) =>
|
||||||
export const toBlob = (src: Blob | ArrayBuffer | Uint8Array<ArrayBufferLike>) =>
|
src instanceof Blob ? src : new Blob([src], { type: mimeType ?? 'application/octet-stream' });
|
||||||
src instanceof Blob ? src : new Blob([src]);
|
|
||||||
|
|
||||||
export function* chunkBuffer(buffer: Uint8Array, blockLen = 4096): Generator<[Uint8Array, number], void> {
|
export function* chunkBuffer(buffer: Uint8Array, blockLen = 4096): Generator<[Uint8Array, number], void> {
|
||||||
const len = buffer.byteLength;
|
const len = buffer.byteLength;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { DecipherFactory, DecipherInstance, Status } from '~/decrypt-worker/Deci
|
|||||||
import { UnsupportedSourceFile } from '~/decrypt-worker/util/DecryptError.ts';
|
import { UnsupportedSourceFile } from '~/decrypt-worker/util/DecryptError.ts';
|
||||||
import { ready as umCryptoReady } from '@unlock-music/crypto';
|
import { ready as umCryptoReady } from '@unlock-music/crypto';
|
||||||
import { go } from '~/util/go.ts';
|
import { go } from '~/util/go.ts';
|
||||||
import { detectAudioExtension } from '~/decrypt-worker/util/audioType.ts';
|
import { getMimeTypeFromExt, detectAudioExtension } from '~/decrypt-worker/util/audioType.ts';
|
||||||
|
|
||||||
class DecryptCommandHandler {
|
class DecryptCommandHandler {
|
||||||
private readonly label: string;
|
private readonly label: string;
|
||||||
@@ -31,6 +31,7 @@ class DecryptCommandHandler {
|
|||||||
const [result, error] = await go(this.tryDecryptWith(decipher));
|
const [result, error] = await go(this.tryDecryptWith(decipher));
|
||||||
if (!error) {
|
if (!error) {
|
||||||
if (result) {
|
if (result) {
|
||||||
|
console.debug(`[${decipher.cipherName}] Decryption OK`);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
errors.push(`${decipher.cipherName}: no response`);
|
errors.push(`${decipher.cipherName}: no response`);
|
||||||
@@ -75,7 +76,7 @@ class DecryptCommandHandler {
|
|||||||
audioExt = 'm4a';
|
audioExt = 'm4a';
|
||||||
}
|
}
|
||||||
|
|
||||||
return { decrypted: URL.createObjectURL(toBlob(result.data)), ext: audioExt };
|
return { decrypted: URL.createObjectURL(toBlob(result.data, getMimeTypeFromExt(audioExt))), ext: audioExt };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,31 +9,31 @@ export function FAQAboutProject() {
|
|||||||
<Header3 id="failed">um-react 是什么</Header3>
|
<Header3 id="failed">um-react 是什么</Header3>
|
||||||
<p>
|
<p>
|
||||||
um-react 是由
|
um-react 是由
|
||||||
<a className="mx-1 link link-info" href="https://git.unlock-music.dev/um">
|
<a className="mx-1 link link-info" href="https://git.um-react.app/um">
|
||||||
Unlock Music
|
Unlock Music
|
||||||
</a>
|
</a>
|
||||||
基于 React 框架制作的一款用于移除已购音乐的加密保护的小工具,使用
|
基于 React 框架制作的一款用于移除已购音乐的加密保护的小工具,使用
|
||||||
<a className="mx-1 link link-info" href="https://git.unlock-music.dev/um/um-react/src/branch/main/LICENSE">
|
<a className="mx-1 link link-info" href="https://git.um-react.app/um/um-react/src/branch/main/LICENSE">
|
||||||
MIT
|
MIT
|
||||||
</a>
|
</a>
|
||||||
授权协议。
|
授权协议。
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
它的解密核心由 <FaRust className="inline" />
|
它的解密核心由 <FaRust className="inline" />
|
||||||
<a className="mx-1 link link-info" href="https://git.unlock-music.dev/um/lib_um_crypto_rust">
|
<a className="mx-1 link link-info" href="https://git.um-react.app/um/lib_um_crypto_rust">
|
||||||
<code>lib_um_crypto_rust</code>
|
<code>lib_um_crypto_rust</code>
|
||||||
</a>
|
</a>
|
||||||
驱动,使用
|
驱动,使用
|
||||||
<a
|
<a
|
||||||
className="mx-1 link link-info"
|
className="mx-1 link link-info"
|
||||||
href="https://git.unlock-music.dev/um/lib_um_crypto_rust/src/branch/main/LICENSE_MIT"
|
href="https://git.um-react.app/um/lib_um_crypto_rust/src/branch/main/LICENSE_MIT"
|
||||||
>
|
>
|
||||||
MIT
|
MIT
|
||||||
</a>
|
</a>
|
||||||
+
|
+
|
||||||
<a
|
<a
|
||||||
className="mx-1 link link-info"
|
className="mx-1 link link-info"
|
||||||
href="https://git.unlock-music.dev/um/lib_um_crypto_rust/src/branch/main/LICENSE_APACHE"
|
href="https://git.um-react.app/um/lib_um_crypto_rust/src/branch/main/LICENSE_APACHE"
|
||||||
>
|
>
|
||||||
Apache
|
Apache
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ExtLink } from '~/components/ExtLink';
|
import { ExtLink } from '~/components/ExtLink';
|
||||||
import { Header2, Header3, Header4 } from '~/components/HelpText/Headers';
|
import { Header2, Header3, Header4 } from '~/components/HelpText/Headers';
|
||||||
import { ProjectIssue } from '~/components/ProjectIssue';
|
|
||||||
|
|
||||||
import { NavLink } from 'react-router';
|
import { NavLink } from 'react-router';
|
||||||
|
|
||||||
@@ -12,15 +11,6 @@ export function OtherFAQ() {
|
|||||||
<p>该项目进行解密处理。如果加密前的资源没有内嵌元信息或封面,解密的文件也没有。</p>
|
<p>该项目进行解密处理。如果加密前的资源没有内嵌元信息或封面,解密的文件也没有。</p>
|
||||||
<p>请使用第三方工具进行编辑或管理元信息。</p>
|
<p>请使用第三方工具进行编辑或管理元信息。</p>
|
||||||
|
|
||||||
<Header3 id="batch-dl">批量下载</Header3>
|
|
||||||
<p>
|
|
||||||
{'暂时没有实现,不过你可以在 '}
|
|
||||||
<ProjectIssue id={34} title="[UI] 全部下载功能" />
|
|
||||||
{' 以及 '}
|
|
||||||
<ProjectIssue id={43} title="批量下载" />
|
|
||||||
{' 追踪该问题。'}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<Header3 id="android-browsers">安卓: 浏览器支持说明</Header3>
|
<Header3 id="android-browsers">安卓: 浏览器支持说明</Header3>
|
||||||
<p>⚠️ 手机端浏览器支持有限,请使用最新版本的 Chrome 或 Firefox 官方浏览器。</p>
|
<p>⚠️ 手机端浏览器支持有限,请使用最新版本的 Chrome 或 Firefox 官方浏览器。</p>
|
||||||
<div className="flex flex-col md:flex-row gap-2 md:gap-8">
|
<div className="flex flex-col md:flex-row gap-2 md:gap-8">
|
||||||
@@ -77,7 +67,7 @@ export function OtherFAQ() {
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
<ExtLink className="mr-2" href="https://git.unlock-music.dev/um/um-react-wry">
|
<ExtLink className="mr-2" href="https://git.um-react.app/um/um-react-wry">
|
||||||
<strong>
|
<strong>
|
||||||
<code>um-react-wry</code>
|
<code>um-react-wry</code>
|
||||||
</strong>
|
</strong>
|
||||||
@@ -89,7 +79,7 @@ export function OtherFAQ() {
|
|||||||
<ul className="list-disc pl-6">
|
<ul className="list-disc pl-6">
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
<ExtLink href="https://git.unlock-music.dev/um/um-react/releases/latest">仓库下载</ExtLink>
|
<ExtLink href="https://git.um-react.app/um/um-react/releases/latest">仓库下载</ExtLink>
|
||||||
{' | 寻找文件名为 '}
|
{' | 寻找文件名为 '}
|
||||||
<code>um-react-win64-</code> 开头的附件
|
<code>um-react-win64-</code> 开头的附件
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import { VQuote } from '~/components/HelpText/VQuote';
|
|||||||
import { MacCommandKey } from '~/components/Key/MacCommandKey';
|
import { MacCommandKey } from '~/components/Key/MacCommandKey';
|
||||||
import { ShiftKey } from '~/components/Key/ShiftKey';
|
import { ShiftKey } from '~/components/Key/ShiftKey';
|
||||||
|
|
||||||
|
import BlockUpdateScript from './assets/QQ 音乐 Mac 屏蔽升级.tar.gz?base64';
|
||||||
|
|
||||||
const MAC_CLIENT_URL =
|
const MAC_CLIENT_URL =
|
||||||
'https://web.archive.org/web/20230903/https://dldir1.qq.com/music/clntupate/mac/QQMusicMac_Mgr.dmg';
|
'https://web.archive.org/web/20230903/https://dldir1.qq.com/music/clntupate/mac/QQMusicMac_Mgr.dmg';
|
||||||
const MAC_CLIENT_TG_URL = 'https://t.me/um_lsr_ch/21';
|
const MAC_CLIENT_TG_URL = 'https://t.me/um_lsr_ch/21';
|
||||||
@@ -43,6 +45,19 @@ export function InstructionsMac() {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<p className="mt-4">
|
||||||
|
有部分用户发现现在会强制更新。你可以下载
|
||||||
|
<ExtLink
|
||||||
|
className="link-info mx-1"
|
||||||
|
download="QQ 音乐 Mac 屏蔽升级.tar.gz"
|
||||||
|
href={`data:application/gzip;base64,${BlockUpdateScript}`}
|
||||||
|
>
|
||||||
|
QQ 音乐 Mac 屏蔽升级.tar.gz
|
||||||
|
</ExtLink>
|
||||||
|
,然后执行 <code>QQ 音乐 Mac 屏蔽升级.command</code>。 其原理是修改 QQ
|
||||||
|
音乐的版本号,让其认为自己是最新版本,从而屏蔽更新。
|
||||||
|
</p>
|
||||||
|
|
||||||
<p className="mt-4">密钥文件通常存储在下述路径:</p>
|
<p className="mt-4">密钥文件通常存储在下述路径:</p>
|
||||||
<FilePathBlock>{DB_PATH}</FilePathBlock>
|
<FilePathBlock>{DB_PATH}</FilePathBlock>
|
||||||
|
|
||||||
|
|||||||
BIN
src/features/settings/panels/QMCv2/assets/QQ 音乐 Mac 屏蔽升级.tar.gz
Normal file
BIN
src/features/settings/panels/QMCv2/assets/QQ 音乐 Mac 屏蔽升级.tar.gz
Normal file
Binary file not shown.
@@ -1,5 +1,6 @@
|
|||||||
import { RiErrorWarningLine } from 'react-icons/ri';
|
import { RiErrorWarningLine } from 'react-icons/ri';
|
||||||
import { SelectFile } from '../components/SelectFile';
|
import { SelectFile } from '../components/SelectFile';
|
||||||
|
import { DownloadAll } from '~/components/DownloadAll.tsx';
|
||||||
|
|
||||||
import { FileListing } from '~/features/file-listing/FileListing';
|
import { FileListing } from '~/features/file-listing/FileListing';
|
||||||
import { useAppDispatch, useAppSelector } from '~/hooks.ts';
|
import { useAppDispatch, useAppSelector } from '~/hooks.ts';
|
||||||
@@ -39,6 +40,7 @@ export function MainTab() {
|
|||||||
<div className="w-full mt-4">
|
<div className="w-full mt-4">
|
||||||
<FileListing />
|
<FileListing />
|
||||||
</div>
|
</div>
|
||||||
|
<DownloadAll />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export class MMKVParser {
|
|||||||
private offset = 4;
|
private offset = 4;
|
||||||
private length: number;
|
private length: number;
|
||||||
|
|
||||||
constructor(private view: DataView) {
|
constructor(private view: DataView<ArrayBuffer>) {
|
||||||
const payloadLength = view.getUint32(0, true);
|
const payloadLength = view.getUint32(0, true);
|
||||||
this.length = 4 + payloadLength;
|
this.length = 4 + payloadLength;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { StagingKugouKey } from '~/features/settings/keyFormats';
|
import type { StagingKugouKey } from '~/features/settings/keyFormats';
|
||||||
import { MMKVParser } from '../MMKVParser';
|
import { MMKVParser } from '../MMKVParser';
|
||||||
|
|
||||||
export function parseAndroidKugouMMKV(view: DataView): Omit<StagingKugouKey, 'id'>[] {
|
export function parseAndroidKugouMMKV(view: DataView<ArrayBuffer>): Omit<StagingKugouKey, 'id'>[] {
|
||||||
const mmkv = new MMKVParser(view);
|
const mmkv = new MMKVParser(view);
|
||||||
const result: Omit<StagingKugouKey, 'id'>[] = [];
|
const result: Omit<StagingKugouKey, 'id'>[] = [];
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { StagingKWMv2Key } from '~/features/settings/keyFormats';
|
import type { StagingKWMv2Key } from '~/features/settings/keyFormats';
|
||||||
import { MMKVParser } from '../MMKVParser';
|
import { MMKVParser } from '../MMKVParser';
|
||||||
|
|
||||||
export function parseAndroidKuwoEKey(view: DataView): Omit<StagingKWMv2Key, 'id'>[] {
|
export function parseAndroidKuwoEKey(view: DataView<ArrayBuffer>): Omit<StagingKWMv2Key, 'id'>[] {
|
||||||
const mmkv = new MMKVParser(view);
|
const mmkv = new MMKVParser(view);
|
||||||
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
@@ -21,7 +21,7 @@ export function parseAndroidKuwoEKey(view: DataView): Omit<StagingKWMv2Key, 'id'
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseIosKuwoEKey(view: DataView): Omit<StagingKWMv2Key, 'id'>[] {
|
export function parseIosKuwoEKey(view: DataView<ArrayBuffer>): Omit<StagingKWMv2Key, 'id'>[] {
|
||||||
const mmkv = new MMKVParser(view);
|
const mmkv = new MMKVParser(view);
|
||||||
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
const result: Omit<StagingKWMv2Key, 'id'>[] = [];
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { MMKVParser } from '../MMKVParser';
|
import { MMKVParser } from '../MMKVParser';
|
||||||
|
|
||||||
export function parseAndroidQmEKey(view: DataView): Map<string, string> {
|
export function parseAndroidQmEKey(view: DataView<ArrayBuffer>): Map<string, string> {
|
||||||
const mmkv = new MMKVParser(view);
|
const mmkv = new MMKVParser(view);
|
||||||
const result = new Map<string, string>();
|
const result = new Map<string, string>();
|
||||||
while (!mmkv.eof) {
|
while (!mmkv.eof) {
|
||||||
|
|||||||
Reference in New Issue
Block a user