mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 05:38:04 +00:00
chore: 整理electron目录
This commit is contained in:
parent
ca4725a46e
commit
8d7ae405a6
15 changed files with 160 additions and 68 deletions
|
|
@ -5,7 +5,7 @@ import { Request, Response } from 'express'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import * as musicMetadata from 'music-metadata'
|
import * as musicMetadata from 'music-metadata'
|
||||||
import { APIs, APIsParams, APIsResponse } from '../shared/CacheAPIs'
|
import { APIs, APIsParams, APIsResponse } from '@/shared/CacheAPIs'
|
||||||
import { TablesStructures } from './db'
|
import { TablesStructures } from './db'
|
||||||
|
|
||||||
class Cache {
|
class Cache {
|
||||||
|
|
@ -3,10 +3,9 @@ import { app } from 'electron'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import SQLite3 from 'better-sqlite3'
|
import SQLite3 from 'better-sqlite3'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
import { createFileIfNotExist } from './utils'
|
import { createFileIfNotExist, dirname } from './utils'
|
||||||
import pkg from '../../package.json'
|
import pkg from '../../../package.json'
|
||||||
import { compare, validate } from 'compare-versions'
|
import { compare, validate } from 'compare-versions'
|
||||||
import { dirname } from './utils'
|
|
||||||
|
|
||||||
export const enum Tables {
|
export const enum Tables {
|
||||||
Track = 'Track',
|
Track = 'Track',
|
||||||
|
|
@ -15,6 +15,7 @@ import { initIpcMain } from './ipcMain'
|
||||||
import { createTray, YPMTray } from './tray'
|
import { createTray, YPMTray } from './tray'
|
||||||
import { IpcChannels } from '@/shared/IpcChannels'
|
import { IpcChannels } from '@/shared/IpcChannels'
|
||||||
import { createTaskbar, Thumbar } from './windowsTaskbar'
|
import { createTaskbar, Thumbar } from './windowsTaskbar'
|
||||||
|
import { createMenu } from './menu'
|
||||||
import { Store as State, initialState } from '@/shared/store'
|
import { Store as State, initialState } from '@/shared/store'
|
||||||
import { isDev, isWindows, isLinux, isMac } from './utils'
|
import { isDev, isWindows, isLinux, isMac } from './utils'
|
||||||
|
|
||||||
|
|
@ -63,6 +64,7 @@ class Main {
|
||||||
this.handleAppEvents()
|
this.handleAppEvents()
|
||||||
this.handleWindowEvents()
|
this.handleWindowEvents()
|
||||||
this.createTray()
|
this.createTray()
|
||||||
|
createMenu(this.win!)
|
||||||
this.createThumbar()
|
this.createThumbar()
|
||||||
initIpcMain(this.win, this.tray, this.thumbar, this.store)
|
initIpcMain(this.win, this.tray, this.thumbar, this.store)
|
||||||
this.initDevTools()
|
this.initDevTools()
|
||||||
|
|
@ -76,13 +78,9 @@ class Main {
|
||||||
const {
|
const {
|
||||||
default: installExtension,
|
default: installExtension,
|
||||||
REACT_DEVELOPER_TOOLS,
|
REACT_DEVELOPER_TOOLS,
|
||||||
REDUX_DEVTOOLS,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
} = require('electron-devtools-installer')
|
} = require('electron-devtools-installer')
|
||||||
installExtension(REACT_DEVELOPER_TOOLS.id).catch((err: any) =>
|
installExtension(REACT_DEVELOPER_TOOLS.id).catch((err: unknown) =>
|
||||||
log.info('An error occurred: ', err)
|
|
||||||
)
|
|
||||||
installExtension(REDUX_DEVTOOLS.id).catch((err: any) =>
|
|
||||||
log.info('An error occurred: ', err)
|
log.info('An error occurred: ', err)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -134,25 +132,26 @@ class Main {
|
||||||
|
|
||||||
disableCORS() {
|
disableCORS() {
|
||||||
if (!this.win) return
|
if (!this.win) return
|
||||||
function UpsertKeyValue(obj, keyToChange, value) {
|
const upsertKeyValue = (
|
||||||
const keyToChangeLower = keyToChange.toLowerCase()
|
object: Record<string, string | string[]>,
|
||||||
for (const key of Object.keys(obj)) {
|
keyToChange: string,
|
||||||
if (key.toLowerCase() === keyToChangeLower) {
|
value: string[]
|
||||||
// Reassign old key
|
) => {
|
||||||
obj[key] = value
|
if (!object) return
|
||||||
// Done
|
for (const key of Object.keys(object)) {
|
||||||
return
|
if (key.toLowerCase() === keyToChange.toLowerCase()) {
|
||||||
|
object[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert at end instead
|
object[keyToChange] = value
|
||||||
obj[keyToChange] = value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.win.webContents.session.webRequest.onBeforeSendHeaders(
|
this.win.webContents.session.webRequest.onBeforeSendHeaders(
|
||||||
(details, callback) => {
|
(details, callback) => {
|
||||||
const { requestHeaders, url } = details
|
const { requestHeaders, url } = details
|
||||||
UpsertKeyValue(requestHeaders, 'Access-Control-Allow-Origin', ['*'])
|
upsertKeyValue(requestHeaders, 'access-control-allow-origin', ['*'])
|
||||||
|
|
||||||
|
// 不加这几个 header 的话,使用 axios 加载 YouTube 音频会很慢
|
||||||
if (url.includes('googlevideo.com')) {
|
if (url.includes('googlevideo.com')) {
|
||||||
requestHeaders['Sec-Fetch-Mode'] = 'no-cors'
|
requestHeaders['Sec-Fetch-Mode'] = 'no-cors'
|
||||||
requestHeaders['Sec-Fetch-Dest'] = 'audio'
|
requestHeaders['Sec-Fetch-Dest'] = 'audio'
|
||||||
|
|
@ -166,8 +165,10 @@ class Main {
|
||||||
this.win.webContents.session.webRequest.onHeadersReceived(
|
this.win.webContents.session.webRequest.onHeadersReceived(
|
||||||
(details, callback) => {
|
(details, callback) => {
|
||||||
const { responseHeaders } = details
|
const { responseHeaders } = details
|
||||||
UpsertKeyValue(responseHeaders, 'Access-Control-Allow-Origin', ['*'])
|
if (responseHeaders) {
|
||||||
UpsertKeyValue(responseHeaders, 'Access-Control-Allow-Headers', ['*'])
|
upsertKeyValue(responseHeaders, 'access-control-allow-origin', ['*'])
|
||||||
|
upsertKeyValue(responseHeaders, 'access-control-allow-headers', ['*'])
|
||||||
|
}
|
||||||
callback({
|
callback({
|
||||||
responseHeaders,
|
responseHeaders,
|
||||||
})
|
})
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { BrowserWindow, ipcMain, app } from 'electron'
|
import { BrowserWindow, ipcMain, app } from 'electron'
|
||||||
import { db, Tables } from './db'
|
import { db, Tables } from './db'
|
||||||
import { IpcChannels, IpcChannelsParams } from '../shared/IpcChannels'
|
import { IpcChannels, IpcChannelsParams } from '@/shared/IpcChannels'
|
||||||
import cache from './cache'
|
import cache from './cache'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import Store from 'electron-store'
|
import Store from 'electron-store'
|
||||||
import { TypedElectronStore } from './index'
|
import { TypedElectronStore } from './index'
|
||||||
import { APIs } from '../shared/CacheAPIs'
|
import { APIs } from '@/shared/CacheAPIs'
|
||||||
import { YPMTray } from './tray'
|
import { YPMTray } from './tray'
|
||||||
import { Thumbar } from './windowsTaskbar'
|
import { Thumbar } from './windowsTaskbar'
|
||||||
import fastFolderSize from 'fast-folder-size'
|
import fastFolderSize from 'fast-folder-size'
|
||||||
74
packages/electron/main/menu.ts
Normal file
74
packages/electron/main/menu.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
import {
|
||||||
|
BrowserWindow,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
MenuItemConstructorOptions,
|
||||||
|
shell,
|
||||||
|
} from 'electron'
|
||||||
|
import { logsPath, isMac } from './utils'
|
||||||
|
import { exec } from 'child_process'
|
||||||
|
|
||||||
|
export const createMenu = (win: BrowserWindow) => {
|
||||||
|
const template: Array<MenuItemConstructorOptions | MenuItem> = [
|
||||||
|
{ role: 'appMenu' },
|
||||||
|
{ role: 'editMenu' },
|
||||||
|
{ role: 'viewMenu' },
|
||||||
|
{ role: 'windowMenu' },
|
||||||
|
{
|
||||||
|
label: '帮助',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: '打开日志文件目录',
|
||||||
|
click: async () => {
|
||||||
|
if (isMac) {
|
||||||
|
exec(`open ${logsPath}`)
|
||||||
|
} else {
|
||||||
|
// TODO: 测试Windows和Linux是否能正确打开日志目录
|
||||||
|
shell.openPath(logsPath)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '打开开发者工具',
|
||||||
|
click: async () => {
|
||||||
|
win.webContents.openDevTools()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '反馈问题',
|
||||||
|
click: async () => {
|
||||||
|
await shell.openExternal(
|
||||||
|
'https://github.com/qier222/YesPlayMusic/issues/new'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
label: '访问 GitHub 仓库',
|
||||||
|
click: async () => {
|
||||||
|
await shell.openExternal('https://github.com/qier222/YesPlayMusic')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '访问论坛',
|
||||||
|
click: async () => {
|
||||||
|
await shell.openExternal(
|
||||||
|
'https://github.com/qier222/YesPlayMusic/discussions'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '加入交流群',
|
||||||
|
click: async () => {
|
||||||
|
await shell.openExternal(
|
||||||
|
'https://github.com/qier222/YesPlayMusic/discussions'
|
||||||
|
)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const menu = Menu.buildFromTemplate(template)
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
}
|
||||||
19
packages/electron/main/preload.ts
Normal file
19
packages/electron/main/preload.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import log from './log'
|
||||||
|
import { app } from 'electron'
|
||||||
|
import {
|
||||||
|
createDirIfNotExist,
|
||||||
|
devUserDataPath,
|
||||||
|
isDev,
|
||||||
|
portableUserDataPath,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
createDirIfNotExist(devUserDataPath)
|
||||||
|
app.setPath('appData', devUserDataPath)
|
||||||
|
}
|
||||||
|
if (process.env.PORTABLE_EXECUTABLE_DIR) {
|
||||||
|
createDirIfNotExist(portableUserDataPath)
|
||||||
|
app.setPath('appData', portableUserDataPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`[index] userData path: ${app.getPath('userData')}`)
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import * as Sentry from '@sentry/node'
|
import * as Sentry from '@sentry/node'
|
||||||
import * as Tracing from '@sentry/tracing'
|
import * as Tracing from '@sentry/tracing'
|
||||||
import pkg from '../../package.json'
|
import pkg from '../../../package.json'
|
||||||
import log from './log'
|
import log from './log'
|
||||||
|
|
||||||
log.info(`[sentry] sentry initializing`)
|
log.info(`[sentry] sentry initializing`)
|
||||||
|
|
@ -6,12 +6,12 @@ import cache from './cache'
|
||||||
import fileUpload from 'express-fileupload'
|
import fileUpload from 'express-fileupload'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { db, Tables } from 'db'
|
import { db, Tables } from './db'
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import type { FetchAudioSourceResponse } from '@/shared/api/Track'
|
import type { FetchAudioSourceResponse } from '@/shared/api/Track'
|
||||||
import UNM from '@unblockneteasemusic/rust-napi'
|
import UNM from '@unblockneteasemusic/rust-napi'
|
||||||
import { APIs as CacheAPIs } from '../shared/CacheAPIs'
|
import { APIs as CacheAPIs } from '@/shared/CacheAPIs'
|
||||||
import { isProd } from 'utils'
|
import { isProd } from './utils'
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
port = Number(
|
port = Number(
|
||||||
|
|
@ -241,21 +241,21 @@ class Server {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// try {
|
try {
|
||||||
// const fromCache = await getFromCache(id)
|
const fromCache = await getFromCache(id)
|
||||||
// if (fromCache) {
|
if (fromCache) {
|
||||||
// res.status(200).send(fromCache)
|
res.status(200).send(fromCache)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
// } catch (error) {
|
} catch (error) {
|
||||||
// log.error(`[server] getFromCache failed: ${String(error)}`)
|
log.error(`[server] getFromCache failed: ${String(error)}`)
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const fromNetease = await getFromNetease(req)
|
const fromNetease = await getFromNetease(req)
|
||||||
// if (fromNetease?.code === 200 && !fromNetease?.data?.[0].freeTrialInfo) {
|
if (fromNetease?.code === 200 && !fromNetease?.data?.[0].freeTrialInfo) {
|
||||||
// res.status(200).send(fromNetease)
|
res.status(200).send(fromNetease)
|
||||||
// return
|
return
|
||||||
// }
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fromUNM = await getFromUNM(id, req)
|
const fromUNM = await getFromUNM(id, req)
|
||||||
|
|
@ -267,11 +267,11 @@ class Server {
|
||||||
log.error(`[server] getFromNetease failed: ${String(error)}`)
|
log.error(`[server] getFromNetease failed: ${String(error)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (fromNetease?.data?.[0].freeTrialInfo) {
|
if (fromNetease?.data?.[0].freeTrialInfo) {
|
||||||
// fromNetease.data[0].url = ''
|
fromNetease.data[0].url = ''
|
||||||
// }
|
}
|
||||||
|
|
||||||
// res.status(fromNetease?.code ?? 500).send(fromNetease)
|
res.status(fromNetease?.code ?? 500).send(fromNetease)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.app.get('/netease/song/url', handler)
|
this.app.get('/netease/song/url', handler)
|
||||||
|
|
@ -34,7 +34,7 @@ function createNativeImage(filename: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMenuTemplate(win: BrowserWindow): MenuItemConstructorOptions[] {
|
function createMenuTemplate(win: BrowserWindow): MenuItemConstructorOptions[] {
|
||||||
let template: MenuItemConstructorOptions[] =
|
const template: MenuItemConstructorOptions[] =
|
||||||
process.platform === 'linux'
|
process.platform === 'linux'
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
|
|
@ -1,5 +1,23 @@
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import pkg from '../../../package.json'
|
||||||
|
|
||||||
|
export const isDev = process.env.NODE_ENV === 'development'
|
||||||
|
export const isProd = process.env.NODE_ENV === 'production'
|
||||||
|
export const isWindows = process.platform === 'win32'
|
||||||
|
export const isMac = process.platform === 'darwin'
|
||||||
|
export const isLinux = process.platform === 'linux'
|
||||||
|
export const dirname = isDev ? process.cwd() : __dirname
|
||||||
|
export const devUserDataPath = path.resolve(process.cwd(), '../../tmp/userData')
|
||||||
|
export const portableUserDataPath = path.resolve(
|
||||||
|
process.env.PORTABLE_EXECUTABLE_DIR || '',
|
||||||
|
'./YesPlayMusic-UserData'
|
||||||
|
)
|
||||||
|
export const logsPath = {
|
||||||
|
linux: `~/.config/${pkg.productName}/logs`,
|
||||||
|
darwin: `~/Library/Logs/${pkg.productName}/`,
|
||||||
|
win32: `%USERPROFILE%\\AppData\\Roaming\\${pkg.productName}\\logs`,
|
||||||
|
}[process.platform as 'darwin' | 'win32' | 'linux']
|
||||||
|
|
||||||
export const createDirIfNotExist = (dir: string) => {
|
export const createDirIfNotExist = (dir: string) => {
|
||||||
if (!fs.existsSync(dir)) {
|
if (!fs.existsSync(dir)) {
|
||||||
|
|
@ -13,10 +31,3 @@ export const createFileIfNotExist = (file: string) => {
|
||||||
fs.writeFileSync(file, '')
|
fs.writeFileSync(file, '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isDev = process.env.NODE_ENV === 'development'
|
|
||||||
export const isProd = process.env.NODE_ENV === 'production'
|
|
||||||
export const isWindows = process.platform === 'win32'
|
|
||||||
export const isMac = process.platform === 'darwin'
|
|
||||||
export const isLinux = process.platform === 'linux'
|
|
||||||
export const dirname = isDev ? process.cwd() : __dirname
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
import log from './log'
|
|
||||||
import path from 'path'
|
|
||||||
import { app } from 'electron'
|
|
||||||
import { createDirIfNotExist, isDev } from './utils'
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
const devUserDataPath = path.resolve(process.cwd(), '../../tmp/userData')
|
|
||||||
createDirIfNotExist(devUserDataPath)
|
|
||||||
app.setPath('appData', devUserDataPath)
|
|
||||||
}
|
|
||||||
log.info(`[index] userData path: ${app.getPath('userData')}`)
|
|
||||||
|
|
@ -23,13 +23,13 @@ const TAG = '[script/build.main.ts]'
|
||||||
const spinner = ora(`${TAG} Main Process Building...`)
|
const spinner = ora(`${TAG} Main Process Building...`)
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
entryPoints: ['./index.ts', './rendererPreload.ts'],
|
entryPoints: ['./main/index.ts', './main/rendererPreload.ts'],
|
||||||
outdir: './dist',
|
outdir: './dist',
|
||||||
platform: 'node',
|
platform: 'node',
|
||||||
format: 'cjs',
|
format: 'cjs',
|
||||||
bundle: true,
|
bundle: true,
|
||||||
sourcemap: true,
|
|
||||||
define: envForEsbuild,
|
define: envForEsbuild,
|
||||||
|
minify: true,
|
||||||
external: [
|
external: [
|
||||||
...builtinModules.filter(
|
...builtinModules.filter(
|
||||||
x => !/^_|^(internal|v8|node-inspect)\/|\//.test(x)
|
x => !/^_|^(internal|v8|node-inspect)\/|\//.test(x)
|
||||||
|
|
@ -95,7 +95,6 @@ if (argv.watch) {
|
||||||
...options.define,
|
...options.define,
|
||||||
'process.env.NODE_ENV': '"production"',
|
'process.env.NODE_ENV': '"production"',
|
||||||
},
|
},
|
||||||
minify: true,
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(TAG, pc.green('Main Process Build Succeeded.'))
|
console.log(TAG, pc.green('Main Process Build Succeeded.'))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue