luci-app-unblockmusic: sync source

This commit is contained in:
CN_SZTL 2019-07-29 08:41:34 +08:00
parent 6407fdf016
commit d8e7895815
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
18 changed files with 224 additions and 70 deletions

View File

@ -15,12 +15,11 @@ LUCI_TITLE:=LuCI support for UnblockNeteaseMusic
LUCI_DEPENDS:=+node +bash +dnsmasq-full +ipset
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-unblockmusic
PKG_VERSION:=1.3
PKG_RELEASE:=2
PKG_VERSION:=1.4
PKG_RELEASE:=1
PKG_MAINTAINER:=<https://github.com/project-openwrt/luci-app-unblockmusic>
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -13,19 +13,29 @@ enabled.description = translate("启用本插件以恢复网易云音乐无版
enabled.default = 0
enabled.rmempty = false
enabled = s:option(Flag, "strict_mode", translate("启用严格模式"))
enabled.description = translate("若将服务部署到公网,则强烈建议使用严格模式,此模式下仅放行网易云音乐所属域名的请求")
enabled = s:option(Flag, "enable_ipset_forward", translate("启用IPSet劫持相关请求"))
enabled.description = translate("开启后所有网易云音乐流量都会被劫持到UnblockNeteaseMusic进行处理")
enabled.default = 1
enabled.rmempty = false
enabled:depends("enabled", 1)
enabled = s:option(Flag, "enable_ipset_forward", translate("启用IPSet转发相关流量"))
enabled.description = translate("开启后所有网易云音乐流量都会被重定向到UnblockNeteaseMusic进行处理但会导致无法正常访问云音乐网页端")
enabled.default = 1
enabled.rmempty = false
enabled:depends("enabled", 1)
account = s:option(Value, "http_port", translate("[HTTP] 监听端口"))
account.description = translate("UnblockNeteaseMusic监听的HTTP端口不可与其他程序/HTTPS共用一个端口")
account.placeholder = "5200"
account.default = "5200"
account.datatype = "port"
account.rmempty = false
account:depends("enabled", 1)
speedtype = s:option(ListValue, "musicapptype", translate("音源选择"))
account = s:option(Value, "https_port", translate("[HTTPS] 监听端口"))
account.description = translate("[如HTTP端口设置为80请将HTTPS端口设置为443] UnblockNeteaseMusic监听的HTTPS端口不可与其他程序/HTTP共用一个端口")
account.placeholder = "5201"
account.default = "5201"
account.datatype = "port"
account.rmempty = false
account:depends("enabled", 1)
speedtype = s:option(ListValue, "musicapptype", translate("音源接口"))
speedtype:value("default", translate("默认"))
speedtype:value("netease", translate("网易云音乐"))
speedtype:value("qq", translate("QQ音乐"))
@ -38,31 +48,57 @@ speedtype:value("joox", translate("JOOX音乐"))
speedtype:value("all", translate("所有平台"))
speedtype.description = translate("音源调用接口")
speedtype.default = "all"
speedtype.rmempty = false
speedtype:depends("enabled", 1)
account = s:option(Value, "port", translate("监听端口"))
account.description = translate("UnblockNeteaseMusic监听的端口不可与其他程序共用一个端口")
account.default = "5200"
account.datatype = "string"
account:depends("enabled", 1)
enabled = s:option(Flag, "set_netease_server_ip", translate("自定义网易云服务器IP"))
enabled.description = translate("如使用Hosts方式则必选否则将会导致连接死循环")
enabled = s:option(Flag, "advanced_mode", translate("启用进阶设置"))
enabled.description = translate("仅推荐高级玩家使用")
enabled.default = 0
enabled.rmempty = false
enabled:depends("enabled", 1)
enabled = s:option(Flag, "pub_access", translate("部署到公网"))
enabled.description = translate("默认仅监听局域网,如需提供公开访问请勾选此选项;与此同时,建议勾选“启用严格模式”")
enabled.default = 0
enabled.rmempty = false
enabled:depends("advanced_mode", 1)
enabled = s:option(Flag, "strict_mode", translate("启用严格模式"))
enabled.description = translate("若将服务部署到公网,则强烈建议使用严格模式,此模式下仅放行网易云音乐所属域名的请求")
enabled.default = 1
enabled.rmempty = false
enabled:depends("advanced_mode", 1)
enabled = s:option(Flag, "ipset_forward_nohttps", translate("[IPSet] 不劫持HTTPS请求"))
enabled.description = translate("默认同时劫持HTTP&HTTPS两种请求如您无相关需求可勾选此选项")
enabled.default = 0
enabled.rmempty = false
enabled:depends("advanced_mode", 1)
enabled = s:option(Flag, "use_hosts", translate("使用Hosts劫持相关请求"))
enabled.description = translate("[仅限HTTP:HTTPS端口设置为80:443时可用不可与IPSet方式同时使用] 开启后网易云音乐相关请求会被劫持到UnblockNeteaseMusic进行处理")
enabled.default = 0
enabled.rmempty = false
enabled:depends("advanced_mode", 1)
enabled = s:option(Flag, "set_netease_server_ip", translate("自定义网易云服务器IP"))
enabled.description = translate("如使用Hosts方式劫持网易云音乐则必选否则将会导致连接死循环")
enabled.default = 0
enabled.rmempty = false
enabled:depends("advanced_mode", 1)
account = s:option(Value, "netease_server_ip", translate("网易云服务器IP"))
account.description = translate("通过 ping music.163.com 即可获得IP地址仅限填写一个")
account.default = "59.111.181.38"
account.datatype = "string"
account.placeholder = "59.111.181.38"
account.datatype = "ipaddr"
account:depends("set_netease_server_ip", 1)
enabled = s:option(Flag, "enable_proxy", translate("使用代理服务器"))
enabled.description = translate("如您的OpenWRT系统部署在海外则此选项必选否则可能无法正常使用")
enabled.description = translate("如您的OpenWRT/LEDE系统部署在海外,则此选项必选,否则可能无法正常使用")
enabled.default = 0
enabled.rmempty = false
enabled:depends("enabled", 1)
enabled:depends("advanced_mode", 1)
account = s:option(Value, "proxy_server_ip", translate("代理服务器IP"))
account.description = translate("具体格式请参考https://github.com/nondanee/UnblockNeteaseMusic")

View File

@ -1,10 +1,15 @@
config unblockmusic
option enabled '0'
option strict_mode '1'
option enable_ipset_forward '1'
option musicapptype 'all'
option enabled '1'
option enable_ipset_forward '0'
option port '5200'
option musicapptype 'default'
option http_port '5200'
option https_port '5201'
option pub_access '0'
option advanced_mode '0'
option strict_mode '1'
option ipset_forward_nohttps '0'
option use_hosts '0'
option set_netease_server_ip '0'
option netease_server_ip '59.111.181.38'
option enable_proxy '0'

View File

@ -3,14 +3,61 @@
START=99
STOP=10
enable="$(uci get unblockmusic.@unblockmusic[0].enabled)"
[ "$(uci get unblockmusic.@unblockmusic[0].strict_mode)" -ne "0" ] && strict_mode="-s"
[ "$(uci get unblockmusic.@unblockmusic[0].strict_mode)" -eq "0" ] || strict_mode="-s"
[ "$(uci get unblockmusic.@unblockmusic[0].set_netease_server_ip)" -ne "0" ] && netease_server_ip="-f $(uci get unblockmusic.@unblockmusic[0].netease_server_ip)"
[ "$(uci get unblockmusic.@unblockmusic[0].enable_proxy)" -ne "0" ] && proxy_server_ip="-u $(uci get unblockmusic.@unblockmusic[0].proxy_server_ip)"
[ "$(uci get unblockmusic.@unblockmusic[0].pub_access)" -ne "0" ] && addr="0.0.0.0" || addr="$(uci get network.lan.ipaddr)"
enable="$(uci get unblockmusic.@unblockmusic[0].enabled)"
type="$(uci get unblockmusic.@unblockmusic[0].musicapptype)"
port="$(uci get unblockmusic.@unblockmusic[0].port)"
http_port="$(uci get unblockmusic.@unblockmusic[0].http_port)"
https_port="$(uci get unblockmusic.@unblockmusic[0].https_port)"
set_firewall(){
if [ "${set_type}" = "start" ]; then
echo "ipset=/.music.163.com/music" >> /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart >/dev/null 2>&1
mkdir -p /var/etc
lan_addr="$(uci get network.lan.ipaddr)"
[ "$(uci get unblockmusic.@unblockmusic[0].ipset_forward_nohttps)" -eq "0" ] && forward_https="iptables -t nat -A cloud_music -i br-lan -p tcp --dport 443 -j DNAT --to ${lan_addr}:${https_port}"
cat > "/var/etc/unblockmusic.include" <<-EOF
if ! ipset list music >/dev/null; then ipset create music hash:ip; fi
iptables -t nat -N cloud_music
iptables -t nat -A cloud_music -i br-lan -p tcp --dport 80 -j DNAT --to ${lan_addr}:${http_port}
${forward_https}
iptables -t nat -A prerouting_rule -i br-lan -p tcp -m set --match-set music dst -j cloud_music
EOF
/etc/init.d/firewall restart >/dev/null 2>&1
elif [ "${set_type}" = "stop" ]; then
echo "" > /var/etc/unblockmusic.include
/etc/init.d/firewall restart >/dev/null 2>&1
sed -i '/ipset=\/.music.163.com\/music/d' /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart >/dev/null 2>&1
fi
}
set_hosts(){
if [ "${set_type}" = "start" ]; then
cfg_name="$(uci add dhcp domain)"
uci set dhcp."${cfg_name}".name='music.163.com'
uci set dhcp."${cfg_name}".ip="$(uci get network.lan.ipaddr)"
uci commit dhcp
cfg_name="$(uci add dhcp domain)"
uci set dhcp."${cfg_name}".name='interface.music.163.com'
uci set dhcp."${cfg_name}".ip="$(uci get network.lan.ipaddr)"
uci commit dhcp
elif [ "${set_type}" = "stop" ]; then
music_id1="$(uci show dhcp| grep "interface"| grep -Eo "domain\[[0-9]+\]"| grep -Eo "[0-9]+")"
uci delete dhcp.@domain["${music_id1}"]
uci commit dhcp
music_id2="$(uci show dhcp| grep "music"| grep -Eo "domain\[[0-9]+\]"| grep -Eo "[0-9]+")"
uci delete dhcp.@domain["${music_id2}"]
uci commit dhcp
fi
}
start()
{
@ -19,26 +66,15 @@ start()
[ "${enable}" -eq "0" ] && exit 0
if [ "${type}" = "default" ]; then
node /usr/share/unblockmusic/app.js -p ${port} ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
node /usr/share/unblockmusic/app.js -a ${addr} -p ${http_port}:${https_port} ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
elif [ "${type}" = "all" ]; then
node /usr/share/unblockmusic/app.js -p ${port} -o kuwo migu xiami kugou qq joox netease ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
node /usr/share/unblockmusic/app.js -a ${addr} -p ${http_port}:${https_port} -o kuwo migu xiami kugou qq joox netease ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
else
node /usr/share/unblockmusic/app.js -p ${port} -o ${type} ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
node /usr/share/unblockmusic/app.js -a ${addr} -p ${http_port}:${https_port} -o ${type} ${netease_server_ip} ${proxy_server_ip} ${strict_mode} >/tmp/unblockmusic.log 2>&1 &
fi
if [ "$(uci get unblockmusic.@unblockmusic[0].enable_ipset_forward)" -ne "0" ]; then
echo -e "ipset=/.music.163.com/music" >> /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart >/dev/null 2>&1
mkdir -p /var/etc
cat > "/var/etc/unblockmusic.include" <<-EOF
if ! ipset list music >/dev/null; then ipset create music hash:ip; fi
iptables -t nat -N cloud_music
iptables -t nat -A cloud_music -i br-lan -p tcp -j REDIRECT --to-ports ${port}
iptables -t nat -A prerouting_rule -i br-lan -p tcp -m set --match-set music dst -j cloud_music
EOF
/etc/init.d/firewall restart >/dev/null 2>&1
fi
[ "$(uci get unblockmusic.@unblockmusic[0].enable_ipset_forward)" -ne "0" ] && set_type="start" && set_firewall
[ "$(uci get unblockmusic.@unblockmusic[0].use_hosts)" -ne "0" ] && set_type="start" && set_hosts
/usr/share/unblockmusic/logcheck.sh >/dev/null 2>&1 &
}
@ -48,8 +84,5 @@ stop()
kill -9 "$(ps | grep app.js | grep -v grep | awk '{print $1}')" >/dev/null 2>&1
kill -9 "$(ps | grep logcheck.sh | grep -v grep | awk '{print $1}')" >/dev/null 2>&1
rm -f /tmp/unblockmusic.log
echo "" > /var/etc/unblockmusic.include
/etc/init.d/firewall restart >/dev/null 2>&1
sed -i '/ipset=\/.music.163.com\/music/d' /etc/dnsmasq.conf
/etc/init.d/dnsmasq restart >/dev/null 2>&1
set_type="stop" && set_firewall && set_hosts
}

View File

@ -5,15 +5,17 @@ const config = require('./cli.js')
.program({name: package.name.replace(/@.+\//, ''), version: package.version})
.option(['-v', '--version'], {action: 'version'})
.option(['-p', '--port'], {metavar: 'port', help: 'specify server port'})
.option(['-a', '--address'], {metavar: 'address', help: 'specify server host'})
.option(['-u', '--proxy-url'], {metavar: 'url', help: 'request through upstream proxy'})
.option(['-f', '--force-host'], {metavar: 'host', help: 'force the netease server ip'})
.option(['-o', '--match-order'], {metavar: 'source', nargs: '+', help: 'set priority of sources'})
.option(['-t', '--token'], {metavar: 'token', help: 'set up http basic authentication'})
.option(['-t', '--token'], {metavar: 'token', help: 'set up proxy authentication'})
.option(['-e', '--endpoint'], {metavar: 'url', help: 'replace virtual endpoint with public host'})
.option(['-s', '--strict'], {action: 'store_true', help: 'enable proxy limitation'})
.option(['-h', '--help'], {action: 'help'})
.parse(process.argv)
global.address = config.address
config.port = (config.port || '8080').split(':').map(string => parseInt(string))
const invalid = value => (isNaN(value) || value < 1 || value > 65535)
if(config.port.some(invalid)){
@ -73,12 +75,12 @@ Promise.all([httpdns(hook.target.host[0])].concat(hook.target.host.map(host => d
hook.target.host = hook.target.host.concat(extra)
server.whitelist = server.whitelist.concat(hook.target.host.map(escape))
if(port[0]){
server.http.listen(port[0])
console.log(`HTTP Server running @ http://0.0.0.0:${port[0]}`)
server.http.listen(port[0], address)
console.log(`HTTP Server running @ http://${address || '0.0.0.0'}:${port[0]}`)
}
if(port[1]){
server.https.listen(port[1])
console.log(`HTTPS Server running @ https://0.0.0.0:${port[1]}`)
server.https.listen(port[1], address)
console.log(`HTTPS Server running @ https://${address || '0.0.0.0'}:${port[1]}`)
}
})
.catch(error => console.log(error))

View File

@ -0,0 +1,25 @@
# Web Extension Port
For test
## Implementation
- Convert node module to ES6 module which can be directly executed in Chrome 61+ without Babel
- Rewrite crypto module (using CryptoJS) and request (using XMLHttpRequest) module for browser environment
- Do matching in background and transfer result with chrome runtime communication
- Inject content script for hijacking Netease Music Web Ajax response
## Build
```
$ node convert.js
```
## Install
Load unpacked extension in Developer mode
## Reference
- [brix/crypto-js](https://github.com/brix/crypto-js)
- [JixunMoe/cuwcl4c](https://github.com/JixunMoe/cuwcl4c)

View File

@ -1,4 +1,5 @@
const cli = {
width: 80,
_program: {},
_options: [],
program: (information = {}) => {
@ -99,7 +100,7 @@ const usage = () => {
return `[${flag} ${name}]`
}
})
let maximum = 80
let maximum = cli.width
let title = `usage: ${cli._program.name}`
let lines = [title]
@ -129,11 +130,16 @@ const help = () => {
return [use, option.help]
})
let align = Math.max.apply(null, positionals.concat(optionals).map(option => option[0].length))
align = align > 26 ? 26 : align
align = align > 30 ? 30 : align
rest = cli.width - align - 4
const publish = option => {
option[0].length > align ?
console.log(` ${option[0]}\n${pad(align + 4)}${option[1]}`) :
console.log(` ${option[0]}${pad(align - option[0].length)} ${option[1]}`)
const slice = string =>
Array.from(Array(Math.ceil(string.length / rest)).keys())
.map(index => string.slice(index * rest, (index + 1) * rest))
.join('\n' + pad(align + 4))
option[0].length < align ?
console.log(` ${option[0]}${pad(align - option[0].length)} ${slice(option[1])}`) :
console.log(` ${option[0]}\n${pad(align + 4)}${slice(option[1])}`)
}
if(positionals.length) console.log('\npositional arguments:')
positionals.forEach(publish)

View File

@ -177,11 +177,11 @@ hook.connect.before = ctx => {
let url = parse('https://' + ctx.req.url)
if(hook.target.host.includes(url.hostname)){
if(url.port == 80){
ctx.req.url = `localhost:${global.port[0]}`
ctx.req.url = `${global.address || 'localhost'}:${global.port[0]}`
ctx.req.local = true
}
else if(global.port[1]){
ctx.req.url = `localhost:${global.port[1]}`
ctx.req.url = `${global.address || 'localhost'}:${global.port[1]}`
ctx.req.local = true
}
else{

View File

@ -0,0 +1,15 @@
#!/bin/bash
docker build \
--build-arg ARCH="armhf" \
-t $DOCKER_REPO:arm \
-f $DOCKERFILE_PATH .
docker build \
--build-arg ARCH="aarch64" \
-t $DOCKER_REPO:arm64 \
-f $DOCKERFILE_PATH .
docker build \
--build-arg ARCH="amd64" \
-t $DOCKER_REPO:amd64 \
-f $DOCKERFILE_PATH .

View File

@ -0,0 +1,20 @@
#!/bin/bash
docker manifest create \
$DOCKER_REPO:latest \
$DOCKER_REPO:amd64 \
$DOCKER_REPO:arm64 \
$DOCKER_REPO:arm
docker manifest annotate \
$DOCKER_REPO:latest \
$DOCKER_REPO:amd64 --os linux --arch amd64
docker manifest annotate \
$DOCKER_REPO:latest \
$DOCKER_REPO:arm64 --os linux --arch arm64
docker manifest annotate \
$DOCKER_REPO:latest \
$DOCKER_REPO:arm --os linux --arch arm
docker manifest push --purge $DOCKER_REPO:latest

View File

@ -0,0 +1,4 @@
#!/bin/bash
apt-get -y update
apt-get -y --only-upgrade install docker-ee
docker run --rm --privileged multiarch/qemu-user-static:register --reset

View File

@ -0,0 +1,4 @@
#!/bin/bash
docker push $DOCKER_REPO:arm
docker push $DOCKER_REPO:arm64
#docker push $DOCKER_REPO:amd64

View File

@ -1,5 +1,5 @@
{
"name": "unblockneteasemusic",
"version": "0.16.2",
"version": "0.17.0",
"lockfileVersion": 1
}

View File

@ -1,10 +1,10 @@
{
"name": "@nondanee/unblockneteasemusic",
"version": "0.16.2",
"version": "0.17.0",
"description": "Revive unavailable songs for Netease Cloud Music",
"main": "provider/match.js",
"bin": {
"UnblockNeteaseMusic": "app.js"
"unblockneteasemusic": "app.js"
},
"scripts": {
"pkg": "pkg . --out-path=dist/"

View File

@ -29,7 +29,7 @@ const track = id => {
.then(response => response.json())
.then(jsonBody => {
if('songList' in jsonBody.data)
return jsonBody.data.songList[0].songLink
return jsonBody.data.songList[0].songLink || null
else
return Promise.reject()
})

View File

@ -17,7 +17,12 @@ const search = info => {
return request('GET', url)
.then(response => response.body())
.then(body => {
let jsonBody = JSON.parse(body.replace(/\'/g, '"').replace('try {var jsondata =', '').replace(';song(jsondata);}catch(e){jsonError(e)}', ''))
let jsonBody = eval(
'(' + body
.replace(/\n/g, '')
.match(/try\s*\{[^=]+=\s*(.+?)\s*\}\s*catch/)[1]
.replace(/;\s*song\s*\(.+\)\s*;\s*/, '') + ')'
)
let matched = jsonBody.abslist[0]
if(matched)
return matched.MUSICRID.split('_').pop()

View File

@ -14,7 +14,7 @@ const provider = {
const match = (id, source) => {
let meta = {}
let candidate = (source || global.source || ['netease', 'qq', 'xiami', 'baidu']).filter(name => name in provider)
let candidate = (source || global.source || ['qq', 'xiami', 'baidu']).filter(name => name in provider)
return find(id)
.then(info => {
meta = info
@ -34,7 +34,7 @@ const match = (id, source) => {
const check = url => {
let song = {size: 0, url: null, md5: null}
return request('HEAD', url)
return Promise.race([request('HEAD', url), new Promise((_, reject) => setTimeout(() => reject(504), 5 * 1000))])
.then(response => {
if(response.statusCode != 200) return
if(url.includes('qq.com'))

View File

@ -78,7 +78,7 @@ const search = info => {
const track = id => {
let url =
'https://www.xiami.com/song/playlist/id/' + id +
'https://emumo.xiami.com/song/playlist/id/' + id +
'/object_name/default/object_id/0/cat/json'
return request('GET', url, headers)