forked from miao-moe/QZMusic_PC
feat: 播放器核心集成;MediaSession集成
This commit is contained in:
@@ -1,27 +1,168 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||||
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
||||
import { ipcMain, BrowserWindow, app, Menu } from "electron";
|
||||
import { createRequire } from "node:module";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
import path$1 from "node:path";
|
||||
import { spawn } from "child_process";
|
||||
import { Socket } from "net";
|
||||
import { EventEmitter } from "events";
|
||||
import path from "path";
|
||||
class MpvController extends EventEmitter {
|
||||
constructor(ipcPath) {
|
||||
super();
|
||||
__publicField(this, "process", null);
|
||||
__publicField(this, "socket", null);
|
||||
__publicField(this, "ipcPath");
|
||||
__publicField(this, "messageBuffer", "");
|
||||
this.ipcPath = ipcPath || this.getIpcPath();
|
||||
}
|
||||
getIpcPath() {
|
||||
if (process.platform === "win32") {
|
||||
return "\\\\.\\pipe\\qzmusic_mpv_socket";
|
||||
}
|
||||
return "/tmp/qzmusic_mpv_socket";
|
||||
}
|
||||
getMpvPath() {
|
||||
const appRoot = process.env.APP_ROOT || process.cwd();
|
||||
if (process.platform === "win32") {
|
||||
return path.join(appRoot, "core", "mpv.exe");
|
||||
}
|
||||
return "mpv";
|
||||
}
|
||||
start() {
|
||||
const mpvPath = this.getMpvPath();
|
||||
console.log("Starting MPV from:", mpvPath);
|
||||
this.process = spawn(mpvPath, [
|
||||
"--idle",
|
||||
"--force-window=no",
|
||||
"--no-media-controls",
|
||||
`--input-ipc-server=${this.ipcPath}`,
|
||||
"--no-terminal"
|
||||
]);
|
||||
this.process.on("error", (err) => {
|
||||
console.error("Failed to start MPV:", err);
|
||||
this.emit("error", err);
|
||||
});
|
||||
this.process.on("exit", (code, signal) => {
|
||||
var _a;
|
||||
console.log(`MPV exited with code ${code} and signal ${signal}`);
|
||||
this.emit("exit", { code, signal });
|
||||
(_a = this.socket) == null ? void 0 : _a.destroy();
|
||||
});
|
||||
this.tryConnect();
|
||||
}
|
||||
tryConnect(retries = 10) {
|
||||
if (retries <= 0) {
|
||||
console.error("Could not connect to MPV socket after multiple attempts.");
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.socket = new Socket();
|
||||
this.socket.on("connect", () => {
|
||||
console.log("Connected to MPV IPC socket");
|
||||
this.emit("ready");
|
||||
this.send(["observe_property", 1, "pause"]);
|
||||
this.send(["observe_property", 2, "time-pos"]);
|
||||
this.send(["observe_property", 3, "duration"]);
|
||||
this.send(["observe_property", 4, "idle-active"]);
|
||||
this.send(["observe_property", 5, "eof-reached"]);
|
||||
});
|
||||
this.socket.on("data", (data) => {
|
||||
this.handleData(data);
|
||||
});
|
||||
this.socket.on("error", (err) => {
|
||||
var _a;
|
||||
(_a = this.socket) == null ? void 0 : _a.destroy();
|
||||
this.tryConnect(retries - 1);
|
||||
});
|
||||
this.socket.connect(this.ipcPath);
|
||||
}, 500);
|
||||
}
|
||||
handleData(data) {
|
||||
const raw = data.toString();
|
||||
this.messageBuffer += raw;
|
||||
const messages = this.messageBuffer.split("\n");
|
||||
this.messageBuffer = messages.pop() || "";
|
||||
for (const msg of messages) {
|
||||
if (!msg.trim()) continue;
|
||||
console.log("[IPC]", msg);
|
||||
try {
|
||||
const json = JSON.parse(msg);
|
||||
this.emit("message", json);
|
||||
if (json.event) {
|
||||
this.emit("event", json);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to parse MPV message:", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
async send(command) {
|
||||
if (!this.socket || this.socket.destroyed) {
|
||||
console.warn("MPV socket not connected");
|
||||
return;
|
||||
}
|
||||
const payload = JSON.stringify({ command });
|
||||
console.log("[MPV TX]", payload);
|
||||
this.socket.write(payload + "\n");
|
||||
}
|
||||
// Convenience methods
|
||||
async load(url) {
|
||||
return this.send(["loadfile", url]);
|
||||
}
|
||||
async play() {
|
||||
return this.send(["set_property", "pause", false]);
|
||||
}
|
||||
async pause() {
|
||||
return this.send(["set_property", "pause", true]);
|
||||
}
|
||||
async togglePause() {
|
||||
return this.send(["cycle", "pause"]);
|
||||
}
|
||||
async stop() {
|
||||
return this.send(["stop"]);
|
||||
}
|
||||
async setVolume(vol) {
|
||||
return this.send(["set_property", "volume", vol]);
|
||||
}
|
||||
async seek(seconds) {
|
||||
return this.send(["seek", seconds, "absolute"]);
|
||||
}
|
||||
destroy() {
|
||||
if (this.process) {
|
||||
console.log("Killing MPV process...");
|
||||
this.process.kill();
|
||||
this.process = null;
|
||||
}
|
||||
if (this.socket) {
|
||||
this.socket.destroy();
|
||||
this.socket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
createRequire(import.meta.url);
|
||||
const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
||||
process.env.APP_ROOT = path.join(__dirname$1, "..");
|
||||
const __dirname$1 = path$1.dirname(fileURLToPath(import.meta.url));
|
||||
process.env.APP_ROOT = path$1.join(__dirname$1, "..");
|
||||
const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"];
|
||||
const MAIN_DIST = path.join(process.env.APP_ROOT, "dist-electron");
|
||||
const RENDERER_DIST = path.join(process.env.APP_ROOT, "dist");
|
||||
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, "public") : RENDERER_DIST;
|
||||
const MAIN_DIST = path$1.join(process.env.APP_ROOT, "dist-electron");
|
||||
const RENDERER_DIST = path$1.join(process.env.APP_ROOT, "dist");
|
||||
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path$1.join(process.env.APP_ROOT, "public") : RENDERER_DIST;
|
||||
let win;
|
||||
let mpv;
|
||||
function createWindow() {
|
||||
win = new BrowserWindow({
|
||||
frame: false,
|
||||
minWidth: 950,
|
||||
minHeight: 700,
|
||||
minHeight: 800,
|
||||
width: 1e3,
|
||||
height: 800,
|
||||
icon: path.join(process.env.VITE_PUBLIC, "electron-vite.svg"),
|
||||
icon: path$1.join(process.env.VITE_PUBLIC, "electron-vite.svg"),
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname$1, "preload.mjs"),
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true
|
||||
preload: path$1.join(__dirname$1, "preload.mjs")
|
||||
// nodeIntegration: false,
|
||||
// contextIsolation: true,
|
||||
}
|
||||
});
|
||||
win.webContents.on("did-finish-load", () => {
|
||||
@@ -30,7 +171,7 @@ function createWindow() {
|
||||
if (VITE_DEV_SERVER_URL) {
|
||||
win.loadURL(VITE_DEV_SERVER_URL);
|
||||
} else {
|
||||
win.loadFile(path.join(RENDERER_DIST, "index.html"));
|
||||
win.loadFile(path$1.join(RENDERER_DIST, "index.html"));
|
||||
}
|
||||
registerZoomShortcuts(win);
|
||||
}
|
||||
@@ -41,12 +182,29 @@ ipcMain.on("window-minimize", (event) => {
|
||||
ipcMain.on("window-maximize", () => (win == null ? void 0 : win.isMaximized()) ? win.unmaximize() : win == null ? void 0 : win.maximize());
|
||||
ipcMain.on("window-close", () => win == null ? void 0 : win.close());
|
||||
ipcMain.handle("window-is-maximized", () => (win == null ? void 0 : win.isMaximized()) || false);
|
||||
ipcMain.handle("mpv-command", async (_, command) => {
|
||||
if (mpv) {
|
||||
mpv.send(command);
|
||||
}
|
||||
});
|
||||
ipcMain.handle("mpv-load", (_, url) => mpv == null ? void 0 : mpv.load(url));
|
||||
ipcMain.handle("mpv-play", () => mpv == null ? void 0 : mpv.play());
|
||||
ipcMain.handle("mpv-pause", () => mpv == null ? void 0 : mpv.pause());
|
||||
ipcMain.handle("mpv-toggle-pause", () => mpv == null ? void 0 : mpv.togglePause());
|
||||
ipcMain.handle("mpv-stop", () => mpv == null ? void 0 : mpv.stop());
|
||||
ipcMain.handle("mpv-set-volume", (e, vol) => mpv == null ? void 0 : mpv.setVolume(vol));
|
||||
ipcMain.handle("mpv-seek", (_, time) => mpv == null ? void 0 : mpv.seek(time));
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
win = null;
|
||||
}
|
||||
});
|
||||
app.on("will-quit", () => {
|
||||
if (mpv) {
|
||||
mpv.destroy();
|
||||
}
|
||||
});
|
||||
function registerZoomShortcuts(win2) {
|
||||
win2.webContents.on("before-input-event", (event, input) => {
|
||||
if (input.control || input.meta) {
|
||||
@@ -75,6 +233,13 @@ app.on("activate", () => {
|
||||
app.whenReady().then(() => {
|
||||
Menu.setApplicationMenu(null);
|
||||
createWindow();
|
||||
mpv = new MpvController();
|
||||
mpv.start();
|
||||
mpv.on("event", (data) => {
|
||||
if (win && !win.isDestroyed()) {
|
||||
win.webContents.send("mpv-event", data);
|
||||
}
|
||||
});
|
||||
});
|
||||
export {
|
||||
MAIN_DIST,
|
||||
|
||||
@@ -5,5 +5,16 @@ electron.contextBridge.exposeInMainWorld("electronAPI", {
|
||||
minimizeWindow: () => electron.ipcRenderer.send("window-minimize"),
|
||||
maximizeWindow: () => electron.ipcRenderer.send("window-maximize"),
|
||||
closeWindow: () => electron.ipcRenderer.send("window-close"),
|
||||
isMaximized: () => electron.ipcRenderer.invoke("window-is-maximized")
|
||||
isMaximized: () => electron.ipcRenderer.invoke("window-is-maximized"),
|
||||
// MPV Control
|
||||
mpv: {
|
||||
load: (url) => electron.ipcRenderer.invoke("mpv-load", url),
|
||||
play: () => electron.ipcRenderer.invoke("mpv-play"),
|
||||
pause: () => electron.ipcRenderer.invoke("mpv-pause"),
|
||||
togglePause: () => electron.ipcRenderer.invoke("mpv-toggle-pause"),
|
||||
stop: () => electron.ipcRenderer.invoke("mpv-stop"),
|
||||
setVolume: (vol) => electron.ipcRenderer.invoke("mpv-set-volume", vol),
|
||||
seek: (time) => electron.ipcRenderer.invoke("mpv-seek", time),
|
||||
onEvent: (callback) => electron.ipcRenderer.on("mpv-event", callback)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import { app, BrowserWindow, Menu, ipcMain } from 'electron'
|
||||
import { createRequire } from 'node:module'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'node:path'
|
||||
import { MpvController } from './mpvController'
|
||||
|
||||
// @ts-ignore
|
||||
const require = createRequire(import.meta.url)
|
||||
@@ -16,6 +17,7 @@ export const RENDERER_DIST = path.join(process.env.APP_ROOT, 'dist')
|
||||
process.env.VITE_PUBLIC = VITE_DEV_SERVER_URL ? path.join(process.env.APP_ROOT, 'public') : RENDERER_DIST
|
||||
|
||||
let win: BrowserWindow | null
|
||||
let mpv: MpvController | null
|
||||
|
||||
// === Electron 窗口逻辑 ===
|
||||
|
||||
@@ -23,14 +25,14 @@ function createWindow() {
|
||||
win = new BrowserWindow({
|
||||
frame: false,
|
||||
minWidth: 950,
|
||||
minHeight: 700,
|
||||
minHeight: 800,
|
||||
width: 1000,
|
||||
height: 800,
|
||||
icon: path.join(process.env.VITE_PUBLIC, 'electron-vite.svg'),
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.mjs'),
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
// nodeIntegration: false,
|
||||
// contextIsolation: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -54,6 +56,23 @@ ipcMain.on('window-maximize', () => win?.isMaximized() ? win.unmaximize() : win?
|
||||
ipcMain.on('window-close', () => win?.close())
|
||||
ipcMain.handle('window-is-maximized', () => win?.isMaximized() || false)
|
||||
|
||||
// --- MPV IPC Handlers ---
|
||||
ipcMain.handle('mpv-command', async (_, command: any[]) => {
|
||||
if (mpv) {
|
||||
mpv.send(command)
|
||||
}
|
||||
})
|
||||
|
||||
// Quick Helpers
|
||||
ipcMain.handle('mpv-load', (_, url) => mpv?.load(url))
|
||||
ipcMain.handle('mpv-play', () => mpv?.play())
|
||||
ipcMain.handle('mpv-pause', () => mpv?.pause())
|
||||
ipcMain.handle('mpv-toggle-pause', () => mpv?.togglePause())
|
||||
ipcMain.handle('mpv-stop', () => mpv?.stop())
|
||||
ipcMain.handle('mpv-set-volume', (e, vol) => mpv?.setVolume(vol))
|
||||
ipcMain.handle('mpv-seek', (_, time) => mpv?.seek(time))
|
||||
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
@@ -61,6 +80,12 @@ app.on('window-all-closed', () => {
|
||||
}
|
||||
})
|
||||
|
||||
app.on('will-quit', () => {
|
||||
if (mpv) {
|
||||
mpv.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
function registerZoomShortcuts(win: BrowserWindow) {
|
||||
win.webContents.on('before-input-event', (event, input) => {
|
||||
if (input.control || input.meta) {
|
||||
@@ -92,4 +117,15 @@ app.on('activate', () => {
|
||||
app.whenReady().then(() => {
|
||||
Menu.setApplicationMenu(null)
|
||||
createWindow()
|
||||
|
||||
// Start MPV
|
||||
mpv = new MpvController()
|
||||
mpv.start()
|
||||
|
||||
mpv.on('event', (data) => {
|
||||
// Forward MPV events to Render Process
|
||||
if (win && !win.isDestroyed()) {
|
||||
win.webContents.send('mpv-event', data)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,4 +6,16 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
maximizeWindow: () => ipcRenderer.send('window-maximize'),
|
||||
closeWindow: () => ipcRenderer.send('window-close'),
|
||||
isMaximized: () => ipcRenderer.invoke('window-is-maximized'),
|
||||
|
||||
// MPV Control
|
||||
mpv: {
|
||||
load: (url: string) => ipcRenderer.invoke('mpv-load', url),
|
||||
play: () => ipcRenderer.invoke('mpv-play'),
|
||||
pause: () => ipcRenderer.invoke('mpv-pause'),
|
||||
togglePause: () => ipcRenderer.invoke('mpv-toggle-pause'),
|
||||
stop: () => ipcRenderer.invoke('mpv-stop'),
|
||||
setVolume: (vol: number) => ipcRenderer.invoke('mpv-set-volume', vol),
|
||||
seek: (time: number) => ipcRenderer.invoke('mpv-seek', time),
|
||||
onEvent: (callback: (event: any, data: any) => void) => ipcRenderer.on('mpv-event', callback)
|
||||
}
|
||||
})
|
||||
57
package-lock.json
generated
57
package-lock.json
generated
@@ -21,7 +21,6 @@
|
||||
"element-plus": "^2.13.0",
|
||||
"jss": "^10.10.0",
|
||||
"jss-preset-default": "^10.10.0",
|
||||
"node-mpv": "^1.5.0",
|
||||
"pinia": "^3.0.4",
|
||||
"tdesign-vue-next": "^1.17.7",
|
||||
"vue": "^3.4.21",
|
||||
@@ -2670,12 +2669,6 @@
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz",
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
@@ -2844,12 +2837,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/browser-fingerprint": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/browser-fingerprint/-/browser-fingerprint-0.0.1.tgz",
|
||||
"integrity": "sha512-b8SXP7yOlzLUJXF8WUvIjmbJzkJC0X6OHe7J9a/SHqEBC7a9Eglag6AANSTJz82h5U582kuxm/5TPudnD68EPA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/buffer": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz",
|
||||
@@ -3317,13 +3304,6 @@
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-1.2.7.tgz",
|
||||
"integrity": "sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==",
|
||||
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
@@ -3402,18 +3382,6 @@
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cuid": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmmirror.com/cuid/-/cuid-1.3.8.tgz",
|
||||
"integrity": "sha512-MoL67ZZuBetDMxzrZtO+Iq1ATajFACQCP52QRinBgd3yTjYdv54mJO8ibUrh06fojKCoX5P2i7KkEatm4VTIOQ==",
|
||||
"deprecated": "Cuid and other k-sortable and non-cryptographic ids (Ulid, ObjectId, KSUID, all UUIDs) are all insecure. Use @paralleldrive/cuid2 instead.",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browser-fingerprint": "0.0.1",
|
||||
"core-js": "^1.1.1",
|
||||
"node-fingerprint": "0.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.11.19",
|
||||
"resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz",
|
||||
@@ -5503,22 +5471,6 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/node-fingerprint": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/node-fingerprint/-/node-fingerprint-0.0.2.tgz",
|
||||
"integrity": "sha512-vPFfTD5EBJieQ4SI3v61fWxlV1kav3m9Dbejd6CjWhOJn8s+XMxpOOosCNAyIrUQ/jJOlPndfrZ0lSw4+RgwcA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-mpv": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/node-mpv/-/node-mpv-1.5.0.tgz",
|
||||
"integrity": "sha512-kvLo+PcWHZ/Sg7t9XeFDi5KJrNOL9XJOEljCEh5wBNOHiE6Wa/txwIsYWKmNaIFuncbEhgjnoOavE4T5YBNV8Q==",
|
||||
"dependencies": {
|
||||
"cuid": "^1.3.8",
|
||||
"lodash": ">= 4.0.0",
|
||||
"promise": "^7.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@@ -5765,15 +5717,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/promise-retry": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz",
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"element-plus": "^2.13.0",
|
||||
"jss": "^10.10.0",
|
||||
"jss-preset-default": "^10.10.0",
|
||||
"node-mpv": "^1.5.0",
|
||||
"pinia": "^3.0.4",
|
||||
"tdesign-vue-next": "^1.17.7",
|
||||
"vue": "^3.4.21",
|
||||
|
||||
37
src/main.ts
37
src/main.ts
@@ -20,6 +20,16 @@ const router = createRouter({
|
||||
path: '/local',
|
||||
name: 'Local',
|
||||
component: () => import('./views/LocalMusic.vue')
|
||||
},
|
||||
{
|
||||
path: '/liked',
|
||||
name: 'Liked',
|
||||
component: () => import('./views/Playlist.vue')
|
||||
},
|
||||
{
|
||||
path: '/recent',
|
||||
name: 'Recent',
|
||||
component: () => import('./views/Playlist.vue')
|
||||
}
|
||||
]
|
||||
})
|
||||
@@ -28,4 +38,29 @@ const app = createApp(App)
|
||||
app.use(pinia)
|
||||
app.use(router)
|
||||
app.use(TDesign)
|
||||
app.mount('#app')
|
||||
app.mount('#app')
|
||||
|
||||
// --- TEST: Auto Play Specific Song ---
|
||||
import { usePlayerStore, PlayMode } from './stores/player'
|
||||
import type { Song } from './types/song'
|
||||
|
||||
const playerStore = usePlayerStore()
|
||||
|
||||
// Set Single Mode
|
||||
playerStore.playMode = PlayMode.Single;
|
||||
|
||||
const testSong: Song = {
|
||||
id: '9999',
|
||||
name: 'Test FLAC',
|
||||
artist: 'Netease',
|
||||
picUrl: 'http://p1.music.126.net/btYBbFLd5mf9w0lDpfNs6w==/109951171506809884.jpg?param=130y130',
|
||||
url: 'http://m801.music.126.net/20260202213928/189743bba596f8fd999bc44fd51d11fd/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/61393856655/24be/6a68/77e4/fb898a5378682427bf7a4fb55640e610.flac',
|
||||
duration: '03:30',
|
||||
source: 'netease',
|
||||
type: 'Remote'
|
||||
};
|
||||
|
||||
// Auto Play
|
||||
playerStore.playSong(testSong).then(() => {
|
||||
playerStore.setPlaylist([testSong]);
|
||||
});
|
||||
10
src/types/electron.d.ts
vendored
10
src/types/electron.d.ts
vendored
@@ -3,6 +3,16 @@ export interface IElectronAPI {
|
||||
maximizeWindow: () => void;
|
||||
closeWindow: () => void;
|
||||
isMaximized: () => Promise<boolean>;
|
||||
mpv: {
|
||||
load: (url: string) => Promise<void>;
|
||||
play: () => Promise<void>;
|
||||
pause: () => Promise<void>;
|
||||
togglePause: () => Promise<void>;
|
||||
stop: () => Promise<void>;
|
||||
setVolume: (vol: number) => Promise<void>;
|
||||
seek: (time: number) => Promise<void>;
|
||||
onEvent: (callback: (event: any, data: any) => void) => void;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
Reference in New Issue
Block a user