mirror of
https://github.com/Melorise/TamaASR.git
synced 2026-11-07 14:39:32 +00:00
perf: 设置页改为按需创建
AI-assisted-by: Codex AI-model: gpt-5.6-sol AI-reasoning-effort: medium Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 项目范围
|
## 项目范围
|
||||||
|
|
||||||
MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.12`。
|
MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.13`。
|
||||||
|
|
||||||
不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。
|
不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 的格式。
|
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 的格式。
|
||||||
|
|
||||||
|
## [0.1.13] - 2026-08-24
|
||||||
|
|
||||||
|
### 变更
|
||||||
|
|
||||||
|
- 设置页改为按需创建,关闭窗口后立即销毁其 renderer 以降低常驻内存。
|
||||||
|
|
||||||
## [0.1.12] - 2026-08-23
|
## [0.1.12] - 2026-08-23
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 项目范围
|
## 项目范围
|
||||||
|
|
||||||
MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.12`。
|
MeloASR 是仅面向 Linux 的 Fcitx5 桌面语音输入工具。项目名为 `MeloASR`,分发包名为 `meloasr`,当前版本为 `0.1.13`。
|
||||||
|
|
||||||
不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。
|
不得恢复 Windows、PowerShell 或 Tauri 输出路径。发行版差异只能存在于依赖说明和打包配置,不能进入语音输入核心逻辑。
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(meloasr-fcitx5 VERSION 0.1.12 LANGUAGES CXX)
|
project(meloasr-fcitx5 VERSION 0.1.13 LANGUAGES CXX)
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Comment[zh_CN]=将 MeloASR 网页后端连接到当前输入上下文
|
|||||||
Type=SharedLibrary
|
Type=SharedLibrary
|
||||||
Library=@MELOASR_LIBRARY_PATH@
|
Library=@MELOASR_LIBRARY_PATH@
|
||||||
Category=Module
|
Category=Module
|
||||||
Version=0.1.12
|
Version=0.1.13
|
||||||
OnDemand=False
|
OnDemand=False
|
||||||
Configurable=False
|
Configurable=False
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "meloasr",
|
"name": "meloasr",
|
||||||
"version": "0.1.12",
|
"version": "0.1.13",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "meloasr",
|
"name": "meloasr",
|
||||||
"version": "0.1.12",
|
"version": "0.1.13",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^24.0.0",
|
"@types/node": "^24.0.0",
|
||||||
"electron": "42.3.0",
|
"electron": "42.3.0",
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "meloasr",
|
"name": "meloasr",
|
||||||
"productName": "MeloASR",
|
"productName": "MeloASR",
|
||||||
"version": "0.1.12",
|
"version": "0.1.13",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "MeloASR contributors",
|
"author": "MeloASR contributors",
|
||||||
"description": "基于网页语音识别后端和 Fcitx5 的 Linux 实时语音输入工具",
|
"description": "基于网页语音识别后端和 Fcitx5 的 Linux 实时语音输入工具",
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Linux 分发打包
|
# Linux 分发打包
|
||||||
|
|
||||||
MeloASR 0.1.12 的系统包由两部分组成:
|
MeloASR 0.1.13 的系统包由两部分组成:
|
||||||
|
|
||||||
- Electron 应用安装到 `/opt/meloasr`,命令入口为 `/usr/bin/meloasr`;
|
- Electron 应用安装到 `/opt/meloasr`,命令入口为 `/usr/bin/meloasr`;
|
||||||
- Fcitx5 常驻 addon 由目标发行版中的 CMake/Fcitx5 开发包编译,并安装到该环境报告的 addon 目录。
|
- Fcitx5 常驻 addon 由目标发行版中的 CMake/Fcitx5 开发包编译,并安装到该环境报告的 addon 目录。
|
||||||
@@ -40,7 +40,7 @@ npm run build:linux:dir
|
|||||||
packaging/deb/build-deb.sh
|
packaging/deb/build-deb.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
产物位于 `packaging/out/meloasr_0.1.12_<arch>.deb`。依赖名称按 Debian/Ubuntu 系列填写,但尚未在各发行版完成安装验证。
|
产物位于 `packaging/out/meloasr_0.1.13_<arch>.deb`。依赖名称按 Debian/Ubuntu 系列填写,但尚未在各发行版完成安装验证。
|
||||||
|
|
||||||
## rpm
|
## rpm
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pkgname=meloasr
|
pkgname=meloasr
|
||||||
pkgver=0.1.12
|
pkgver=0.1.13
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc='Web-backed voice input for Fcitx5'
|
pkgdesc='Web-backed voice input for Fcitx5'
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Arch Linux 构建
|
# Arch Linux 构建
|
||||||
|
|
||||||
发布时把项目源码归档为 `meloasr-0.1.12.tar.gz`,与 `PKGBUILD` 放在同一目录,随后运行:
|
发布时把项目源码归档为 `meloasr-0.1.13.tar.gz`,与 `PKGBUILD` 放在同一目录,随后运行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
makepkg --syncdeps --cleanbuild
|
makepkg --syncdeps --cleanbuild
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<binary>meloasr</binary>
|
<binary>meloasr</binary>
|
||||||
</provides>
|
</provides>
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="0.1.13" date="2026-08-24"/>
|
||||||
<release version="0.1.12" date="2026-08-23"/>
|
<release version="0.1.12" date="2026-08-23"/>
|
||||||
<release version="0.1.11" date="2026-08-23"/>
|
<release version="0.1.11" date="2026-08-23"/>
|
||||||
<release version="0.1.10" date="2026-08-23"/>
|
<release version="0.1.10" date="2026-08-23"/>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
version="${MELOASR_VERSION:-0.1.12}"
|
version="${MELOASR_VERSION:-0.1.13}"
|
||||||
arch="${MELOASR_DEB_ARCH:-$(dpkg --print-architecture)}"
|
arch="${MELOASR_DEB_ARCH:-$(dpkg --print-architecture)}"
|
||||||
app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}"
|
app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}"
|
||||||
work_dir="${project_dir}/packaging/out/deb-root"
|
work_dir="${project_dir}/packaging/out/deb-root"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
project_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
version="${MELOASR_VERSION:-0.1.12}"
|
version="${MELOASR_VERSION:-0.1.13}"
|
||||||
app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}"
|
app_dir="${1:-${MELOASR_ELECTRON_APP_DIR:-${project_dir}/release/linux-unpacked}}"
|
||||||
stage_dir="${project_dir}/packaging/out/rpm-root"
|
stage_dir="${project_dir}/packaging/out/rpm-root"
|
||||||
top_dir="${project_dir}/packaging/out/rpmbuild"
|
top_dir="${project_dir}/packaging/out/rpmbuild"
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ tar -C %{buildroot} -xzf %{SOURCE0}
|
|||||||
/etc/xdg/autostart/meloasr.desktop
|
/etc/xdg/autostart/meloasr.desktop
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Aug 24 2026 MeloASR contributors - 0.1.13-1
|
||||||
|
- Create the settings renderer only when it is opened and destroy it on close.
|
||||||
|
|
||||||
* Sun Aug 23 2026 MeloASR contributors - 0.1.12-1
|
* Sun Aug 23 2026 MeloASR contributors - 0.1.12-1
|
||||||
- Disable Electron GPU acceleration for background web renderers.
|
- Disable Electron GPU acceleration for background web renderers.
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -39,9 +39,7 @@ async function bootstrap(): Promise<void> {
|
|||||||
const repositoryUrl = process.env.MELOASR_REPOSITORY_URL?.trim() ||
|
const repositoryUrl = process.env.MELOASR_REPOSITORY_URL?.trim() ||
|
||||||
'https://github.com/Melorise/MeloASR';
|
'https://github.com/Melorise/MeloASR';
|
||||||
const settingsWindow = new SettingsWindow(settings, backends, overlay, sessions, repositoryUrl);
|
const settingsWindow = new SettingsWindow(settings, backends, overlay, sessions, repositoryUrl);
|
||||||
const settingsWindowReady = settingsWindow.create();
|
|
||||||
registerIpc({ settings, autoStart, bridge, backends, overlay, sessions, settingsWindow });
|
registerIpc({ settings, autoStart, bridge, backends, overlay, sessions, settingsWindow });
|
||||||
await settingsWindowReady;
|
|
||||||
const tray = new TrayController(
|
const tray = new TrayController(
|
||||||
backends,
|
backends,
|
||||||
settingsWindow,
|
settingsWindow,
|
||||||
@@ -68,7 +66,7 @@ async function bootstrap(): Promise<void> {
|
|||||||
await backends.ensure(settings.get().backendId);
|
await backends.ensure(settings.get().backendId);
|
||||||
tray.refresh();
|
tray.refresh();
|
||||||
|
|
||||||
app.on('second-instance', () => settingsWindow.show());
|
app.on('second-instance', () => void settingsWindow.show());
|
||||||
app.on('before-quit', () => { (app as typeof app & { isQuitting?: boolean }).isQuitting = true; });
|
app.on('before-quit', () => { (app as typeof app & { isQuitting?: boolean }).isQuitting = true; });
|
||||||
app.on('will-quit', () => {
|
app.on('will-quit', () => {
|
||||||
tray.destroy();
|
tray.destroy();
|
||||||
|
|||||||
+25
-12
@@ -9,6 +9,7 @@ import type { SettingsStore } from './settings-store';
|
|||||||
|
|
||||||
export class SettingsWindow {
|
export class SettingsWindow {
|
||||||
window: BrowserWindow | null = null;
|
window: BrowserWindow | null = null;
|
||||||
|
private creating: Promise<BrowserWindow> | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly settings: SettingsStore,
|
private readonly settings: SettingsStore,
|
||||||
@@ -18,8 +19,19 @@ export class SettingsWindow {
|
|||||||
private readonly repositoryUrl: string | null
|
private readonly repositoryUrl: string | null
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(): Promise<void> {
|
private async ensureWindow(): Promise<BrowserWindow> {
|
||||||
this.window = new BrowserWindow({
|
if (this.window && !this.window.isDestroyed()) return this.window;
|
||||||
|
if (this.creating) return this.creating;
|
||||||
|
this.creating = this.createWindow();
|
||||||
|
try {
|
||||||
|
return await this.creating;
|
||||||
|
} finally {
|
||||||
|
this.creating = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createWindow(): Promise<BrowserWindow> {
|
||||||
|
const window = new BrowserWindow({
|
||||||
width: 720,
|
width: 720,
|
||||||
height: 820,
|
height: 820,
|
||||||
minWidth: 640,
|
minWidth: 640,
|
||||||
@@ -35,18 +47,19 @@ export class SettingsWindow {
|
|||||||
sandbox: true
|
sandbox: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.window.on('close', (event) => {
|
this.window = window;
|
||||||
if ((app as typeof app & { isQuitting?: boolean }).isQuitting) return;
|
window.on('closed', () => {
|
||||||
event.preventDefault();
|
this.overlay.endPositioning();
|
||||||
this.window?.hide();
|
if (this.window === window) this.window = null;
|
||||||
});
|
});
|
||||||
this.window.on('hide', () => this.overlay.endPositioning());
|
await window.loadFile(path.join(__dirname, '..', 'renderer', 'settings.html'));
|
||||||
await this.window.loadFile(path.join(__dirname, '..', 'renderer', 'settings.html'));
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
show(): void {
|
async show(): Promise<void> {
|
||||||
this.window?.show();
|
const window = await this.ensureWindow();
|
||||||
this.window?.focus();
|
window.show();
|
||||||
|
window.focus();
|
||||||
this.publish();
|
this.publish();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +73,7 @@ export class SettingsWindow {
|
|||||||
const definition = this.backends.activeDefinition();
|
const definition = this.backends.activeDefinition();
|
||||||
const decision = resolveDebugLoginAction(Boolean(current.loginNoticeShown[definition.id]), confirmed);
|
const decision = resolveDebugLoginAction(Boolean(current.loginNoticeShown[definition.id]), confirmed);
|
||||||
if (decision.action === 'prompt') {
|
if (decision.action === 'prompt') {
|
||||||
this.show();
|
await this.show();
|
||||||
this.window?.webContents.send('settings:login-notice', { backendLabel: definition.label });
|
this.window?.webContents.send('settings:login-notice', { backendLabel: definition.label });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class TrayController {
|
|||||||
create(): void {
|
create(): void {
|
||||||
this.tray = new Tray(trayImage('loading'));
|
this.tray = new Tray(trayImage('loading'));
|
||||||
this.tray.setToolTip('MeloASR · 正在加载');
|
this.tray.setToolTip('MeloASR · 正在加载');
|
||||||
this.tray.on('click', () => this.settingsWindow.show());
|
this.tray.on('click', () => void this.settingsWindow.show());
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ export class TrayController {
|
|||||||
this.tray.setImage(trayImage(state));
|
this.tray.setImage(trayImage(state));
|
||||||
this.tray.setToolTip(`MeloASR · ${status.detail}`);
|
this.tray.setToolTip(`MeloASR · ${status.detail}`);
|
||||||
this.tray.setContextMenu(Menu.buildFromTemplate([
|
this.tray.setContextMenu(Menu.buildFromTemplate([
|
||||||
{ label: '设置', click: () => this.settingsWindow.show() },
|
{ label: '设置', click: () => void this.settingsWindow.show() },
|
||||||
{ label: '打开登录/调试页面', click: () => void this.settingsWindow.openDebug() },
|
{ label: '打开登录/调试页面', click: () => void this.settingsWindow.openDebug() },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ label: '重启', click: this.onRestart },
|
{ label: '重启', click: this.onRestart },
|
||||||
|
|||||||
Reference in New Issue
Block a user