diff --git a/src/js/app.js b/src/js/app.js index 78af4df..7d6591a 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -138,6 +138,19 @@ Anot({ this.playSong(idx, repeat) }) + + window.foo = _ => { + var n = 128, + t + t = setInterval(() => { + n-- + this.play(1) + if (n < 0) { + clearInterval(t) + } + }, 100) + } + // foo() }, watch: { volume(v) { diff --git a/src/js/lib/audio/index.js b/src/js/lib/audio/index.js index a937091..9cf7f73 100644 --- a/src/js/lib/audio/index.js +++ b/src/js/lib/audio/index.js @@ -19,10 +19,54 @@ function hide(target, key, value) { }) } +class AudioTrack { + constructor(elem) { + var AC = new AudioContext() + + this._el = elem + + this.gain = AC.createGain() + + this._track = AC.createMediaElementSource(elem) + .connect(this.gain) + .connect(AC.destination) + + this.__playFn = $.bind(elem, 'timeupdate', _ => { + this.emit('play', elem.currentTime) + }) + this.__stopFn = $.bind(elem, 'ended', _ => { + this.emit('stop') + }) + } + + set volume(val) { + if (this.gain) { + this.gain.gain.value = val + } + } + + destroy() { + $.unbind(this._el, 'timeupdate', this.__playFn) + $.unbind(this._el, 'ended', this.__stopFn) + this.removeAllListeners() + + this._track.disconnect() + + this._el.src = '' + this._el.currentTime = 0 + this._el.pause() + + delete this.__playFn + delete this.__stopFn + delete this._el + delete this.gain + delete this._track + } +} + export default class Player { constructor() { hide(this, '__LIST__', []) - hide(this, '__AC__', new AudioContext()) hide(this, 'props', { curr: '', stat: 'ready', @@ -30,32 +74,6 @@ export default class Player { duration: 0 }) hide(this, 'track', null) - hide(this, 'gain', null) - - this.__main__() - } - - __main__() { - hide(this, '__AUDIO__', new Audio()) - - this.__playFn = $.bind(this.__AUDIO__, 'timeupdate', _ => { - this.emit('play', this.__AUDIO__.currentTime) - }) - this.__stopFn = $.bind(this.__AUDIO__, 'ended', _ => { - this.props.stat = 'paused' - this.emit('stop') - }) - } - - __destroy__() { - $.unbind(this.__AUDIO__, 'timeupdate', this.__playFn) - $.unbind(this.__AUDIO__, 'ended', this.__stopFn) - - this.__AUDIO__.pause() - this.__AUDIO__.currentTime = 0 - - delete this.__playFn - delete this.__stopFn } load(list) { @@ -64,18 +82,17 @@ export default class Player { } async _getTrack(file) { - this.__main__() + hide(this, '__AUDIO__', new Audio()) + this.__AUDIO__.src = URL.createObjectURL( await fetch(file).then(r => r.blob()) ) - this.gain = this.__AC__.createGain() - this.gain.gain.value = this.volume + this.track = new AudioTrack(this.__AUDIO__) + this.track.volume = this.props.volume - this.track = this.__AC__ - .createMediaElementSource(this.__AUDIO__) - .connect(this.gain) - .connect(this.__AC__.destination) + this.track.on('play', t => this.emit('play', t)) + this.track.on('stop', _ => this.emit('stop')) } get volume() { @@ -91,8 +108,8 @@ export default class Player { val = 1 } this.props.volume = val - if (this.gain) { - this.gain.gain.value = val + if (this.track) { + this.track.volume = val } } @@ -108,7 +125,7 @@ export default class Player { * id: 歌曲序号 * force: 强制重新播放 */ - play(id, force = false) { + async play(id, force = false) { if (id === -1) { if (this.track) { if (force) { @@ -134,7 +151,7 @@ export default class Player { } this.props.curr = url - this._getTrack(url) + await this._getTrack(url) this.__AUDIO__.play() this.props.stat = 'playing' @@ -149,13 +166,11 @@ export default class Player { stop() { if (this.track) { - this.track.disconnect() - this.track = null - this.gain = null - this.__destroy__() + this.track.destroy() this.props.stat = 'stoped' } } } +util.inherits(AudioTrack, EventEmitter) util.inherits(Player, EventEmitter) diff --git a/src/main.js b/src/main.js index 2f10992..dd6b884 100644 --- a/src/main.js +++ b/src/main.js @@ -45,17 +45,30 @@ protocol.registerSchemesAsPrivileged([ // 初始化应用 app.once('ready', () => { // 注册协议 - protocol.registerBufferProtocol('app', function (req, cb) { + protocol.registerStreamProtocol('app', function(req, cb) { var file = decodeURIComponent(req.url.replace(/^app:\/\/local\//, '')) var ext = path.extname(req.url) - var buff = fs.cat(path.resolve(__dirname, file)) - cb({ data: buff, mimeType: MIME_TYPES[ext] }) + file = path.resolve(__dirname, file) + + cb({ + data: fs.origin.createReadStream(file), + mimeType: MIME_TYPES[ext], + headers: { + 'Cache-Control': 'max-age=144000000' + } + }) }) - protocol.registerBufferProtocol('sonist', function (req, cb) { + protocol.registerStreamProtocol('sonist', function(req, cb) { var file = decodeURIComponent(req.url.replace(/^sonist:[\/]+/, '/')) var ext = path.extname(req.url) - cb({ data: fs.cat(file), mimeType: MIME_TYPES[ext] || MIME_TYPES.all }) + cb({ + data: fs.origin.createReadStream(file), + mimeType: MIME_TYPES[ext] || MIME_TYPES.all, + headers: { + 'Cache-Control': 'max-age=144000000' + } + }) }) // 修改app的UA session.defaultSession.setUserAgent( diff --git a/src/tools/windows.js b/src/tools/windows.js index 0a86d18..1d91495 100644 --- a/src/tools/windows.js +++ b/src/tools/windows.js @@ -12,7 +12,7 @@ const createMenu = require('./menu.js') /** * 应用主窗口 */ -exports.createMainWindow = function (icon) { +exports.createMainWindow = function(icon) { // 创建浏览器窗口 let win = new BrowserWindow({ title: 'sonist', @@ -46,7 +46,7 @@ exports.createMainWindow = function (icon) { win.on('ready-to-show', _ => { win.show() - // win.openDevTools() + win.openDevTools() }) win.on('close', ev => {