diff --git a/.gitignore b/.gitignore
index b57dc95..572f82f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
.DS_Store
node_modules
-/build
+build
.svelte-kit
/package
.env
diff --git a/Dockerfile b/Dockerfile
index 805fe03..88a6340 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,20 +4,17 @@ FROM oven/bun:latest
# Set the working directory inside the container
WORKDIR /app
-# Copy the package.json and bun.lockb files to the working directory
-COPY package.json bun.lockb ./
+# Copy the application code
+COPY . .
# Install dependencies
RUN bun install
-# Copy the rest of the application code
-COPY . .
-
# Build the app
-RUN bun run build
+RUN bun run web:build
# Expose the port the app runs on
-EXPOSE 4173
+EXPOSE 2611
# Command to run the application
-CMD ["bun", "go"]
+CMD ["bun", "web:deploy"]
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 05e4800..56f79c7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,12 +4,12 @@ services:
aquavox:
build: .
ports:
- - "4173:4173"
+ - "2611:2611"
environment:
- NODE_ENV=production
volumes:
- .:/app
- command: ["bun", "go"]
+ command: ["bun", "web:deploy"]
volumes:
node_modules:
diff --git a/package.json b/package.json
index b369cbf..db822f6 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,9 @@
"scripts": {
"electron:dev": "bun --filter 'electron' dev",
"web:dev": "bun --filter 'web' dev",
- "dev": "bun --filter '**' dev"
+ "dev": "bun --filter '**' dev",
+ "web:build": "bun --filter 'web' build",
+ "web:deploy": "bun --filter 'web' go"
},
"devDependencies": {
"@iconify/svelte": "^4.0.2",
diff --git a/packages/electron/README.md b/packages/electron/README.md
deleted file mode 100644
index 340cce7..0000000
--- a/packages/electron/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-# AquaVox - 洛水之音
-
-AquaVox 是一个为中文虚拟歌手爱好者献上的产品。
-
-> VOCALOID IS ALIVE.
-
-这是一个 **开源、本地优先、有 B 站良好支持、界面美观优雅** 的 **音乐播放器**。
-
-## 使用
-
-当前 AquaVox 的公开预览版位于 [aquavox.app](https://aquavox.app) 上。
-
-[](https://wakatime.com/badge/user/018f0628-909b-47e4-bcfd-0153235426d9/project/b67c03ef-ee0b-45f2-85ec-d9c60269cc55)
-
-## 项目起源
-
-**开发者寒寒的话:**
-
-AquaVox 这个播放器项目的灵感根本上来自于 Apple Music,以其优雅流畅的界面设计而著称。
-
-我的中 V 曲之前基本是在 B 站听的,而中文虚拟歌手社区也基本上扎根于 B 站。但在 B 站听歌也有不少劣势——
-首先自然是 B 站本身并不是一个音乐软件或播放器,自然在相关的功能上并没有过多开发,“听视频”的功能也仅在移动端可用;
-其次,不少人听歌还是有看歌词的需求的,而许多中 V 曲发布时附上的 PV 中的歌词,为了美观,歌词并不会以一个常规视频的字幕样式呈现,而是采用了美术字等更为艺术化的表现形式,这使得查看歌词并不方便,更不用说在“听视频”模式下 PV 根本没有播放的情况。
-
-而后来,我选择了通过将 B 站的歌曲导入到 Apple Music 的方案,而为什么选择 AM 呢?尽管很多中 V 曲在网易云等平台上有更丰富的资源,但我依然选择了 AM。很大一个原因自然是我对 AM 播放器界面和交互设计及用户体验的喜爱,但另一方面,网易云的中 V 曲库其实也并不算全,最终还要使用导入的方法才能将自己所有喜欢的歌囊括其中,那么既然要导入,何不直接将歌曲全部导入 AM 呢?
-
-但很快,我也发现了 AM 的一个致命问题:自行导入的歌曲没有动态歌词的功能,只能以一个静态的模式查看全部的歌词。而动态歌词的漂亮设计是我很大一部分喜欢 Apple Music 的原因,但我自己导入的歌曲却无法享受这个功能,不是很令人失望吗?
-
-因此,最后,我还是最终决定自行开发一个播放器,加上所有我喜欢的东西——Apple Music 的页面设计和交互、从 B 站直接获取的曲库、通过网页、PWA 和 Electron 使全平台有一致的体验。
-
-## “赠品”
-
-**开发者寒寒的话:**
-在熟虑后,我决定让 AquaVox 不仅是一个播放器。更进一步,我希望它是一个属于整个中文虚拟歌手社区的数据库。从音源、作者(P 主及 staff)、虚拟歌手、歌曲元信息、动态歌词,在整个链路上成为一个中文虚拟歌手的终极“Archive”。
-
-因此,我们需要你的帮助。
-
-> 声明:AquaVox 并不是音乐(流媒体)平台,官方并未提供任何音源的分发和(或)售卖,也不存在其它形式的任何盈利行为。
diff --git a/packages/electron/package.json b/packages/electron/package.json
deleted file mode 100644
index a26dd85..0000000
--- a/packages/electron/package.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "name": "electron",
- "private": true,
- "type": "module",
- "scripts": {
- "dev": "cross-env NODE_ENV=dev bun run dev:all",
- "dev:all": "concurrently -n=svelte,electron -c='#ff3e00',blue \"bun run dev:svelte\" \"bun run dev:electron\"",
- "dev:svelte": "vite dev",
- "dev:electron": "electron src/electron.js",
- "build": "cross-env NODE_ENV=production bun run build:svelte && bun run build:electron",
- "build:svelte": "vite build",
- "build:electron": "electron-builder -mwl --config build.config.json"
- },
- "devDependencies": {
- "@iconify/svelte": "^4.0.2",
- "@sveltejs/adapter-auto": "^3.2.0",
- "@sveltejs/adapter-node": "^5.0.1",
- "@sveltejs/kit": "^2.5.9",
- "@sveltejs/vite-plugin-svelte": "^3.1.0",
- "@types/eslint": "^8.56.10",
- "@types/node": "^20.14.10",
- "@types/uuid": "^9.0.8",
- "autoprefixer": "^10.4.19",
- "eslint": "^8.57.0",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-svelte": "^2.39.0",
- "postcss": "^8.4.38",
- "prettier": "^3.2.5",
- "prettier-plugin-svelte": "^3.2.3",
- "svelte": "4.2.19",
- "svelte-check": "^3.7.1",
- "tailwindcss": "^3.4.3",
- "typescript": "^5.4.5",
- "vite": "5.4.6",
- "vite-plugin-wasm": "^3.3.0",
- "vitest": "^1.6.0"
- },
- "dependencies": {
- "@applemusic-like-lyrics/core": "^0.1.3",
- "@applemusic-like-lyrics/lyric": "^0.2.2",
- "@esbuild-plugins/node-globals-polyfill": "^0.2.3",
- "@rollup/plugin-commonjs": "^28.0.1",
- "@rollup/plugin-node-resolve": "^15.3.0",
- "@types/bun": "^1.1.6",
- "bezier-easing": "^2.1.0",
- "electron": "^33.0.2",
- "jotai": "^2.8.0",
- "jotai-svelte": "^0.0.2",
- "jss": "^10.10.0",
- "jss-preset-default": "^10.10.0",
- "localforage": "^1.10.0",
- "lrc-parser-ts": "^1.0.3",
- "music-metadata-browser": "^2.5.10",
- "node-cache": "^5.1.2",
- "uuid": "^9.0.1"
- }
-}
diff --git a/packages/electron/postcss.config.js b/packages/electron/postcss.config.js
deleted file mode 100644
index 2e7af2b..0000000
--- a/packages/electron/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/packages/electron/src/app.css b/packages/electron/src/app.css
deleted file mode 100644
index 7d063e6..0000000
--- a/packages/electron/src/app.css
+++ /dev/null
@@ -1,34 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-h1 {
- @apply text-4xl font-bold leading-[4rem];
-}
-
-h2 {
- @apply text-3xl font-medium leading-[3rem];
-}
-
-.text-shadow {
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
-}
-
-.text-shadow-md {
- text-shadow:
- 0 4px 8px rgba(0, 0, 0, 0.12),
- 0 2px 4px rgba(0, 0, 0, 0.08);
-}
-
-.text-shadow-lg {
- text-shadow:
- 0 15px 30px rgba(0, 0, 0, 0.11),
- 0 5px 15px rgba(0, 0, 0, 0.08);
-}
-
-body,
-html {
- position: fixed;
- overflow: hidden;
- overscroll-behavior: none;
-}
diff --git a/packages/electron/src/app.d.ts b/packages/electron/src/app.d.ts
deleted file mode 100644
index 743f07b..0000000
--- a/packages/electron/src/app.d.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// See https://kit.svelte.dev/docs/types#app
-// for information about these interfaces
-declare global {
- namespace App {
- // interface Error {}
- // interface Locals {}
- // interface PageData {}
- // interface PageState {}
- // interface Platform {}
- }
-}
-
-export {};
diff --git a/packages/electron/src/app.html b/packages/electron/src/app.html
deleted file mode 100644
index 7d5373c..0000000
--- a/packages/electron/src/app.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
- AquaVox
- %sveltekit.head%
-
-
- %sveltekit.body%
-
-
-
diff --git a/packages/electron/src/electron.js b/packages/electron/src/electron.js
deleted file mode 100644
index 146bac5..0000000
--- a/packages/electron/src/electron.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import windowStateManager from 'electron-window-state';
-import { app, BrowserWindow, ipcMain } from 'electron';
-import contextMenu from 'electron-context-menu';
-import serve from 'electron-serve';
-
-try {
- require('electron-reloader')(module);
-} catch (e) {
- console.error(e);
-}
-
-const serveURL = serve({ directory: '.' });
-const port = process.env.PORT || 5173;
-const dev = !app.isPackaged;
-let mainWindow;
-
-function createWindow() {
- let windowState = windowStateManager({
- defaultWidth: 800,
- defaultHeight: 600,
- });
-
- const mainWindow = new BrowserWindow({
- backgroundColor: 'whitesmoke',
- titleBarStyle: 'hidden',
- autoHideMenuBar: true,
- minHeight: 450,
- minWidth: 500,
- webPreferences: {
- enableRemoteModule: true,
- contextIsolation: true,
- nodeIntegration: true,
- spellcheck: false,
- devTools: dev,
-
- },
- x: windowState.x,
- y: windowState.y,
- width: windowState.width,
- height: windowState.height,
- });
-
- windowState.manage(mainWindow);
-
- mainWindow.once('ready-to-show', () => {
- mainWindow.show();
- mainWindow.focus();
- });
-
- mainWindow.on('close', () => {
- windowState.saveState(mainWindow);
- });
-
- return mainWindow;
-}
-
-contextMenu({
- showLookUpSelection: true,
- showSearchWithGoogle: true,
- showCopyImage: true,
-});
-
-function loadVite(port) {
- mainWindow.loadURL(`http://localhost:${port}`).catch((e) => {
- console.log('Error loading URL, retrying', e);
- setTimeout(() => {
- loadVite(port);
- }, 200);
- });
-}
-
-function createMainWindow() {
- mainWindow = createWindow();
- mainWindow.once('close', () => {
- mainWindow = null;
- });
-
- if (dev) loadVite(port);
- else serveURL(mainWindow);
-}
-
-app.once('ready', createMainWindow);
-app.on('activate', () => {
- if (!mainWindow) {
- createMainWindow();
- }
-});
-app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') app.quit();
-});
-
-ipcMain.on('to-main', (event, count) => {
- return mainWindow.webContents.send('from-main', `next count is ${count + 1}`);
-});
\ No newline at end of file
diff --git a/packages/electron/src/lib/components/background.svelte b/packages/electron/src/lib/components/background.svelte
deleted file mode 100644
index 0e60697..0000000
--- a/packages/electron/src/lib/components/background.svelte
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
diff --git a/packages/electron/src/lib/components/cover.svelte b/packages/electron/src/lib/components/cover.svelte
deleted file mode 100644
index 6767845..0000000
--- a/packages/electron/src/lib/components/cover.svelte
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-{#if hasLyrics}
-
-{:else}
-
-{/if}
\ No newline at end of file
diff --git a/packages/electron/src/lib/components/database/songCard.svelte b/packages/electron/src/lib/components/database/songCard.svelte
deleted file mode 100644
index 6cae97b..0000000
--- a/packages/electron/src/lib/components/database/songCard.svelte
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-

-
-
-
{songData.name}
-
-
- {songData.producer}
-
-
- {#if songData.duration}
- {formatDuration(songData.duration)}
- {/if}
-
- {#if songData.views}
- {formatViews(songData.views)}播放
- {/if}
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/electron/src/lib/components/import/addIcon.svelte b/packages/electron/src/lib/components/import/addIcon.svelte
deleted file mode 100644
index ffa4aad..0000000
--- a/packages/electron/src/lib/components/import/addIcon.svelte
+++ /dev/null
@@ -1,17 +0,0 @@
-
diff --git a/packages/electron/src/lib/components/import/fileList.d.ts b/packages/electron/src/lib/components/import/fileList.d.ts
deleted file mode 100644
index 555018b..0000000
--- a/packages/electron/src/lib/components/import/fileList.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-interface FileItem {
- name: string;
- size?: number;
- type: string;
- lastModified?: number;
- lastModifiedDate?: Date;
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/components/import/fileList.svelte b/packages/electron/src/lib/components/import/fileList.svelte
deleted file mode 100644
index ea0f424..0000000
--- a/packages/electron/src/lib/components/import/fileList.svelte
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
- {#each displayItems as item}
- -
- {extractFileName(item.name)}
- {toHumanSize(item.size)}
- {#if item.type}
- · {formatText(item.type)}
- {:else if item.name.split('.').length > 1}
- · {formatText(item.name.split('.')[item.name.split('.').length - 1])}
- {:else}
- · 未知格式
- {/if}
- {#if item.duration}
- · {formatDuration(item.duration)}
- {/if}
- {#if item.pic !== undefined && item.pic !== 'N/A'}
-
- {/if}
-
- {/each}
-
diff --git a/packages/electron/src/lib/components/import/fileSelector.svelte b/packages/electron/src/lib/components/import/fileSelector.svelte
deleted file mode 100644
index 521c5c1..0000000
--- a/packages/electron/src/lib/components/import/fileSelector.svelte
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
diff --git a/packages/electron/src/lib/components/import/importIcon.svelte b/packages/electron/src/lib/components/import/importIcon.svelte
deleted file mode 100644
index cf982d5..0000000
--- a/packages/electron/src/lib/components/import/importIcon.svelte
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/packages/electron/src/lib/components/import/sourceCard.svelte b/packages/electron/src/lib/components/import/sourceCard.svelte
deleted file mode 100644
index 35c3ee3..0000000
--- a/packages/electron/src/lib/components/import/sourceCard.svelte
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
diff --git a/packages/electron/src/lib/components/interactiveBox.svelte b/packages/electron/src/lib/components/interactiveBox.svelte
deleted file mode 100644
index 51bd229..0000000
--- a/packages/electron/src/lib/components/interactiveBox.svelte
+++ /dev/null
@@ -1,380 +0,0 @@
-
-
-{#if showInfoTop}
-
- {name}
- {singer}
-
-{/if}
-
-
- {#if !showInfoTop}
-
-
- {name}
-
-
{singer}
-
- {/if}
-
-
-
- {formatDuration(progress)}
-
-
{
- userAdjustingProgress.set(true);
- }}
- on:mousemove={(e) => {
- if ($userAdjustingProgress) {
- adjustDisplayProgress(e.offsetX / progressBar.getBoundingClientRect().width);
- }
- }}
- on:mouseup={(e) => {
- const offsetX = e.offsetX;
- progressBarOnClick(e);
- // Q: why it needs delay?
- // A: I do not know.
- setTimeout(()=> {
- userAdjustingProgress.set(false);
- progressBarMouseUp(offsetX);
- }, 50);
- }}
- role="slider"
- tabindex="0"
- >
-
-
-
-
{formatDuration(duration)}
-
-
-
-
-
-
-
-

-
volumeBarOnChange(e)}
- on:keydown
- on:keyup
- on:mousedown={() => {
- userAdjustingVolume = true;
- }}
- on:mousemove={(e) => {
- if (userAdjustingVolume) {
- volumeBarOnChange(e);
- }
- }}
- on:mouseup={() => {
- userAdjustingVolume = false;
- }}
- on:touchend={(e) => {
- e.preventDefault();
- userAdjustingVolume = false;
- }}
- on:touchmove={(e) => {
- e.preventDefault();
- userAdjustingVolume = true;
- if (userAdjustingVolume) {
- volumeBarChangeTouch(e);
- }
- }}
- on:touchstart={(e) => {
- if (e.cancelable) {
- e.preventDefault();
- }
- userAdjustingVolume = true;
- }}
- role="slider"
- tabindex="0"
- >
-
-
-

-
-
-
-
-
diff --git a/packages/electron/src/lib/components/lyrics/lyricLine.svelte b/packages/electron/src/lib/components/lyrics/lyricLine.svelte
deleted file mode 100644
index 0337b75..0000000
--- a/packages/electron/src/lib/components/lyrics/lyricLine.svelte
+++ /dev/null
@@ -1,174 +0,0 @@
-
-
-
-
- {
- clickMask.style.backgroundColor = 'rgba(255,255,255,.3)';
- }}
- on:touchend={() => {
- clickMask.style.backgroundColor = 'transparent';
- }}
- on:click={() => {
- lyricClick(index);
- }}
->
-
-
- {#if debugMode}
-
- {index}: duration: {(line.end - line.start).toFixed(3)}, {line.start.toFixed(3)}~{line.end.toFixed(3)}
-
- {/if}
-
- {line.text}
-
- {#if line.translation}
-
-
- {line.translation}
-
- {/if}
-
-
-
diff --git a/packages/electron/src/lib/components/lyrics/newLyrics.svelte b/packages/electron/src/lib/components/lyrics/newLyrics.svelte
deleted file mode 100644
index da14660..0000000
--- a/packages/electron/src/lib/components/lyrics/newLyrics.svelte
+++ /dev/null
@@ -1,265 +0,0 @@
-
-
-
-
-{#if debugMode}
-
- progress: {progress.toFixed(2)}, nextUpdate: {nextUpdate}, scrolling: {scrolling}, current: {currentLyricIndex}
-
-{/if}
-
-{#if originalLyrics && originalLyrics.scripts}
-
- {#each lyricLines as lyric, i}
-
- {/each}
-
-{/if}
diff --git a/packages/electron/src/lib/components/lyrics/type.d.ts b/packages/electron/src/lib/components/lyrics/type.d.ts
deleted file mode 100644
index 115703b..0000000
--- a/packages/electron/src/lib/components/lyrics/type.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface LyricPos {
- x: number;
- y: number;
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/fileList.state.ts b/packages/electron/src/lib/state/fileList.state.ts
deleted file mode 100644
index dd9609f..0000000
--- a/packages/electron/src/lib/state/fileList.state.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { atom } from 'jotai-svelte'
-
-export const fileListState = atom([] as any[]);
-export const finalFileListState = atom([] as any[]);
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/localImportStatus.state.ts b/packages/electron/src/lib/state/localImportStatus.state.ts
deleted file mode 100644
index ebde8aa..0000000
--- a/packages/electron/src/lib/state/localImportStatus.state.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { atom } from 'jotai-svelte'
-
-export const localImportSuccess = atom([] as any[]);
-export const localImportFailed = atom([] as any[]);
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/nextUpdate.ts b/packages/electron/src/lib/state/nextUpdate.ts
deleted file mode 100644
index 1ef1ac9..0000000
--- a/packages/electron/src/lib/state/nextUpdate.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { writable } from 'svelte/store';
-const nextUpdate = writable(-1);
-export default nextUpdate;
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/progressBarRaw.ts b/packages/electron/src/lib/state/progressBarRaw.ts
deleted file mode 100644
index 73e6aae..0000000
--- a/packages/electron/src/lib/state/progressBarRaw.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { writable } from 'svelte/store';
-const progressBarRaw = writable(0);
-export default progressBarRaw;
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/progressBarSlideValue.ts b/packages/electron/src/lib/state/progressBarSlideValue.ts
deleted file mode 100644
index ccd863a..0000000
--- a/packages/electron/src/lib/state/progressBarSlideValue.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { writable } from 'svelte/store';
-const progressBarSlideValue = writable(0);
-export default progressBarSlideValue;
\ No newline at end of file
diff --git a/packages/electron/src/lib/state/userAdjustingProgress.ts b/packages/electron/src/lib/state/userAdjustingProgress.ts
deleted file mode 100644
index cd932dd..0000000
--- a/packages/electron/src/lib/state/userAdjustingProgress.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { writable } from 'svelte/store';
-const userAdjustingProgress = writable(false);
-export default userAdjustingProgress;
\ No newline at end of file
diff --git a/packages/electron/src/lib/ttml/index.ts b/packages/electron/src/lib/ttml/index.ts
deleted file mode 100644
index 79fec1c..0000000
--- a/packages/electron/src/lib/ttml/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./parser";
-export * from "./writer";
-export type * from "./ttml-types";
diff --git a/packages/electron/src/lib/ttml/parser.ts b/packages/electron/src/lib/ttml/parser.ts
deleted file mode 100644
index 3cdb8eb..0000000
--- a/packages/electron/src/lib/ttml/parser.ts
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * @fileoverview
- * 解析 TTML 歌词文档到歌词数组的解析器
- * 用于解析从 Apple Music 来的歌词文件,且扩展并支持翻译和音译文本。
- * @see https://www.w3.org/TR/2018/REC-ttml1-20181108/
- */
-
-import type {
- LyricLine,
- LyricWord,
- TTMLLyric,
- TTMLMetadata,
-} from "./ttml-types";
-
-const timeRegexp =
- /^(((?[0-9]+):)?(?[0-9]+):)?(?[0-9]+([.:]([0-9]+))?)/;
-function parseTimespan(timeSpan: string): number {
- const matches = timeRegexp.exec(timeSpan);
- if (matches) {
- const hour = Number(matches.groups?.hour || "0");
- const min = Number(matches.groups?.min || "0");
- const sec = Number(matches.groups?.sec.replace(/:/, ".") || "0");
- return Math.floor((hour * 3600 + min * 60 + sec) * 1000);
- }
- throw new TypeError(`时间戳字符串解析失败:${timeSpan}`);
-}
-
-export function parseTTML(ttmlText: string): TTMLLyric {
- const domParser = new DOMParser();
- const ttmlDoc: XMLDocument = domParser.parseFromString(
- ttmlText,
- "application/xml",
- );
-
- let mainAgentId = "v1";
-
- const metadata: TTMLMetadata[] = [];
- for (const meta of ttmlDoc.querySelectorAll("meta")) {
- if (meta.tagName === "amll:meta") {
- const key = meta.getAttribute("key");
- if (key) {
- const value = meta.getAttribute("value");
- if (value) {
- const existing = metadata.find((m) => m.key === key);
- if (existing) {
- existing.value.push(value);
- } else {
- metadata.push({
- key,
- value: [value],
- });
- }
- }
- }
- }
- }
-
- for (const agent of ttmlDoc.querySelectorAll("ttm\\:agent")) {
- if (agent.getAttribute("type") === "person") {
- const id = agent.getAttribute("xml:id");
- if (id) {
- mainAgentId = id;
- }
- }
- }
-
- const lyricLines: LyricLine[] = [];
-
- function parseParseLine(lineEl: Element, isBG = false, isDuet = false) {
- const line: LyricLine = {
- words: [],
- translatedLyric: "",
- romanLyric: "",
- isBG,
- isDuet:
- !!lineEl.getAttribute("ttm:agent") &&
- lineEl.getAttribute("ttm:agent") !== mainAgentId,
- startTime: 0,
- endTime: 0,
- };
- if (isBG) line.isDuet = isDuet;
- let haveBg = false;
-
- for (const wordNode of lineEl.childNodes) {
- if (wordNode.nodeType === Node.TEXT_NODE) {
- line.words?.push({
- word: wordNode.textContent ?? "",
- startTime: 0,
- endTime: 0,
- });
- } else if (wordNode.nodeType === Node.ELEMENT_NODE) {
- const wordEl = wordNode as Element;
- const role = wordEl.getAttribute("ttm:role");
-
- if (wordEl.nodeName === "span" && role) {
- if (role === "x-bg") {
- parseParseLine(wordEl, true, line.isDuet);
- haveBg = true;
- } else if (role === "x-translation") {
- line.translatedLyric = wordEl.innerHTML;
- } else if (role === "x-roman") {
- line.romanLyric = wordEl.innerHTML;
- }
- } else if (wordEl.hasAttribute("begin") && wordEl.hasAttribute("end")) {
- const word: LyricWord = {
- word: wordNode.textContent ?? "",
- startTime: parseTimespan(wordEl.getAttribute("begin") ?? ""),
- endTime: parseTimespan(wordEl.getAttribute("end") ?? ""),
- };
- const emptyBeat = wordEl.getAttribute("amll:empty-beat");
- if (emptyBeat) {
- word.emptyBeat = Number(emptyBeat);
- }
- line.words.push(word);
- }
- }
- }
-
- if (line.isBG) {
- const firstWord = line.words?.[0];
- if (firstWord?.word.startsWith("(")) {
- firstWord.word = firstWord.word.substring(1);
- if (firstWord.word.length === 0) {
- line.words.shift();
- }
- }
-
- const lastWord = line.words?.[line.words.length - 1];
- if (lastWord?.word.endsWith(")")) {
- lastWord.word = lastWord.word.substring(0, lastWord.word.length - 1);
- if (lastWord.word.length === 0) {
- line.words.pop();
- }
- }
- }
-
- const startTime = lineEl.getAttribute("begin");
- const endTime = lineEl.getAttribute("end");
- if (startTime && endTime) {
- line.startTime = parseTimespan(startTime);
- line.endTime = parseTimespan(endTime);
- } else {
- line.startTime = line.words
- .filter((v) => v.word.trim().length > 0)
- .reduce((pv, cv) => Math.min(pv, cv.startTime), Infinity);
- line.endTime = line.words
- .filter((v) => v.word.trim().length > 0)
- .reduce((pv, cv) => Math.max(pv, cv.endTime), 0);
- }
-
- if (haveBg) {
- const bgLine = lyricLines.pop();
- lyricLines.push(line);
- if (bgLine) lyricLines.push(bgLine);
- } else {
- lyricLines.push(line);
- }
- }
-
- for (const lineEl of ttmlDoc.querySelectorAll("body p[begin][end]")) {
- parseParseLine(lineEl);
- }
-
- return {
- metadata,
- lyricLines: lyricLines,
- };
-}
diff --git a/packages/electron/src/lib/ttml/ttml-types.ts b/packages/electron/src/lib/ttml/ttml-types.ts
deleted file mode 100644
index 644a870..0000000
--- a/packages/electron/src/lib/ttml/ttml-types.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export interface TTMLMetadata {
- key: string;
- value: string[];
-}
-
-export interface TTMLLyric {
- metadata: TTMLMetadata[];
- lyricLines: LyricLine[];
-}
-
-export interface LyricWord {
- startTime: number;
- endTime: number;
- word: string;
- emptyBeat?: number;
-}
-
-export interface LyricLine {
- words: LyricWord[];
- translatedLyric: string;
- romanLyric: string;
- isBG: boolean;
- isDuet: boolean;
- startTime: number;
- endTime: number;
-}
diff --git a/packages/electron/src/lib/ttml/writer.ts b/packages/electron/src/lib/ttml/writer.ts
deleted file mode 100644
index 30668a1..0000000
--- a/packages/electron/src/lib/ttml/writer.ts
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * @fileoverview
- * 用于将内部歌词数组对象导出成 TTML 格式的模块
- * 但是可能会有信息会丢失
- */
-
-import type { LyricLine, LyricWord, TTMLLyric } from "./ttml-types";
-
-function msToTimestamp(timeMS: number): string {
- let time = timeMS;
- if (!Number.isSafeInteger(time) || time < 0) {
- return "00:00.000";
- }
- if (time === Infinity) {
- return "99:99.999";
- }
- time = time / 1000;
- const secs = time % 60;
- time = (time - secs) / 60;
- const mins = time % 60;
- const hrs = (time - mins) / 60;
-
- const h = hrs.toString().padStart(2, "0");
- const m = mins.toString().padStart(2, "0");
- const s = secs.toFixed(3).padStart(6, "0");
-
- if (hrs > 0) {
- return `${h}:${m}:${s}`;
- }
- return `${m}:${s}`;
-}
-
-export function exportTTML(ttmlLyric: TTMLLyric, pretty = false): string {
- const params: LyricLine[][] = [];
- const lyric = ttmlLyric.lyricLines;
-
- let tmp: LyricLine[] = [];
- for (const line of lyric) {
- if (line.words.length === 0 && tmp.length > 0) {
- params.push(tmp);
- tmp = [];
- } else {
- tmp.push(line);
- }
- }
-
- if (tmp.length > 0) {
- params.push(tmp);
- }
-
- const doc = new Document();
-
- function createWordElement(word: LyricWord): Element {
- const span = doc.createElement("span");
- span.setAttribute("begin", msToTimestamp(word.startTime));
- span.setAttribute("end", msToTimestamp(word.endTime));
- if (word.emptyBeat) {
- span.setAttribute("amll:empty-beat", `${word.emptyBeat}`);
- }
- span.appendChild(doc.createTextNode(word.word));
- return span;
- }
-
- const ttRoot = doc.createElement("tt");
-
- ttRoot.setAttribute("xmlns", "http://www.w3.org/ns/ttml");
- ttRoot.setAttribute("xmlns:ttm", "http://www.w3.org/ns/ttml#metadata");
- ttRoot.setAttribute("xmlns:amll", "http://www.example.com/ns/amll");
- ttRoot.setAttribute(
- "xmlns:itunes",
- "http://music.apple.com/lyric-ttml-internal",
- );
-
- doc.appendChild(ttRoot);
-
- const head = doc.createElement("head");
-
- ttRoot.appendChild(head);
-
- const body = doc.createElement("body");
- const hasOtherPerson = !!lyric.find((v) => v.isDuet);
-
- const metadataEl = doc.createElement("metadata");
- const mainPersonAgent = doc.createElement("ttm:agent");
- mainPersonAgent.setAttribute("type", "person");
- mainPersonAgent.setAttribute("xml:id", "v1");
-
- metadataEl.appendChild(mainPersonAgent);
-
- if (hasOtherPerson) {
- const otherPersonAgent = doc.createElement("ttm:agent");
- otherPersonAgent.setAttribute("type", "other");
- otherPersonAgent.setAttribute("xml:id", "v2");
-
- metadataEl.appendChild(otherPersonAgent);
- }
-
- for (const metadata of ttmlLyric.metadata) {
- for (const value of metadata.value) {
- const metaEl = doc.createElement("amll:meta");
- metaEl.setAttribute("key", metadata.key);
- metaEl.setAttribute("value", value);
- metadataEl.appendChild(metaEl);
- }
- }
-
- head.appendChild(metadataEl);
-
- let i = 0;
-
- const guessDuration = lyric[lyric.length - 1]?.endTime ?? 0;
- body.setAttribute("dur", msToTimestamp(guessDuration));
-
- for (const param of params) {
- const paramDiv = doc.createElement("div");
- const beginTime = param[0]?.startTime ?? 0;
- const endTime = param[param.length - 1]?.endTime ?? 0;
-
- paramDiv.setAttribute("begin", msToTimestamp(beginTime));
- paramDiv.setAttribute("end", msToTimestamp(endTime));
-
- for (let lineIndex = 0; lineIndex < param.length; lineIndex++) {
- const line = param[lineIndex];
- const lineP = doc.createElement("p");
- const beginTime = line.startTime ?? 0;
- const endTime = line.endTime;
-
- lineP.setAttribute("begin", msToTimestamp(beginTime));
- lineP.setAttribute("end", msToTimestamp(endTime));
-
- lineP.setAttribute("ttm:agent", line.isDuet ? "v2" : "v1");
- lineP.setAttribute("itunes:key", `L${++i}`);
-
- if (line.words.length > 1) {
- let beginTime = Infinity;
- let endTime = 0;
- for (const word of line.words) {
- if (word.word.trim().length === 0) {
- lineP.appendChild(doc.createTextNode(word.word));
- } else {
- const span = createWordElement(word);
- lineP.appendChild(span);
- beginTime = Math.min(beginTime, word.startTime);
- endTime = Math.max(endTime, word.endTime);
- }
- }
- lineP.setAttribute("begin", msToTimestamp(line.startTime));
- lineP.setAttribute("end", msToTimestamp(line.endTime));
- } else if (line.words.length === 1) {
- const word = line.words[0];
- lineP.appendChild(doc.createTextNode(word.word));
- lineP.setAttribute("begin", msToTimestamp(word.startTime));
- lineP.setAttribute("end", msToTimestamp(word.endTime));
- }
-
- const nextLine = param[lineIndex + 1];
- if (nextLine?.isBG) {
- lineIndex++;
- const bgLine = nextLine;
- const bgLineSpan = doc.createElement("span");
- bgLineSpan.setAttribute("ttm:role", "x-bg");
-
- if (bgLine.words.length > 1) {
- let beginTime = Infinity;
- let endTime = 0;
- for (
- let wordIndex = 0;
- wordIndex < bgLine.words.length;
- wordIndex++
- ) {
- const word = bgLine.words[wordIndex];
- if (word.word.trim().length === 0) {
- bgLineSpan.appendChild(doc.createTextNode(word.word));
- } else {
- const span = createWordElement(word);
- if (wordIndex === 0) {
- span.prepend(doc.createTextNode("("));
- } else if (wordIndex === bgLine.words.length - 1) {
- span.appendChild(doc.createTextNode(")"));
- }
- bgLineSpan.appendChild(span);
- beginTime = Math.min(beginTime, word.startTime);
- endTime = Math.max(endTime, word.endTime);
- }
- }
- bgLineSpan.setAttribute("begin", msToTimestamp(beginTime));
- bgLineSpan.setAttribute("end", msToTimestamp(endTime));
- } else if (bgLine.words.length === 1) {
- const word = bgLine.words[0];
- bgLineSpan.appendChild(doc.createTextNode(`(${word.word})`));
- bgLineSpan.setAttribute("begin", msToTimestamp(word.startTime));
- bgLineSpan.setAttribute("end", msToTimestamp(word.endTime));
- }
-
- if (bgLine.translatedLyric) {
- const span = doc.createElement("span");
- span.setAttribute("ttm:role", "x-translation");
- span.setAttribute("xml:lang", "zh-CN");
- span.appendChild(doc.createTextNode(bgLine.translatedLyric));
- bgLineSpan.appendChild(span);
- }
-
- if (bgLine.romanLyric) {
- const span = doc.createElement("span");
- span.setAttribute("ttm:role", "x-roman");
- span.appendChild(doc.createTextNode(bgLine.romanLyric));
- bgLineSpan.appendChild(span);
- }
-
- lineP.appendChild(bgLineSpan);
- }
-
- if (line.translatedLyric) {
- const span = doc.createElement("span");
- span.setAttribute("ttm:role", "x-translation");
- span.setAttribute("xml:lang", "zh-CN");
- span.appendChild(doc.createTextNode(line.translatedLyric));
- lineP.appendChild(span);
- }
-
- if (line.romanLyric) {
- const span = doc.createElement("span");
- span.setAttribute("ttm:role", "x-roman");
- span.appendChild(doc.createTextNode(line.romanLyric));
- lineP.appendChild(span);
- }
-
- paramDiv.appendChild(lineP);
- }
-
- body.appendChild(paramDiv);
- }
-
- ttRoot.appendChild(body);
-
- if (pretty) {
- const xsltDoc = new DOMParser().parseFromString(
- [
- '',
- ' ',
- ' ',
- ' ',
- " ",
- ' ',
- ' ',
- " ",
- ' ',
- "",
- ].join("\n"),
- "application/xml",
- );
-
- const xsltProcessor = new XSLTProcessor();
- xsltProcessor.importStylesheet(xsltDoc);
- const resultDoc = xsltProcessor.transformToDocument(doc);
-
- return new XMLSerializer().serializeToString(resultDoc);
- }
- return new XMLSerializer().serializeToString(doc);
-}
diff --git a/packages/electron/src/lib/utils/convertCoverData.ts b/packages/electron/src/lib/utils/convertCoverData.ts
deleted file mode 100644
index f1d49d5..0000000
--- a/packages/electron/src/lib/utils/convertCoverData.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export default function(dataObject: any) {
- // Create a blob from the UInt8Array data
- const blob = new Blob([dataObject.data], { type: dataObject.format });
-
- // Create a URL for the blob
- const imageUrl = URL.createObjectURL(blob);
-
- // Create an Image object
- const image = new Image();
- image.src = imageUrl;
-
- return imageUrl; // return the URL of the image
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/extractFileName.ts b/packages/electron/src/lib/utils/extractFileName.ts
deleted file mode 100644
index ce739d1..0000000
--- a/packages/electron/src/lib/utils/extractFileName.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default function(fullname: string){
- if (!fullname) return '';
- return fullname.split('.').slice(0, -1).join('.')
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/formatDuration.ts b/packages/electron/src/lib/utils/formatDuration.ts
deleted file mode 100644
index b3d88bc..0000000
--- a/packages/electron/src/lib/utils/formatDuration.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export default function(durationInSeconds: number): string {
- // Calculate hours, minutes, and seconds
- const hours = Math.floor(durationInSeconds / 3600);
- const minutes = Math.floor((durationInSeconds % 3600) / 60);
- const seconds = Math.floor(durationInSeconds) % 60;
-
- // Format hours, minutes, and seconds into string
- let formattedTime = '';
- if (hours > 0) {
- formattedTime += hours + ':';
- }
- if (minutes < 10 && hours > 0) {
- formattedTime += '0';
- }
- formattedTime += minutes + ':';
- formattedTime += (seconds < 10 ? '0' : '') + seconds;
-
- return formattedTime;
-}
diff --git a/packages/electron/src/lib/utils/formatText.ts b/packages/electron/src/lib/utils/formatText.ts
deleted file mode 100644
index f234083..0000000
--- a/packages/electron/src/lib/utils/formatText.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export default function(key: string){
- const dict = {
- "audio/mpeg": "MP3 音频",
- "audio/ogg": "OGG 容器",
- "audio/flac": "FLAC 无损音频",
- "audio/aac": "AAC 音频",
- "lrc": "LRC 歌词"
- }
- if (!key) return "未知格式";
- else return dict[key as keyof typeof dict];
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/formatViews.ts b/packages/electron/src/lib/utils/formatViews.ts
deleted file mode 100644
index 27f33a9..0000000
--- a/packages/electron/src/lib/utils/formatViews.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export function formatViews(num: number): string {
- if (num >= 10000) {
- const formattedNum = Math.floor(num / 1000) / 10; // 向下保留1位小数
- return `${formattedNum} 万`;
- } else {
- return num.toString() + " ";
- }
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/getAudioCoverURL.ts b/packages/electron/src/lib/utils/getAudioCoverURL.ts
deleted file mode 100644
index 7b3a9f0..0000000
--- a/packages/electron/src/lib/utils/getAudioCoverURL.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import * as musicMetadata from 'music-metadata-browser';
-
-export default function getAudioMeta(audio: File, callback: Function) {
- musicMetadata.parseBlob(audio).then((metadata) => {
- if (metadata)
- callback(metadata);
- else
- callback(null);
- })
-}
diff --git a/packages/electron/src/lib/utils/getVersion.ts b/packages/electron/src/lib/utils/getVersion.ts
deleted file mode 100644
index 2d1145d..0000000
--- a/packages/electron/src/lib/utils/getVersion.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as pjson from "../../../package.json";
-
-export default function getVersion(){
- return pjson.version;
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/humanSize.ts b/packages/electron/src/lib/utils/humanSize.ts
deleted file mode 100644
index 7317b87..0000000
--- a/packages/electron/src/lib/utils/humanSize.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export default function toHumanSize(size: number | undefined){
- if (!size) return '0 B'
- const units = ['B', 'KB', 'MB', 'GB'];
- let unitIndex = 0;
- while (size >= 1000 && unitIndex < units.length - 1) {
- size /= 1000;
- unitIndex++;
- }
- return `${size.toFixed(2)} ${units[unitIndex]}`
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/songUpdateTime.ts b/packages/electron/src/lib/utils/songUpdateTime.ts
deleted file mode 100644
index 6c8899a..0000000
--- a/packages/electron/src/lib/utils/songUpdateTime.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export function getCurrentFormattedDateTime() {
- const now = new Date();
-
- const year = now.getFullYear();
- const month = String(now.getMonth() + 1).padStart(2, '0'); // getMonth() is zero-based
- const day = String(now.getDate()).padStart(2, '0');
-
- const hours = String(now.getHours()).padStart(2, '0');
- const minutes = String(now.getMinutes()).padStart(2, '0');
- const seconds = String(now.getSeconds()).padStart(2, '0');
-
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
-}
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/storage.ts b/packages/electron/src/lib/utils/storage.ts
deleted file mode 100644
index 0424ae6..0000000
--- a/packages/electron/src/lib/utils/storage.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import localforage from "localforage";
-
-localforage.config({
- driver: localforage.INDEXEDDB,
- name: 'audioDB'
-});
-
-export default localforage;
\ No newline at end of file
diff --git a/packages/electron/src/lib/utils/truncate.ts b/packages/electron/src/lib/utils/truncate.ts
deleted file mode 100644
index c10b4a4..0000000
--- a/packages/electron/src/lib/utils/truncate.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function truncate(value: number, min: number, max: number) {
- return Math.min(Math.max(value, min), max);
-}
\ No newline at end of file
diff --git a/packages/electron/src/routes/+layout.svelte b/packages/electron/src/routes/+layout.svelte
deleted file mode 100644
index 6e3f91b..0000000
--- a/packages/electron/src/routes/+layout.svelte
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/electron/src/routes/+page.server.js b/packages/electron/src/routes/+page.server.js
deleted file mode 100644
index 5829b7e..0000000
--- a/packages/electron/src/routes/+page.server.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ssr = false;
\ No newline at end of file
diff --git a/packages/electron/src/routes/+page.svelte b/packages/electron/src/routes/+page.svelte
deleted file mode 100644
index 0b7cfca..0000000
--- a/packages/electron/src/routes/+page.svelte
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
- Aquavox - 音乐库
-
-
-
-
AquaVox
-
音乐库
-
-
- AquaVox {getVersion()} · 早期公开预览 · 源代码参见
- GitHub
-
-
导入音乐
-
-
-
你可以在这里探索,提交和分享好听的歌曲。
-
-
-
diff --git a/packages/electron/src/routes/database/+layout.svelte b/packages/electron/src/routes/database/+layout.svelte
deleted file mode 100644
index d154c1e..0000000
--- a/packages/electron/src/routes/database/+layout.svelte
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/packages/electron/src/routes/database/+page.server.ts b/packages/electron/src/routes/database/+page.server.ts
deleted file mode 100644
index 79f69f6..0000000
--- a/packages/electron/src/routes/database/+page.server.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { songData } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData.js';
-import type { PageServerLoad } from './$types';
-
-export const load: PageServerLoad = () => {
- loadData();
- const songIDList = songData.keys().slice(0, 20);
- const songDataList = [];
- for (const songID of songIDList) {
- songDataList.push(songData.get(songID)!);
- }
- return {
- songDataList: songDataList
- };
-};
-
-export const ssr = true;
\ No newline at end of file
diff --git a/packages/electron/src/routes/database/+page.svelte b/packages/electron/src/routes/database/+page.svelte
deleted file mode 100644
index 3f41ca0..0000000
--- a/packages/electron/src/routes/database/+page.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
- AquaVox 音乐数据库
-
-
-
-
-
-
-
-
- {#each songList as song}
-
- {/each}
-
-
diff --git a/packages/electron/src/routes/database/edit/[id]/+page.server.ts b/packages/electron/src/routes/database/edit/[id]/+page.server.ts
deleted file mode 100644
index ce0f590..0000000
--- a/packages/electron/src/routes/database/edit/[id]/+page.server.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import fs from 'fs';
-import type { PageServerLoad } from './$types';
-import { safePath } from '$lib/server/safePath';
-
-export const load: PageServerLoad = ({ params }) => {
- const filePath = safePath(`${params.id}.json`, { base: './data/song' });
- if (!filePath) {
- return {
- songData: null
- };
- }
- try {
- const dataBuffer = fs.readFileSync(filePath);
- const data = JSON.parse(dataBuffer.toString());
- return {
- songData: data
- };
- } catch {
- return {
- songData: null
- }
- }
-}
diff --git a/packages/electron/src/routes/database/edit/[id]/+page.svelte b/packages/electron/src/routes/database/edit/[id]/+page.svelte
deleted file mode 100644
index 147bbad..0000000
--- a/packages/electron/src/routes/database/edit/[id]/+page.svelte
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
- 建议编辑: {data.songData.name} ({songID})
-
-
-
-
-建议编辑: {data.songData.name} ({songID})
-
-
-
-
\ No newline at end of file
diff --git a/packages/electron/src/routes/database/page/[id]/+page.server.ts b/packages/electron/src/routes/database/page/[id]/+page.server.ts
deleted file mode 100644
index e037184..0000000
--- a/packages/electron/src/routes/database/page/[id]/+page.server.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { songData } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData.js';
-import type { PageServerLoad } from './$types';
-
-export const load: PageServerLoad = ({ params }) => {
- const offset = (parseInt(params.id) - 1) * 20;
- loadData();
- const songIDList = songData.keys().slice(offset, offset + 20);
- const songDataList = [];
- for (const songID of songIDList) {
- songDataList.push(songData.get(songID)!);
- }
- return {
- songDataList: songDataList
- };
-};
-
-export const ssr = true;
\ No newline at end of file
diff --git a/packages/electron/src/routes/database/page/[id]/+page.svelte b/packages/electron/src/routes/database/page/[id]/+page.svelte
deleted file mode 100644
index 3f41ca0..0000000
--- a/packages/electron/src/routes/database/page/[id]/+page.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
- AquaVox 音乐数据库
-
-
-
-
-
-
-
-
- {#each songList as song}
-
- {/each}
-
-
diff --git a/packages/electron/src/routes/database/submit/+page.svelte b/packages/electron/src/routes/database/submit/+page.svelte
deleted file mode 100644
index 4eabc23..0000000
--- a/packages/electron/src/routes/database/submit/+page.svelte
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
- 提交新曲
-
-
-
-
-提交新曲
-
-
-
-
diff --git a/packages/electron/src/routes/import/+layout.svelte b/packages/electron/src/routes/import/+layout.svelte
deleted file mode 100644
index d154c1e..0000000
--- a/packages/electron/src/routes/import/+layout.svelte
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/packages/electron/src/routes/import/+page.svelte b/packages/electron/src/routes/import/+page.svelte
deleted file mode 100644
index d43d801..0000000
--- a/packages/electron/src/routes/import/+page.svelte
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-导入
-希望从哪里导入你的歌曲?
-
-
\ No newline at end of file
diff --git a/packages/electron/src/routes/import/[id]/lyric/+page.server.js b/packages/electron/src/routes/import/[id]/lyric/+page.server.js
deleted file mode 100644
index 5829b7e..0000000
--- a/packages/electron/src/routes/import/[id]/lyric/+page.server.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ssr = false;
\ No newline at end of file
diff --git a/packages/electron/src/routes/import/[id]/lyric/+page.svelte b/packages/electron/src/routes/import/[id]/lyric/+page.svelte
deleted file mode 100644
index 2b151ac..0000000
--- a/packages/electron/src/routes/import/[id]/lyric/+page.svelte
+++ /dev/null
@@ -1,42 +0,0 @@
-
-
-
-歌词导入
-当前为 {audioId} 导入歌词
-
-
-
歌词文件
-
-
-
-
-
-
- {status}
-
-
diff --git a/packages/electron/src/routes/import/local/+page.server.js b/packages/electron/src/routes/import/local/+page.server.js
deleted file mode 100644
index 5829b7e..0000000
--- a/packages/electron/src/routes/import/local/+page.server.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ssr = false;
\ No newline at end of file
diff --git a/packages/electron/src/routes/import/local/+page.svelte b/packages/electron/src/routes/import/local/+page.svelte
deleted file mode 100644
index 7f0b348..0000000
--- a/packages/electron/src/routes/import/local/+page.svelte
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-本地导入向导
-欢迎使用本地导入向导!
-
- 你可以选择从本地导入你喜欢的音乐文件,并同时将封面、歌词、歌手与制作者等其他信息一并囊括其中。
-
-
-
-
音频
-
-
-
-
-
-
- 待处理 {$fileList.length} 个文件
- {#if $success.length > 0}
- {$success.length} 个文件导入成功
- {/if}
- {#if $failed.length > 0}
- {$failed.length} 个文件导入失败
- {/if}
-
-
diff --git a/packages/electron/src/routes/play/[id]/+page.server.js b/packages/electron/src/routes/play/[id]/+page.server.js
deleted file mode 100644
index 5829b7e..0000000
--- a/packages/electron/src/routes/play/[id]/+page.server.js
+++ /dev/null
@@ -1 +0,0 @@
-export const ssr = false;
\ No newline at end of file
diff --git a/packages/electron/src/routes/play/[id]/+page.svelte b/packages/electron/src/routes/play/[id]/+page.svelte
deleted file mode 100644
index 0a7f6b5..0000000
--- a/packages/electron/src/routes/play/[id]/+page.svelte
+++ /dev/null
@@ -1,271 +0,0 @@
-
-
-
- {name} - AquaVox
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/electron/static/edit.svg b/packages/electron/static/edit.svg
deleted file mode 100644
index 5b03e2d..0000000
--- a/packages/electron/static/edit.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/packages/electron/static/next.svg b/packages/electron/static/next.svg
deleted file mode 100644
index cd44252..0000000
--- a/packages/electron/static/next.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/packages/electron/static/pause.svg b/packages/electron/static/pause.svg
deleted file mode 100644
index 4509dde..0000000
--- a/packages/electron/static/pause.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/packages/electron/static/play.svg b/packages/electron/static/play.svg
deleted file mode 100644
index 654ddf5..0000000
--- a/packages/electron/static/play.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/packages/electron/static/previous.svg b/packages/electron/static/previous.svg
deleted file mode 100644
index 8a141f5..0000000
--- a/packages/electron/static/previous.svg
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/packages/electron/static/volumeDown.svg b/packages/electron/static/volumeDown.svg
deleted file mode 100644
index 238da4b..0000000
--- a/packages/electron/static/volumeDown.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/electron/static/volumeUp.svg b/packages/electron/static/volumeUp.svg
deleted file mode 100644
index b9dc17a..0000000
--- a/packages/electron/static/volumeUp.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/packages/electron/svelte.config.js b/packages/electron/svelte.config.js
deleted file mode 100644
index 331f4eb..0000000
--- a/packages/electron/svelte.config.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import adapter from '@sveltejs/adapter-node';
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
-
-/** @type {import('@sveltejs/kit').Config} */
-const config = {
- kit: {
- // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
- // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
- // See https://kit.svelte.dev/docs/adapters for more information about adapters.
- adapter: adapter()
- },
- preprocess: vitePreprocess()
-};
-
-export default config;
diff --git a/packages/electron/tailwind.config.js b/packages/electron/tailwind.config.js
deleted file mode 100644
index f81fe61..0000000
--- a/packages/electron/tailwind.config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-export default {
- content: ['./src/**/*.{html,js,svelte,ts}'],
- theme: {
- extend: {},
- },
- plugins: [],
-}
\ No newline at end of file
diff --git a/packages/electron/tsconfig.json b/packages/electron/tsconfig.json
deleted file mode 100644
index fbfe65c..0000000
--- a/packages/electron/tsconfig.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "extends": ["./.svelte-kit/tsconfig.json", "../../tsconfig.base.json"],
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@core/*": ["../../packages/core/*"],
- "$lib/*": ["./src/lib/*"]
- },
- "allowJs": true,
- "checkJs": false,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "resolveJsonModule": true,
- "skipLibCheck": true,
- "sourceMap": true,
- "strict": true,
- "moduleResolution": "bundler",
- "types": ["bun"]
- }
- // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
- // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
- //
- // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
- // from the referenced tsconfig.json - TypeScript does not merge them in
-}
diff --git a/packages/electron/vite.config.js b/packages/electron/vite.config.js
deleted file mode 100644
index 2f46d10..0000000
--- a/packages/electron/vite.config.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { sveltekit } from '@sveltejs/kit/vite';
-import { defineConfig } from 'vitest/config';
-import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill';
-import rollupNodePolyFill from 'rollup-plugin-node-polyfills';
-import wasm from 'vite-plugin-wasm';
-import path from 'node:path';
-
-export default defineConfig({
- plugins: [sveltekit(), wasm()],
- resolve: {
- alias: {
- '@core': path.resolve(__dirname, '../../packages/core'),
- }
- },
- test: {
- include: ['src/**/*.{test,spec}.{js,ts}']
- },
- optimizeDeps: {
- esbuildOptions: {
- define: {
- global: 'globalThis'
- },
- plugins: [
- NodeGlobalsPolyfillPlugin({
- buffer: true
- })
- ]
- }
- },
- build: {
- rollupOptions: {
- plugins: [rollupNodePolyFill()]
- }
- },
- server: {
- fs: {
- allow: ['./package.json']
- }
- }
-});
diff --git a/packages/web/package.json b/packages/web/package.json
index 28240cf..5b613dd 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -8,7 +8,8 @@
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch",
- "test": "vitest"
+ "test": "vitest",
+ "go": "PORT=2611 bun ./build"
},
"devDependencies": {
"@iconify/svelte": "^4.0.2",
diff --git a/packages/web/src/app.html b/packages/web/src/app.html
index 876c155..2b59310 100644
--- a/packages/web/src/app.html
+++ b/packages/web/src/app.html
@@ -5,6 +5,7 @@
+
AquaVox
%sveltekit.head%
diff --git a/packages/web/src/routes/api/database/search/+server.ts b/packages/web/src/routes/api/database/search/+server.ts
deleted file mode 100644
index 52fa9c7..0000000
--- a/packages/web/src/routes/api/database/search/+server.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { songNameCache } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData';
-import { error, json } from '@sveltejs/kit';
-import type { RequestHandler } from './$types';
-
-export const GET: RequestHandler = async ({ url }) => {
- const keyword = url.searchParams.get('keyword');
-
- await loadData();
-
- if (keyword === null) {
- return error(400, {
- 'message': 'Miss parameter: keyword'
- });
- }
-
- const resultList: MusicMetadata[] = [];
-
- for (const songName of songNameCache.keys()) {
- if (songName.toLocaleLowerCase().includes(keyword.toLocaleLowerCase())) {
- resultList.push(songNameCache.get(songName)!);
- }
- }
-
- return json({
- 'result': resultList
- });
-};
\ No newline at end of file
diff --git a/packages/web/src/routes/api/database/song/[id]/+server.ts b/packages/web/src/routes/api/database/song/[id]/+server.ts
deleted file mode 100644
index 3c8a69d..0000000
--- a/packages/web/src/routes/api/database/song/[id]/+server.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { safePath } from '@core/server/safePath';
-import { getCurrentFormattedDateTime } from '@core/utils/songUpdateTime';
-import { json, error } from '@sveltejs/kit';
-import fs from 'fs';
-import type { RequestHandler } from './$types';
-import type { MusicMetadata } from '@core/server/database/musicInfo';
-
-export const GET: RequestHandler = async ({ params }) => {
- const filePath = safePath(`${params.id}.json`, { base: './data/song' });
- if (!filePath) {
- return error(404, {
- message: "No correspoding song."
- });
- }
- let data;
- try { data = fs.readFileSync(filePath); } catch (e) {
- return error(404, {
- message: "No corresponding song."
- });
- }
- return json(JSON.parse(data.toString()));
-}
-
-export const POST: RequestHandler = async ({ request, params }) => {
- const timeStamp = new Date().getTime();
- try {
- if (!fs.existsSync("./data/pending/")) {
- fs.mkdirSync("./data/pending", { mode: 0o755 });
- }
- const filePath = `./data/pending/${params.id}-${timeStamp}.json`;
- const data: MusicMetadata = await request.json();
- data.updateTime = getCurrentFormattedDateTime();
- fs.writeFileSync(filePath, JSON.stringify(data, null, 4), { mode: 0o644 });
- return json({
- "message": "successfully created"
- }, {
- status: 201
- });
- } catch (e) {
- return error(500, {
- message: "Internal server error."
- });
- }
-}
\ No newline at end of file
diff --git a/packages/web/src/routes/api/database/songs/+server.ts b/packages/web/src/routes/api/database/songs/+server.ts
deleted file mode 100644
index 101b9c7..0000000
--- a/packages/web/src/routes/api/database/songs/+server.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { songData } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData.js';
-import { json } from '@sveltejs/kit';
-import type { RequestHandler } from './$types';
-
-export const GET: RequestHandler = async ({ url }) => {
- const limit = parseInt(url.searchParams.get("limit") ?? "20");
- const offset = parseInt(url.searchParams.get("offset") ?? "0");
- loadData();
- const songIDList = songData.keys().slice(offset, offset + limit);
- const songDataList = [];
- for (const songID of songIDList) {
- songDataList.push(songData.get(songID)!);
- }
- return json(songDataList);
-}
\ No newline at end of file
diff --git a/packages/web/src/routes/database/+layout.svelte b/packages/web/src/routes/database/+layout.svelte
deleted file mode 100644
index d154c1e..0000000
--- a/packages/web/src/routes/database/+layout.svelte
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/packages/web/src/routes/database/+page.server.ts b/packages/web/src/routes/database/+page.server.ts
deleted file mode 100644
index 79f69f6..0000000
--- a/packages/web/src/routes/database/+page.server.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { songData } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData.js';
-import type { PageServerLoad } from './$types';
-
-export const load: PageServerLoad = () => {
- loadData();
- const songIDList = songData.keys().slice(0, 20);
- const songDataList = [];
- for (const songID of songIDList) {
- songDataList.push(songData.get(songID)!);
- }
- return {
- songDataList: songDataList
- };
-};
-
-export const ssr = true;
\ No newline at end of file
diff --git a/packages/web/src/routes/database/+page.svelte b/packages/web/src/routes/database/+page.svelte
deleted file mode 100644
index 3f41ca0..0000000
--- a/packages/web/src/routes/database/+page.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
- AquaVox 音乐数据库
-
-
-
-
-
-
-
-
- {#each songList as song}
-
- {/each}
-
-
diff --git a/packages/web/src/routes/database/edit/[id]/+page.server.ts b/packages/web/src/routes/database/edit/[id]/+page.server.ts
deleted file mode 100644
index ce0f590..0000000
--- a/packages/web/src/routes/database/edit/[id]/+page.server.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import fs from 'fs';
-import type { PageServerLoad } from './$types';
-import { safePath } from '$lib/server/safePath';
-
-export const load: PageServerLoad = ({ params }) => {
- const filePath = safePath(`${params.id}.json`, { base: './data/song' });
- if (!filePath) {
- return {
- songData: null
- };
- }
- try {
- const dataBuffer = fs.readFileSync(filePath);
- const data = JSON.parse(dataBuffer.toString());
- return {
- songData: data
- };
- } catch {
- return {
- songData: null
- }
- }
-}
diff --git a/packages/web/src/routes/database/edit/[id]/+page.svelte b/packages/web/src/routes/database/edit/[id]/+page.svelte
deleted file mode 100644
index 147bbad..0000000
--- a/packages/web/src/routes/database/edit/[id]/+page.svelte
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
- 建议编辑: {data.songData.name} ({songID})
-
-
-
-
-建议编辑: {data.songData.name} ({songID})
-
-
-
-
\ No newline at end of file
diff --git a/packages/web/src/routes/database/page/[id]/+page.server.ts b/packages/web/src/routes/database/page/[id]/+page.server.ts
deleted file mode 100644
index e037184..0000000
--- a/packages/web/src/routes/database/page/[id]/+page.server.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-import { songData } from '$lib/server/cache.js';
-import { loadData } from '$lib/server/database/loadData.js';
-import type { PageServerLoad } from './$types';
-
-export const load: PageServerLoad = ({ params }) => {
- const offset = (parseInt(params.id) - 1) * 20;
- loadData();
- const songIDList = songData.keys().slice(offset, offset + 20);
- const songDataList = [];
- for (const songID of songIDList) {
- songDataList.push(songData.get(songID)!);
- }
- return {
- songDataList: songDataList
- };
-};
-
-export const ssr = true;
\ No newline at end of file
diff --git a/packages/web/src/routes/database/page/[id]/+page.svelte b/packages/web/src/routes/database/page/[id]/+page.svelte
deleted file mode 100644
index fc70194..0000000
--- a/packages/web/src/routes/database/page/[id]/+page.svelte
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
- AquaVox 音乐数据库
-
-
-
-
-
-
-
-
- {#each songList as song}
-
- {/each}
-
-
diff --git a/packages/web/src/routes/database/submit/+page.svelte b/packages/web/src/routes/database/submit/+page.svelte
deleted file mode 100644
index bc7196f..0000000
--- a/packages/web/src/routes/database/submit/+page.svelte
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
- 提交新曲
-
-
-
-
-提交新曲
-
-
-
-
diff --git a/packages/web/static/favicon.png b/packages/web/static/favicon.png
new file mode 100644
index 0000000..9743671
Binary files /dev/null and b/packages/web/static/favicon.png differ
diff --git a/packages/web/vite.config.js b/packages/web/vite.config.js
index 00f9d53..53907da 100644
--- a/packages/web/vite.config.js
+++ b/packages/web/vite.config.js
@@ -15,6 +15,9 @@ export default defineConfig({
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
},
+ preview: {
+ port: 4173,
+ },
optimizeDeps: {
esbuildOptions: {
define: {