This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
appcat
/
sonist
Archived
1
0
Fork 0

重写进程通讯交互

2.x
宇天 2020-11-18 16:32:33 +08:00
parent cb66f9b287
commit ea4bdddffa
14 changed files with 261 additions and 246 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "top.yutent.sonist", "name": "top.yutent.sonist",
"version": "2.0.0-alpha-1", "version": "2.0.0-alpha-2",
"description": "Music Player", "description": "Music Player",
"main": "src/main.js", "main": "src/main.js",
"scripts": { "scripts": {
@ -15,7 +15,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"crypto.js": "^2.0.2", "crypto.js": "^2.0.2",
"iofs": "^1.5.1" "iofs": "^1.5.1",
"sqlite3": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {
"electron": "^10.0.0", "electron": "^10.0.0",
@ -33,7 +34,12 @@
"version": "10.1.5", "version": "10.1.5",
"mirror": "https://npm.taobao.org/mirrors/electron/" "mirror": "https://npm.taobao.org/mirrors/electron/"
}, },
"files": ["src/**/*", "node_modules/iofs/*", "node_modules/crypto.js/*"], "files": [
"src/**/*",
"node_modules/iofs/*",
"node_modules/sqlite3/*",
"node_modules/crypto.js/*"
],
"mac": { "mac": {
"category": "public.app-category.music", "category": "public.app-category.music",
"target": "dmg", "target": "dmg",

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@
position:relative; position:relative;
display:flex;flex-direction:column; display:flex;flex-direction:column;
width:100%;height:100%; width:100%;height:100%;
background:rgba(0, 0, 0, .2); background:rgba(0, 0, 0, .3);
// //
.title-bar { .title-bar {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -53,71 +53,11 @@
<div class="scroll-box"> <div class="scroll-box">
<wc-scroll class="list"> <wc-scroll class="list">
<section class="item"> <section class="item" :for="i it in list">
<span class="idx">01</span> <span class="idx" :text="i + 1"></span>
<span class="name">情是何物</span> <span class="name" :text="it.name"></span>
<span class="artist">周深</span> <span class="artist" :text="it.artist"></span>
<span class="duration">04:23</span> <span class="duration" :text="it.duration"></span>
</section>
<section class="item">
<span class="idx">02</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item on">
<span class="idx">03</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">04</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">05</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">06</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">07</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">08</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">09</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">10</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section>
<section class="item">
<span class="idx">11</span>
<span class="name">情是何物</span>
<span class="artist">周深</span>
<span class="duration">04:23</span>
</section> </section>
</wc-scroll> </wc-scroll>

View File

@ -6,13 +6,23 @@
import Anot from '/js/lib/anot.js' import Anot from '/js/lib/anot.js'
import '/js/lib/scroll/index.js' import '/js/lib/scroll/index.js'
import app from '/js/lib/socket.js'
// const {} from ''
Anot({ Anot({
$id: 'app', $id: 'app',
state: { state: {
isplaying: true, isplaying: true,
playmode: 1, playmode: 1,
mute: false mute: false,
list: []
},
mounted() {
var list = app.dispatch('scan-dir', { path: '/Volumes/extends/music' })
this.list = list
console.log(list)
}, },
methods: { methods: {
play() { play() {

13
src/js/lib/socket.js Normal file
View File

@ -0,0 +1,13 @@
/**
* 与主进程的通讯
* @author yutent<yutent.io@gmail.com>
* @date 2020/07/14 11:42:02
*/
const { ipcRenderer } = require('electron')
export default {
dispatch(type = '', params = {}) {
return ipcRenderer.sendSync('app', Object.assign(params, { type }))
}
}

View File

@ -1,16 +1,19 @@
/** /**
* 主入口 * 主入口
* @author yutent<yutent@doui.cc> * @author yutent<yutent.io@gmail.com>
* @date 2019/12/13 00:37:04 * @date 2020/11/18 09:27:09
*/ */
'use strict'
const { app, session, protocol, globalShortcut } = require('electron') const { app, session, protocol, globalShortcut } = require('electron')
const path = require('path') const path = require('path')
const fs = require('iofs') const fs = require('iofs')
const { exec } = require('child_process') // const {exec} = require('child_process')
const log = console.log
require('./tools/init.js')
const { createAppTray, createLrcTray } = require('./tools/tray.js')
const createMenu = require('./tools/menu.js')
const { createMainWindow, createMiniWindow } = require('./tools/windows.js')
const MIME_TYPES = { const MIME_TYPES = {
'.js': 'text/javascript', '.js': 'text/javascript',
'.html': 'text/html', '.html': 'text/html',
@ -23,14 +26,6 @@ const MIME_TYPES = {
'.ico': 'image/ico' '.ico': 'image/ico'
} }
require('./tools/init')
const createTray = require('./tools/tray')
const createMenu = require('./tools/menu')
const { createMainWindow, createErrorWindow } = require('./tools/windows')
const ROOT = __dirname
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
app.commandLine.appendSwitch('--lang', 'zh-CN') app.commandLine.appendSwitch('--lang', 'zh-CN')
app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required') app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required')
@ -47,7 +42,7 @@ app.once('ready', () => {
protocol.registerBufferProtocol('app', (req, cb) => { protocol.registerBufferProtocol('app', (req, cb) => {
let file = req.url.replace(/^app:\/\/local\//, '') let file = req.url.replace(/^app:\/\/local\//, '')
let ext = path.extname(req.url) let ext = path.extname(req.url)
let buff = fs.cat(path.resolve(ROOT, file)) let buff = fs.cat(path.resolve(__dirname, file))
cb({ data: buff, mimeType: MIME_TYPES[ext] }) cb({ data: buff, mimeType: MIME_TYPES[ext] })
}) })
// 修改app的UA // 修改app的UA
@ -55,13 +50,12 @@ app.once('ready', () => {
'KugouMusic/2.9.5 (Mac OS X Version 10.15.7 (Build 19H2))' 'KugouMusic/2.9.5 (Mac OS X Version 10.15.7 (Build 19H2))'
) )
let win = createMainWindow(path.resolve(ROOT, './images/app.png')) let win = createMainWindow(path.resolve(__dirname, './images/app.png'))
createTray(win) createAppTray(win)
createLrcTray(win)
createMenu(win) createMenu(win)
app.__MAIN__ = win
// mac专属事件,点击dock栏图标,可激活窗口 // mac专属事件,点击dock栏图标,可激活窗口
app.on('activate', _ => { app.on('activate', _ => {
if (win) { if (win) {

63
src/tools/db/index.js Normal file
View File

@ -0,0 +1,63 @@
/**
*
* @authors yutent (yutent.io@gmail.com)
* @date 2018-08-06 15:55:54
*/
Promise.defer = function() {
var obj = {}
obj.promise = new Promise((resolve, reject) => {
obj.resolve = resolve
obj.reject = reject
})
return obj
}
const sqlite3 = require('sqlite3').verbose()
class Sqlite {
constructor(db) {
this.db = new sqlite3.Database(db)
}
query(sql, ...param) {
let defer = Promise.defer()
param.unshift(sql)
param.push(err => {
if (err) {
return defer.reject(err)
}
defer.resolve(true)
})
this.db.run.apply(this.db, param)
return defer.promise
}
getAll(sql, ...param) {
let defer = Promise.defer()
param.unshift(sql)
param.push((err, row) => {
if (err) {
return defer.reject(err)
}
defer.resolve(row)
})
this.db.all.apply(this.db, param)
return defer.promise
}
get(sql, ...param) {
let defer = Promise.defer()
param.unshift(sql)
param.push((err, row) => {
if (err) {
return defer.reject(err)
}
defer.resolve(row)
})
this.db.get.apply(this.db, param)
return defer.promise
}
}
module.exports = Sqlite

53
src/tools/db/init.js Normal file
View File

@ -0,0 +1,53 @@
/**
* 初始化数据库
* @author yutent<yutent.io@gmail.com>
* @date 2020/07/14 18:17:59
*/
const TABLE_PLAYLIST = `
CREATE TABLE IF NOT EXISTS "playlist" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" char(128) NOT NULL
)
`
const TABLE_SONGS = `
CREATE TABLE IF NOT EXISTS "songs" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"pid" integer NOT NULL,
"aid" integer NOT NULL,
"name" char(128) NOT NULL,
"album" char(128) NOT NULL,
"cover" char(256) NOT NULL,
"lrc" text NOT NULL,
)
`
// 歌曲和播放列表的关系表(多对多)
const TABLE_RELATIONS = `
CREATE TABLE IF NOT EXISTS "relations" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"sid" integer NOT NULL,
"pid" integer NOT NULL,
)
`
const TABLE_ARTISTS = `
CREATE TABLE IF NOT EXISTS "artists" (
"id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" integer NOT NULL,
"avatar" char(256) NOT NULL
)
`
function error(err) {
console.log('----------------------------------------')
console.error(err)
console.log('----------------------------------------')
}
module.exports = function(db) {
db.query(TABLE_PLAYLIST).catch(error)
db.query(TABLE_SONGS).catch(error)
db.query(TABLE_RELATIONS).catch(error)
db.query(TABLE_ARTISTS).catch(error)
}

View File

@ -4,12 +4,15 @@
* @date 2019/01/26 18:11:26 * @date 2019/01/26 18:11:26
*/ */
'use strict'
const { app, ipcMain, globalShortcut: GS } = require('electron') const { app, ipcMain, globalShortcut: GS } = require('electron')
const path = require('path') const path = require('path')
const fs = require('iofs') const fs = require('iofs')
const Shortcut = require('./shortcut') const Shortcut = require('./shortcut')
const Sqlite = require('./db')
const dbinit = require('./db/init')
const HOME = path.resolve(app.getPath('userData'))
/* ********** 修复环境变量 start *********** */ /* ********** 修复环境变量 start *********** */
let PATH_SET = new Set() let PATH_SET = new Set()
@ -24,105 +27,75 @@ PATH_SET = null
/* ********** 修复环境变量 end *********** */ /* ********** 修复环境变量 end *********** */
const HOME = app.getPath('home') const DB_FILE = path.join(HOME, 'sqlite3.cache')
const INIT_FILE = path.join(HOME, 'app.ini')
const APP_ROOT = path.resolve(HOME, '.sonist/') const CACHE_DIR = path.join(HOME, 'other_cache')
const LRC_DIR = path.join(APP_ROOT, 'lyrics')
const CACHE_DIR = path.join(APP_ROOT, 'cache')
const INIT_FILE = path.join(APP_ROOT, 'app.ini')
const DB_FILE = path.join(APP_ROOT, 'music.db')
const TEMP_DB = path.join(APP_ROOT, 'temp.db')
if (!fs.exists(APP_ROOT)) {
fs.mkdir(APP_ROOT)
fs.mkdir(LRC_DIR)
fs.mkdir(CACHE_DIR)
fs.echo('{}', INIT_FILE)
fs.echo('[]', TEMP_DB)
fs.echo('[]', DB_FILE)
}
const SUPPORTED_EXTS = ['.mp3', '.webm', '.ogg', '.flac', '.m4a', '.aac'] const SUPPORTED_EXTS = ['.mp3', '.webm', '.ogg', '.flac', '.m4a', '.aac']
const DB = { var isFirstTimeLaunch = false
read(file) { var db = null
let cache = (fs.cat(file) || '[]').toString('utf-8')
try { if (!fs.exists(DB_FILE)) {
return JSON.parse(cache) fs.echo('{}', INIT_FILE)
} catch (err) { fs.mkdir(CACHE_DIR)
return cache isFirstTimeLaunch = true
}
},
save(file, data) {
fs.echo(JSON.stringify(data), file)
}
} }
db = new Sqlite(DB_FILE)
if (isFirstTimeLaunch) {
dbinit(db)
}
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
/* --------------------- 事件开始 ------------------------- */ /* --------------------- 事件开始 ------------------------- */
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
ipcMain.on('sonist', (ev, conn) => { ipcMain.on('app', (ev, conn) => {
switch (conn.type) { switch (conn.type) {
// 获取所有书籍
case 'get-playlist':
db.getAll('SELECT * FROM `playlist`')
.then(res => {
ev.returnValue = res
})
.catch(err => {
ev.returnValue = err
})
break
// 获取应用配置 // 获取应用配置
case 'get-init': case 'get-init':
ev.returnValue = DB.read(INIT_FILE) var ini = fs.cat(INIT_FILE).toString('')
ev.returnValue = JSON.parse(ini)
break break
// 设置应用配置 // 设置应用配置
case 'set-init': case 'set-init':
DB.save(INIT_FILE, conn.data) fs.echo(JSON.stringify(conn.data, null, 2), INIT_FILE)
break
// 获取音乐数据库
case 'get-music':
ev.returnValue = DB.read(DB_FILE)
break
// 更新音乐数据库
case 'set-music':
DB.save(DB_FILE, conn.data)
break
// 获取临时音乐数据库
case 'get-temp':
ev.returnValue = DB.read(TEMP_DB)
break
// 更新临时音乐数据库
case 'set-temp':
DB.save(TEMP_DB, conn.data)
break
// 读取歌词文件
case 'read-lrc':
let lrc = path.join(LRC_DIR, `${conn.id}.lrc`)
if (fs.exists(lrc)) {
ev.returnValue = DB.read(lrc)
} else {
ev.returnValue = null
}
break
// 保存歌词文件
case 'save-lrc':
fs.echo(conn.data, path.join(LRC_DIR, `${conn.id}.lrc`))
break
// 保存音乐文件
case 'save-cache':
let file = path.join(CACHE_DIR, conn.file)
fs.echo(conn.data, file)
ev.returnValue = `file://${file}`
break break
// 扫描目录 // 扫描目录
case 'scan-dir': case 'scan-dir':
if (fs.isdir(conn.path)) { if (fs.isdir(conn.path)) {
let list = fs.ls(conn.path, true).filter(_ => { let list = fs
if (fs.isdir(_)) { .ls(conn.path, true)
.filter(it => {
if (fs.isdir(it)) {
return false return false
} else { } else {
let { ext, name } = path.parse(_) let { ext, name } = path.parse(it)
if (!ext || name.startsWith('.')) { if (!ext || name.startsWith('.')) {
return false return false
} }
return SUPPORTED_EXTS.includes(ext) return SUPPORTED_EXTS.includes(ext)
} }
}) })
.map(it => {
var { ext, name } = path.parse(it)
return { uuid: '', ext, name, path: it }
})
ev.returnValue = list ev.returnValue = list
} else { } else {
ev.returnValue = null ev.returnValue = []
} }
break break

View File

@ -6,31 +6,44 @@
'use strict' 'use strict'
const { app, Tray, Menu } = require('electron') const { ipcMain, Tray, Menu, nativeImage } = require('electron')
const path = require('path') const path = require('path')
const ROOT = __dirname
module.exports = function(win) { function ctrlTrayBtn() {
app.__TRAY__ = new Tray(path.join(ROOT, '../images/trays/trayTemplate.png')) var prev = new Tray(path.join(__dirname, '../images/ctrl/prev.png'))
let menuList = Menu.buildFromTemplate([ var next = new Tray(path.join(__dirname, '../images/ctrl/next.png'))
{ }
label: '显示主窗口',
click() { exports.createAppTray = function(win) {
win.webContents.send('dock-click') var tray = new Tray(path.join(__dirname, '../images/trays/trayTemplate.png'))
} tray.setIgnoreDoubleClickEvents(true)
}, // let menuList = Menu.buildFromTemplate([
{ type: 'separator' }, // {
{ label: '退出', role: 'quit' } // label: '显示主窗口',
]) // click() {
// win.webContents.send('dock-click')
if (process.platform === 'darwin') { // }
app.__TRAY__.on('click', _ => { // },
win.webContents.send('dock-click') // { type: 'separator' },
}) // { label: '退出', role: 'quit' }
app.__TRAY__.on('right-click', _ => { // ])
app.__TRAY__.popUpContextMenu(menuList) // if (process.platform === 'darwin') {
}) // tray.on('click', _ => {
} else { // win.webContents.send('dock-click')
app.__TRAY__.setContextMenu(menuList) // })
} // tray.on('right-click', _ => {
// tray.popUpContextMenu(menuList)
// })
// } else {
// tray.setContextMenu(menuList)
// }
}
exports.createLrcTray = function(win) {
var nullImage = nativeImage.createEmpty()
var topbarLrc = new Tray(nullImage)
topbarLrc.setTitle('这是顶栏歌词, blablablabla...')
topbarLrc.setIgnoreDoubleClickEvents(true)
// ctrlTrayBtn()
} }

View File

@ -4,8 +4,6 @@
* @date 2019/01/26 18:28:22 * @date 2019/01/26 18:28:22
*/ */
'use strict'
const { BrowserWindow } = require('electron') const { BrowserWindow } = require('electron')
/** /**
@ -45,55 +43,6 @@ exports.createMainWindow = function(icon) {
return win return win
} }
/**
* 依赖异常显示窗口
*/
exports.createErrorWindow = function() {
let win = new BrowserWindow({
width: 600,
height: 360,
skipTaskbar: true,
maximizable: false,
minimizable: false,
resizable: false,
webPreferences: {
devTools: false
}
})
win.setMenuBarVisibility(false)
win.loadURL('app://local/depends.html')
win.on('closed', _ => {
app.exit()
})
}
/**
* 桌面歌词窗口
*/
exports.createDesktopLrcWindow = function(screen) {
let win = new BrowserWindow({
title: '',
width: 1000,
height: 100,
frame: false,
resizable: false,
alwaysOnTop: true,
skipTaskbar: true,
x: (screen.width - 1024) / 2,
y: screen.height - 100,
transparent: true,
hasShadow: false,
thickFrame: false,
show: false,
webPreferences: {
nodeIntegration: true
}
})
win.loadURL('app://local/desktop-lrc.html')
return win
}
/** /**
* 应用迷你窗口 * 应用迷你窗口
*/ */
@ -108,9 +57,10 @@ exports.createMiniWindow = function(screen) {
skipTaskbar: true, skipTaskbar: true,
x: screen.width - 320, x: screen.width - 320,
y: 0, y: 0,
thickFrame: false,
show: false, show: false,
webPreferences: { webPreferences: {
webSecurity: false,
experimentalFeatures: true,
nodeIntegration: true nodeIntegration: true
} }
}) })