From b21ec9117006b865ac423b9a4bbc10501cd8fa3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=87=E5=A4=A9?= Date: Thu, 19 Nov 2020 20:49:53 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=9F=B3=E9=A2=91=E6=92=AD?= =?UTF-8?q?=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/app.js | 17 +- src/js/lib/audio/index.js | 326 ++++++++++++--------------------- src/js/lib/audio/old.js | 183 ++++++++++++++++++ src/js/lib/drag/doc.md | 85 --------- src/js/lib/fetch/index.js | 1 + src/js/lib/fetch/lib/format.js | 1 + src/js/lib/fetch/next.js | 1 + src/main.js | 21 ++- 8 files changed, 339 insertions(+), 296 deletions(-) create mode 100644 src/js/lib/audio/old.js delete mode 100644 src/js/lib/drag/doc.md create mode 100644 src/js/lib/fetch/index.js create mode 100644 src/js/lib/fetch/lib/format.js create mode 100644 src/js/lib/fetch/next.js diff --git a/src/js/app.js b/src/js/app.js index ade805d..441251c 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -9,12 +9,19 @@ import '/js/lib/scroll/index.js' import Keyboard from '/js/lib/keyboard/index.js' import app from '/js/lib/socket.js' +import fetch from '/js/lib/fetch/index.js' + +import Player from '/js/lib/audio/index.js' -// const id3 = require('jsmediatags') const id3 = require('music-metadata') var kb = new Keyboard() +var player = new Player() + +window.fetch = fetch +window.player = player + Anot({ $id: 'app', state: { @@ -52,6 +59,8 @@ Anot({ it.duration = duration } + player.load(list.map(it => `sonist://${it.path}`)) + kb.on(['left'], ev => { var time = this.song.time - 5 if (time < 0) { @@ -68,6 +77,12 @@ Anot({ }) }, methods: { + load() { + // window.player = new Howl({ + // src: [`sonist://${this.list[0].path}`] + // }) + // window.player = this.__PLAYER__ + }, play() { this.isplaying = !this.isplaying }, diff --git a/src/js/lib/audio/index.js b/src/js/lib/audio/index.js index 96878fd..881a73c 100644 --- a/src/js/lib/audio/index.js +++ b/src/js/lib/audio/index.js @@ -1,214 +1,126 @@ /** - * 播放器 - * @author yutent - * @date 2018/12/23 23:14:40 + * + * @author yutent + * @date 2020/11/19 17:32:19 */ -'use strict' +import fetch from '../fetch/index.js' -const { exec } = require('child_process') -const { EventEmitter } = require('events') -const util = require('util') -const path = require('path') - -class AudioPlayer { - constructor() { - this.__PLAYER__ = new Audio() - this.__IS_PLAYED__ = false - this.__CURR__ = -1 // 当前播放的歌曲的id - this.__LIST__ = [] //播放列表 - this.__PLAY_MODE__ = 'all' // all | single | random - this.__PLAYER__.volume = 0.7 - - this.__init__() - } - - __init__() { - this.__PLAYER__.addEventListener( - 'timeupdate', - _ => { - this.emit('play', this.__PLAYER__.currentTime) - }, - false - ) - - this.__PLAYER__.addEventListener( - 'ended', - _ => { - this.emit('end') - }, - false - ) - } - - get stat() { - return this.__LIST__.length ? 'ready' : 'stop' - } - - get IS_MUTED() { - return this.__PLAYER__.muted - } - - set volume(val) { - this.__PLAYER__.muted = false - this.__PLAYER__.volume = val / 100 - } - - set mode(val = 'all') { - this.__PLAY_MODE__ = val - } - - clear() { - this.__LIST__ = [] - } - - push(songs) { - this.__LIST__.push.apply(this.__LIST__, songs) - } - - getCurrSong() { - if (this.__CURR__ > -1) { - return this.__LIST__[this.__CURR__] - } - return null - } - - // 上一首 - prev() { - let id = this.__CURR__ - - switch (this.__PLAY_MODE__) { - case 'all': - id-- - if (id < 0) { - id = this.__LIST__.length - 1 - } - break - case 'random': - id = (Math.random() * this.__LIST__.length) >>> 0 - break - // single - default: - break - } - - this.play(id) - return Promise.resolve(this.__LIST__[id]) - } - - // 下一首 - next() { - let id = this.__CURR__ - - switch (this.__PLAY_MODE__) { - case 'all': - id++ - if (id >= this.__LIST__.length) { - id = 0 - } - break - case 'random': - id = (Math.random() * this.__LIST__.length) >>> 0 - break - // single - default: - break - } - - this.play(id) - return Promise.resolve(this.__LIST__[id]) - } - - // 播放 - play(id) { - // 播放列表里没有数据的话, 不作任何处理 - if (!this.__LIST__.length) { - return Promise.reject(this.__LIST__) - } - - // 有ID的话,不管之前是否在播放,都切换歌曲 - if (id !== undefined) { - let song = this.__LIST__[id] - if (song) { - this.__CURR__ = id - this.__IS_PLAYED__ = true - - this.__PLAYER__.pause() - this.__PLAYER__.currentTime = 0 - this.__PLAYER__.src = song.path - this.__PLAYER__.play() - - Anot.ls('last-play', id) - return Promise.resolve(song) - } - return Promise.reject('song not found') - } else { - if (!this.__IS_PLAYED__) { - this.__IS_PLAYED__ = true - this.__PLAYER__.play() - } - return Promise.resolve(true) - } - } - - // 暂停 - pause() { - if (!this.__IS_PLAYED__) { - return - } - this.__IS_PLAYED__ = false - - this.__PLAYER__.pause() - } - - // 切换静音 - mute() { - if (this.__CURR__ < 0) { - return false - } - this.__PLAYER__.muted = !this.__PLAYER__.muted - return this.__PLAYER__.muted - } - - // 跳到指定位置播放 - seek(time) { - if (this.__CURR__ < 0) { - return - } - this.__PLAYER__.currentTime = time - } -} - -util.inherits(AudioPlayer, EventEmitter) - -export const ID3 = song => { - let cmd = `ffprobe -v quiet -print_format json -show_entries format "${song}"` - let pc = exec(cmd) - let buf = '' - return new Promise((resolve, reject) => { - pc.stdout.on('data', _ => { - buf += _ - }) - - pc.stderr.on('data', reject) - - pc.stdout.on('close', _ => { - try { - let { format } = JSON.parse(buf) - let name = path.basename(song) - format.tags = format.tags || {} - resolve({ - title: format.tags.TITLE || format.tags.title || name, - album: format.tags.ALBUM || format.tags.album || '', - artist: format.tags.ARTIST || format.tags.artist || '', - duration: Math.ceil(format.duration), - size: +(format.size / 1024 / 1024).toFixed(2) - }) - } catch (err) { - reject(err) - } - }) +function hide(target, key, value) { + Object.defineProperty(target, key, { + value, + writable: true, + enumerable: false, + configurable: true }) } -export default AudioPlayer +export default class Player { + constructor() { + hide(this, '__LIST__', []) + hide(this, '__AC__', new AudioContext()) + hide(this, '__AUDIO__', new Audio()) + hide(this, 'props', { + curr: '', + stat: 'ready', + volume: 0.5, + mode: 'all', // 循环模式, all, single, rand + time: 0, + duration: 0 + }) + hide(this, 'track', null) + } + + load(list) { + this.stop() + this.__LIST__ = list + } + + async _getTrack(file) { + this.__AUDIO__.src = URL.createObjectURL( + await fetch(file).then(r => r.blob()) + ) + console.log(this.__AUDIO__) + return this.__AC__.createMediaElementSource(this.__AUDIO__) + } + + get volume() { + return this.props.volume + } + + set volume(val) { + val = +val || 0.5 + if (val < 0) { + val = 0 + } + if (val > 1) { + val = 1 + } + this.props.volume = val + } + + get mode() { + return this.props.mode + } + + set mode(val) { + this.props.mode = val + } + + get time() { + return this.props.time + } + + get stat() { + return this.props.stat + } + + async play(id) { + var url, gain + + if (id === undefined) { + if (this.track) { + if (this.stat === 'playing') { + this.props.time = this.track.context.currentTime + this.__AUDIO__.pause() + this.props.stat = 'paused' + } else if (this.stat === 'paused') { + this.__AUDIO__.play() + this.props.stat = 'playing' + } + } + } else { + url = this.__LIST__[id] + if (!url || this.props.curr === url) { + return + } + + gain = this.__AC__.createGain() + + if (this.track) { + this.stop() + } + + gain.gain.value = this.volume + + this.track = await this._getTrack(url) + this.track.connect(gain).connect(this.__AC__.destination) + + this.__AUDIO__.play() + this.props.stat = 'playing' + } + } + + seek(time) { + this.props.time = time + } + + stop() { + if (this.track) { + this.__AUDIO__.pause() + this.track = null + this.props.time = 0 + this.props.stat = 'stoped' + } + } +} diff --git a/src/js/lib/audio/old.js b/src/js/lib/audio/old.js new file mode 100644 index 0000000..2c2c6cf --- /dev/null +++ b/src/js/lib/audio/old.js @@ -0,0 +1,183 @@ +/** + * 播放器 + * @author yutent + * @date 2018/12/23 23:14:40 + */ + +'use strict' + +const { EventEmitter } = require('events') +const util = require('util') +const path = require('path') + +class AudioPlayer { + constructor() { + this.__PLAYER__ = new Audio() + this.__IS_PLAYED__ = false + this.__CURR__ = -1 // 当前播放的歌曲的id + this.__LIST__ = [] //播放列表 + this.__PLAY_MODE__ = 'all' // all | single | random + this.__PLAYER__.volume = 0.7 + + this.__init__() + } + + __init__() { + this.__PLAYER__.addEventListener( + 'timeupdate', + _ => { + this.emit('play', this.__PLAYER__.currentTime) + }, + false + ) + + this.__PLAYER__.addEventListener( + 'ended', + _ => { + this.emit('stop') + }, + false + ) + } + + get stat() { + return this.__LIST__.length ? 'ready' : 'stop' + } + + get IS_MUTED() { + return this.__PLAYER__.muted + } + + set volume(val) { + this.__PLAYER__.muted = false + this.__PLAYER__.volume = val / 100 + } + + set mode(val = 'all') { + this.__PLAY_MODE__ = val + } + + clear() { + this.__LIST__ = [] + } + + push(songs) { + this.__LIST__.push.apply(this.__LIST__, songs) + } + + getCurrSong() { + if (this.__CURR__ > -1) { + return this.__LIST__[this.__CURR__] + } + return null + } + + // 上一首 + prev() { + let id = this.__CURR__ + + switch (this.__PLAY_MODE__) { + case 'all': + id-- + if (id < 0) { + id = this.__LIST__.length - 1 + } + break + case 'random': + id = (Math.random() * this.__LIST__.length) >>> 0 + break + // single + default: + break + } + + this.play(id) + return Promise.resolve(this.__LIST__[id]) + } + + // 下一首 + next() { + let id = this.__CURR__ + + switch (this.__PLAY_MODE__) { + case 'all': + id++ + if (id >= this.__LIST__.length) { + id = 0 + } + break + case 'random': + id = (Math.random() * this.__LIST__.length) >>> 0 + break + // single + default: + break + } + + this.play(id) + return Promise.resolve(this.__LIST__[id]) + } + + // 播放 + play(id) { + // 播放列表里没有数据的话, 不作任何处理 + if (!this.__LIST__.length) { + return Promise.reject(this.__LIST__) + } + + // 有ID的话,不管之前是否在播放,都切换歌曲 + if (id !== undefined) { + let song = this.__LIST__[id] + if (song) { + this.__CURR__ = id + this.__IS_PLAYED__ = true + + this.__PLAYER__.pause() + this.__PLAYER__.currentTime = 0 + this.__PLAYER__.src = song.path + this.__PLAYER__.play() + + Anot.ls('last-play', id) + return Promise.resolve(song) + } + return Promise.reject('song not found') + } else { + if (!this.__IS_PLAYED__) { + this.__IS_PLAYED__ = true + this.__PLAYER__.play() + } + return Promise.resolve(true) + } + } + + // 暂停 + pause() { + if (!this.__IS_PLAYED__) { + return + } + this.__IS_PLAYED__ = false + + this.__PLAYER__.pause() + } + + // 切换静音 + mute() { + if (this.__CURR__ < 0) { + return false + } + this.__PLAYER__.muted = !this.__PLAYER__.muted + return this.__PLAYER__.muted + } + + // 跳到指定位置播放 + seek(time) { + if (this.__CURR__ < 0) { + return + } + this.__PLAYER__.currentTime = time + } +} + +util.inherits(AudioPlayer, EventEmitter) + +export default AudioPlayer diff --git a/src/js/lib/drag/doc.md b/src/js/lib/drag/doc.md deleted file mode 100644 index 0cd4766..0000000 --- a/src/js/lib/drag/doc.md +++ /dev/null @@ -1,85 +0,0 @@ -# 拖拽插件 -> 该插件可以让任意一个元素可以被拖拽,而不需要该元素是否具有定位属性。 -> 使用时,在目标元素上添加`:drag`属性即可以实现拖拽功能。 - -## 依赖 -> 依赖`Anot`框架 - -## 浏览器兼容性 -+ chrome -+ firefox -+ safari -+ IE10+ - - -## 用法 -> 只需要在要拖拽的元素上添加`:drag`即可; -> 如果要拖拽的元素不是当前元素,只需要给该属性增加一个值为想要拖拽元素的类名或ID。 -> 具体请看示例: -> **注意:** `拖拽的元素不是本身时,只会往父级一级一级找相匹配的` - -```html - - - - - - - - -
- -
-
-
- - - - - - -``` - - -## 额外参数 - -### `data-limit` -> 用于限制元素的拖动范围,默认没有限制。 可选值为 "window"和"parent", 分别为 "限制在可视区"和"限制在父级元素的范围" - -### `data-axis` -> 用于限制拖动的方向, 默认值为 "xy",即不限制方向。可选值为 "x"和"y", 即只能在"x轴"或"y轴"方向拖动。 - -### `data-beforedrag` -> 拖动前的回调,如果有设置回调方法, 则该回调的返回值,可决定该元素是否能被拖拽, 可用于在特殊场景下,临时禁用拖拽。 -> `注:` -> 1. 该回调方法,会传入3个参数, 第1个为被拖拽的元素(dom对象), 第2个参数为 该元素的x轴绝对坐标, 第3个元素为y轴绝对坐标; -> 2. 该回调方法, 返回false时, 本次拖拽将临时失效, 返回其他值,或没有返回值,则忽略。 - - -### `data-dragging` -> 元素被拖动时的回调。 -> `注:` -> 1.该回调方法,会传入3个参数, 第1个为被拖拽的元素(dom对象), 第2个参数为 该元素的x轴绝对坐标, 第3个元素为y轴绝对坐标; - - -### `data-dragged` -> 元素被拖动结束后的回调。 -> `注:` -> 1. 该回调方法,会传入3个参数, 第1个为被拖拽的元素(dom对象), 第2个参数为 该元素的x轴绝对坐标, 第3个元素为y轴绝对坐标; - - - - - - - - diff --git a/src/js/lib/fetch/index.js b/src/js/lib/fetch/index.js new file mode 100644 index 0000000..957263e --- /dev/null +++ b/src/js/lib/fetch/index.js @@ -0,0 +1 @@ +import{Format,toS}from"./lib/format.js";const noop=function(e,t){this.defer.resolve(t)},NOBODY_METHODS=["GET","HEAD"],FORM_TYPES={form:"application/x-www-form-urlencoded; charset=UTF-8",json:"application/json; charset=UTF-8",text:"text/plain; charset=UTF-8"},ERRORS={10001:"Argument url is required",10012:"Parse error",10100:"Request canceled",10104:"Request pending...",10200:"Ok",10204:"No content",10304:"Not modified",10500:"Internal Server Error",10504:"Connected timeout"};Promise.defer=function(){var e={};return e.promise=new Promise(function(t,s){e.resolve=t,e.reject=s}),e};class _Request{constructor(e="",t={},{BASE_URL:s,__INIT__:r}){if(!e)throw new Error(ERRORS[10001]);if(e=e.replace(/#.*$/,""),s&&(/^([a-z]+:|\/\/)/.test(e)||(e=s+e)),t.method=(t.method||"get").toUpperCase(),this.xhr=new XMLHttpRequest,this.defer=Promise.defer(),this.options={headers:{"X-Requested-With":"XMLHttpRequest","content-type":FORM_TYPES.form},body:null,cache:"default",credentials:!1,signal:null,timeout:3e4},!t.signal){var o=new AbortController;t.signal=o.signal}this.defer.promise.abort=function(){o.abort()};var i=this.options.headers;return r.headers&&Object.assign(i,r.headers),t.headers&&(Object.assign(i,t.headers),delete t.headers),Object.assign(this.options,r,t,{url:e,headers:i}),this.__next__(),this.defer.promise}__next__(){var e=this.options,t=null,s=!1,r=!1,o=NOBODY_METHODS.includes(e.method);if(e.signal.onabort=(e=>{this.cancel=!0,this.xhr.abort()}),e.body)switch(typeof e.body){case"number":case"string":this.__type__("text"),t=e.body;break;case"object":if("FORM"===e.body.nodeName)e.method=e.body.method.toUpperCase()||"POST",s=(t=Format.parseForm(e.body)).constructor===FormData;else if(e.body.constructor===FormData)s=!0,o&&(e.method="POST"),t=e.body;else{for(let t in e.body)if("[object File]"===toS.call(e.body[t])){s=!0;break}s?(o&&(e.method="POST"),t=Format.mkFormData(e.body)):t=e.body}}s&&delete e.headers["content-type"];try{let t=document.createElement("a");t.href=e.url,r=location.protocol!==t.protocol||location.host!==t.host}catch(e){}r&&(e.credentials?this.xhr.withCredentials=!0:delete e.headers["X-Requested-With"]),o?((t=Format.param(t))&&(e.url+=(~e.url.indexOf("?")?"&":"?")+t),"no-store"===e.cache&&(e.url+=(~e.url.indexOf("?")?"&":"?")+"_t_="+Date.now())):s||(t=~e.headers["content-type"].indexOf("json")?JSON.stringify(t):Format.param(t)),this.xhr.responseType="blob",this.xhr.onreadystatechange=(t=>{e.timeout>0&&(e["time"+this.xhr.readyState]=t.timeStamp,4===this.xhr.readyState&&(e.isTimeout=e.time4-e.time1>e.timeout)),4===this.xhr.readyState&&this.__dispatch__(e.isTimeout)}),this.xhr.open(e.method,e.url);for(let t in e.headers)this.xhr.setRequestHeader(t,e.headers[t]);this.xhr.send(t),e.timeout&&e.timeout>0&&(this.xhr.timeout=e.timeout)}__type__(e){this.options.headers["content-type"]=FORM_TYPES[e]}__dispatch__(e){let t={status:200,statusText:"ok",body:"",headers:Object.create(null)};if(this.cancel)return this.__cancel__();if(e)return this.__timeout__();let s=this.xhr.status>=200&&this.xhr.status<400,r=this.xhr.getAllResponseHeaders().split("\n")||[];for(let e of r)if(e=e.trim()){let s=(e=e.split(":")).shift().toLowerCase();e=e.join(":").trim(),t.headers[s]=e}s?(t.status=this.xhr.status,204===t.status?t.statusText=ERRORS[10204]:304===t.status&&(t.statusText=ERRORS[10304])):(t.status=this.xhr.status||500,t.statusText=this.xhr.statusText||ERRORS[10500]),t.body=this.xhr.response,this.__success__(s,t)}__success__(e,t){var s=new _Response(t.status,t.statusText,t.body,t.headers);e?this.defer.resolve(s):this.defer.reject(s),delete this.xhr,delete this.options,delete this.defer}__cancel__(e){var t=new _Response(0,ERRORS[10100],Object.create(null));this.defer.reject(t),delete this.xhr,delete this.options,delete this.defer}__timeout__(e){var t=new _Response(504,ERRORS[10504],Object.create(null));this.defer.reject(t),delete this.xhr,delete this.options,delete this.defer}}class _Response{constructor(e=200,t="OK",s=null,r={}){this.status=e,this.statusText=t,this.ok=e>=200&&e<400,this.headers=r,Object.defineProperty(this,"__R__",{value:s,writable:!0,enumerable:!1,configurable:!0})}text(){return this.__R__.text()}json(){return this.__R__.text().then(e=>JSON.parse(e))}blob(){return this.__R__}arrayBuffer(){return this.__R__.arrayBuffer()}}const _fetch=function(e,t){return new _Request(e,t,{BASE_URL:_fetch.BASE_URL,__INIT__:_fetch.__INIT__||Object.create(null)})};_fetch.create=function(e,t=Object.create(null)){return function(s,r){return new _Request(s,r,{BASE_URL:e,__INIT__:t})}};export default _fetch; \ No newline at end of file diff --git a/src/js/lib/fetch/lib/format.js b/src/js/lib/fetch/lib/format.js new file mode 100644 index 0000000..f3747b4 --- /dev/null +++ b/src/js/lib/fetch/lib/format.js @@ -0,0 +1 @@ +export const toS=Object.prototype.toString;export const encode=encodeURIComponent;export const decode=decodeURIComponent;function serialize(e,t,o){var a;if(Array.isArray(t))t.forEach(function(t,r){a=e?`${e}[${Array.isArray(t)?r:""}]`:r,"object"==typeof t?serialize(a,t,o):o(a,t)});else for(let r in t)a=e?`${e}[${r}]`:r,"object"==typeof t[r]?serialize(a,t[r],o):o(a,t[r])}export const Format={parseForm(e){let t={},o=!1;for(let a,r=0;a=e.elements[r++];)switch(a.type){case"select-one":case"select-multiple":if(a.name.length&&!a.disabled)for(let e,o=0;e=a.options[o++];)e.selected&&(t[a.name]=e.value||e.text);break;case"file":a.name.length&&!a.disabled&&(t[a.name]=a.files[0],o=!0);break;case void 0:case"submit":case"reset":case"button":break;case"radio":case"checkbox":if(!a.checked)break;default:a.name.length&&!a.disabled&&(t[a.name]=a.value)}return o?this.mkFormData(t):t},mkFormData(e){let t=new FormData;for(let o in e){let a=e[o];Array.isArray(a)?a.forEach(function(e){t.append(o+"[]",e)}):t.append(o,e[o])}return t},param(e){if(!e||"string"==typeof e||"number"==typeof e)return e;let t=[];return"object"==typeof e&&serialize("",e,function(e,o){/native code/.test(o)||(o="function"==typeof o?o():o,o="[object File]"===toS.call(o)?o:encode(o),t.push(encode(e)+"="+o))}),t.join("&")}}; \ No newline at end of file diff --git a/src/js/lib/fetch/next.js b/src/js/lib/fetch/next.js new file mode 100644 index 0000000..bef023e --- /dev/null +++ b/src/js/lib/fetch/next.js @@ -0,0 +1 @@ +import{Format,toS}from"./lib/format.js";const noop=function(e,t){this.defer.resolve(t)},NOBODY_METHODS=["GET","HEAD"],FORM_TYPES={form:"application/x-www-form-urlencoded; charset=UTF-8",json:"application/json; charset=UTF-8",text:"text/plain; charset=UTF-8"};class _Request{constructor(e="",t={},{BASE_URL:o,__INIT__:r}){if(!e)throw new Error("Argument url is required");e=e.replace(/#.*$/,""),o&&(/^([a-z]+:|\/\/)/.test(e)||(e=o+e)),t.method=(t.method||"get").toUpperCase(),this.options={headers:{"X-Requested-With":"XMLHttpRequest","content-type":FORM_TYPES.form},body:null,cache:"default",signal:null,timeout:3e4},t.signal||(this.control=new AbortController,t.signal=this.control.signal);var s=this.options.headers;return r.headers&&Object.assign(s,r.headers),t.headers&&(Object.assign(s,t.headers),delete t.headers),Object.assign(this.options,r,t,{url:e,headers:s}),this.__next__()}__next__(){var e=this.options,t=null,o=!1,r=!1,s=NOBODY_METHODS.includes(e.method);if(e.body)switch(typeof e.body){case"number":case"string":this.__type__("text"),t=e.body;break;case"object":if("FORM"===e.body.nodeName)e.method=e.body.method.toUpperCase()||"POST",o=(t=Format.parseForm(e.body)).constructor===FormData;else if(e.body.constructor===FormData)o=!0,s&&(e.method="POST"),t=e.body;else{for(let t in e.body)if("[object File]"===toS.call(e.body[t])){o=!0;break}o?(s&&(e.method="POST"),t=Format.mkFormData(e.body)):t=e.body}}o&&delete e.headers["content-type"];try{let t=document.createElement("a");t.href=e.url,r=location.protocol!==t.protocol||location.host!==t.host}catch(e){}r&&"omit"===e.credentials&&delete e.headers["X-Requested-With"],s?((t=Format.param(t))&&(e.url+=(~e.url.indexOf("?")?"&":"?")+t),"no-store"===e.cache&&(e.url+=(~e.url.indexOf("?")?"&":"?")+"_t_="+Date.now())):o||(t=~e.headers["content-type"].indexOf("json")?JSON.stringify(t):Format.param(t)),e.timeout&&e.timeout>0&&(this.timer=setTimeout(e=>{this.abort()},e.timeout),delete e.timeout);var n=e.url;delete e.url;for(let t in e)null!==e[t]&&void 0!==e[t]&&""!==e[t]||delete e[t];return window.fetch(n,e).then(e=>{return clearTimeout(this.timer),e.status>=200&&e.status<400?e:Promise.reject(e)}).catch(e=>(clearTimeout(this.timer),Promise.reject(e)))}abort(){this.control.abort()}__type__(e){this.options.headers["content-type"]=FORM_TYPES[e]}}const _fetch=function(e,t){return new _Request(e,t,{BASE_URL:_fetch.BASE_URL,__INIT__:_fetch.__INIT__||Object.create(null)})};_fetch.create=function(e,t=Object.create(null)){return function(o,r){return new _Request(o,r,{BASE_URL:e,__INIT__:t})}};export default _fetch; \ No newline at end of file diff --git a/src/main.js b/src/main.js index 92351f4..3e27817 100644 --- a/src/main.js +++ b/src/main.js @@ -23,7 +23,14 @@ const MIME_TYPES = { '.png': 'image/png', '.gif': 'image/gif', '.svg': 'image/svg+xml', - '.ico': 'image/ico' + '.ico': 'image/ico', + '.mp3': 'audio/mpeg', + '.m4a': 'audio/m4a', + '.aac': 'audio/x-aac', + '.ogg': 'audio/ogg', + '.wav': 'audio/x-wav', + '.flac': 'audio/flac', + all: 'audio/*' } /* ----------------------------------------------------- */ @@ -31,7 +38,8 @@ app.commandLine.appendSwitch('--lang', 'zh-CN') app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required') protocol.registerSchemesAsPrivileged([ - { scheme: 'app', privileges: { secure: true, standard: true } } + { scheme: 'app', privileges: { secure: true, standard: true } }, + { scheme: 'sonist', privileges: { secure: true, standard: true } } ]) /* ----------------------------------------------------- */ @@ -40,11 +48,18 @@ protocol.registerSchemesAsPrivileged([ app.once('ready', () => { // 注册协议 protocol.registerBufferProtocol('app', (req, cb) => { - let file = req.url.replace(/^app:\/\/local\//, '') + let file = decodeURIComponent(req.url.replace(/^app:\/\/local\//, '')) let ext = path.extname(req.url) let buff = fs.cat(path.resolve(__dirname, file)) cb({ data: buff, mimeType: MIME_TYPES[ext] }) }) + + protocol.registerBufferProtocol('sonist', (req, cb) => { + let file = decodeURIComponent(req.url.replace(/^sonist:[\/]+/, '/')) + let ext = path.extname(req.url) + let buff = fs.cat(file) + cb({ data: buff, mimeType: MIME_TYPES[ext] || MIME_TYPES.all }) + }) // 修改app的UA session.defaultSession.setUserAgent( 'KugouMusic/2.9.5 (Mac OS X Version 10.15.7 (Build 19H2))'