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-19 20:49:53 +08:00
parent 6bd72fcbac
commit b21ec91170
8 changed files with 339 additions and 296 deletions

View File

@ -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
},

View File

@ -1,214 +1,126 @@
/**
* 播放器
* @author yutent<yutent@doui.cc>
* @date 2018/12/23 23:14:40
*
* @author yutent<yutent.io@gmail.com>
* @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')
function hide(target, key, value) {
Object.defineProperty(target, key, {
value,
writable: true,
enumerable: false,
configurable: true
})
}
class AudioPlayer {
export default class Player {
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__()
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)
}
__init__() {
this.__PLAYER__.addEventListener(
'timeupdate',
_ => {
this.emit('play', this.__PLAYER__.currentTime)
},
false
)
this.__PLAYER__.addEventListener(
'ended',
_ => {
this.emit('end')
},
false
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 stat() {
return this.__LIST__.length ? 'ready' : 'stop'
}
get IS_MUTED() {
return this.__PLAYER__.muted
get volume() {
return this.props.volume
}
set volume(val) {
this.__PLAYER__.muted = false
this.__PLAYER__.volume = val / 100
val = +val || 0.5
if (val < 0) {
val = 0
}
if (val > 1) {
val = 1
}
this.props.volume = val
}
set mode(val = 'all') {
this.__PLAY_MODE__ = val
get mode() {
return this.props.mode
}
clear() {
this.__LIST__ = []
set mode(val) {
this.props.mode = val
}
push(songs) {
this.__LIST__.push.apply(this.__LIST__, songs)
get time() {
return this.props.time
}
getCurrSong() {
if (this.__CURR__ > -1) {
return this.__LIST__[this.__CURR__]
}
return null
get stat() {
return this.props.stat
}
// 上一首
prev() {
let id = this.__CURR__
async play(id) {
var url, gain
switch (this.__PLAY_MODE__) {
case 'all':
id--
if (id < 0) {
id = this.__LIST__.length - 1
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'
}
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__) {
url = this.__LIST__[id]
if (!url || this.props.curr === url) {
return
}
this.__IS_PLAYED__ = false
this.__PLAYER__.pause()
gain = this.__AC__.createGain()
if (this.track) {
this.stop()
}
// 切换静音
mute() {
if (this.__CURR__ < 0) {
return false
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'
}
this.__PLAYER__.muted = !this.__PLAYER__.muted
return this.__PLAYER__.muted
}
// 跳到指定位置播放
seek(time) {
if (this.__CURR__ < 0) {
return
this.props.time = time
}
stop() {
if (this.track) {
this.__AUDIO__.pause()
this.track = null
this.props.time = 0
this.props.stat = 'stoped'
}
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)
}
})
})
}
export default AudioPlayer

183
src/js/lib/audio/old.js Normal file
View File

@ -0,0 +1,183 @@
/**
* 播放器
* @author yutent<yutent@doui.cc>
* @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

View File

@ -1,85 +0,0 @@
# 拖拽插件
> 该插件可以让任意一个元素可以被拖拽,而不需要该元素是否具有定位属性。
> 使用时,在目标元素上添加`:drag`属性即可以实现拖拽功能。
## 依赖
> 依赖`Anot`框架
## 浏览器兼容性
+ chrome
+ firefox
+ safari
+ IE10+
## 用法
> 只需要在要拖拽的元素上添加`:drag`即可;
> 如果要拖拽的元素不是当前元素,只需要给该属性增加一个值为想要拖拽元素的类名或ID。
> 具体请看示例:
> **注意:** `拖拽的元素不是本身时,只会往父级一级一级找相匹配的`
```html
<!DOCTYPE html>
<html>
<head>
<style>
* {margin:0;padding:0}
.box {width:200px;height:100px;background:#aaa;}
.box .handle {width:200px;height:30px;background:#f30;}
</style>
</head>
<body :controller="test">
<div class="box" :drag></div>
<div class="box">
<div class="handle" :drag="box"></div>
</div>
<script>
import Anot from 'lib/drag/index.js'
Anot({
$id: 'test'
})
</script>
</body>
</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轴绝对坐标;

View File

@ -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;

View File

@ -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("&")}};

1
src/js/lib/fetch/next.js Normal file
View File

@ -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;

View File

@ -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))'