diff --git a/README.md b/README.md index b213a60..72f98dd 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ - XML卡片在群聊中会变成链接,经查是被阻挡了。 - Share卡片在群聊中无法发送,同上。 - LightApp已经完全改成Mirai,旧版本LightApp卡片无法继续发送。 +- 百度音乐(千千)API暂时失效,请等待修复。 # 声明 - 本插件仅作为学习交流等使用,请勿用于盈利,否则法律后果自负。 - 本插件提供的所有API均来源于公开资料,如有侵权请发邮件或者issue联系进行删除。 @@ -129,7 +130,8 @@ Linux: |`hintsourcenotfound`|找不到源文本提示| |`enable_local`|全部搜索时是否包含本地搜索,默认不包含。| |`verbose`|是否启用命令执行输出,缺省默认为true。
设置值:true/执行语音操作时在控制台输出详细信息 false/不输出信息,直接执行| -|`adddefault`|是否添加默认指令,缺省默认为true。
设置值:true/添加readme所述的指令列表 false/不添加任何指令| +|`adddefault`|是否添加默认指令,缺省默认为true。
设置值:true/添加readme所述的指令列表并添加默认解析 false/不添加任何指令和解析| +|`enableParser`|是否启用链接解析,缺省默认为true。启用机器人会对每一条信息进行正则匹配并在找到音乐分享链接时发送对应卡片,因此对机器人可能会有一定的性能负担。true/启用,false/关闭。详见[后文](#自定义解析)| |`extracommands`|通过配置添加新指令的列表,可以完全自定义指令。详见[后文](#自定义指令)| # 自定义指令 范例: @@ -175,6 +177,25 @@ extracommands: source: 网易电台节目 card: Mirai ``` +# 自定义解析 +范例: +``` +extraparsers: + "0": #解析名称,只要各个解析的名称不重复即可 + pattern: "music\\.163\\.com/.*song/([0-9]+)" + source: 网易 #搜索来源 + card: AMR #分享外观 + "1": + ... +``` +|参数|值范围|用途| +|------|------|------| +|pattern|正则表达式|在搜索消息中的歌曲时,会使用该正则表达式进行匹配,如果匹配成功,则会把group(1)的结果作为歌曲ID进行搜索,并发送卡片| +|source|QQ音乐
网易
网易HQ
酷狗
千千
喜马拉雅
本地
Bilibili|设定搜索歌曲的来源
注意:部分平台不支持。| +|card|LightApp:小程序分享
Mirai:采用Mirai的MusicShare卡片,如果不存在则fallback为XML卡片
XML:卡片分享
Share:普通分享(不能播放)
Message:以纯信息形式分享,可以很方便取得音乐的各种链接。
AMR:AMR语音,需要配置好`ffmpeg_path`
Silk:SILK语音,需要同时配置好`silkenc_path`和`ffmpeg_path`,由于tx限流,质量可能很差(不推荐使用)|设定分享出来的音乐的外观| + +如果不需要原版的解析,可以设置配置项`adddefault`为false。 + # 权限系统 权限系统可以用于配置各个机器人、群和好友的权限。 权限文件位于`data/com.khjxiaogu.mirai.MiraiSongPlugin`目录下。 diff --git a/pom.xml b/pom.xml index f4f6846..01c18e7 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.khjxiaogu MiraiSongPlugin - 1.2.0 + 1.2.1 MiraiSongPlugin 使用“#音乐 关键词”、“#QQ 关键词”、“#网易 关键词”等方式进行点歌的插件。 diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/HttpRequestBuilder.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/HttpRequestBuilder.java new file mode 100644 index 0000000..2957b44 --- /dev/null +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/HttpRequestBuilder.java @@ -0,0 +1,154 @@ +package com.khjxiaogu.MiraiSongPlugin; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class HttpRequestBuilder { + private StringBuilder url; + + List headers=new ArrayList<>(); + + public HttpRequestBuilder(String ourl) { + url=new StringBuilder(ourl); + } + public static HttpRequestBuilder create(String host) { + return new HttpRequestBuilder("https://"+host).host(host); + } + public static HttpRequestBuilder create(String protocol,String host) { + return new HttpRequestBuilder(protocol+"://"+host).host(host); + } + public HttpRequestBuilder url(String v) { + url.append(v); + return this; + } + public HttpRequestBuilder url(int v) { + url.append(v); + return this; + } + public HttpRequestBuilder url(char v) { + url.append(v); + return this; + } + public HttpRequestBuilder header(String k,String v) { + headers.add(new String[] {k,v}); + return this; + } + public HttpRequestBuilder referer(String v) { + headers.add(new String[] {"referer",v}); + return this; + } + public HttpRequestBuilder contenttype(String v) { + headers.add(new String[] {"content-type",v}); + return this; + } + public HttpRequestBuilder cookie(String v) { + headers.add(new String[] {"cookie",v}); + return this; + } + public HttpRequestBuilder host(String v) { + headers.add(new String[] {"Host",v}); + return this; + } + public HttpRequestBuilder defUA() { + headers.add(new String[] {"User-Agent", + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"}); + return this; + } + public HttpRequestBuilder ua(String v) { + headers.add(new String[] {"User-Agent",v}); + return this; + } + public static class OpenedConnectionBuilder { + HttpURLConnection huc; + public OutputStream os; + public OpenedConnectionBuilder(HttpURLConnection huc,boolean doOut) throws IOException { + super(); + this.huc = huc; + if(doOut) + this.os = huc.getOutputStream(); + } + public OpenedConnectionBuilder(HttpURLConnection huc) { + super(); + this.huc = huc; + } + public OpenedConnectionBuilder send(String s) throws IOException { + if(os==null) + os=huc.getOutputStream(); + os.write(s.getBytes(StandardCharsets.UTF_8)); + return this; + } + public OpenedConnectionBuilder send(byte[] s) throws IOException { + if(os==null) + os=huc.getOutputStream(); + os.write(s); + return this; + } + public String readString() throws IOException { + return new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8); + } + public JsonObject readJson() throws IOException { + return JsonParser.parseString(new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8)).getAsJsonObject(); + } + } + private HttpURLConnection openConn() throws IOException { + URL url = new URL(this.url.toString()); + HttpURLConnection huc = (HttpURLConnection) url.openConnection(); + huc.setInstanceFollowRedirects(true); + huc.setConnectTimeout(5000); + huc.setReadTimeout(5000); + for(String[] header:headers) { + huc.setRequestProperty(header[0], header[1]); + } + + return huc; + } + public OpenedConnectionBuilder post(boolean doOutput) throws IOException { + HttpURLConnection huc=openConn(); + huc.setRequestMethod("POST"); + huc.setDoOutput(doOutput); + huc.setDoInput(true); + huc.connect(); + return new OpenedConnectionBuilder(huc,doOutput); + + } + public OpenedConnectionBuilder post() throws IOException { + HttpURLConnection huc=openConn(); + huc.setRequestMethod("POST"); + huc.setDoOutput(true); + huc.setDoInput(true); + huc.connect(); + return new OpenedConnectionBuilder(huc,true); + } + public OpenedConnectionBuilder get(boolean doOutput) throws IOException { + HttpURLConnection huc=openConn(); + huc.setRequestMethod("GET"); + huc.setDoOutput(doOutput); + huc.setDoInput(true); + huc.connect(); + return new OpenedConnectionBuilder(huc,doOutput); + } + public OpenedConnectionBuilder get() throws IOException { + HttpURLConnection huc=openConn(); + huc.setRequestMethod("GET"); + huc.connect(); + return new OpenedConnectionBuilder(huc,false); + } + public OpenedConnectionBuilder open(String met,boolean doInput,boolean doOutput) throws IOException { + HttpURLConnection huc=openConn(); + huc.setRequestMethod(met); + huc.setDoOutput(doOutput); + huc.setDoInput(doInput); + huc.connect(); + return new OpenedConnectionBuilder(huc,doOutput); + } + + +} diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/JsonBuilder.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/JsonBuilder.java new file mode 100644 index 0000000..2a7abd9 --- /dev/null +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/JsonBuilder.java @@ -0,0 +1,114 @@ +package com.khjxiaogu.MiraiSongPlugin; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +public class JsonBuilder { + + public JsonBuilder() { + } + public static JsonArrayBuilder array(){ + return new JsonArrayBuilder<>(null); + } + public static JsonObjectBuilder object(){ + return new JsonObjectBuilder<>(null); + } + public static class JsonArrayBuilder { + JsonArray jo=new JsonArray(); + T parent; + private JsonArrayBuilder(T par) { + parent=par; + } + public T end() { + if(parent==null) + return (T) jo; + return parent; + } + public JsonArrayBuilder add(String v){ + jo.add(v); + return this; + } + public JsonArrayBuilder add(Number v){ + jo.add(v); + return this; + } + public JsonArrayBuilder add(boolean v){ + jo.add(v); + return this; + } + public JsonArrayBuilder add(Character v){ + jo.add(v); + return this; + } + public JsonArrayBuilder add(JsonElement v){ + jo.add(v); + return this; + } + public JsonObjectBuilder> object(){ + JsonObjectBuilder> job= new JsonObjectBuilder<>(this); + this.add(job.get()); + return job; + } + public JsonArrayBuilder> array(){ + JsonArrayBuilder> job= new JsonArrayBuilder<>(this); + this.add(job.get()); + return job; + } + public JsonArray get() { + return jo; + }; + public String toString() { + return jo.toString(); + } + } + public static class JsonObjectBuilder { + JsonObject jo=new JsonObject(); + T parent; + private JsonObjectBuilder(T par) { + parent=par; + } + + public T end() { + if(parent==null) + return (T) jo; + return parent; + } + public JsonObjectBuilder add(String k,String v){ + jo.addProperty(k,v); + return this; + } + public JsonObjectBuilder add(String k,Number v){ + jo.addProperty(k,v); + return this; + } + public JsonObjectBuilder add(String k,boolean v){ + jo.addProperty(k,v); + return this; + } + public JsonObjectBuilder add(String k,Character v){ + jo.addProperty(k, v); + return this; + } + public JsonObjectBuilder add(String k,JsonElement v){ + jo.add(k, v); + return this; + } + public JsonObjectBuilder> object(String k){ + JsonObjectBuilder> job= new JsonObjectBuilder>(this); + this.add(k, job.get()); + return job; + } + public JsonArrayBuilder> array(String k){ + JsonArrayBuilder> job= new JsonArrayBuilder<>(this); + this.add(k,job.get()); + return job; + } + public JsonObject get() { + return jo; + }; + public String toString() { + return jo.toString(); + } + } +} diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MiraiSongPlugin.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MiraiSongPlugin.java index 0eec8fd..a114307 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MiraiSongPlugin.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MiraiSongPlugin.java @@ -24,9 +24,11 @@ import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -52,7 +54,6 @@ import com.khjxiaogu.MiraiSongPlugin.musicsource.NetEaseHQMusicSource; import com.khjxiaogu.MiraiSongPlugin.musicsource.NetEaseMusicSource; import com.khjxiaogu.MiraiSongPlugin.musicsource.NetEaseRadioSource; -import com.khjxiaogu.MiraiSongPlugin.musicsource.QQMusicHQSource; import com.khjxiaogu.MiraiSongPlugin.musicsource.QQMusicSource; import com.khjxiaogu.MiraiSongPlugin.musicsource.XimalayaSource; import com.khjxiaogu.MiraiSongPlugin.permission.GlobalMatcher; @@ -103,7 +104,7 @@ public MiraiSongPlugin() { static { // 注册音乐来源 sources.put("QQ音乐", new QQMusicSource()); - sources.put("QQ音乐HQ", new QQMusicHQSource()); + sources.put("QQ音乐HQ", new QQMusicSource()); sources.put("网易", new NetEaseMusicSource()); sources.put("网易电台节目", new NetEaseAdvancedRadio()); sources.put("网易电台", new NetEaseRadioSource()); @@ -113,9 +114,9 @@ public MiraiSongPlugin() { sources.put("Bilibili", new BiliBiliMusicSource()); sources.put("喜马拉雅", new XimalayaSource()); sources.put("本地", new LocalFileSource()); - //Register music source + // Register music source sources.put("QQMusic", new QQMusicSource()); - sources.put("QQMusicHQ", new QQMusicHQSource()); + sources.put("QQMusicHQ", new QQMusicSource()); sources.put("NeteaseCloudMusic", new NetEaseMusicSource()); sources.put("NeteaseRadioProgramme", new NetEaseAdvancedRadio()); sources.put("NeteaseRadio", new NetEaseRadioSource()); @@ -125,7 +126,7 @@ public MiraiSongPlugin() { sources.put("Bilibili", new BiliBiliMusicSource()); sources.put("Ximalaya", new XimalayaSource()); sources.put("Local", new LocalFileSource()); - + // 注册外观 // cards.put("LightApp", new LightAppCardProvider()); cards.put("LightApp", new MiraiMusicCard()); @@ -137,28 +138,29 @@ public MiraiSongPlugin() { cards.put("Message", new PlainMusicInfoProvider()); cards.put("Mirai", new MiraiMusicCard()); } - static { - HttpURLConnection.setFollowRedirects(true); - } private static MiraiSongPlugin plugin; public static MiraiLogger getMLogger() { return plugin.getLogger(); } + public static List urlMatchers = new ArrayList<>(); GlobalMatcher matcher = new GlobalMatcher(); String unfoundSong; String unavailableShare; String templateNotFound; String sourceNotFound; - public void makeCommand(String cmd,String source, String card) { - if(cmd.equals("/msp")) + boolean enableParser; + public void makeCommand(String cmd, String source, String card) { + if (cmd.equals("/msp")) throw new IllegalArgumentException("/msp can not be overriden"); - commands.put(cmd,makeTemplate(source,card)); + commands.put(cmd, makeTemplate(source, card)); } + public void removeCommand(String cmd) { commands.remove(cmd); } + private BiConsumer makeTemplate(String source, String card) { if (source.equals("all")) return makeSearchesTemplate(card); @@ -180,8 +182,8 @@ private BiConsumer makeTemplate(String source, String ca return; } try { - Message m=cb.process(mi, Utils.getProperReceiver(event)); - if(m!=null) { + Message m = cb.process(mi, Utils.getProperReceiver(event)); + if (m != null) { Utils.getProperReceiver(event).sendMessage(m); return; } @@ -219,8 +221,8 @@ private BiConsumer makeSearchesTemplate(String card) { continue; } try { - Message m=cb.process(mi, Utils.getProperReceiver(event)); - if(m!=null) { + Message m = cb.process(mi, Utils.getProperReceiver(event)); + if (m != null) { Utils.getProperReceiver(event).sendMessage(m); return; } @@ -288,45 +290,85 @@ public void onEnable() { GlobalEventChannel.INSTANCE.registerListenerHost(new SimpleListenerHost(this.getCoroutineContext()) { @EventHandler public void onGroup(GroupMessageEvent event) { - String[] args = Utils.getPlainText(event.getMessage()).split(spliter); + String orig = Utils.getPlainText(event.getMessage()); + String[] args = orig.split(spliter); BiConsumer exec = commands.get(args[0]); - if (exec != null) + if (exec != null) { if (matcher.match(new MatchInfo(args[0], event.getSender())).isAllowed()) exec.accept(event, args); + return; + } + if (enableParser&&matcher.match(new MatchInfo("parse", event.getSender())).isAllowed()) + parseExternLink(orig,event); } @EventHandler public void onFriend(FriendMessageEvent event) { - String[] args = Utils.getPlainText(event.getMessage()).split(spliter); + String orig = Utils.getPlainText(event.getMessage()); + String[] args = orig.split(spliter); BiConsumer exec = commands.get(args[0]); - if (exec != null) + if (exec != null) { if (matcher.match(new MatchInfo(args[0], event.getSender(), false)).isAllowed()) exec.accept(event, args); + return; + } + if (enableParser&&matcher.match(new MatchInfo("parse", event.getSender(), false)).isAllowed()) + parseExternLink(orig,event); } @EventHandler public void onTemp(StrangerMessageEvent event) { - String[] args = Utils.getPlainText(event.getMessage()).split(spliter); + String orig = Utils.getPlainText(event.getMessage()); + String[] args = orig.split(spliter); BiConsumer exec = commands.get(args[0]); - if (exec != null) + if (exec != null) { if (matcher.match(new MatchInfo(args[0], event.getSender(), true)).isAllowed()) exec.accept(event, args); + return; + } + if (enableParser&&matcher.match(new MatchInfo("parse", event.getSender(), true)).isAllowed()) + parseExternLink(orig,event); } }); getLogger().info("插件加载完毕!"); } + public void parseExternLink(String orig, MessageEvent event) { + + for (SongIdMatcher sim : urlMatchers) { + Message m = null; + try { + m = sim.test(orig, event.getSender()); + } catch (Exception e) { + continue; + } + if (m != null) { + Utils.getProperReceiver(event).sendMessage(m); + break; + } + } + } + public static SongIdMatcher makeMatcher(String pattern,String source,String card) { + return new SongIdMatcher(pattern,sources.get(source),cards.get(card)); + } public void reload() { YamlMap cfg = Yaml.getDefault().decodeYamlMapFromString( new String(Utils.readAll(new File(this.getDataFolder(), "config.yml")), StandardCharsets.UTF_8)); matcher.load(this.getDataFolder()); YamlMap excs = (YamlMap) cfg.get(new YamlLiteral("extracommands")); + YamlMap exps = (YamlMap) cfg.get(new YamlLiteral("extraparsers")); String addDefault = cfg.getStringOrNull("adddefault"); commands.clear(); + + + if (addDefault == null || addDefault.equals("true")) { + urlMatchers.add(makeMatcher("music\\.163\\.com.*/song.*\\?.*id=([0-9]+)","网易","Mirai")); + urlMatchers.add(makeMatcher("i\\.y\\.qq\\.com/v8/playsong\\.html\\?.*songid=([0-9]+)","QQ音乐","Mirai")); + urlMatchers.add(makeMatcher("y\\.qq\\.com/n/yqq/song/([0-9A-Za-z]+)","QQ音乐","Mirai")); commands.put("#音乐", makeSearchesTemplate("Mirai")); commands.put("#外链", makeSearchesTemplate("Message")); commands.put("#语音", makeSearchesTemplate("AMR")); @@ -374,11 +416,17 @@ public void reload() { } if (excs != null) for (YamlElement cmd : excs.getKeys()) { - makeCommand(cmd.toString(),((YamlMap) excs.get(cmd)).getString("source"), + makeCommand(cmd.toString(), ((YamlMap) excs.get(cmd)).getString("source"), ((YamlMap) excs.get(cmd)).getString("card")); } + if (exps != null) + for (YamlElement cmd : exps.getKeys()) { + urlMatchers.add(makeMatcher(((YamlMap) excs.get(cmd)).getString("pattern"),((YamlMap) excs.get(cmd)).getString("source"),((YamlMap) excs.get(cmd)).getString("card"))); + } commands.put("/msp", (ev, args) -> { - if (!matcher.match(new MatchInfo(args[0], ev.getSender(), true).mustMatchCommand()).and(matcher.match(new MatchInfo(args[0] + "." + args[1], ev.getSender(), true).mustMatchCommand())).isForceAllowed()) + if (!matcher.match(new MatchInfo(args[0], ev.getSender(), true).mustMatchCommand()) + .and(matcher.match(new MatchInfo(args[0] + "." + args[1], ev.getSender(), true).mustMatchCommand())) + .isForceAllowed()) return; if (args[1].equals("reload")) { @@ -436,6 +484,8 @@ public void reload() { String usecc = cfg.getStringOrNull("use_custom_ffmpeg_command"); String ulocal = cfg.getStringOrNull("enable_local"); String vb = cfg.getStringOrNull("verbose"); + String it=cfg.getStringOrNull("enableParser"); + enableParser=it==null||it.equals("true"); unfoundSong = cfg.getStringOrNull("hintsongnotfound"); if (unfoundSong == null) unfoundSong = "无法找到歌曲。"; diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicInfo.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicInfo.java index 22276af..c7601db 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicInfo.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicInfo.java @@ -122,4 +122,10 @@ public MusicInfo(String title, String desc, String purl, String murl, String jur this.icon = icon; this.appid = 0; } + + @Override + public String toString() { + return "歌曲信息\n歌名:" + title + "\n作者:" + desc + "\n封面:" + purl + "\n音频:" + murl + "\n链接:" + jurl + + "\n来自:" + source + "\n小图标:" + icon + "\nAPPID:" + appid; + } } \ No newline at end of file diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicSource.java index 2cf8076..b2a3afd 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/MusicSource.java @@ -37,6 +37,15 @@ public interface MusicSource { * @throws Exception 如果发生异常或者找不到音乐,都抛出异常。 */ public MusicInfo get(String keyword) throws Exception; + /** + * 搜索对应音乐ID并返回音乐信息.
+ * 返回音乐信息不能为null。 + * + * @param keyword 音乐 + * @return return 返回音乐信息数据类 + * @throws Exception 如果发生异常或者找不到音乐,都抛出异常。 + */ + public MusicInfo getId(String id) throws Exception; /** * 返回是否对全部搜索可见
diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/NetEaseCrypto.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/NetEaseCrypto.java index 2418b53..d88c46e 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/NetEaseCrypto.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/NetEaseCrypto.java @@ -217,4 +217,13 @@ public static String[] weapiEncrypt(String content) { return result; } + public static String weapiEncryptParam(String content) { + String[] encrypt=weapiEncrypt(content); + StringBuilder sb = new StringBuilder("params="); + sb.append(encrypt[0]); + sb.append("&encSecKey="); + sb.append(encrypt[1]); + return sb.toString(); + + } } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/SongIdMatcher.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/SongIdMatcher.java new file mode 100644 index 0000000..6f87669 --- /dev/null +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/SongIdMatcher.java @@ -0,0 +1,26 @@ +package com.khjxiaogu.MiraiSongPlugin; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.mamoe.mirai.contact.Contact; +import net.mamoe.mirai.message.data.Message; + +public class SongIdMatcher { + Pattern mc; + MusicSource src; + MusicCardProvider card; + public SongIdMatcher(String regex,MusicSource src,MusicCardProvider cd) { + mc=Pattern.compile(regex); + this.src=Objects.requireNonNull(src); + this.card=Objects.requireNonNull(cd); + } + public Message test(String s,Contact ct) throws Exception { + Matcher m=mc.matcher(s); + if(m.find()) { + return card.process(src.getId(m.group(1)),ct); + } + return null; + } +} diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BaiduMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BaiduMusicSource.java index 5043239..208ee87 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BaiduMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BaiduMusicSource.java @@ -22,6 +22,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.Utils; @@ -33,26 +34,25 @@ public BaiduMusicSource() { @Override public MusicInfo get(String keyword) throws Exception { - keyword=Utils.urlEncode(keyword); JsonObject jo; - HttpURLConnection huc; int requested = 0; + HttpRequestBuilder req=HttpRequestBuilder.create("http","music.baidu.com") + .url("/v1/restserver/ting?format=json&calback=&from=webapp_music&method=baidu.ting.search.catalogSug&query=") + .url(Utils.urlEncode(keyword)) + .referer("http://music.91q.com/") + .defUA(); do { - huc = (HttpURLConnection) new URL( - "http://tingapi.ting.baidu.com/v1/restserver/ting?format=json&calback=&from=webapp_music&method=baidu.ting.search.catalogSug&query=" - + keyword).openConnection(); - huc.setRequestProperty("Host", "tingapi.ting.baidu.com"); - huc.setRequestProperty("Referrer", "http://http://music.taihe.com/"); - huc.setRequestProperty("User-Agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36"); - huc.setRequestMethod("GET"); - huc.connect(); - jo = JsonParser.parseString(new String(Utils.readAll(huc.getInputStream()), "UTF-8")).getAsJsonObject(); - } while (jo.get("error_code").getAsInt() != 22000 && requested++ < 3);// 傻逼百度有时候会请求失败,不断请求直到成功。 + + jo = req.get().readJson(); + } while (jo.get("error_code").getAsInt() != 22000 && requested++ < 3);// 百度有时候会请求失败,不断请求直到成功。 String sid = jo.getAsJsonObject().getAsJsonObject().get("song").getAsJsonArray().get(0).getAsJsonObject() .get("songid").getAsString(); - huc.disconnect(); - huc = (HttpURLConnection) new URL( + return getId(sid); + } + + @Override + public MusicInfo getId(String sid) throws Exception { + HttpURLConnection huc = (HttpURLConnection) new URL( "http://tingapi.ting.baidu.com/v1/restserver/ting?format=json&calback=&from=webapp_music&method=baidu.ting.song.play&songid=" + sid).openConnection(); huc.setRequestProperty("Host", "tingapi.ting.baidu.com"); diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BiliBiliMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BiliBiliMusicSource.java index ffc8b95..099aefd 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BiliBiliMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/BiliBiliMusicSource.java @@ -17,15 +17,11 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.io.FileNotFoundException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.Utils; @@ -34,20 +30,12 @@ public class BiliBiliMusicSource implements MusicSource { @Override public MusicInfo get(String keyword) throws Exception { - keyword=Utils.urlEncode(keyword); - URL url = new URL("https://api.bilibili.com/audio/music-service-c/s?keyword=" + keyword); - HttpURLConnection huc = (HttpURLConnection) url.openConnection(); - huc.setDoInput(true); - huc.setDoOutput(true); - huc.setRequestMethod("GET"); - huc.connect(); - JsonArray ja; + JsonArray ja=HttpRequestBuilder.create("api.bilibili.com") + .url("/audio/music-service-c/s?keyword=") + .url(Utils.urlEncode(keyword)) + .get() + .readJson().get("data").getAsJsonObject().get("result").getAsJsonArray(); String murl; - if (huc.getResponseCode() == 200) { - ja = JsonParser.parseString(new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8)) - .getAsJsonObject().get("data").getAsJsonObject().get("result").getAsJsonArray(); - } else - throw new FileNotFoundException(); JsonObject jo = ja.get(0).getAsJsonObject(); JsonArray pl = jo.get("play_url_list").getAsJsonArray(); int i = 0; @@ -67,4 +55,9 @@ public MusicInfo get(String keyword) throws Exception { return mi; } + @Override + public MusicInfo getId(String id) throws Exception { + throw new UnsupportedOperationException("暂不支持"); + } + } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/KugouMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/KugouMusicSource.java index fec11b2..a1fef1c 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/KugouMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/KugouMusicSource.java @@ -17,11 +17,9 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.net.HttpURLConnection; -import java.net.URL; - import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.Utils; @@ -35,31 +33,33 @@ public KugouMusicSource() { @Override public MusicInfo get(String keyword) throws Exception { keyword=Utils.urlEncode(keyword); - HttpURLConnection huc = (HttpURLConnection) new URL( - "http://msearchcdn.kugou.com/api/v3/search/song?showtype=14&highlight=em&pagesize=1&tag_aggr=1&tagtype=%E5%85%A8%E9%83%A8&plat=0&sver=5&correct=1&api_ver=1&version=9108&page=1&area_code=1&tag=1&with_res_tag=1&keyword=" - + keyword).openConnection(); - huc.setRequestMethod("GET"); - huc.setRequestProperty("Host", "msearchcdn.kugou.com"); - huc.connect(); JsonObject je = JsonParser - .parseString(new String(Utils.readAll(huc.getInputStream()), "UTF-8").replaceAll("", "")) - .getAsJsonObject(); + .parseString(HttpRequestBuilder.create("http","msearchcdn.kugou.com") + .url("/api/v3/search/song?showtype=14&highlight=em&pagesize=1&tag_aggr=1&tagtype=%E5%85%A8%E9%83%A8&plat=0&sver=5&correct=1&api_ver=1&version=9108&page=1&area_code=1&tag=1&with_res_tag=1&keyword=") + .url(keyword) + .get().readString().replaceAll("", "")) + .getAsJsonObject(); String song = je.get("data").getAsJsonObject().get("info").getAsJsonArray().get(0).getAsJsonObject().get("hash") .getAsString(); String album_id = je.get("data").getAsJsonObject().get("info").getAsJsonArray().get(0).getAsJsonObject() .get("album_id").getAsString(); - HttpURLConnection ihuc = (HttpURLConnection) new URL( - "https://wwwapi.kugou.com/yy/index.php?r=play/getdata&hash=" + song + "&album_id=" + album_id + "&_=" - + Utils.getTime()).openConnection(); - ihuc.setRequestMethod("GET"); - ihuc.setRequestProperty("Host", "www.kugou.com"); - ihuc.setRequestProperty("Cookie", COOKIE); - ihuc.connect(); - JsonObject info = JsonParser.parseString(new String(Utils.readAll(ihuc.getInputStream()), "UTF-8")) - .getAsJsonObject().get("data").getAsJsonObject(); + JsonObject info = HttpRequestBuilder.create("wwwapi.kugou.com") + .url("/yy/index.php?r=play/getdata&hash=") + .url(song) + .url("&album_id=") + .url(album_id) + .url("&_=") + .url(String.valueOf(Utils.getTime())) + .cookie(COOKIE) + .get().readJson().get("data").getAsJsonObject(); return new MusicInfo(info.get("audio_name").getAsString(), info.get("author_name").getAsString(), info.get("img").getAsString(), info.get("play_url").getAsString(), "https://www.kugou.com/song/#hash=" + song + "&album_id=" + info.get("album_id").getAsString(), "酷狗","",205141); } + @Override + public MusicInfo getId(String id) throws Exception { + throw new UnsupportedOperationException("暂不支持"); + } + } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/LocalFileSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/LocalFileSource.java index d624f84..e6f9899 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/LocalFileSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/LocalFileSource.java @@ -71,4 +71,9 @@ public MusicInfo get(String keyword) throws Exception { } } + @Override + public MusicInfo getId(String id) throws Exception { + throw new UnsupportedOperationException("暂不支持"); + } + } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseHQMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseHQMusicSource.java index 3661156..bc24ed1 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseHQMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseHQMusicSource.java @@ -17,15 +17,11 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; - import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; +import com.khjxiaogu.MiraiSongPlugin.JsonBuilder; import com.khjxiaogu.MiraiSongPlugin.NetEaseCrypto; -import com.khjxiaogu.MiraiSongPlugin.Utils; public class NetEaseHQMusicSource extends NetEaseMusicSource { @@ -34,47 +30,20 @@ public NetEaseHQMusicSource() { @Override public String queryRealUrl(String id) throws Exception { - JsonObject params = new JsonObject(); - params.addProperty("ids","[" + id + "]"); - params.addProperty("br",999000); - String[] encrypt = NetEaseCrypto.weapiEncrypt(params.toString()); - StringBuilder sb = new StringBuilder("params="); - sb.append(encrypt[0]); - sb.append("&encSecKey="); - sb.append(encrypt[1]); - byte[] towrite = sb.toString().getBytes("UTF-8"); - URL u = new URL("http://music.163.com/weapi/song/enhance/player/url?csrf_token="); - HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod("POST"); - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setConnectTimeout(4000); - conn.setReadTimeout(4000); - conn.setFixedLengthStreamingMode(towrite.length); - conn.setInstanceFollowRedirects(true); - conn.setRequestProperty("Accept", "*/*"); - conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4"); - conn.setRequestProperty("Connection", "keep-alive"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("Content-Length", Integer.toString(towrite.length)); - conn.setRequestProperty("Referer", "https://music.163.com"); - conn.setRequestProperty("Host", "music.163.com"); - conn.setRequestProperty("User-Agent", NetEaseCrypto.getUserAgent()); - conn.connect(); - conn.getOutputStream().write(towrite); - if (conn.getResponseCode() == 200) { - InputStream is = conn.getInputStream(); - byte[] bs = null; - bs = Utils.readAll(is); - is.close(); - conn.disconnect(); - JsonObject main = JsonParser.parseString(new String(bs, "UTF-8")).getAsJsonObject(); - if (main.get("code").getAsInt() == 200) { - JsonArray data = main.get("data").getAsJsonArray(); - JsonObject song = data.get(0).getAsJsonObject(); - if (song.get("code").getAsInt() == 200) { - return song.get("url").getAsString().trim(); - } + + JsonObject main = HttpRequestBuilder.create("music.163.com") + .url("/weapi/song/enhance/player/url?csrf_token=") + .contenttype("application/x-www-form-urlencoded") + .referer("https://music.163.com") + .ua(NetEaseCrypto.getUserAgent()) + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object().add("ids","[" + id + "]").add("br",999000).toString())) + .readJson(); + if (main.get("code").getAsInt() == 200) { + JsonArray data = main.get("data").getAsJsonArray(); + JsonObject song = data.get(0).getAsJsonObject(); + if (song.get("code").getAsInt() == 200) { + return song.get("url").getAsString().trim(); } } return null; diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseMusicSource.java index 1f23a3d..cf64995 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseMusicSource.java @@ -17,15 +17,10 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.io.FileNotFoundException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; - import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; +import com.khjxiaogu.MiraiSongPlugin.JsonBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.NetEaseCrypto; @@ -39,38 +34,19 @@ public NetEaseMusicSource() { public String queryRealUrl(String id) throws Exception { return "http://music.163.com/song/media/outer/url?id=" + id + ".mp3"; } + @Override public MusicInfo get(String keyword) throws Exception { - keyword=Utils.urlEncode(keyword); - JsonObject params = new JsonObject(); - params.addProperty("s", URLDecoder.decode(keyword, "UTF-8")); - params.addProperty("type",1); - params.addProperty("offset",0); - params.addProperty("limit",3); - String[] encrypt = NetEaseCrypto.weapiEncrypt(params.toString()); - StringBuilder sb = new StringBuilder("params="); - sb.append(encrypt[0]); - sb.append("&encSecKey="); - sb.append(encrypt[1]); - URL url = new URL("https://music.163.com/weapi/cloudsearch/get/web?csrf_token="); - HttpURLConnection huc = (HttpURLConnection) url.openConnection(); - huc.setDoInput(true); - huc.setDoOutput(true); - huc.setRequestMethod("POST"); - huc.setRequestProperty("Referer", "http://music.163.com/"); - huc.setRequestProperty("Cookie", "appver=1.5.0.75771;"); - huc.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - huc.connect(); - huc.getOutputStream().write(sb.toString().getBytes(StandardCharsets.UTF_8)); - JsonArray ja; String murl; - String data=new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8); - if (huc.getResponseCode() == 200) { - ja = JsonParser.parseString(data) - .getAsJsonObject().get("result").getAsJsonObject().get("songs").getAsJsonArray(); - } else - throw new FileNotFoundException(); + JsonArray ja=HttpRequestBuilder.create("music.163.com") + .url("/weapi/cloudsearch/get/web?csrf_token=") + .referer("http://music.163.com/") + .cookie("appver=1.5.0.75771;") + .contenttype("application/x-www-form-urlencoded") + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object().add("s", keyword).add("type", 1).add("offset", 0).add("limit", 3).toString())) + .readJson().get("result").getAsJsonObject().get("songs").getAsJsonArray(); JsonObject jo = ja.get(0).getAsJsonObject(); murl = queryRealUrl(jo.get("id").getAsString()); int i = 0; @@ -84,4 +60,24 @@ public MusicInfo get(String keyword) throws Exception { "https://y.music.163.com/m/song?id=" + jo.get("id").getAsString(), "网易云音乐", "", 100495085); } + @Override + public MusicInfo getId(String id) throws Exception { + String murl; + JsonObject jo =HttpRequestBuilder.create("music.163.com") + .url("/weapi/song/detail?csrf_token=") + .referer("http://music.163.com/") + .cookie("appver=1.5.0.75771;") + .contenttype("application/x-www-form-urlencoded") + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object().array("ids").add(id).end().toString())) + .readJson() + .get("songs").getAsJsonArray() + .get(0).getAsJsonObject(); + murl = queryRealUrl(id); + return new MusicInfo(jo.get("name").getAsString(), + jo.get("artists").getAsJsonArray().get(0).getAsJsonObject().get("name").getAsString(), + jo.get("album").getAsJsonObject().get("picUrl").getAsString(), murl, + "https://y.music.163.com/m/song?id=" + jo.get("id").getAsString(), "网易云音乐", "", 100495085); + } + } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseRadioSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseRadioSource.java index 56a7ad6..8a4e03d 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseRadioSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/NetEaseRadioSource.java @@ -17,17 +17,13 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; +import com.khjxiaogu.MiraiSongPlugin.JsonBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.NetEaseCrypto; @@ -42,49 +38,36 @@ public String queryRealUrl(String id) throws Exception { return "http://music.163.com/song/media/outer/url?id=" + id + ".mp3"; } protected JsonObject getSlice(String id,int offset,int limit) throws IOException { - JsonObject params = new JsonObject(); - params.addProperty("radioId",id); - params.addProperty("limit",limit); - params.addProperty("offset",offset); - params.addProperty("asc", true); - String[] encrypt = NetEaseCrypto.weapiEncrypt(params.toString()); - StringBuilder sb = new StringBuilder("params="); - sb.append(encrypt[0]); - sb.append("&encSecKey="); - sb.append(encrypt[1]); - byte[] towrite = sb.toString().getBytes("UTF-8"); - URL u = new URL("https://music.163.com/weapi/dj/program/byradio?csrf_token="); - HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod("POST"); - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setConnectTimeout(4000); - conn.setReadTimeout(4000); - conn.setFixedLengthStreamingMode(towrite.length); - conn.setInstanceFollowRedirects(true); - conn.setRequestProperty("Accept", "*/*"); - conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4"); - conn.setRequestProperty("Connection", "keep-alive"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setRequestProperty("Content-Length", Integer.toString(towrite.length)); - conn.setRequestProperty("Referer", "https://music.163.com"); - conn.setRequestProperty("Host", "music.163.com"); - conn.setRequestProperty("User-Agent", NetEaseCrypto.getUserAgent()); - conn.connect(); - conn.getOutputStream().write(towrite); - - if (conn.getResponseCode() == 200) { - InputStream is = conn.getInputStream(); - byte[] bs = null; - bs = Utils.readAll(is); - is.close(); - conn.disconnect(); - return JsonParser.parseString(new String(bs, "UTF-8")).getAsJsonObject(); - + return HttpRequestBuilder.create("music.163.com") + .url("/weapi/dj/program/byradio?csrf_token=") + .defUA() + .contenttype("application/x-www-form-urlencoded") + .referer("https://music.163.com") + .ua(NetEaseCrypto.getUserAgent()) + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object() + .add("radioId",id) + .add("limit",limit) + .add("offset",offset) + .add("asc", true) + .toString())) + .readJson(); + } + protected JsonObject getProgramSong(String id) throws IOException { + JsonObject main=HttpRequestBuilder.create("music.163.com") + .url("/weapi/dj/program/detail?csrf_token=") + .defUA() + .contenttype("application/x-www-form-urlencoded") + .referer("https://music.163.com") + .ua(NetEaseCrypto.getUserAgent()) + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object().add("id",id).toString())) + .readJson(); + if (main != null && main.get("code").getAsInt() == 200) { + return main.get("program").getAsJsonObject(); } return null; } - protected JsonObject getRadioSong(String id, String keyword) throws IOException { JsonObject main = getSlice(id, 0, 10); int cur=10; @@ -135,44 +118,32 @@ public MusicInfo get(String keyword) throws Exception { public MusicInfo get(String keyword, String songname) throws Exception { - JsonObject params = new JsonObject(); - params.addProperty("s",keyword); - params.addProperty("type",1009); - params.addProperty("offset",0); - params.addProperty("limit",3); - String[] encrypt = NetEaseCrypto.weapiEncrypt(params.toString()); - StringBuilder sb = new StringBuilder("params="); - sb.append(encrypt[0]); - sb.append("&encSecKey="); - sb.append(encrypt[1]); - URL url = new URL("https://music.163.com/weapi/cloudsearch/get/web?csrf_token="); - HttpURLConnection huc = (HttpURLConnection) url.openConnection(); - huc.setDoInput(true); - huc.setDoOutput(true); - huc.setRequestMethod("POST"); - huc.setRequestProperty("Referer", "http://music.163.com/"); - huc.setRequestProperty("Cookie", "appver=1.5.0.75771;"); - huc.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - huc.connect(); - huc.getOutputStream().write(sb.toString().getBytes(StandardCharsets.UTF_8)); - JsonArray ja; - String murl; - if (huc.getResponseCode() == 200) { - String s = new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8); - ja = JsonParser.parseString(s).getAsJsonObject().get("result").getAsJsonObject().get("djRadios") - .getAsJsonArray(); - } else - throw new FileNotFoundException(); - JsonObject detail = ja.get(0).getAsJsonObject(); + JsonArray ja=HttpRequestBuilder.create("music.163.com") + .url("/weapi/cloudsearch/get/web?csrf_token=") + .ua(NetEaseCrypto.getUserAgent()) + .cookie("appver=1.5.0.75771;") + .referer("http://music.163.com/") + .contenttype("application/x-www-form-urlencoded") + .post() + .send(NetEaseCrypto.weapiEncryptParam(JsonBuilder.object() + .add("s",keyword) + .add("type",1009) + .add("offset",0) + .add("limit",3) + .toString())) + .readJson() + .get("result").getAsJsonObject() + .get("djRadios").getAsJsonArray(); + String murl; + JsonObject detail = ja.get(0).getAsJsonObject(); JsonObject jo = getRadioSong(detail.get("id").getAsString(), songname); murl = queryRealUrl(jo.get("id").getAsString()); JsonObject dj = detail.get("dj").getAsJsonObject(); return new MusicInfo(jo.get("name").getAsString(), dj.get("nickname").getAsString(), detail.get("picUrl").getAsString(), murl, - "http://music.163.com/program/" + detail.get("lastProgramId").getAsString() + "/" - + dj.get("userId").getAsString() + "/?userid=" + dj.get("userId").getAsString(), + "http://music.163.com/program?id=" + detail.get("lastProgramId").getAsString(), "网易云电台", "", 100495085); } @@ -180,4 +151,15 @@ public MusicInfo get(String keyword, String songname) throws Exception { public boolean isVisible() { return false; } + + @Override + public MusicInfo getId(String id) throws Exception { + JsonObject jo = getProgramSong(id); + String murl = queryRealUrl(jo.get("mainSong").getAsJsonObject().get("id").getAsString()); + JsonObject dj = jo.get("dj").getAsJsonObject(); + return new MusicInfo(jo.get("name").getAsString(), dj.get("nickname").getAsString(), + jo.get("radio").getAsJsonObject().get("picUrl").getAsString(), murl, + "http://music.163.com/program?id=" + id, + "网易云电台", "", 100495085); + } } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicHQSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicHQSource.java deleted file mode 100644 index e6f9b0f..0000000 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicHQSource.java +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Mirai Song Plugin - * Copyright (C) 2021 khjxiaogu - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.khjxiaogu.MiraiSongPlugin.musicsource; - -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.khjxiaogu.MiraiSongPlugin.Utils; - -public class QQMusicHQSource extends QQMusicSource { - String[] availenc = new String[] { "D00A", // .flac - "A000", // .ape - "F000", // .flac - "M800", // .mp3 - //"O600", // .ogg - "C400", // .m4a - "M500",// .mp3 - }; - String[] availext = new String[] { ".flac", ".ape", ".flac", ".mp3",/* ".ogg",*/ ".m4a", ".mp3", }; - - public QQMusicHQSource() { - } - public static void main(String[] args) { - System.out.println(new QQMusicHQSource().queryRealUrl("000wXPFa1voP29")); - } - //static String cookie=null; - //static long qq=0; - @Override - public String queryRealUrl(String songmid) { - JsonObject main=new JsonObject(); - JsonObject r0=new JsonObject(); - JsonObject comm=new JsonObject(); - JsonObject param=new JsonObject(); - JsonArray fns=new JsonArray(); - JsonArray ids=new JsonArray(); - JsonArray types=new JsonArray(); - String guid=String.valueOf((int)(Math.random()*9000000+1000000)); - main.add("req_0",r0); - r0.addProperty("module","vkey.GetVkeyServer"); - r0.addProperty("method", "CgiGetVkey"); - r0.add("param", param); - //param.addProperty("uin",qq); - param.addProperty("loginflag",1); - param.addProperty("platform", "20"); - param.addProperty("guid",guid); - types.add(0); - param.add("songtype",types); - param.add("songmid",ids); - ids.add(songmid); - param.add("filename",fns); - main.add("comm",comm); - //comm.addProperty("uin",qq); - comm.addProperty("format","json"); - comm.addProperty("ct",19); - comm.addProperty("cv", 0); - //comm.addProperty("authst",""); - StringBuilder urlsb = new StringBuilder("https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey&g_tk=5381"); - //urlsb.append("&loginUin="+qq); - urlsb.append("&format=json&platform=yqq.json&data="); - String out = null; - String iqual = "2"; - int i = 0; - if (iqual != null) - i = Integer.parseInt(iqual); - try { - if (i < availenc.length) - for (; i < availenc.length; i++) { - if(fns.size()>0) - fns.remove(0); - fns.add(availenc[i] + songmid +songmid + availext[i]); - URL u = new URL(urlsb.toString() + URLEncoder.encode(main.toString(),"UTF-8")); - //System.out.println("incoming " + u.toString()); - HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setDoOutput(true); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Host", "u.y.qq.com"); - conn.setRequestProperty("Referer", "http://y.qq.com"); - conn.setRequestProperty("User-Agent", - "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"); - //conn.setRequestProperty("cookie",cookie); - conn.connect(); - byte[] bs = Utils.readAll(conn.getInputStream()); - //System.out.println(new String(bs, "UTF-8")); - out = JsonParser.parseString(new String(bs, "UTF-8")).getAsJsonObject().get("req_0") - .getAsJsonObject().get("data").getAsJsonObject().get("midurlinfo").getAsJsonArray().get(0).getAsJsonObject().get("purl").getAsString(); - - if (out.length()==0) { - continue; - } - break; - } - StringBuilder sb = new StringBuilder("http://ws.stream.qqmusic.qq.com/") - .append(out); - return sb.toString(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public boolean isVisible() { - return false; - } - -} diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicSource.java index e0cf460..3c3f738 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/QQMusicSource.java @@ -18,14 +18,11 @@ package com.khjxiaogu.MiraiSongPlugin.musicsource; import java.io.FileNotFoundException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; - import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; +import com.khjxiaogu.MiraiSongPlugin.JsonBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.Utils; @@ -37,21 +34,14 @@ public QQMusicSource() { public String queryRealUrl(String songmid) { try { - StringBuilder urlsb = new StringBuilder( - "https://u.y.qq.com/cgi-bin/musicu.fcg?format=json&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22"); - urlsb.append(songmid); - urlsb.append( - "%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%2218585073516%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D"); - URL u = new URL(urlsb.toString()); - HttpURLConnection conn = (HttpURLConnection) u.openConnection(); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Host", "u.y.qq.com"); - conn.setRequestProperty("User-Agent", - "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"); - conn.connect(); - byte[] bs = Utils.readAll(conn.getInputStream()); - - JsonObject out = JsonParser.parseString(new String(bs, "UTF-8")).getAsJsonObject(); + JsonObject out =HttpRequestBuilder.create("u.y.qq.com") + .url("/cgi-bin/musicu.fcg?format=json&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%22358840384%22%2C%22songmid%22%3A%5B%22") + .url(songmid) + .url( + "%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%221443481947%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%2218585073516%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D") + .defUA() + .get() + .readJson(); if (out.get("code").getAsInt() != 0) { return null; } @@ -67,35 +57,69 @@ public String queryRealUrl(String songmid) { return null; } + public String fetchMid(String songid) { + try { + JsonObject out =HttpRequestBuilder.create("c.y.qq.com") + .url("/v8/fcg-bin/fcg_play_single_song.fcg?tpl=yqq_song_detail&format=json&songid=") + .url(songid) + .defUA() + .get() + .readJson(); + + return out.get("data").getAsJsonArray().get(0).getAsJsonObject().get("mid").getAsString(); + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + + public JsonObject querySongDetail(String songmid) { + try { + JsonObject out =HttpRequestBuilder.create("u.y.qq.com") + .url("/cgi-bin/musicu.fcg?format=json&data=%7B%22req_0%22%3A%7B%22module%22%3A%22music.pf_song_detail_svr%22%2C%22method%22%3A%22get_song_detail_yqq%22%2C%22param%22%3A%7B%22song_mid%22%3A%22") + .url(songmid) + .url("%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A%221905222%22%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D") + .defUA() + .get() + .readJson(); + if (out.get("code").getAsInt() != 0) { + return null; + } + return out.get("req_0").getAsJsonObject().get("data").getAsJsonObject().get("track_info").getAsJsonObject(); + } catch (Throwable e) { + e.printStackTrace(); + } + return null; + } + @Override public MusicInfo get(String keyword) throws Exception { - URL url = new URL("https://u.y.qq.com/cgi-bin/musicu.fcg"); - HttpURLConnection huc = (HttpURLConnection) url.openConnection(); - huc.setRequestProperty("User-Agent", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"); + - JsonObject scs=new JsonObject(); - JsonObject search=new JsonObject(); - JsonObject searchParam=new JsonObject(); - searchParam.addProperty("query", keyword); - searchParam.addProperty("num_per_page",3); - searchParam.addProperty("search_type",0); - searchParam.addProperty("page_num",1); - search.add("param",searchParam); - search.addProperty("module","music.search.SearchCgiService"); - search.addProperty("method", "DoSearchForQQMusicDesktop"); - scs.add("music.search.SearchCgiService", search); - huc.setRequestMethod("POST"); - huc.setRequestProperty("referer","https://y.qq.com"); - huc.setDoOutput(true); - huc.connect(); - huc.getOutputStream().write(scs.toString().getBytes(StandardCharsets.UTF_8)); - String s=new String(Utils.readAll(huc.getInputStream()), StandardCharsets.UTF_8); - s=s.substring(s.indexOf("{")); - s=s.substring(0,s.lastIndexOf("}")+1); - JsonArray ss = JsonParser.parseString(s).getAsJsonObject().get("music.search.SearchCgiService") - .getAsJsonObject().get("data").getAsJsonObject().get("body").getAsJsonObject().get("song").getAsJsonObject().get("list") - .getAsJsonArray(); + JsonArray ss =HttpRequestBuilder.create("u.y.qq.com") + .url("/cgi-bin/musicu.fcg") + .defUA() + .referer("https://y.qq.com") + .post() + .send(JsonBuilder.object() + .object("music.search.SearchCgiService") + .add("module", "music.search.SearchCgiService") + .add("method", "DoSearchForQQMusicDesktop") + .object("param") + .add("query", keyword) + .add("num_per_page", 3) + .add("search_type", 0) + .add("page_num", 1) + .end() + .end() + .toString()) + .readJson() + .getAsJsonObject() + .get("music.search.SearchCgiService").getAsJsonObject() + .get("data").getAsJsonObject() + .get("body").getAsJsonObject() + .get("song").getAsJsonObject() + .get("list").getAsJsonArray(); JsonObject song = ss.get(0).getAsJsonObject();// .data.song.list String mid = song.get("mid").getAsString(); String musicURL = queryRealUrl(mid); @@ -119,14 +143,45 @@ public MusicInfo get(String keyword) throws Exception { desc = song.get("album").getAsJsonObject().get("name").getAsString(); } - if (musicURL == null) { + if (musicURL == null) throw new FileNotFoundException(); - } + return new MusicInfo(song.get("title").getAsString(), desc, - "http://y.gtimg.cn/music/photo_new/T002R300x300M000" + song.get("album").getAsJsonObject().get("mid").getAsString() + ".jpg", + "http://y.gtimg.cn/music/photo_new/T002R300x300M000" + + song.get("album").getAsJsonObject().get("mid").getAsString() + ".jpg", musicURL, "https://i.y.qq.com/v8/playsong.html?_wv=1&songid=" + song.get("id").getAsString() + "&source=qqshare&ADTAG=qqshare", "QQ音乐", "https://url.cn/PwqZ4Jpi", 100497308); } + @Override + public MusicInfo getId(String id) throws Exception { + String mid=null; + try { + long l=Long.parseLong(id); + if(id.length()>11) + throw new RuntimeException(); + mid=fetchMid(id); + }catch(RuntimeException ex) { + mid=id; + } + if(mid==null)throw new IllegalArgumentException("错误的歌曲ID或MID"); + JsonObject song = querySongDetail(mid); + String desc; + JsonArray singers = song.get("singer").getAsJsonArray(); + StringBuilder sgs = new StringBuilder(); + for (JsonElement je : singers) { + sgs.append(je.getAsJsonObject().get("name").getAsString()); + sgs.append(";"); + } + sgs.deleteCharAt(sgs.length() - 1); + desc = sgs.toString(); + return new MusicInfo(song.get("title").getAsString(), desc, + "http://y.gtimg.cn/music/photo_new/T002R300x300M000" + + song.get("album").getAsJsonObject().get("mid").getAsString() + ".jpg", + queryRealUrl(song.get("mid").getAsString()), "https://i.y.qq.com/v8/playsong.html?_wv=1&songid=" + + song.get("id").getAsString() + "&source=qqshare&ADTAG=qqshare", + "QQ音乐", "https://url.cn/PwqZ4Jpi", 100497308); + } + } diff --git a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/XimalayaSource.java b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/XimalayaSource.java index 065417a..d5134cb 100644 --- a/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/XimalayaSource.java +++ b/src/main/java/com/khjxiaogu/MiraiSongPlugin/musicsource/XimalayaSource.java @@ -17,12 +17,9 @@ */ package com.khjxiaogu.MiraiSongPlugin.musicsource; -import java.net.HttpURLConnection; -import java.net.URL; - import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; +import com.khjxiaogu.MiraiSongPlugin.HttpRequestBuilder; import com.khjxiaogu.MiraiSongPlugin.MusicInfo; import com.khjxiaogu.MiraiSongPlugin.MusicSource; import com.khjxiaogu.MiraiSongPlugin.Utils; @@ -31,31 +28,44 @@ public class XimalayaSource implements MusicSource { @Override public MusicInfo get(String keyword) throws Exception { - keyword=Utils.urlEncode(keyword); - HttpURLConnection huc = (HttpURLConnection) new URL( - "https://www.ximalaya.com/revision/search/main?page=1&spellchecker=true&paidFilter=true&condition=relation&rows=10&device=iPhone&core=track&kw=" - + keyword).openConnection(); - huc.setRequestMethod("GET"); - huc.setRequestProperty("Host", "www.ximalaya.com"); - huc.connect(); - - JsonArray ja = JsonParser - .parseString(new String(Utils.readAll(huc.getInputStream()), "UTF-8")) - .getAsJsonObject().get("data").getAsJsonObject().get("track").getAsJsonObject().get("docs").getAsJsonArray(); + JsonArray ja =HttpRequestBuilder.create("www.ximalaya.com") + .url("/revision/search/main?page=1&spellchecker=true&paidFilter=true&condition=relation&rows=10&device=iPhone&core=track&kw=") + .url(Utils.urlEncode(keyword)) + + .get() + .readJson() + .get("data").getAsJsonObject() + .get("track").getAsJsonObject() + .get("docs").getAsJsonArray(); JsonObject song; int i=-1; do { song=ja.get(++i).getAsJsonObject(); }while(song.get("isPaid").getAsBoolean()); - HttpURLConnection huc2 = (HttpURLConnection) new URL( - "https://www.ximalaya.com/tracks/"+song.get("id").getAsString()+".json").openConnection(); - huc2.setRequestMethod("GET"); - huc2.setRequestProperty("Host", "www.ximalaya.com"); - huc2.connect(); - String out=new String(Utils.readAll(huc2.getInputStream()), "UTF-8"); - String path=JsonParser.parseString(out).getAsJsonObject().get("play_path").getAsString(); + String path=HttpRequestBuilder.create("www.ximalaya.com") + .url("/tracks/") + .url(song.get("id").getAsString()) + .url(".json") + .get() + .readJson().get("play_path").getAsString(); return new MusicInfo(song.get("title").getAsString(),song.get("nickname").getAsString(),"https:"+song.get("coverPath").getAsString(),path,"https://www.ximalaya.com"+song.get("trackUrl").getAsString(),"喜马拉雅"); } + @Override + public MusicInfo getId(String id) throws Exception { + JsonObject out=HttpRequestBuilder.create("www.ximalaya.com") + .url("/tracks/") + .url(id) + .url(".json") + .get() + .readJson(); + return new MusicInfo(out.get("title").getAsString(), + String.valueOf(out.get("nickname")), + out.get("cover_url").getAsString(), + out.get("play_path").getAsString(), + "https://www.ximalaya.com/sound/"+id, + "喜马拉雅"); + } + } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index bce59cb..71afec7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -11,6 +11,7 @@ hintsongnotfound: "无法找到歌曲。" hintcarderror: "分享歌曲失败。" hintnotemplate: "无法找到卡片。" hintsourcenotfound: "无法找到来源。" +enableParser: 1 admins: - 0 extracommands: