一大波优化
parent
b42d7ae19a
commit
4bcc894ec3
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sonist",
|
"name": "sonist",
|
||||||
"version": "0.9.4",
|
"version": "0.9.5",
|
||||||
"description": "Music Player",
|
"description": "Music Player",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -29,11 +29,7 @@
|
||||||
"buildResources": "icons",
|
"buildResources": "icons",
|
||||||
"output": "build"
|
"output": "build"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": ["src/**/*", "node_modules/iofs/*", "node_modules/crypto.js/*"],
|
||||||
"src/**/*",
|
|
||||||
"node_modules/iofs/*",
|
|
||||||
"node_modules/crypto.js/*"
|
|
||||||
],
|
|
||||||
"mac": {
|
"mac": {
|
||||||
"category": "public.app-category.music",
|
"category": "public.app-category.music",
|
||||||
"target": "dmg",
|
"target": "dmg",
|
||||||
|
|
|
@ -20,24 +20,18 @@ import Search from '/js/modules/search.js'
|
||||||
import KTV from '/js/modules/ktv.js'
|
import KTV from '/js/modules/ktv.js'
|
||||||
import PLAYCTRL from '/js/modules/play-ctrl.js'
|
import PLAYCTRL from '/js/modules/play-ctrl.js'
|
||||||
|
|
||||||
import {
|
|
||||||
createDesktopLrcWindow,
|
|
||||||
createMiniWindow
|
|
||||||
} from '/js/modules/extra-win.js'
|
|
||||||
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
|
|
||||||
const fs = require('iofs')
|
const fs = require('iofs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote, ipcRenderer } = require('electron')
|
||||||
|
|
||||||
|
const { createDesktopLrcWindow, createMiniWindow } = remote.app.windows
|
||||||
|
|
||||||
const WIN = remote.getCurrentWindow()
|
const WIN = remote.getCurrentWindow()
|
||||||
const MAIN_SCREEN = remote.screen.getPrimaryDisplay()
|
const MAIN_SCREEN = remote.screen.getPrimaryDisplay()
|
||||||
|
|
||||||
const HOME_PATH = remote.app.getPath('appData')
|
|
||||||
const APP_INI_PATH = path.join(HOME_PATH, 'app.ini')
|
|
||||||
const LYRICS_PATH = path.join(HOME_PATH, 'lyrics')
|
|
||||||
const PLAY_MODE = {
|
const PLAY_MODE = {
|
||||||
0: 'all',
|
0: 'all',
|
||||||
1: 'single',
|
1: 'single',
|
||||||
|
@ -51,22 +45,20 @@ window.TS = store.collection('temp')
|
||||||
window.SONIST = new AudioPlayer()
|
window.SONIST = new AudioPlayer()
|
||||||
window.LYRICS = new Lyrics()
|
window.LYRICS = new Lyrics()
|
||||||
|
|
||||||
let appInit = fs.cat(APP_INI_PATH)
|
let appInit = ipcRenderer.sendSync('get-init')
|
||||||
|
|
||||||
Anot.ss('app-init', appInit + '')
|
Anot.ss('app-init', appInit)
|
||||||
|
|
||||||
appInit = JSON.parse(appInit)
|
|
||||||
|
|
||||||
const LRC_WIN = createDesktopLrcWindow(MAIN_SCREEN)
|
const LRC_WIN = createDesktopLrcWindow(MAIN_SCREEN)
|
||||||
const MINI_WIN = createMiniWindow(MAIN_SCREEN, WIN)
|
// const MINI_WIN = createMiniWindow(MAIN_SCREEN, WIN)
|
||||||
|
|
||||||
WIN.hide()
|
// WIN.hide()
|
||||||
MINI_WIN.show()
|
// MINI_WIN.show()
|
||||||
|
|
||||||
MINI_WIN.opener = WIN
|
// MINI_WIN.opener = WIN
|
||||||
MINI_WIN.openDevTools()
|
// MINI_WIN.openDevTools()
|
||||||
|
|
||||||
window.MINI_WIN = MINI_WIN
|
// window.MINI_WIN = MINI_WIN
|
||||||
Anot({
|
Anot({
|
||||||
$id: 'app',
|
$id: 'app',
|
||||||
state: {
|
state: {
|
||||||
|
@ -330,7 +322,7 @@ Anot({
|
||||||
this.updateCurr(song)
|
this.updateCurr(song)
|
||||||
this.isPlaying = true
|
this.isPlaying = true
|
||||||
this.draw(true)
|
this.draw(true)
|
||||||
LYRICS.__init__(song.lyrics)
|
LYRICS.__init__(song.id)
|
||||||
} else {
|
} else {
|
||||||
if (SONIST.stat === 'ready') {
|
if (SONIST.stat === 'ready') {
|
||||||
let played = this.isPlaying
|
let played = this.isPlaying
|
||||||
|
@ -351,7 +343,7 @@ Anot({
|
||||||
this.draw(true)
|
this.draw(true)
|
||||||
// this.ktvMode = 1
|
// this.ktvMode = 1
|
||||||
|
|
||||||
LYRICS.__init__(it.lyrics)
|
LYRICS.__init__(it.id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
/**
|
|
||||||
* 额外的小窗口
|
|
||||||
* @author yutent<yutent@doui.cc>
|
|
||||||
* @date 2019/01/21 21:24:04
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const {
|
|
||||||
remote: { BrowserWindow }
|
|
||||||
} = require('electron')
|
|
||||||
|
|
||||||
export const createDesktopLrcWindow = function(screen) {
|
|
||||||
let win = new BrowserWindow({
|
|
||||||
title: '',
|
|
||||||
width: 1024,
|
|
||||||
height: 100,
|
|
||||||
frame: false,
|
|
||||||
resizable: false,
|
|
||||||
alwaysOnTop: true,
|
|
||||||
x: (screen.size.width - 1024) / 2,
|
|
||||||
y: screen.size.height - 100,
|
|
||||||
skipTaskbar: true,
|
|
||||||
hasShadow: false,
|
|
||||||
thickFrame: false,
|
|
||||||
transparent: true,
|
|
||||||
show: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// win.loadURL('http://127.0.0.1:10240/desktop-lrc.html')
|
|
||||||
win.loadURL('app://local/desktop-lrc.html')
|
|
||||||
return win
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createMiniWindow = function(screen, pwin) {
|
|
||||||
let win = new BrowserWindow({
|
|
||||||
title: '',
|
|
||||||
width: 320,
|
|
||||||
height: 60,
|
|
||||||
frame: false,
|
|
||||||
// parent: pwin,
|
|
||||||
resizable: false,
|
|
||||||
alwaysOnTop: true,
|
|
||||||
x: screen.size.width - 320,
|
|
||||||
y: 0,
|
|
||||||
skipTaskbar: true,
|
|
||||||
show: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// win.loadURL('http://127.0.0.1:10240/mini-win.html')
|
|
||||||
win.loadURL('app://local/mini-win.html')
|
|
||||||
return win
|
|
||||||
}
|
|
|
@ -9,13 +9,7 @@
|
||||||
import Api from '/js/api.js'
|
import Api from '/js/api.js'
|
||||||
import Local from '/js/modules/local.js'
|
import Local from '/js/modules/local.js'
|
||||||
|
|
||||||
const fs = require('iofs')
|
const { ipcRenderer } = require('electron')
|
||||||
const path = require('path')
|
|
||||||
const { app } = require('electron').remote
|
|
||||||
|
|
||||||
const HOME_PATH = app.getPath('appData')
|
|
||||||
const MUSIC_DB_PATH = path.join(HOME_PATH, 'music.db')
|
|
||||||
const LYRICS_PATH = path.join(HOME_PATH, 'lyrics')
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -85,9 +79,8 @@ export default {
|
||||||
song.albumId = json.album_id
|
song.albumId = json.album_id
|
||||||
song.kgHash = json.hash
|
song.kgHash = json.hash
|
||||||
song.cover = json.img
|
song.cover = json.img
|
||||||
song.lyrics = path.join(LYRICS_PATH, `${song.id}.lrc`)
|
|
||||||
|
|
||||||
LS.insert(song)
|
LS.update(id, song)
|
||||||
Local.list.set(SONIST.__CURR__, song)
|
Local.list.set(SONIST.__CURR__, song)
|
||||||
|
|
||||||
SONIST.clear()
|
SONIST.clear()
|
||||||
|
@ -96,10 +89,10 @@ export default {
|
||||||
this.updateCurr(song)
|
this.updateCurr(song)
|
||||||
this.draw(true)
|
this.draw(true)
|
||||||
|
|
||||||
fs.echo(json.lyrics, song.lyrics)
|
ipcRenderer.send('save-lrc', { id, lrc: json.lyrics })
|
||||||
fs.echo(JSON.stringify(LS.getAll(), '', 2), MUSIC_DB_PATH)
|
ipcRenderer.send('set-music', LS.getAll())
|
||||||
|
|
||||||
LYRICS.__init__(song.lyrics)
|
LYRICS.__init__(id)
|
||||||
|
|
||||||
layer.toast('歌词应用成功...')
|
layer.toast('歌词应用成功...')
|
||||||
|
|
||||||
|
|
|
@ -9,21 +9,14 @@
|
||||||
import Api from '/js/api.js'
|
import Api from '/js/api.js'
|
||||||
import { ID3 } from '/lib/audio/index.js'
|
import { ID3 } from '/lib/audio/index.js'
|
||||||
|
|
||||||
const fs = require('iofs')
|
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const crypto = require('crypto.js')
|
const crypto = require('crypto.js')
|
||||||
const { app, dialog } = require('electron').remote
|
const { remote, ipcRenderer } = require('electron')
|
||||||
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
const HOME_PATH = app.getPath('appData')
|
|
||||||
const MUSIC_DB_PATH = path.join(HOME_PATH, 'music.db')
|
|
||||||
const LYRICS_PATH = path.join(HOME_PATH, 'lyrics')
|
|
||||||
|
|
||||||
const SUPPORTED_EXTS = ['.mp3', '.webm', '.ogg', '.flac', '.m4a', '.aac']
|
|
||||||
|
|
||||||
let appInit = {}
|
let appInit = {}
|
||||||
let dbCache = fs.cat(MUSIC_DB_PATH)
|
let dbCache = []
|
||||||
dbCache = JSON.parse(dbCache)
|
|
||||||
|
|
||||||
export default Anot({
|
export default Anot({
|
||||||
$id: 'local',
|
$id: 'local',
|
||||||
|
@ -40,8 +33,10 @@ export default Anot({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
LS.insert(dbCache)
|
|
||||||
appInit = JSON.parse(Anot.ss('app-init'))
|
appInit = JSON.parse(Anot.ss('app-init'))
|
||||||
|
dbCache = ipcRenderer.sendSync('get-music')
|
||||||
|
|
||||||
|
LS.insert(dbCache)
|
||||||
|
|
||||||
dbCache = null
|
dbCache = null
|
||||||
this.__APP__ = Anot.vmodels.app
|
this.__APP__ = Anot.vmodels.app
|
||||||
|
@ -78,12 +73,6 @@ export default Anot({
|
||||||
if (!it.cover) {
|
if (!it.cover) {
|
||||||
if (idx === undefined) {
|
if (idx === undefined) {
|
||||||
idx = SONIST.__CURR__
|
idx = SONIST.__CURR__
|
||||||
// for (let i in this.list.$model) {
|
|
||||||
// if (this.list[i].id === it.id) {
|
|
||||||
// idx = i
|
|
||||||
// break
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
let _P = Promise.resolve(true)
|
let _P = Promise.resolve(true)
|
||||||
if (!it.kgHash) {
|
if (!it.kgHash) {
|
||||||
|
@ -105,7 +94,6 @@ export default Anot({
|
||||||
it.albumId = json.album_id
|
it.albumId = json.album_id
|
||||||
it.kgHash = json.hash
|
it.kgHash = json.hash
|
||||||
it.cover = json.img
|
it.cover = json.img
|
||||||
it.lyrics = path.join(LYRICS_PATH, `${it.id}.lrc`)
|
|
||||||
|
|
||||||
LS.insert(it)
|
LS.insert(it)
|
||||||
this.list.set(idx, it)
|
this.list.set(idx, it)
|
||||||
|
@ -116,10 +104,13 @@ export default Anot({
|
||||||
this.__APP__.updateCurr(it)
|
this.__APP__.updateCurr(it)
|
||||||
this.__APP__.draw(true)
|
this.__APP__.draw(true)
|
||||||
|
|
||||||
fs.echo(json.lyrics, it.lyrics)
|
ipcRenderer.send('save-lrc', {
|
||||||
fs.echo(JSON.stringify(LS.getAll(), '', 2), MUSIC_DB_PATH)
|
id: it.id,
|
||||||
|
lrc: json.lyrics
|
||||||
|
})
|
||||||
|
ipcRenderer.send('set-music', LS.getAll())
|
||||||
|
|
||||||
LYRICS.__init__(it.lyrics)
|
LYRICS.__init__(it.id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -144,7 +135,7 @@ export default Anot({
|
||||||
SONIST.clear()
|
SONIST.clear()
|
||||||
SONIST.push(dbCache)
|
SONIST.push(dbCache)
|
||||||
|
|
||||||
fs.echo(JSON.stringify(dbCache, '', 2), MUSIC_DB_PATH)
|
ipcRenderer.send('set-music', dbCache)
|
||||||
dbCache = null
|
dbCache = null
|
||||||
|
|
||||||
layer.toast(`刷新缓存完成,新增${this.__NEW_NUM__}首`)
|
layer.toast(`刷新缓存完成,新增${this.__NEW_NUM__}首`)
|
||||||
|
@ -160,6 +151,7 @@ export default Anot({
|
||||||
let item = LS.get(hash)
|
let item = LS.get(hash)
|
||||||
if (item) {
|
if (item) {
|
||||||
item.path = `file://${song}`
|
item.path = `file://${song}`
|
||||||
|
delete item.lyrics
|
||||||
LS.update(hash, item)
|
LS.update(hash, item)
|
||||||
return this.__checkSong__(el)
|
return this.__checkSong__(el)
|
||||||
}
|
}
|
||||||
|
@ -182,22 +174,12 @@ export default Anot({
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (appInit.musicPath) {
|
if (appInit.musicPath) {
|
||||||
if (fs.isdir(appInit.musicPath)) {
|
this.__LIST__ = ipcRenderer.sendSync('scan-dir', appInit.musicPath)
|
||||||
|
if (this.__LIST__) {
|
||||||
this.__APP__.loading = true
|
this.__APP__.loading = true
|
||||||
|
|
||||||
this.__LIST__ = fs.ls(appInit.musicPath, true).filter(_ => {
|
|
||||||
if (fs.isdir(_)) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
let { ext, name } = path.parse(_)
|
|
||||||
if (!ext || name.startsWith('.')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return SUPPORTED_EXTS.includes(ext)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.__WAIT_FOR_SCAN__ = this.__LIST__.length
|
this.__WAIT_FOR_SCAN__ = this.__LIST__.length
|
||||||
this.__NEW_NUM__ = 0
|
this.__NEW_NUM__ = 0
|
||||||
|
|
||||||
ev.target.textContent = '正在扫描, 请稍候...'
|
ev.target.textContent = '正在扫描, 请稍候...'
|
||||||
this.__checkSong__(ev.target)
|
this.__checkSong__(ev.target)
|
||||||
} else {
|
} else {
|
||||||
|
@ -238,7 +220,7 @@ export default Anot({
|
||||||
SONIST.clear()
|
SONIST.clear()
|
||||||
SONIST.push(LS.getAll())
|
SONIST.push(LS.getAll())
|
||||||
|
|
||||||
fs.echo(JSON.stringify(LS.getAll(), '', 2), MUSIC_DB_PATH)
|
ipcRenderer.send('set-music', LS.getAll())
|
||||||
},
|
},
|
||||||
handleMenu(it, idx, ev) {
|
handleMenu(it, idx, ev) {
|
||||||
let that = this
|
let that = this
|
||||||
|
@ -281,7 +263,7 @@ export default Anot({
|
||||||
SONIST.clear()
|
SONIST.clear()
|
||||||
SONIST.push(LS.getAll())
|
SONIST.push(LS.getAll())
|
||||||
|
|
||||||
fs.echo(JSON.stringify(LS.getAll(), '', 2), MUSIC_DB_PATH)
|
ipcRenderer.send('set-music', LS.getAll())
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,17 +8,14 @@
|
||||||
|
|
||||||
import '/lib/form/index.js'
|
import '/lib/form/index.js'
|
||||||
|
|
||||||
const fs = require('iofs')
|
const {
|
||||||
const path = require('path')
|
remote: { app, dialog },
|
||||||
const { app, dialog } = require('electron').remote
|
ipcRenderer
|
||||||
|
} = require('electron')
|
||||||
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
|
|
||||||
const HOME_PATH = app.getPath('appData')
|
let appInit = ipcRenderer.sendSync('get-init')
|
||||||
const APP_INI_PATH = path.join(HOME_PATH, 'app.ini')
|
|
||||||
|
|
||||||
let appInit = fs.cat(APP_INI_PATH)
|
|
||||||
|
|
||||||
appInit = JSON.parse(appInit)
|
|
||||||
|
|
||||||
export default Anot({
|
export default Anot({
|
||||||
$id: 'profile',
|
$id: 'profile',
|
||||||
|
@ -58,9 +55,9 @@ export default Anot({
|
||||||
|
|
||||||
Object.assign(appInit, setting)
|
Object.assign(appInit, setting)
|
||||||
|
|
||||||
let cache = JSON.stringify(appInit, '', 2)
|
ipcRenderer.send('set-init', appInit)
|
||||||
fs.echo(cache, APP_INI_PATH)
|
|
||||||
Anot.ss('app-init', cache)
|
Anot.ss('app-init', appInit)
|
||||||
|
|
||||||
layer.toast('保存成功')
|
layer.toast('保存成功')
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -7,13 +7,13 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const log = console.log
|
const log = console.log
|
||||||
const fs = require('iofs')
|
|
||||||
const { EventEmitter } = require('events')
|
const { EventEmitter } = require('events')
|
||||||
const util = require('util')
|
const util = require('util')
|
||||||
|
const { ipcRenderer } = require('electron')
|
||||||
|
|
||||||
class Lyrics {
|
class Lyrics {
|
||||||
// 歌词初始化
|
// 歌词初始化
|
||||||
__init__(lrcFile) {
|
__init__(id) {
|
||||||
this.lib = []
|
this.lib = []
|
||||||
this.curr = []
|
this.curr = []
|
||||||
this.lrc = {
|
this.lrc = {
|
||||||
|
@ -21,21 +21,16 @@ class Lyrics {
|
||||||
r: { bg: '', txt: '' }
|
r: { bg: '', txt: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lrcFile || !fs.exists(lrcFile)) {
|
let lrc = ipcRenderer.sendSync('read-lrc', id)
|
||||||
log('no lrc file', lrcFile)
|
if (!id || lrc === null) {
|
||||||
|
log('no lrc file', id)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.__LRC__ = lrcFile
|
this.__ID__ = id
|
||||||
|
|
||||||
// log(this.__LRC__)
|
|
||||||
|
|
||||||
let lrc = fs
|
|
||||||
.cat(lrcFile)
|
|
||||||
.toString('utf8')
|
|
||||||
.split('\n')
|
|
||||||
|
|
||||||
this.lib = lrc
|
this.lib = lrc
|
||||||
|
.split('\n')
|
||||||
.map(it => {
|
.map(it => {
|
||||||
if (it) {
|
if (it) {
|
||||||
let matches = it.match(/^\[([0-9\.\:]+)\](.+)/)
|
let matches = it.match(/^\[([0-9\.\:]+)\](.+)/)
|
||||||
|
@ -85,7 +80,7 @@ class Lyrics {
|
||||||
|
|
||||||
// 歌词向前调整指定时间
|
// 歌词向前调整指定时间
|
||||||
forward(time = 0) {
|
forward(time = 0) {
|
||||||
if (!this.__LRC__) {
|
if (!this.__ID__) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clearTimeout(this.__TIMER__)
|
clearTimeout(this.__TIMER__)
|
||||||
|
@ -109,7 +104,7 @@ class Lyrics {
|
||||||
|
|
||||||
// 延时3秒写入
|
// 延时3秒写入
|
||||||
this.__TIMER__ = setTimeout(() => {
|
this.__TIMER__ = setTimeout(() => {
|
||||||
fs.echo(lrc, this.__LRC__)
|
ipcRenderer.sendSync('save-lrc', { id: this.__ID__, lrc })
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
const __STORE__={};function parse$And(_){let t="";for(let e in _){let i=_[e];switch(Anot.type(i)){case"object":if(i.$has){t+=`it.${e}.indexOf(${JSON.stringify(i.$has)}) > -1`;break}if(i.$in){t+=`${JSON.stringify(i.$in)}.indexOf(it.${e}) > -1`;break}if(i.$regex){t+=`${i.$regex}.test(it.${e})`;break}if(i.$lt||i.$lte){t+=`it.${e} <${i.$lte?"=":""} ${i.$lt||i.$lte}`,(i.$gt||i.$gte)&&(t+=` && it.${e} >${i.$gte?"=":""} ${i.$gt||i.$gte}`);break}if(i.$gt||i.$gte){t+=`it.${e} >${i.$gte?"=":""} ${i.$gt||i.$gte}`;break}if(i.$eq){t+=`it.${e} === ${i.$eq}`;break}default:t+=`it.${e} === ${JSON.stringify(_[e])}`}t+=" && "}return(t=t.slice(0,-4))||(t="true"),t}function parse$Or(_){let t="";return _.forEach(_=>{t+="(",t+=parse$And(_),t+=") || "}),t.slice(0,-4)}class AnotStore{constructor(_){Anot.hideProperty(this,"__name__",_),Anot.hideProperty(this,"__LAST_QUERY__",""),Anot.hideProperty(this,"__QUERY_HISTORY__",[]),__STORE__[_]||(__STORE__[_]=[],__STORE__[`${_}Dict`]={})}static collection(_){return new this(_)}__MAKE_FN__(_){let t="\n let result = [];\n let num = 0;\n for (let it of arr) {\n if(";return _.$or?t+=parse$Or(_.$or):t+=parse$And(_),t+="){\n result.push(it)\n num++\n if(limit > 0 && num >= limit){\n break\n }\n }\n }\n return result;",Function("arr","limit",t)}clear(_){this.__QUERY_HISTORY__=[],this.__LAST_QUERY__="",_&&(__STORE__[this.__name__]=[],__STORE__[`${this.__name__}Dict`]={})}getAll({filter:_,limit:t=[]}={}){const e=__STORE__[this.__name__];let i=[],r=!1;if(!e||!e.length)return i;if(t.length<1&&(t=[0]),t.length<2&&_&&(r=!0,t[0]>0&&t.unshift(0)),_){let n=JSON.stringify(_);if(this.__LAST_QUERY__===n)i=this.__QUERY_HISTORY__.slice.apply(this.__QUERY_HISTORY__,t);else{i=this.__MAKE_FN__(_)(e,r&&t[1]||0),r||(this.__LAST_QUERY__=n,this.__QUERY_HISTORY__=i,i=this.__QUERY_HISTORY__.slice.apply(this.__QUERY_HISTORY__,t))}}else i=e.slice.apply(e,t);return Anot.deepCopy(i)}get(_){const t=__STORE__[`${this.__name__}Dict`];return Anot.deepCopy(t[_])||null}count({filter:_}={}){return _?this.__LAST_QUERY__===JSON.stringify(_)?this.__QUERY_HISTORY__.length:this.getAll({filter:_,limit:[0]}).length:__STORE__[this.__name__].length}__INSERT__(_,t){let e=__STORE__[this.__name__],i=__STORE__[`${this.__name__}Dict`],r=_[t||"id"];i[r]?this.update(r,_):(e.push(_),i[r]=_)}insert(_,t){Array.isArray(_)||(_=[_]),_.forEach(_=>{this.__INSERT__(_,t)}),this.clear()}sort(_,t,e){let i="";t&&window.Intl&&(i+="\n let col = new Intl.Collator('zh')\n "),i+=e?"return arr.sort((b, a) => {":"return arr.sort((a, b) => {",i+=`\n let filter = function(val) {\n try {\n return val.${_} || ''\n } catch (err) {\n return ''\n }\n }\n `,t?window.Intl?i+="return col.compare(filter(a), filter(b))":i+="return (filter(a) + '').localeCompare(filter(b), 'zh')":i+="return filter(a) - filter(b)",i+="\n})",Function("arr",i).call(this,__STORE__[this.__name__]),this.clear()}update(_,t){let e=__STORE__[this.__name__],i=__STORE__[`${this.__name__}Dict`],r=i[_],n=e.indexOf(r);Object.assign(r,t),e.splice(n,1,r),i[_]=r}remove(_){let t=__STORE__[this.__name__],e=__STORE__[`${this.__name__}Dict`],i=e[_],r=t.indexOf(i);t.splice(r,1),delete e[_]}}Anot.store=window.store=AnotStore;export default AnotStore;
|
const __STORE__={};function parse$And(_){let t="";for(let e in _){let i=_[e];switch(Anot.type(i)){case"object":if(i.$has){t+=`it.${e}.indexOf(${JSON.stringify(i.$has)}) > -1`;break}if(i.$in){t+=`${JSON.stringify(i.$in)}.indexOf(it.${e}) > -1`;break}if(i.$regex){t+=`${i.$regex}.test(it.${e})`;break}if(i.$lt||i.$lte){t+=`it.${e} <${i.$lte?"=":""} ${i.$lt||i.$lte}`,(i.$gt||i.$gte)&&(t+=` && it.${e} >${i.$gte?"=":""} ${i.$gt||i.$gte}`);break}if(i.$gt||i.$gte){t+=`it.${e} >${i.$gte?"=":""} ${i.$gt||i.$gte}`;break}if(i.$eq){t+=`it.${e} === ${i.$eq}`;break}default:t+=`it.${e} === ${JSON.stringify(_[e])}`}t+=" && "}return(t=t.slice(0,-4))||(t="true"),t}function parse$Or(_){let t="";return _.forEach(_=>{t+="(",t+=parse$And(_),t+=") || "}),t.slice(0,-4)}class AnotStore{constructor(_){Anot.hideProperty(this,"__name__",_),Anot.hideProperty(this,"__LAST_QUERY__",""),Anot.hideProperty(this,"__QUERY_HISTORY__",[]),__STORE__[_]||(__STORE__[_]=[],__STORE__[`${_}Dict`]={})}static collection(_){return new this(_)}__MAKE_FN__(_){let t="\n let result = [];\n let num = 0;\n for (let it of arr) {\n if(";return _.$or?t+=parse$Or(_.$or):t+=parse$And(_),t+="){\n result.push(it)\n num++\n if(limit > 0 && num >= limit){\n break\n }\n }\n }\n return result;",Function("arr","limit",t)}clear(_){this.__QUERY_HISTORY__=[],this.__LAST_QUERY__="",_&&(__STORE__[this.__name__]=[],__STORE__[`${this.__name__}Dict`]={})}getAll({filter:_,limit:t=[]}={}){const e=__STORE__[this.__name__];let i=[],r=!1;if(!e||!e.length)return i;if(t.length<1&&(t=[0]),t.length<2&&_&&(r=!0,t[0]>0&&t.unshift(0)),_){let n=JSON.stringify(_);if(this.__LAST_QUERY__===n)i=this.__QUERY_HISTORY__.slice.apply(this.__QUERY_HISTORY__,t);else{i=this.__MAKE_FN__(_)(e,r&&t[1]||0),r||(this.__LAST_QUERY__=n,this.__QUERY_HISTORY__=i,i=this.__QUERY_HISTORY__.slice.apply(this.__QUERY_HISTORY__,t))}}else i=e.slice.apply(e,t);return Anot.deepCopy(i)}get(_){const t=__STORE__[`${this.__name__}Dict`];return Anot.deepCopy(t[_])||null}count({filter:_}={}){return _?this.__LAST_QUERY__===JSON.stringify(_)?this.__QUERY_HISTORY__.length:this.getAll({filter:_,limit:[0]}).length:__STORE__[this.__name__].length}__INSERT__(_,t){let e=__STORE__[this.__name__],i=__STORE__[`${this.__name__}Dict`],r=_[t||"id"];i[r]?this.update(r,_):(e.push(_),i[r]=_)}insert(_,t){Array.isArray(_)||(_=[_]),_.forEach(_=>{this.__INSERT__(_,t)}),this.clear()}sort(_,t,e){let i="";t&&window.Intl&&(i+="\n let col = new Intl.Collator('zh')\n "),i+=e?"return arr.sort((b, a) => {":"return arr.sort((a, b) => {",i+=`\n let filter = function(val) {\n try {\n return val.${_} || ''\n } catch (err) {\n return ''\n }\n }\n `,t?window.Intl?i+="return col.compare(filter(a), filter(b))":i+="return (filter(a) + '').localeCompare(filter(b), 'zh')":i+="return filter(a) - filter(b)",i+="\n})",Function("arr",i).call(this,__STORE__[this.__name__]),this.clear()}update(_,t){let e=__STORE__[this.__name__],i=__STORE__[`${this.__name__}Dict`],r=i[_],n=e.indexOf(r);e.splice(n,1,t),i[_]=t}remove(_){let t=__STORE__[this.__name__],e=__STORE__[`${this.__name__}Dict`],i=e[_],r=t.indexOf(i);t.splice(r,1),delete e[_]}}Anot.store=window.store=AnotStore;export default AnotStore;
|
105
src/main.js
105
src/main.js
|
@ -22,112 +22,55 @@ const MIME_TYPES = {
|
||||||
'.ico': 'image/ico'
|
'.ico': 'image/ico'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require('./tools/init')
|
||||||
const createTray = require('./tools/tray')
|
const createTray = require('./tools/tray')
|
||||||
const createMenu = require('./tools/menu')
|
const createMenu = require('./tools/menu')
|
||||||
|
const {
|
||||||
|
createMainWindow,
|
||||||
|
createErrorWindow,
|
||||||
|
createDesktopLrcWindow,
|
||||||
|
createMiniWindow
|
||||||
|
} = require('./tools/windows')
|
||||||
|
|
||||||
/* ******************************* */
|
app.windows = { createDesktopLrcWindow, createMiniWindow }
|
||||||
/* **********修复环境变量*********** */
|
|
||||||
/* ******************************* */
|
|
||||||
let PATH_SET = new Set()
|
|
||||||
process.env.PATH.split(':').forEach(_ => {
|
|
||||||
PATH_SET.add(_)
|
|
||||||
})
|
|
||||||
PATH_SET.add('/usr/local/bin')
|
|
||||||
PATH_SET.add('/usr/local/sbin')
|
|
||||||
|
|
||||||
process.env.PATH = Array.from(PATH_SET).join(':')
|
|
||||||
PATH_SET = null
|
|
||||||
|
|
||||||
const ROOT = __dirname
|
const ROOT = __dirname
|
||||||
const HOME = app.getPath('home')
|
|
||||||
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
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')
|
||||||
|
|
||||||
app.setPath('appData', path.resolve(HOME, '.sonist/'))
|
|
||||||
protocol.registerStandardSchemes(['app'], { secure: true })
|
protocol.registerStandardSchemes(['app'], { secure: true })
|
||||||
|
|
||||||
let appPath = app.getPath('appData')
|
|
||||||
if (!fs.exists(appPath)) {
|
|
||||||
fs.mkdir(appPath)
|
|
||||||
fs.mkdir(path.join(appPath, 'lyrics'))
|
|
||||||
fs.mkdir(path.join(appPath, 'cache'))
|
|
||||||
fs.echo('{}', path.join(appPath, 'app.ini'))
|
|
||||||
fs.echo('[]', path.join(appPath, 'music.db'))
|
|
||||||
}
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
function createWindow() {
|
// 初始化应用
|
||||||
// 创建浏览器窗口
|
|
||||||
let win = new BrowserWindow({
|
|
||||||
title: 'sonist',
|
|
||||||
width: 1024,
|
|
||||||
height: 640,
|
|
||||||
frame: false,
|
|
||||||
resizable: false,
|
|
||||||
icon: path.resolve(ROOT, './images/app.png'),
|
|
||||||
webPreferences: {
|
|
||||||
webSecurity: false,
|
|
||||||
experimentalFeatures: true
|
|
||||||
},
|
|
||||||
show: false
|
|
||||||
})
|
|
||||||
|
|
||||||
// 然后加载应用的 index.html。
|
|
||||||
|
|
||||||
win.loadURL('app://local/index.html')
|
|
||||||
|
|
||||||
win.on('ready-to-show', _ => {
|
|
||||||
win.show()
|
|
||||||
win.openDevTools()
|
|
||||||
})
|
|
||||||
|
|
||||||
return win
|
|
||||||
}
|
|
||||||
/* ****************************************** */
|
|
||||||
/* ************* init ******************* */
|
|
||||||
/* ****************************************** */
|
|
||||||
|
|
||||||
// 创建窗口
|
|
||||||
app.once('ready', () => {
|
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(ROOT, file))
|
||||||
cb({ data: buff, mimeType: MIME_TYPES[ext] })
|
cb({ data: buff, mimeType: MIME_TYPES[ext] })
|
||||||
})
|
})
|
||||||
|
// 修改app的UA
|
||||||
|
session.defaultSession.setUserAgent(
|
||||||
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
|
||||||
|
)
|
||||||
|
|
||||||
|
// 判断依赖
|
||||||
exec('which ffprobe', (err, res) => {
|
exec('which ffprobe', (err, res) => {
|
||||||
if (res) {
|
if (res) {
|
||||||
session.defaultSession.setUserAgent(
|
let win = createMainWindow(path.resolve(ROOT, './images/app.png'))
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'
|
|
||||||
)
|
|
||||||
|
|
||||||
let win = createWindow()
|
|
||||||
|
|
||||||
createTray(win)
|
createTray(win)
|
||||||
createMenu(win)
|
createMenu(win)
|
||||||
|
// mac专属事件,点击dock栏图标,可激活窗口
|
||||||
|
app.on('activate', _ => {
|
||||||
|
if (win) {
|
||||||
|
win.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
win = new BrowserWindow({
|
createErrorWindow()
|
||||||
width: 600,
|
|
||||||
height: 360,
|
|
||||||
skipTaskbar: true,
|
|
||||||
maximizable: false,
|
|
||||||
minimizable: false,
|
|
||||||
resizable: false,
|
|
||||||
titleBarStyle: 'hiddenInset'
|
|
||||||
})
|
|
||||||
win.setMenuBarVisibility(false)
|
|
||||||
win.loadURL('app://local/depends.html')
|
|
||||||
win.on('closed', _ => {
|
|
||||||
app.exit()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('activate', _ => {
|
|
||||||
if (win) {
|
|
||||||
win.show()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/**
|
||||||
|
* 配置/DB通讯
|
||||||
|
* @author yutent<yutent@doui.cc>
|
||||||
|
* @date 2019/01/26 18:11:26
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { app, ipcMain } = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const fs = require('iofs')
|
||||||
|
|
||||||
|
/* ********** 修复环境变量 start *********** */
|
||||||
|
let PATH_SET = new Set()
|
||||||
|
process.env.PATH.split(':').forEach(_ => {
|
||||||
|
PATH_SET.add(_)
|
||||||
|
})
|
||||||
|
PATH_SET.add('/usr/local/bin')
|
||||||
|
PATH_SET.add('/usr/local/sbin')
|
||||||
|
|
||||||
|
process.env.PATH = Array.from(PATH_SET).join(':')
|
||||||
|
PATH_SET = null
|
||||||
|
|
||||||
|
/* ********** 修复环境变量 end *********** */
|
||||||
|
|
||||||
|
const HOME = app.getPath('home')
|
||||||
|
|
||||||
|
const APP_ROOT = path.resolve(HOME, '.sonist/')
|
||||||
|
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')
|
||||||
|
|
||||||
|
if (!fs.exists(APP_ROOT)) {
|
||||||
|
fs.mkdir(APP_ROOT)
|
||||||
|
fs.mkdir(LRC_DIR)
|
||||||
|
fs.mkdir(CACHE_DIR)
|
||||||
|
fs.echo('{}', INIT_FILE)
|
||||||
|
fs.echo('[]', DB_FILE)
|
||||||
|
}
|
||||||
|
const SUPPORTED_EXTS = ['.mp3', '.webm', '.ogg', '.flac', '.m4a', '.aac']
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------- */
|
||||||
|
/* --------------------- 事件开始 ------------------------- */
|
||||||
|
/* ---------------------------------------------------------------- */
|
||||||
|
|
||||||
|
// 获取应用配置
|
||||||
|
ipcMain.on('get-init', (ev, val) => {
|
||||||
|
let cache = fs.cat(INIT_FILE).toString('utf-8')
|
||||||
|
cache = JSON.parse(cache)
|
||||||
|
ev.returnValue = cache
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置应用配置
|
||||||
|
ipcMain.on('set-init', (ev, val) => {
|
||||||
|
fs.echo(JSON.stringify(val), INIT_FILE)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取音乐数据库
|
||||||
|
ipcMain.on('get-music', (ev, val) => {
|
||||||
|
let cache = fs.cat(DB_FILE).toString('utf-8')
|
||||||
|
cache = JSON.parse(cache)
|
||||||
|
ev.returnValue = cache
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新音乐数据库
|
||||||
|
ipcMain.on('set-music', (ev, val) => {
|
||||||
|
fs.echo(JSON.stringify(val), DB_FILE)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存歌词文件
|
||||||
|
*/
|
||||||
|
ipcMain.on('save-lrc', (ev, obj) => {
|
||||||
|
fs.echo(obj.lrc, path.join(LRC_DIR, `${obj.id}.lrc`))
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取歌词文件
|
||||||
|
*/
|
||||||
|
ipcMain.on('read-lrc', (ev, id) => {
|
||||||
|
let file = path.join(LRC_DIR, `${id}.lrc`)
|
||||||
|
if (fs.exists(file)) {
|
||||||
|
ev.returnValue = fs.cat(file).toString('utf8')
|
||||||
|
} else {
|
||||||
|
ev.returnValue = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存音乐文件
|
||||||
|
*/
|
||||||
|
ipcMain.on('save-cache', (ev, obj) => {
|
||||||
|
fs.echo(obj.data, path.join(CACHE_DIR, obj.file))
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扫描目录
|
||||||
|
*/
|
||||||
|
ipcMain.on('scan-dir', (ev, dir) => {
|
||||||
|
if (fs.isdir(dir)) {
|
||||||
|
let list = fs.ls(dir, true).filter(_ => {
|
||||||
|
if (fs.isdir(_)) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
let { ext, name } = path.parse(_)
|
||||||
|
if (!ext || name.startsWith('.')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return SUPPORTED_EXTS.includes(ext)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ev.returnValue = list
|
||||||
|
} else {
|
||||||
|
ev.returnValue = null
|
||||||
|
}
|
||||||
|
})
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* 各种窗口创建
|
||||||
|
* @author yutent<yutent@doui.cc>
|
||||||
|
* @date 2019/01/26 18:28:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const { BrowserWindow } = require('electron')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用主窗口
|
||||||
|
*/
|
||||||
|
exports.createMainWindow = function(icon) {
|
||||||
|
// 创建浏览器窗口
|
||||||
|
let win = new BrowserWindow({
|
||||||
|
title: 'sonist',
|
||||||
|
width: 1024,
|
||||||
|
height: 640,
|
||||||
|
frame: false,
|
||||||
|
resizable: false,
|
||||||
|
icon,
|
||||||
|
webPreferences: {
|
||||||
|
webSecurity: false,
|
||||||
|
experimentalFeatures: true
|
||||||
|
},
|
||||||
|
show: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// 然后加载应用的 index.html。
|
||||||
|
|
||||||
|
win.loadURL('app://local/index.html')
|
||||||
|
|
||||||
|
win.on('ready-to-show', _ => {
|
||||||
|
win.show()
|
||||||
|
win.openDevTools()
|
||||||
|
})
|
||||||
|
|
||||||
|
return win
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 依赖异常显示窗口
|
||||||
|
*/
|
||||||
|
exports.createErrorWindow = function() {
|
||||||
|
let win = new BrowserWindow({
|
||||||
|
width: 600,
|
||||||
|
height: 360,
|
||||||
|
skipTaskbar: true,
|
||||||
|
maximizable: false,
|
||||||
|
minimizable: false,
|
||||||
|
resizable: false,
|
||||||
|
titleBarStyle: 'hiddenInset'
|
||||||
|
})
|
||||||
|
win.setMenuBarVisibility(false)
|
||||||
|
win.loadURL('app://local/depends.html')
|
||||||
|
win.on('closed', _ => {
|
||||||
|
app.exit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 桌面歌词窗口
|
||||||
|
*/
|
||||||
|
exports.createDesktopLrcWindow = function(screen) {
|
||||||
|
let win = new BrowserWindow({
|
||||||
|
title: '',
|
||||||
|
width: 1024,
|
||||||
|
height: 100,
|
||||||
|
frame: false,
|
||||||
|
resizable: false,
|
||||||
|
alwaysOnTop: true,
|
||||||
|
x: (screen.size.width - 1024) / 2,
|
||||||
|
y: screen.size.height - 100,
|
||||||
|
skipTaskbar: true,
|
||||||
|
hasShadow: false,
|
||||||
|
thickFrame: false,
|
||||||
|
transparent: true,
|
||||||
|
show: false
|
||||||
|
})
|
||||||
|
|
||||||
|
win.loadURL('app://local/desktop-lrc.html')
|
||||||
|
return win
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用迷你窗口
|
||||||
|
*/
|
||||||
|
exports.createMiniWindow = function(screen) {
|
||||||
|
let win = new BrowserWindow({
|
||||||
|
title: '',
|
||||||
|
width: 320,
|
||||||
|
height: 60,
|
||||||
|
frame: false,
|
||||||
|
resizable: false,
|
||||||
|
alwaysOnTop: true,
|
||||||
|
x: screen.size.width - 320,
|
||||||
|
y: 0,
|
||||||
|
skipTaskbar: true,
|
||||||
|
show: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// win.loadURL('http://127.0.0.1:10240/mini-win.html')
|
||||||
|
win.loadURL('app://local/mini-win.html')
|
||||||
|
return win
|
||||||
|
}
|
Reference in New Issue