mirror of
https://git.um-react.app/um/um-react.git
synced 2025-11-28 19:43:02 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d91e2fffe4 | ||
|
|
88cfbcd337 | ||
|
|
e9480ce6a4 | ||
|
|
a07bcf2575 | ||
|
|
a40ecc4569 | ||
|
|
1abfe3498f | ||
|
|
e69393d1bc |
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
||||
dist
|
||||
node_modules
|
||||
*.log
|
||||
@@ -1,3 +0,0 @@
|
||||
dist/
|
||||
node_modules/
|
||||
coverage/
|
||||
@@ -1,27 +0,0 @@
|
||||
/* eslint-env node */
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es2020: true },
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:react-hooks/recommended',
|
||||
'prettier',
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
|
||||
plugins: ['react-refresh'],
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
varsIgnorePattern: '^_',
|
||||
argsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
5
.vscode/extensions.json
vendored
5
.vscode/extensions.json
vendored
@@ -3,9 +3,6 @@
|
||||
"editorconfig.editorconfig",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"christian-kohler.path-intellisense",
|
||||
"txava.region-marker",
|
||||
"foxundermoon.shell-format",
|
||||
"jock.svg"
|
||||
"foxundermoon.shell-format"
|
||||
]
|
||||
}
|
||||
|
||||
25
Dockerfile
Normal file
25
Dockerfile
Normal file
@@ -0,0 +1,25 @@
|
||||
FROM node:22-slim AS build
|
||||
ENV PNPM_HOME="/p"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
WORKDIR /app
|
||||
|
||||
RUN corepack enable pnpm \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends git \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY package.json pnpm-lock.yaml .npmrc ./
|
||||
RUN pnpm exec true
|
||||
COPY . .
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
ARG GIT_COMMIT=
|
||||
ARG GIT_COMMIT_FULL=
|
||||
|
||||
RUN pnpm build
|
||||
|
||||
FROM caddy:latest
|
||||
COPY --from=build /app/dist /srv/um-react
|
||||
EXPOSE 80
|
||||
CMD ["caddy", "file-server", "--root", "/srv/um-react"]
|
||||
27
README.MD
27
README.MD
@@ -59,6 +59,33 @@
|
||||
|
||||
[project-issues]: https://git.unlock-music.dev/um/um-react/issues/new
|
||||
|
||||
## 使用 Docker 构建、部署 (Linux)
|
||||
|
||||
首先克隆仓库并进入目录:
|
||||
|
||||
```sh
|
||||
git clone https://git.unlock-music.dev/um/um-react.git
|
||||
cd um-react
|
||||
```
|
||||
|
||||
构建 Docker 镜像:
|
||||
|
||||
```sh
|
||||
docker build \
|
||||
-t um-react \
|
||||
--build-arg GIT_COMMIT_FULL="$(git describe --long --dirty --tags --always)" \
|
||||
--build-arg GIT_COMMIT="$(git rev-parse --short HEAD)" \
|
||||
.
|
||||
```
|
||||
|
||||
在后台运行 Docker 容器:
|
||||
|
||||
```sh
|
||||
docker run -d -p 8080:80 --name um-react um-react
|
||||
```
|
||||
|
||||
然后访问 `http://localhost:8080` 即可。
|
||||
|
||||
## 开发相关
|
||||
|
||||
从源码运行或编译生产版本,请参考文档「[新手上路](./docs/getting-started.zh.md)」。
|
||||
|
||||
43
eslint.config.mjs
Normal file
43
eslint.config.mjs
Normal file
@@ -0,0 +1,43 @@
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import reactRefresh from 'eslint-plugin-react-refresh';
|
||||
import reactHooks from 'eslint-plugin-react-hooks';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
||||
import globals from 'globals';
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
reactRefresh.configs.recommended,
|
||||
reactHooks.configs['recommended-latest'],
|
||||
eslintConfigPrettier,
|
||||
|
||||
{
|
||||
rules: {
|
||||
'react-refresh/only-export-components': 'warn',
|
||||
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
varsIgnorePattern: '^_',
|
||||
argsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
ignores: ['**/dist/', '**/node_modules/', '**/coverage/'],
|
||||
},
|
||||
|
||||
{
|
||||
files: ['scripts/*.mjs'],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
81
package.json
81
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "um-react",
|
||||
"private": true,
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.7",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "vite",
|
||||
@@ -19,56 +19,61 @@
|
||||
"dependencies": {
|
||||
"@chakra-ui/anatomy": "^2.3.4",
|
||||
"@chakra-ui/icons": "^2.2.4",
|
||||
"@chakra-ui/react": "^2.10.4",
|
||||
"@chakra-ui/react": "^2.10.7",
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@reduxjs/toolkit": "^2.5.0",
|
||||
"@unlock-music/crypto": "0.1.6",
|
||||
"framer-motion": "^11.14.4",
|
||||
"nanoid": "^5.0.9",
|
||||
"@reduxjs/toolkit": "^2.6.1",
|
||||
"@unlock-music/crypto": "0.1.9",
|
||||
"framer-motion": "^12.6.2",
|
||||
"nanoid": "^5.1.5",
|
||||
"next-themes": "^0.4.6",
|
||||
"radash": "^12.1.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dropzone": "^14.3.5",
|
||||
"react-icons": "^5.4.0",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-dropzone": "^14.3.8",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-promise-suspense": "^0.3.4",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-syntax-highlighter": "^15.6.1",
|
||||
"sass": "^1.83.0",
|
||||
"sql.js": "^1.12.0"
|
||||
"sass": "^1.86.0",
|
||||
"sql.js": "^1.13.0",
|
||||
"workbox-build": "^7.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-replace": "^6.0.1",
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@rollup/plugin-replace": "^6.0.2",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.1.0",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/react": "^18.3.16",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@testing-library/user-event": "^14.6.1",
|
||||
"@types/node": "^22.13.14",
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@types/sql.js": "^1.4.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
||||
"@typescript-eslint/parser": "^8.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"@vitest/coverage-v8": "^2.1.8",
|
||||
"@vitest/ui": "^2.1.8",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"eslint-plugin-react-refresh": "^0.4.16",
|
||||
"@vitest/coverage-v8": "^3.0.9",
|
||||
"@vitest/ui": "^3.0.9",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"globals": "^16.0.0",
|
||||
"husky": "^9.1.7",
|
||||
"jsdom": "^25.0.1",
|
||||
"lint-staged": "^15.2.11",
|
||||
"prettier": "^3.4.2",
|
||||
"rollup": "^4.28.1",
|
||||
"simple-git-hooks": "^2.11.1",
|
||||
"terser": "^5.37.0",
|
||||
"typescript": "^5.7.2",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-pwa": "^0.20.5",
|
||||
"vite-plugin-top-level-await": "^1.4.4",
|
||||
"vite-plugin-wasm": "^3.3.0",
|
||||
"vitest": "^2.1.8",
|
||||
"jsdom": "^26.0.0",
|
||||
"lint-staged": "^15.5.0",
|
||||
"prettier": "^3.5.3",
|
||||
"rollup": "^4.38.0",
|
||||
"simple-git-hooks": "^2.12.1",
|
||||
"terser": "^5.39.0",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.28.0",
|
||||
"vite": "^6.2.3",
|
||||
"vite-plugin-pwa": "^1.0.0",
|
||||
"vite-plugin-top-level-await": "^1.5.0",
|
||||
"vite-plugin-wasm": "^3.4.1",
|
||||
"vitest": "^3.0.9",
|
||||
"workbox-window": "^7.3.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
|
||||
4139
pnpm-lock.yaml
generated
4139
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,13 @@ import { execSync } from 'node:child_process';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const commitHash = execSync('git rev-parse --short HEAD').toString('utf-8').trim();
|
||||
let commitHash = process.env.GIT_COMMIT || 'unknown';
|
||||
try {
|
||||
commitHash = execSync('git rev-parse --short HEAD').toString('utf-8').trim();
|
||||
} catch (e) {
|
||||
console.error('Failed to get commit hash:', e);
|
||||
}
|
||||
|
||||
const pkgJson = JSON.parse(readFileSync(__dirname + '/../package.json', 'utf-8'));
|
||||
const pkgVer = `${pkgJson.version ?? 'unknown'}-${commitHash ?? 'unknown'}` + '\n';
|
||||
const pkgVer = `${pkgJson.version ?? 'unknown'}-${commitHash}` + '\n';
|
||||
writeFileSync(__dirname + '/../dist/version.txt', pkgVer, 'utf-8');
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
VStack,
|
||||
} from '@chakra-ui/react';
|
||||
import { PanelQMCv2Key } from './panels/PanelQMCv2Key';
|
||||
import { useState } from 'react';
|
||||
import { useState, type FC } from 'react';
|
||||
import { MdExpandMore, MdMenu, MdOutlineSettingsBackupRestore } from 'react-icons/md';
|
||||
import { useAppDispatch, useAppSelector } from '~/hooks';
|
||||
import { commitStagingChange, discardStagingChanges } from './settingsSlice';
|
||||
@@ -33,7 +33,7 @@ import { selectIsSettingsNotSaved } from './settingsSelector';
|
||||
import { PanelQingTing } from './panels/PanelQingTing';
|
||||
import { PanelKGGKey } from '~/features/settings/panels/PanelKGGKey.tsx';
|
||||
|
||||
const TABS: { name: string; Tab: () => JSX.Element }[] = [
|
||||
const TABS: { name: string; Tab: FC }[] = [
|
||||
{ name: 'QMCv2 密钥', Tab: PanelQMCv2Key },
|
||||
{ name: 'KWMv2 密钥', Tab: PanelKWMv2Key },
|
||||
{ name: 'KGG 密钥', Tab: PanelKGGKey },
|
||||
|
||||
@@ -69,7 +69,17 @@ export class DatabaseKeyExtractor {
|
||||
|
||||
let sql: undefined | string;
|
||||
if (this.hasTable(db, 'ShareFileItems')) {
|
||||
sql = `select EncryptionKeyId, EncryptionKey from ShareFileItems where EncryptionKey != '' group by EncryptionKeyId`;
|
||||
sql = `
|
||||
select H, K from (
|
||||
select EncryptionKeyId as H, EncryptionKey as K from ShareFileItems
|
||||
union all
|
||||
select EnHash as H, EnKey as K from DownloadItem
|
||||
) t
|
||||
where
|
||||
t.H is not null and t.H != ''
|
||||
and t.K is not null and t.K != ''
|
||||
group by t.H
|
||||
`;
|
||||
}
|
||||
if (!sql) return null;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as initSqlite from 'sql.js';
|
||||
|
||||
const urlWasm = new URL('@nm/sql.js/dist/sql-wasm.wasm', import.meta.url).toString();
|
||||
const urlWasm = new URL('@sql-wasm', import.meta.url).toString();
|
||||
|
||||
export type SQLStatic = Awaited<ReturnType<(typeof initSqlite)['default']>>;
|
||||
export type SQLDatabase = SQLStatic['Database']['prototype'];
|
||||
|
||||
3
src/vite-env.d.ts
vendored
3
src/vite-env.d.ts
vendored
@@ -4,6 +4,5 @@ module 'virtual:pwa-register' {
|
||||
/**
|
||||
* See: {@link https://vite-pwa-org.netlify.app/guide/prompt-for-update.html}
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
declare function registerSW(opts: unknown): () => void;
|
||||
declare function registerSW(_opts: unknown): () => void;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ import url from 'node:url';
|
||||
const projectRoot = url.fileURLToPath(new URL('../', import.meta.url));
|
||||
|
||||
export function command(cmd: string, dir = '') {
|
||||
return cp.execSync(cmd, { cwd: path.join(projectRoot, dir), encoding: 'utf-8' }).trim();
|
||||
return cp.execSync(cmd, { cwd: path.resolve(projectRoot, dir), encoding: 'utf-8' }).trim();
|
||||
}
|
||||
|
||||
export function tryCommand(cmd: string, dir = '', fallback = '') {
|
||||
try {
|
||||
return command(cmd, dir);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"esModuleInterop": true,
|
||||
"paths": {
|
||||
"~/*": ["./src/*"],
|
||||
"@nm/*": ["./node_modules/*"]
|
||||
"@sql-wasm": ["./node_modules/sql.js/dist/sql-wasm.wasm"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
|
||||
@@ -15,8 +15,8 @@ const projectRoot = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
const pkg = JSON.parse(fs.readFileSync(projectRoot + '/package.json', 'utf-8'));
|
||||
|
||||
const COMMAND_GIT_VERSION = 'git describe --long --dirty --tags --always';
|
||||
const shortCommit = tryCommand(COMMAND_GIT_VERSION, __dirname, 'unknown');
|
||||
const version = `${pkg.version}-${shortCommit}`;
|
||||
const shortCommit = process.env.GIT_COMMIT || tryCommand(COMMAND_GIT_VERSION, __dirname, 'unknown');
|
||||
const version = `${pkg.version} (${shortCommit})`;
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
@@ -85,7 +85,7 @@ export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
'~': path.resolve(__dirname, 'src'),
|
||||
'@nm': path.resolve(__dirname, 'node_modules'),
|
||||
'@sql-wasm': path.resolve(__dirname, 'node_modules', 'sql.js', 'dist', 'sql-wasm.wasm'),
|
||||
|
||||
// workaround for vite, workbox (PWA)
|
||||
module: path.resolve(__dirname, 'src', 'dummy.mjs'),
|
||||
|
||||
Reference in New Issue
Block a user