mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-23 23:57:22 +08:00
refactor: 更新 eslint 和 prettier 配置 格式化代码
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import axios from 'axios';
|
||||
import { app, dialog, ipcMain, Notification, protocol, shell } from 'electron';
|
||||
import Store from 'electron-store';
|
||||
import { fileTypeFromFile } from 'file-type';
|
||||
import * as fs from 'fs';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as NodeID3 from 'node-id3';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import * as mm from 'music-metadata';
|
||||
import { fileTypeFromFile } from 'file-type';
|
||||
import * as NodeID3 from 'node-id3';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
import { getStore } from './config';
|
||||
|
||||
@@ -42,18 +42,18 @@ export function initializeFileManager() {
|
||||
// 注册本地文件协议
|
||||
protocol.registerFileProtocol('local', (request, callback) => {
|
||||
try {
|
||||
let url = request.url;
|
||||
const url = request.url;
|
||||
// local://C:/Users/xxx.mp3
|
||||
let filePath = decodeURIComponent(url.replace('local:///', ''));
|
||||
|
||||
|
||||
// 兼容 local:///C:/Users/xxx.mp3 这种情况
|
||||
if (/^\/[a-zA-Z]:\//.test(filePath)) {
|
||||
filePath = filePath.slice(1);
|
||||
}
|
||||
|
||||
|
||||
// 还原为系统路径格式
|
||||
filePath = path.normalize(filePath);
|
||||
|
||||
|
||||
// 检查文件是否存在
|
||||
if (!fs.existsSync(filePath)) {
|
||||
console.error('File not found:', filePath);
|
||||
@@ -128,13 +128,13 @@ export function initializeFileManager() {
|
||||
ipcMain.handle('get-downloads-path', () => {
|
||||
return app.getPath('downloads');
|
||||
});
|
||||
|
||||
|
||||
// 获取存储的配置值
|
||||
ipcMain.handle('get-store-value', (_, key) => {
|
||||
const store = new Store();
|
||||
return store.get(key);
|
||||
});
|
||||
|
||||
|
||||
// 设置存储的配置值
|
||||
ipcMain.on('set-store-value', (_, key, value) => {
|
||||
const store = new Store();
|
||||
@@ -189,7 +189,8 @@ export function initializeFileManager() {
|
||||
const validEntriesPromises = await Promise.all(
|
||||
entriesArray.map(async ([path, info]) => {
|
||||
try {
|
||||
const exists = await fs.promises.access(path)
|
||||
const exists = await fs.promises
|
||||
.access(path)
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
return exists ? info : null;
|
||||
@@ -202,7 +203,7 @@ export function initializeFileManager() {
|
||||
|
||||
// 过滤有效的歌曲并排序
|
||||
const validSongs = validEntriesPromises
|
||||
.filter(song => song !== null)
|
||||
.filter((song) => song !== null)
|
||||
.sort((a, b) => (b.downloadTime || 0) - (a.downloadTime || 0));
|
||||
|
||||
// 更新存储,移除不存在的文件记录
|
||||
@@ -376,9 +377,9 @@ async function downloadMusic(
|
||||
const downloadPath =
|
||||
(configStore.get('set.downloadPath') as string) || app.getPath('downloads');
|
||||
const apiPort = configStore.get('set.musicApiPort') || 30488;
|
||||
|
||||
|
||||
// 获取文件名格式设置
|
||||
const nameFormat =
|
||||
const nameFormat =
|
||||
(configStore.get('set.downloadNameFormat') as string) || '{songName} - {artistName}';
|
||||
|
||||
// 根据格式创建文件名
|
||||
@@ -388,7 +389,7 @@ async function downloadMusic(
|
||||
const artistName = songInfo.ar?.map((a: any) => a.name).join('/') || '未知艺术家';
|
||||
const songName = songInfo.name || filename;
|
||||
const albumName = songInfo.al?.name || '未知专辑';
|
||||
|
||||
|
||||
// 应用自定义格式
|
||||
formattedFilename = nameFormat
|
||||
.replace(/\{songName\}/g, songName)
|
||||
@@ -401,12 +402,12 @@ async function downloadMusic(
|
||||
|
||||
// 创建临时文件路径 (在系统临时目录中创建)
|
||||
const tempDir = path.join(os.tmpdir(), 'AlgerMusicPlayerTemp');
|
||||
|
||||
|
||||
// 确保临时目录存在
|
||||
if (!fs.existsSync(tempDir)) {
|
||||
fs.mkdirSync(tempDir, { recursive: true });
|
||||
}
|
||||
|
||||
|
||||
tempFilePath = path.join(tempDir, `${Date.now()}_${sanitizedFilename}.tmp`);
|
||||
|
||||
// 先获取文件大小
|
||||
@@ -460,7 +461,7 @@ async function downloadMusic(
|
||||
|
||||
// 检测文件类型
|
||||
let fileExtension = '';
|
||||
|
||||
|
||||
try {
|
||||
// 首先尝试使用file-type库检测
|
||||
const fileType = await fileTypeFromFile(tempFilePath);
|
||||
@@ -475,26 +476,28 @@ async function downloadMusic(
|
||||
const formatInfo = metadata.format;
|
||||
const container = formatInfo.container || '';
|
||||
const codec = formatInfo.codec || '';
|
||||
|
||||
|
||||
// 音频格式映射表
|
||||
const formatMap = {
|
||||
'mp3': ['MPEG', 'MP3', 'mp3'],
|
||||
'aac': ['AAC'],
|
||||
'flac': ['FLAC'],
|
||||
'ogg': ['Ogg', 'Vorbis'],
|
||||
'wav': ['WAV', 'PCM'],
|
||||
'm4a': ['M4A', 'MP4']
|
||||
mp3: ['MPEG', 'MP3', 'mp3'],
|
||||
aac: ['AAC'],
|
||||
flac: ['FLAC'],
|
||||
ogg: ['Ogg', 'Vorbis'],
|
||||
wav: ['WAV', 'PCM'],
|
||||
m4a: ['M4A', 'MP4']
|
||||
};
|
||||
|
||||
|
||||
// 查找匹配的格式
|
||||
const format = Object.entries(formatMap).find(([_, keywords]) =>
|
||||
keywords.some(keyword => container.includes(keyword) || codec.includes(keyword))
|
||||
const format = Object.entries(formatMap).find(([_, keywords]) =>
|
||||
keywords.some((keyword) => container.includes(keyword) || codec.includes(keyword))
|
||||
);
|
||||
|
||||
|
||||
// 设置文件扩展名,如果没找到则默认为mp3
|
||||
fileExtension = format ? `.${format[0]}` : '.mp3';
|
||||
|
||||
console.log(`music-metadata检测结果: 容器:${container}, 编码:${codec}, 扩展名: ${fileExtension}`);
|
||||
|
||||
console.log(
|
||||
`music-metadata检测结果: 容器:${container}, 编码:${codec}, 扩展名: ${fileExtension}`
|
||||
);
|
||||
} else {
|
||||
// 两种方法都失败,使用传入的type或默认mp3
|
||||
fileExtension = type ? `.${type}` : '.mp3';
|
||||
@@ -593,7 +596,7 @@ async function downloadMusic(
|
||||
try {
|
||||
// 在写入ID3标签前,先移除可能存在的旧标签
|
||||
NodeID3.removeTags(finalFilePath);
|
||||
|
||||
|
||||
const tags = {
|
||||
title: filename,
|
||||
artist: artistNames,
|
||||
@@ -676,7 +679,7 @@ async function downloadMusic(
|
||||
const notificationId = `download-${finalFilePath}`;
|
||||
if (!sentNotifications.has(notificationId)) {
|
||||
sentNotifications.set(notificationId, true);
|
||||
|
||||
|
||||
// 发送桌面通知
|
||||
try {
|
||||
const artistNames =
|
||||
@@ -687,13 +690,13 @@ async function downloadMusic(
|
||||
body: `${songInfo?.name || filename} - ${artistNames}`,
|
||||
silent: false
|
||||
});
|
||||
|
||||
|
||||
notification.on('click', () => {
|
||||
shell.showItemInFolder(finalFilePath);
|
||||
});
|
||||
|
||||
|
||||
notification.show();
|
||||
|
||||
|
||||
// 60秒后清理通知记录,释放内存
|
||||
setTimeout(() => {
|
||||
sentNotifications.delete(notificationId);
|
||||
@@ -722,7 +725,7 @@ async function downloadMusic(
|
||||
if (writer) {
|
||||
writer.end();
|
||||
}
|
||||
|
||||
|
||||
// 清理临时文件
|
||||
if (tempFilePath && fs.existsSync(tempFilePath)) {
|
||||
try {
|
||||
@@ -731,7 +734,7 @@ async function downloadMusic(
|
||||
console.error('Failed to delete temporary file:', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 清理未完成的最终文件
|
||||
if (finalFilePath && fs.existsSync(finalFilePath)) {
|
||||
try {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import cors from 'cors';
|
||||
import { ipcMain } from 'electron';
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import os from 'os';
|
||||
import { getStore } from './config';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { getStore } from './config';
|
||||
|
||||
// 定义远程控制相关接口
|
||||
export interface RemoteControlConfig {
|
||||
@@ -72,9 +73,9 @@ export function initializeRemoteControl(mainWindow: Electron.BrowserWindow) {
|
||||
if (server) {
|
||||
stopServer();
|
||||
}
|
||||
|
||||
|
||||
store.set('remoteControl', newConfig);
|
||||
|
||||
|
||||
if (newConfig.enabled) {
|
||||
startServer(newConfig);
|
||||
}
|
||||
@@ -105,16 +106,16 @@ function startServer(config: RemoteControlConfig) {
|
||||
}
|
||||
|
||||
app = express();
|
||||
|
||||
|
||||
// 跨域配置
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
|
||||
// IP 过滤中间件
|
||||
app.use((req, res, next) => {
|
||||
const clientIp = req.ip || req.socket.remoteAddress || '';
|
||||
const cleanIp = clientIp.replace(/^::ffff:/, ''); // 移除IPv6前缀
|
||||
console.log('config',config)
|
||||
console.log('config', config);
|
||||
if (config.allowedIps.length === 0 || config.allowedIps.includes(cleanIp)) {
|
||||
next();
|
||||
} else {
|
||||
@@ -216,7 +217,7 @@ function setupRoutes(app: express.Application) {
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
const htmlPath = path.join(process.cwd(), 'resources', 'html', 'remote-control.html');
|
||||
const finalPath = isDev ? htmlPath : path.join(resourcesPath, 'html', 'remote-control.html');
|
||||
|
||||
|
||||
if (fs.existsSync(finalPath)) {
|
||||
res.sendFile(finalPath);
|
||||
} else {
|
||||
@@ -228,4 +229,4 @@ function setupRoutes(app: express.Application) {
|
||||
res.status(500).send('加载远程控制界面失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ export function updateTrayMenu(mainWindow: BrowserWindow) {
|
||||
|
||||
// 初始化状态栏Tray
|
||||
function initializeStatusBarTray(mainWindow: BrowserWindow) {
|
||||
const store = getStore()
|
||||
const store = getStore();
|
||||
if (process.platform !== 'darwin' || !store.get('set.showTopAction')) return;
|
||||
|
||||
const iconSize = getProperIconSize();
|
||||
|
||||
+141
-132
@@ -31,8 +31,6 @@ export interface WindowState {
|
||||
isMaximized: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 窗口大小管理器
|
||||
* 负责保存、恢复和维护窗口大小状态
|
||||
@@ -42,12 +40,12 @@ class WindowSizeManager {
|
||||
private mainWindow: BrowserWindow | null = null;
|
||||
private savedState: WindowState | null = null;
|
||||
private isInitialized: boolean = false;
|
||||
|
||||
|
||||
constructor() {
|
||||
this.store = store;
|
||||
// 初始化时不做与screen相关的操作,等app ready后再初始化
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化窗口大小管理器
|
||||
* 必须在app ready后调用
|
||||
@@ -57,17 +55,17 @@ class WindowSizeManager {
|
||||
console.warn('WindowSizeManager.initialize() 必须在 app ready 之后调用!');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (this.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.initMinimumWindowSize();
|
||||
this.setupIPCHandlers();
|
||||
this.isInitialized = true;
|
||||
console.log('窗口大小管理器初始化完成');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置主窗口引用
|
||||
*/
|
||||
@@ -75,19 +73,19 @@ class WindowSizeManager {
|
||||
if (!this.isInitialized) {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
|
||||
this.mainWindow = win;
|
||||
|
||||
|
||||
// 读取保存的状态
|
||||
this.savedState = this.getWindowState();
|
||||
|
||||
|
||||
// 监听重要事件
|
||||
this.setupEventListeners(win);
|
||||
|
||||
|
||||
// 立即保存初始状态
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化最小窗口尺寸
|
||||
*/
|
||||
@@ -96,14 +94,17 @@ class WindowSizeManager {
|
||||
console.warn('不能在 app ready 之前访问 screen 模块');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const { width: workAreaWidth, height: workAreaHeight } = screen.getPrimaryDisplay().workArea;
|
||||
|
||||
|
||||
// 根据工作区大小设置合理的最小尺寸
|
||||
MIN_WIDTH = Math.min(Math.round(DEFAULT_MAIN_WIDTH * 0.5), Math.round(workAreaWidth * 0.3));
|
||||
MIN_HEIGHT = Math.min(Math.round(DEFAULT_MAIN_HEIGHT * 0.5), Math.round(workAreaHeight * 0.3));
|
||||
|
||||
MIN_HEIGHT = Math.min(
|
||||
Math.round(DEFAULT_MAIN_HEIGHT * 0.5),
|
||||
Math.round(workAreaHeight * 0.3)
|
||||
);
|
||||
|
||||
console.log(`设置最小窗口尺寸: ${MIN_WIDTH}x${MIN_HEIGHT}`);
|
||||
} catch (error) {
|
||||
console.error('初始化最小窗口尺寸失败:', error);
|
||||
@@ -112,7 +113,7 @@ class WindowSizeManager {
|
||||
MIN_HEIGHT = Math.round(DEFAULT_MAIN_HEIGHT * 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置事件监听器
|
||||
*/
|
||||
@@ -123,46 +124,46 @@ class WindowSizeManager {
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 监听窗口移动事件
|
||||
win.on('move', () => {
|
||||
if (!win.isDestroyed() && !win.isMinimized()) {
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 监听窗口最大化事件
|
||||
win.on('maximize', () => {
|
||||
if (!win.isDestroyed()) {
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 监听窗口从最大化恢复事件
|
||||
win.on('unmaximize', () => {
|
||||
if (!win.isDestroyed()) {
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 监听窗口关闭事件,确保保存最终状态
|
||||
win.on('close', () => {
|
||||
if (!win.isDestroyed()) {
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 在页面加载完成后确保窗口大小正确
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
this.enforceCorrectSize(win);
|
||||
});
|
||||
|
||||
|
||||
// 在窗口准备好显示时确保尺寸正确
|
||||
win.on('ready-to-show', () => {
|
||||
this.enforceCorrectSize(win);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 强制应用正确的窗口大小
|
||||
*/
|
||||
@@ -170,30 +171,36 @@ class WindowSizeManager {
|
||||
if (!this.savedState || win.isMaximized() || win.isMinimized() || win.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const [currentWidth, currentHeight] = win.getSize();
|
||||
|
||||
if (Math.abs(currentWidth - this.savedState.width) > 2 ||
|
||||
Math.abs(currentHeight - this.savedState.height) > 2) {
|
||||
console.log(`强制调整窗口大小: 当前=${currentWidth}x${currentHeight}, 目标=${this.savedState.width}x${this.savedState.height}`);
|
||||
|
||||
|
||||
if (
|
||||
Math.abs(currentWidth - this.savedState.width) > 2 ||
|
||||
Math.abs(currentHeight - this.savedState.height) > 2
|
||||
) {
|
||||
console.log(
|
||||
`强制调整窗口大小: 当前=${currentWidth}x${currentHeight}, 目标=${this.savedState.width}x${this.savedState.height}`
|
||||
);
|
||||
|
||||
// 临时禁用minimum size限制
|
||||
const [minWidth, minHeight] = win.getMinimumSize();
|
||||
win.setMinimumSize(1, 1);
|
||||
|
||||
|
||||
// 强制设置正确大小
|
||||
win.setSize(this.savedState.width, this.savedState.height, false);
|
||||
|
||||
|
||||
// 恢复原始minimum size
|
||||
win.setMinimumSize(minWidth, minHeight);
|
||||
|
||||
|
||||
// 验证尺寸设置是否成功
|
||||
const [newWidth, newHeight] = win.getSize();
|
||||
console.log(`调整后窗口大小: ${newWidth}x${newHeight}`);
|
||||
|
||||
|
||||
// 如果调整后的大小仍然与目标不一致,尝试再次调整
|
||||
if (Math.abs(newWidth - this.savedState.width) > 1 ||
|
||||
Math.abs(newHeight - this.savedState.height) > 1) {
|
||||
if (
|
||||
Math.abs(newWidth - this.savedState.width) > 1 ||
|
||||
Math.abs(newHeight - this.savedState.height) > 1
|
||||
) {
|
||||
console.log(`窗口大小调整后仍不一致,将再次尝试调整`);
|
||||
setTimeout(() => {
|
||||
if (!win.isDestroyed() && !win.isMaximized() && !win.isMinimized()) {
|
||||
@@ -201,12 +208,12 @@ class WindowSizeManager {
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
|
||||
// // 开始尺寸强制执行
|
||||
// this.startSizeEnforcement(win);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 开启尺寸强制执行定时器
|
||||
*/
|
||||
@@ -216,15 +223,15 @@ class WindowSizeManager {
|
||||
// clearInterval(this.enforceTimer);
|
||||
// this.enforceTimer = null;
|
||||
// }
|
||||
|
||||
|
||||
// this.enforceCount = 0;
|
||||
|
||||
|
||||
// // 创建新的定时器,每50ms检查一次窗口大小
|
||||
// this.enforceTimer = setInterval(() => {
|
||||
// if (this.enforceCount >= this.MAX_ENFORCE_COUNT ||
|
||||
// !this.savedState ||
|
||||
// win.isDestroyed() ||
|
||||
// win.isMaximized() ||
|
||||
// if (this.enforceCount >= this.MAX_ENFORCE_COUNT ||
|
||||
// !this.savedState ||
|
||||
// win.isDestroyed() ||
|
||||
// win.isMaximized() ||
|
||||
// win.isMinimized()) {
|
||||
// // 达到最大检查次数或不需要检查,清除定时器
|
||||
// if (this.enforceTimer) {
|
||||
@@ -233,35 +240,35 @@ class WindowSizeManager {
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
|
||||
|
||||
// const [currentWidth, currentHeight] = win.getSize();
|
||||
|
||||
// if (Math.abs(currentWidth - this.savedState.width) > 2 ||
|
||||
|
||||
// if (Math.abs(currentWidth - this.savedState.width) > 2 ||
|
||||
// Math.abs(currentHeight - this.savedState.height) > 2) {
|
||||
// console.log(`[定时检查] 强制调整窗口大小: 当前=${currentWidth}x${currentHeight}, 目标=${this.savedState.width}x${this.savedState.height}`);
|
||||
|
||||
|
||||
// // 临时禁用minimum size限制
|
||||
// const [minWidth, minHeight] = win.getMinimumSize();
|
||||
// win.setMinimumSize(1, 1);
|
||||
|
||||
|
||||
// // 强制设置正确大小
|
||||
// win.setSize(this.savedState.width, this.savedState.height, false);
|
||||
|
||||
|
||||
// // 恢复原始minimum size
|
||||
// win.setMinimumSize(minWidth, minHeight);
|
||||
|
||||
|
||||
// // 验证尺寸设置是否成功
|
||||
// const [newWidth, newHeight] = win.getSize();
|
||||
// if (Math.abs(newWidth - this.savedState.width) <= 1 &&
|
||||
// if (Math.abs(newWidth - this.savedState.width) <= 1 &&
|
||||
// Math.abs(newHeight - this.savedState.height) <= 1) {
|
||||
// console.log(`窗口大小已成功调整为目标尺寸: ${newWidth}x${newHeight}`);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// this.enforceCount++;
|
||||
// }, 50);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* 获取窗口创建选项
|
||||
*/
|
||||
@@ -270,10 +277,10 @@ class WindowSizeManager {
|
||||
if (!this.isInitialized && app.isReady()) {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
|
||||
// 读取保存的状态
|
||||
const savedState = this.getWindowState();
|
||||
|
||||
|
||||
// 准备选项
|
||||
const options: Electron.BrowserWindowConstructorOptions = {
|
||||
width: savedState?.width || DEFAULT_MAIN_WIDTH,
|
||||
@@ -287,7 +294,7 @@ class WindowSizeManager {
|
||||
contextIsolation: true
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 如果有保存的位置,且位置有效,则使用该位置
|
||||
if (savedState?.x !== undefined && savedState?.y !== undefined && app.isReady()) {
|
||||
if (this.isPositionVisible(savedState.x, savedState.y)) {
|
||||
@@ -295,49 +302,57 @@ class WindowSizeManager {
|
||||
options.y = savedState.y;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`窗口创建选项: 大小=${options.width}x${options.height}, 位置=(${options.x}, ${options.y})`);
|
||||
|
||||
|
||||
console.log(
|
||||
`窗口创建选项: 大小=${options.width}x${options.height}, 位置=(${options.x}, ${options.y})`
|
||||
);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 应用窗口初始状态
|
||||
* 在窗口创建后调用
|
||||
*/
|
||||
applyInitialState(win: BrowserWindow): void {
|
||||
const savedState = this.getWindowState();
|
||||
|
||||
|
||||
if (!savedState) {
|
||||
win.center();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 如果需要最大化,直接最大化
|
||||
if (savedState.isMaximized) {
|
||||
console.log('应用已保存的最大化状态');
|
||||
win.maximize();
|
||||
}
|
||||
}
|
||||
// 如果位置无效,则居中显示
|
||||
else if (!app.isReady() || savedState.x === undefined || savedState.y === undefined ||
|
||||
!this.isPositionVisible(savedState.x, savedState.y)) {
|
||||
else if (
|
||||
!app.isReady() ||
|
||||
savedState.x === undefined ||
|
||||
savedState.y === undefined ||
|
||||
!this.isPositionVisible(savedState.x, savedState.y)
|
||||
) {
|
||||
console.log('保存的位置无效,窗口居中显示');
|
||||
win.center();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存窗口状态
|
||||
*/
|
||||
saveWindowState(win: BrowserWindow): WindowState {
|
||||
// 如果窗口已销毁,则返回之前的状态或默认状态
|
||||
console.log('win.isDestroyed()',win.isDestroyed())
|
||||
console.log('win.isDestroyed()', win.isDestroyed());
|
||||
if (win.isDestroyed()) {
|
||||
return this.savedState || {
|
||||
width: DEFAULT_MAIN_WIDTH,
|
||||
height: DEFAULT_MAIN_HEIGHT,
|
||||
isMaximized: false
|
||||
};
|
||||
return (
|
||||
this.savedState || {
|
||||
width: DEFAULT_MAIN_WIDTH,
|
||||
height: DEFAULT_MAIN_HEIGHT,
|
||||
isMaximized: false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// 检查是否是mini模式窗口(根据窗口大小判断)
|
||||
@@ -352,9 +367,10 @@ class WindowSizeManager {
|
||||
// 由于 Electron 的限制,最大化状态下 getBounds() 可能不准确
|
||||
// 所以我们尽量保留之前保存的非最大化时的大小
|
||||
const currentBounds = win.getBounds();
|
||||
const previousSize = this.savedState && !this.savedState.isMaximized
|
||||
? { width: this.savedState.width, height: this.savedState.height }
|
||||
: { width: currentBounds.width, height: currentBounds.height };
|
||||
const previousSize =
|
||||
this.savedState && !this.savedState.isMaximized
|
||||
? { width: this.savedState.width, height: this.savedState.height }
|
||||
: { width: currentBounds.width, height: currentBounds.height };
|
||||
|
||||
state = {
|
||||
width: previousSize.width,
|
||||
@@ -363,19 +379,18 @@ class WindowSizeManager {
|
||||
y: currentBounds.y,
|
||||
isMaximized: true
|
||||
};
|
||||
console.log('state IsMaximized',state)
|
||||
|
||||
}
|
||||
else if (win.isMinimized()) {
|
||||
console.log('state IsMaximized', state);
|
||||
} else if (win.isMinimized()) {
|
||||
// 最小化状态下不保存窗口大小,因为可能不准确
|
||||
console.log('state IsMinimized',this.savedState)
|
||||
return this.savedState || {
|
||||
width: DEFAULT_MAIN_WIDTH,
|
||||
height: DEFAULT_MAIN_HEIGHT,
|
||||
isMaximized: false
|
||||
};
|
||||
}
|
||||
else {
|
||||
console.log('state IsMinimized', this.savedState);
|
||||
return (
|
||||
this.savedState || {
|
||||
width: DEFAULT_MAIN_WIDTH,
|
||||
height: DEFAULT_MAIN_HEIGHT,
|
||||
isMaximized: false
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 正常状态下保存当前大小和位置
|
||||
const [width, height] = win.getSize();
|
||||
const [x, y] = win.getPosition();
|
||||
@@ -387,7 +402,7 @@ class WindowSizeManager {
|
||||
y,
|
||||
isMaximized: false
|
||||
};
|
||||
console.log('state IsNormal',state)
|
||||
console.log('state IsNormal', state);
|
||||
}
|
||||
|
||||
// 如果是mini模式,不保存到持久化存储,只返回状态用于内存中的恢复
|
||||
@@ -402,11 +417,11 @@ class WindowSizeManager {
|
||||
|
||||
// 更新内部状态
|
||||
this.savedState = state;
|
||||
console.log('state',state)
|
||||
console.log('state', state);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取保存的窗口状态
|
||||
*/
|
||||
@@ -432,8 +447,6 @@ class WindowSizeManager {
|
||||
return validatedState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 检查位置是否在可见屏幕范围内
|
||||
*/
|
||||
@@ -441,18 +454,13 @@ class WindowSizeManager {
|
||||
if (!app.isReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const displays = screen.getAllDisplays();
|
||||
|
||||
|
||||
for (const display of displays) {
|
||||
const { x: screenX, y: screenY, width, height } = display.workArea;
|
||||
if (
|
||||
x >= screenX &&
|
||||
x < screenX + width &&
|
||||
y >= screenY &&
|
||||
y < screenY + height
|
||||
) {
|
||||
if (x >= screenX && x < screenX + width && y >= screenY && y < screenY + height) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -460,10 +468,10 @@ class WindowSizeManager {
|
||||
console.error('检查位置可见性失败:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算适合当前缩放比的缩放因子
|
||||
*/
|
||||
@@ -472,14 +480,14 @@ class WindowSizeManager {
|
||||
if (!app.isReady()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// 获取系统的缩放因子
|
||||
const { scaleFactor } = screen.getPrimaryDisplay();
|
||||
|
||||
|
||||
// 缩放因子默认为1
|
||||
let zoomFactor = 1;
|
||||
|
||||
|
||||
// 只在高DPI情况下调整
|
||||
if (scaleFactor > 1) {
|
||||
// 自定义逻辑来根据不同的缩放比例进行调整
|
||||
@@ -500,38 +508,40 @@ class WindowSizeManager {
|
||||
zoomFactor = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 获取用户的自定义缩放设置(如果有)
|
||||
const userZoomFactor = this.store.get('set.contentZoomFactor') as number | undefined;
|
||||
if (userZoomFactor) {
|
||||
zoomFactor = userZoomFactor;
|
||||
}
|
||||
|
||||
|
||||
return zoomFactor;
|
||||
} catch (error) {
|
||||
console.error('计算内容缩放因子失败:', error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 应用页面内容缩放
|
||||
*/
|
||||
applyContentZoom(win: BrowserWindow): void {
|
||||
const zoomFactor = this.calculateContentZoomFactor();
|
||||
win.webContents.setZoomFactor(zoomFactor);
|
||||
|
||||
|
||||
if (app.isReady()) {
|
||||
try {
|
||||
console.log(`应用页面缩放因子: ${zoomFactor}, 系统缩放比: ${screen.getPrimaryDisplay().scaleFactor}`);
|
||||
console.log(
|
||||
`应用页面缩放因子: ${zoomFactor}, 系统缩放比: ${screen.getPrimaryDisplay().scaleFactor}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(`应用页面缩放因子: ${zoomFactor}`);
|
||||
console.error('获取系统缩放比失败:', error);
|
||||
}
|
||||
} else {
|
||||
console.log(`应用页面缩放因子: ${zoomFactor}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化IPC消息处理程序
|
||||
*/
|
||||
@@ -541,25 +551,25 @@ class WindowSizeManager {
|
||||
console.log('IPC处理程序已注册,跳过重复注册');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
console.log('注册窗口大小相关的IPC处理程序');
|
||||
|
||||
|
||||
// 标记为已注册
|
||||
ipcHandlersRegistered = true;
|
||||
|
||||
|
||||
// 安全地移除已存在的处理程序(如果有)
|
||||
const removeHandlerSafely = (channel: string) => {
|
||||
try {
|
||||
ipcMain.removeHandler(channel);
|
||||
} catch (error) {
|
||||
// 忽略错误,处理程序可能不存在
|
||||
console.warn(`移除IPC处理程序 ${channel} 时出错:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 为需要使用handle方法的通道先移除已有处理程序
|
||||
removeHandlerSafely('get-content-zoom');
|
||||
removeHandlerSafely('get-system-scale-factor');
|
||||
|
||||
|
||||
// 注册新的处理程序
|
||||
ipcMain.on('set-content-zoom', (event, zoomFactor) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
@@ -568,7 +578,7 @@ class WindowSizeManager {
|
||||
this.store.set('set.contentZoomFactor', zoomFactor);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ipcMain.handle('get-content-zoom', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
@@ -576,12 +586,12 @@ class WindowSizeManager {
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
|
||||
ipcMain.handle('get-system-scale-factor', () => {
|
||||
if (!app.isReady()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
return screen.getPrimaryDisplay().scaleFactor;
|
||||
} catch (error) {
|
||||
@@ -589,7 +599,7 @@ class WindowSizeManager {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ipcMain.on('reset-content-zoom', (event) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
@@ -597,25 +607,25 @@ class WindowSizeManager {
|
||||
this.applyContentZoom(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ipcMain.on('resize-window', (event, width, height) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
console.log(`接收到调整窗口大小请求: ${width}x${height}`);
|
||||
|
||||
|
||||
// 确保尺寸不小于最小值
|
||||
const adjustedWidth = Math.max(width, MIN_WIDTH);
|
||||
const adjustedHeight = Math.max(height, MIN_HEIGHT);
|
||||
|
||||
|
||||
// 设置窗口的大小
|
||||
win.setSize(adjustedWidth, adjustedHeight);
|
||||
console.log(`窗口大小已调整为: ${adjustedWidth}x${adjustedHeight}`);
|
||||
|
||||
|
||||
// 保存窗口状态
|
||||
this.saveWindowState(win);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ipcMain.on('resize-mini-window', (event, showPlaylist) => {
|
||||
const win = BrowserWindow.fromWebContents(event.sender);
|
||||
if (win && !win.isDestroyed()) {
|
||||
@@ -632,7 +642,7 @@ class WindowSizeManager {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 只在app ready后设置显示器变化监听
|
||||
if (app.isReady()) {
|
||||
// 监听显示器变化事件
|
||||
@@ -642,13 +652,13 @@ class WindowSizeManager {
|
||||
if (changedMetrics.includes('scaleFactor')) {
|
||||
this.applyContentZoom(this.mainWindow);
|
||||
}
|
||||
|
||||
|
||||
// 重新初始化最小尺寸
|
||||
this.initMinimumWindowSize();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 监听 store 中的缩放设置变化
|
||||
this.store.onDidChange('set.contentZoomFactor', () => {
|
||||
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
|
||||
@@ -712,4 +722,3 @@ export const initWindowSizeHandlers = (mainWindow: BrowserWindow | null): void =
|
||||
export const calculateMinimumWindowSize = (): { minWidth: number; minHeight: number } => {
|
||||
return { minWidth: MIN_WIDTH, minHeight: MIN_HEIGHT };
|
||||
};
|
||||
|
||||
|
||||
+58
-35
@@ -1,18 +1,28 @@
|
||||
import { is } from '@electron-toolkit/utils';
|
||||
import { app, BrowserWindow, nativeImage, globalShortcut, ipcMain, screen, session, shell } from 'electron';
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
globalShortcut,
|
||||
ipcMain,
|
||||
nativeImage,
|
||||
screen,
|
||||
session,
|
||||
shell
|
||||
} from 'electron';
|
||||
import Store from 'electron-store';
|
||||
import { join } from 'path';
|
||||
|
||||
import {
|
||||
DEFAULT_MAIN_WIDTH,
|
||||
DEFAULT_MAIN_HEIGHT,
|
||||
DEFAULT_MINI_WIDTH,
|
||||
DEFAULT_MINI_HEIGHT,
|
||||
applyContentZoom,
|
||||
saveWindowState,
|
||||
applyInitialState,
|
||||
initWindowSizeHandlers,
|
||||
DEFAULT_MAIN_HEIGHT,
|
||||
DEFAULT_MAIN_WIDTH,
|
||||
DEFAULT_MINI_HEIGHT,
|
||||
DEFAULT_MINI_WIDTH,
|
||||
getWindowOptions,
|
||||
getWindowState,
|
||||
initWindowSizeHandlers,
|
||||
saveWindowState,
|
||||
WindowState
|
||||
} from './window-size';
|
||||
|
||||
@@ -68,34 +78,32 @@ function setThumbarButtons(window: BrowserWindow) {
|
||||
window.setThumbarButtons([
|
||||
{
|
||||
tooltip: 'prev',
|
||||
icon: nativeImage
|
||||
.createFromPath(join(app.getAppPath(), 'resources/icons', 'prev.png')),
|
||||
icon: nativeImage.createFromPath(join(app.getAppPath(), 'resources/icons', 'prev.png')),
|
||||
click() {
|
||||
window.webContents.send('global-shortcut', 'prevPlay');
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
tooltip: isPlaying ? 'pause' : 'play',
|
||||
icon: nativeImage
|
||||
.createFromPath(join(app.getAppPath(), 'resources/icons', isPlaying ? 'pause.png' : 'play.png')),
|
||||
icon: nativeImage.createFromPath(
|
||||
join(app.getAppPath(), 'resources/icons', isPlaying ? 'pause.png' : 'play.png')
|
||||
),
|
||||
click() {
|
||||
window.webContents.send('global-shortcut', 'togglePlay');
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
tooltip: 'next',
|
||||
icon: nativeImage
|
||||
.createFromPath(join(app.getAppPath(), 'resources/icons', 'next.png')),
|
||||
icon: nativeImage.createFromPath(join(app.getAppPath(), 'resources/icons', 'next.png')),
|
||||
click() {
|
||||
window.webContents.send('global-shortcut', 'nextPlay');
|
||||
},
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化窗口管理相关的IPC监听
|
||||
*/
|
||||
@@ -159,7 +167,11 @@ export function initializeWindowManager() {
|
||||
win.setMaximumSize(DEFAULT_MINI_WIDTH, DEFAULT_MINI_HEIGHT);
|
||||
win.setSize(DEFAULT_MINI_WIDTH, DEFAULT_MINI_HEIGHT, false); // 禁用动画
|
||||
// 将迷你窗口放在工作区的右上角,留出一些边距
|
||||
win.setPosition(screenX + screenWidth - DEFAULT_MINI_WIDTH - 20, display.workArea.y + 20, false);
|
||||
win.setPosition(
|
||||
screenX + screenWidth - DEFAULT_MINI_WIDTH - 20,
|
||||
display.workArea.y + 20,
|
||||
false
|
||||
);
|
||||
win.setAlwaysOnTop(true);
|
||||
win.setSkipTaskbar(false);
|
||||
win.setResizable(false);
|
||||
@@ -186,7 +198,10 @@ export function initializeWindowManager() {
|
||||
console.log('从迷你模式恢复,使用保存的状态:', JSON.stringify(preMiniModeState));
|
||||
|
||||
// 设置适当的最小尺寸
|
||||
win.setMinimumSize(Math.max(DEFAULT_MAIN_WIDTH * 0.5, 600), Math.max(DEFAULT_MAIN_HEIGHT * 0.5, 400));
|
||||
win.setMinimumSize(
|
||||
Math.max(DEFAULT_MAIN_WIDTH * 0.5, 600),
|
||||
Math.max(DEFAULT_MAIN_HEIGHT * 0.5, 400)
|
||||
);
|
||||
|
||||
// 恢复窗口状态
|
||||
win.setAlwaysOnTop(false);
|
||||
@@ -223,9 +238,13 @@ export function initializeWindowManager() {
|
||||
if (!win.isDestroyed() && !win.isMaximized() && !win.isMinimized()) {
|
||||
// 再次验证窗口大小
|
||||
const [width, height] = win.getSize();
|
||||
if (Math.abs(width - preMiniModeState.width) > 2 ||
|
||||
Math.abs(height - preMiniModeState.height) > 2) {
|
||||
console.log(`恢复后窗口大小不一致,再次调整: 当前=${width}x${height}, 目标=${preMiniModeState.width}x${preMiniModeState.height}`);
|
||||
if (
|
||||
Math.abs(width - preMiniModeState.width) > 2 ||
|
||||
Math.abs(height - preMiniModeState.height) > 2
|
||||
) {
|
||||
console.log(
|
||||
`恢复后窗口大小不一致,再次调整: 当前=${width}x${height}, 目标=${preMiniModeState.width}x${preMiniModeState.height}`
|
||||
);
|
||||
win.setSize(preMiniModeState.width, preMiniModeState.height, false);
|
||||
}
|
||||
}
|
||||
@@ -234,7 +253,6 @@ export function initializeWindowManager() {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
ipcMain.on('update-play-state', (_, playing: boolean) => {
|
||||
isPlaying = playing;
|
||||
if (mainWindowInstance) {
|
||||
@@ -279,14 +297,16 @@ export function createMainWindow(icon: Electron.NativeImage): BrowserWindow {
|
||||
webSecurity: false
|
||||
};
|
||||
|
||||
console.log(`创建窗口,使用选项: ${JSON.stringify({
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
x: options.x,
|
||||
y: options.y,
|
||||
minWidth: options.minWidth,
|
||||
minHeight: options.minHeight
|
||||
})}`);
|
||||
console.log(
|
||||
`创建窗口,使用选项: ${JSON.stringify({
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
x: options.x,
|
||||
y: options.y,
|
||||
minWidth: options.minWidth,
|
||||
minHeight: options.minHeight
|
||||
})}`
|
||||
);
|
||||
|
||||
// 创建窗口
|
||||
const mainWindow = new BrowserWindow(options);
|
||||
@@ -340,9 +360,13 @@ export function createMainWindow(icon: Electron.NativeImage): BrowserWindow {
|
||||
if (!mainWindow.isDestroyed() && !mainWindow.isMaximized()) {
|
||||
const [currentWidth, currentHeight] = mainWindow.getSize();
|
||||
if (savedState && !savedState.isMaximized) {
|
||||
if (Math.abs(currentWidth - savedState.width) > 2 ||
|
||||
Math.abs(currentHeight - savedState.height) > 2) {
|
||||
console.log(`窗口大小不匹配,再次调整: 当前=${currentWidth}x${currentHeight}, 目标=${savedState.width}x${savedState.height}`);
|
||||
if (
|
||||
Math.abs(currentWidth - savedState.width) > 2 ||
|
||||
Math.abs(currentHeight - savedState.height) > 2
|
||||
) {
|
||||
console.log(
|
||||
`窗口大小不匹配,再次调整: 当前=${currentWidth}x${currentHeight}, 目标=${savedState.width}x${savedState.height}`
|
||||
);
|
||||
mainWindow.setSize(savedState.width, savedState.height, false);
|
||||
}
|
||||
}
|
||||
@@ -371,7 +395,6 @@ export function createMainWindow(icon: Electron.NativeImage): BrowserWindow {
|
||||
|
||||
initWindowSizeHandlers(mainWindow);
|
||||
|
||||
|
||||
// 保存主窗口引用
|
||||
mainWindowInstance = mainWindow;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user