-
在此声明,本内容仅供个人学习、研究或娱乐之用,严禁任何形式的商业用途。若您发现本内容被用于商业目的,请立即删除,及时与小编联系,我们将删除原代码。
-
我们尊重并保护所有原创作品的知识产权。
-
为了营造一个健康、积极的网络环境,我们鼓励用户遵守相关法律法规,尊重他人劳动成果,不进行任何形式的侵权行为。同时,我们也将持续优化内容审核机制,加强对侵权行为的打击力度,保障广大用户的合法权益。
-
如有任何疑问或建议,欢迎随时联系小编。我们将竭诚为您提供帮助,共同维护一个和谐、有序的网络空间。
<!-- fastjson格式 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<!--实体类参数校验-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- gson转实体类配置-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.11.0</version>
</dependency>
(1)歌曲查找请求返回示例:
{
"code": 200,
"msg": "成功!",
"data": [
{
"id": "64563865",
"fileName": "小贱、星弟 - 不想做朋友",
"albumName": "不想做朋友",
"singerName": "小贱、星弟",
"albumId": "975285",
"duration": 236,
"singers": [
{
"name": "小贱",
"ip_id": 0,
"id": 3227
},
{
"name": "星弟",
"ip_id": 0,
"id": 3161
}
],
"mvHash": "D42F35525BDA84550E01177191D17B0D",
"type": "audio",
"image": "http://imge.kugou.com/stdmusic/{size}/20210112/20210112235153293725.jpg",
"suffix": "",
"transParam": {
"unionCover": "http://imge.kugou.com/stdmusic/{size}/20210112/20210112235153293725.jpg",
"language": "国语"
},
"timestamp": 1726210030,
"isHaveMv": true,
"playDuration": "3:56",
"playUrl": null,
"hash": null,
"lyrics": null,
"emixSongId": "12ftsp9e"
},
{
"id": "313917307",
"fileName": "钟小明 - 不想做朋友",
"albumName": "翻唱",
"singerName": "钟小明",
"albumId": "44694996",
"duration": 236,
"singers": [
{
"name": "钟小明",
"ip_id": 0,
"id": 5281518
}
],
"mvHash": "CFEF1B0B2A1E2C2309442113CF506994",
"type": "audio",
"image": "http://imge.kugou.com/stdmusic/{size}/20210516/20210516100230949417.jpg",
"suffix": "",
"transParam": {
"unionCover": "http://imge.kugou.com/stdmusic/{size}/20210516/20210516100230949417.jpg",
"language": "国语"
},
"timestamp": 1726210030,
"isHaveMv": true,
"playDuration": "3:56",
"playUrl": null,
"hash": null,
"lyrics": null,
"emixSongId": "56wc574a"
}]
(2)歌曲下载请求返回示例:
{
"code": 200,
"msg": "获取成功",
"data": {
"id": "64563865",
"fileName": "小贱、星弟 - 不想做朋友",
"albumName": "不想做朋友",
"singerName": "小贱、星弟",
"albumId": "975285",
"duration": 236,
"singers": [
{
"name": "小贱",
"ip_id": 0,
"id": 3227
},
{
"name": "星弟",
"ip_id": 0,
"id": 3161
}
],
"mvHash": "D42F35525BDA84550E01177191D17B0D",
"type": "audio",
"image": "http://imge.kugou.com/stdmusic/20210112/20210112235153293725.jpg",
"suffix": "",
"transParam": {
"unionCover": "http://imge.kugou.com/stdmusic/{size}/20210112/20210112235153293725.jpg",
"language": "国语"
},
"timestamp": 1726210030,
"isHaveMv": true,
"playDuration": "3:56",
"playUrl": "https://webfs.kugou.com/202409131515/81c41fb53bb0654a303111f155be5fdb/v3/2168b82c91dbe9b89e19a6a0c6f97bd0/yp/full/ap1014_us635334580_mii0w1iw8z2ai2iphcu80ooo2ki81120_pi406_mx64563865_s2318522131.mp3",
"hash": "2168B82C91DBE9B89E19A6A0C6F97BD0",
"lyrics": "\ufeff[id:$00000000]\r\n[ar:星弟/小贱]\r\n[ti:不想做朋友]\r\n[by:]\r\n[hash:2168b82c91dbe9b89e19a6a0c6f97bd0]\r\n[al:不想做朋友]\r\n[sign:]\r\n[qq:]\r\n[total:0]\r\n[offset:0]\r\n[00:00.00]小贱、星弟 - 不想做朋友\r\n[00:00.26]作词:小贱\r\n[00:01.19]作曲:星弟\r\n[00:14.14]编曲:星弟\r\n[00:17.27]星:\r\n[00:18.31]那句我还爱你差点说出口\r\n[00:24.96]却被你一声问候堵在了心头\r\n[00:32.25]小:\r\n[00:32.59]真的沦落成朋友也能笑着接受\r\n[00:41.09]只是见面时心会比较痛\r\n[00:50.05]其实我不洒脱只是装英雄\r\n[00:56.46]那么爱你怎可能一滴泪没有\r\n[01:04.11]星:\r\n[01:04.37]我说我会再牵手有很多人等候\r\n[01:12.66]合:\r\n[01:13.06]可谁能给我 那样的感动\r\n[01:19.86]星:\r\n[01:20.26]不想和你做朋友\r\n[01:24.04]小:\r\n[01:25.10]夜深的时候\r\n[01:28.22]合:\r\n[01:28.92]还希望有你温暖我胸口\r\n[01:35.42]小:\r\n[01:36.09]不想和你做朋友\r\n[01:39.97]星:\r\n[01:41.06]我会再等候\r\n[01:44.39]合:\r\n[01:44.89]也许等到你 忘了我以后\r\n[02:08.47]星:\r\n[02:09.52]其实我不洒脱只是装英雄\r\n[02:16.12]那么爱你怎可能一滴泪没有\r\n[02:23.08]小:\r\n[02:23.69]我说我会再牵手有很多人等候\r\n[02:31.95]合:\r\n[02:32.36]可谁能给我那样的感动\r\n[02:39.57]小:\r\n[02:39.77]不想和你做朋友\r\n[02:43.27]星:\r\n[02:44.46]夜深的时候\r\n[02:47.67]合:\r\n[02:48.30]还希望有你温暖我胸口\r\n[02:54.86]星:\r\n[02:55.43]不想和你做朋友\r\n[02:59.69]小:\r\n[03:00.28]我会再等候\r\n[03:03.86]合:\r\n[03:04.30]也许等到你 忘了我以后\r\n[03:10.82]小:\r\n[03:11.64]不想和你做朋友夜深的时候\r\n[03:19.77]还希望有你温暖我胸口\r\n[03:26.32]星:\r\n[03:27.03]不想和你做朋友\r\n[03:30.22]小:\r\n[03:30.55]不做朋友\r\n[03:32.12]星:\r\n[03:32.26]我会再等候\r\n[03:34.21]小:\r\n[03:34.37]我会再等候\r\n[03:35.98]星:\r\n[03:36.13]也许等到你 忘了我以后\r\n",
"emixSongId": "12ftsp9e"
}
}
(3) 上请求示例代码
public static void main(String[] args) throws IOException {
long timestamp = System.currentTimeMillis() / 1000;
KuGouHand hand = new KuGouHand();
List<KuGou> list =audioIdList("凯小晴",timestamp,hand);
for (KuGou kuGous : list) {
fetchUrl(kuGous.getEMixSongId(),timestamp,kuGous,hand);
}
}
/**
* 获取MD5验签
*/
public static String setMd5Sign(long timestamp, String audioId,KuGouHand hand) {
List<String> signatureList = new ArrayList<>();
signatureList.add("NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt");
signatureList.add("appid="+hand.getAppid());
signatureList.add("clienttime=" + timestamp);
signatureList.add("clientver=20000");
signatureList.add("dfid="+hand.getDfid());
signatureList.add("encode_album_audio_id=" + audioId);
signatureList.add("mid="+hand.getMid());
signatureList.add("platid="+hand.getPlatid());
signatureList.add("srcappid="+hand.getSrcappid());
signatureList.add("token="+hand.getToken());
signatureList.add("userid="+hand.getUserid());
signatureList.add("uuid="+hand.getUuid());
signatureList.add("NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt");
StringBuilder stringBuilder = new StringBuilder();
for (String s : signatureList) {
stringBuilder.append(s);
}
String sign = getMD5(stringBuilder.toString());
return sign;
}
/**
* MD5算法转换
*/
private static String getMD5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : messageDigest) {
hexString.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* 获取搜索验签
*/
public static String md5SignSearch(String timestamp, String musicName,KuGouHand hand) {
String[] signatureList = {
"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt",
"appid="+hand.getAppid(),
"bitrate="+hand.getBitrate(),
"callback="+hand.getCallback(),
"clienttime=" + timestamp,
"clientver=1000",
"dfid="+hand.getDfid(),
"filter="+hand.getFilter(),
"inputtype="+hand.getInputtype(),
"iscorrection="+hand.getIscorrection(),
"isfuzzy="+hand.getIsfuzzy(),
"keyword=" + musicName,
"mid="+hand.getMid(),
"page="+hand.getPage(),
"pagesize="+hand.getPagesize(),
"platform="+hand.getPlatform(),
"privilege_filter="+hand.getPrivilegefilter(),
"srcappid="+hand.getSrcappid(),
"token="+hand.getToken(),
"userid="+hand.getUserid(),
"uuid="+hand.getUuid(),
"NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt"
};
StringBuilder stringBuilder = new StringBuilder();
for (String s : signatureList) {
stringBuilder.append(s);
}
String string = stringBuilder.toString();
return getMD5(string);
}
/**
* 获取下载地址
*/
public static void fetchUrl(String audioId, long timestamp, KuGou kuGou, KuGouHand hand) throws IOException {
OkHttpClient client = new OkHttpClient();
LinkedHashMap<String, String> param = new LinkedHashMap<>();
param.put("srcappid",hand.getSrcappid() );
param.put("clientver", "20000");
param.put("clienttime", String.valueOf(timestamp));
param.put("mid", hand.getMid());
param.put("uuid", hand.getUuid());
param.put("dfid", hand.getDfid());
param.put("appid", hand.getAppid());
param.put("platid", hand.getPlatid());
param.put("encode_album_audio_id", audioId);
param.put("token", hand.getToken());
param.put("userid", hand.getUserid());
param.put("signature", setMd5Sign(timestamp, audioId,hand));
String url = "https://wwwapi.kugou.com/play/songinfo" + GetParams(param);
Request request = new Request.Builder()
.url(url)
// .headers(headers)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
String responseBody = response.body().string();
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Type type2 = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> map = gson.fromJson(responseBody, type);
Map<String, Object> map2 = gson.fromJson(JSON.toJSONString(map.get("data")), type2);
System.out.println(map2.get("play_url"));
kuGou.setPlayUrl(String.valueOf(map2.get("play_url")));
kuGou.setHash(String.valueOf(map2.get("hash")));
kuGou.setLyrics(String.valueOf(map2.get("lyrics")));
String img = String.valueOf(map2.get("img"));
if (img!=null){
kuGou.setImage(img);
}
}
}
/**
* 获取音乐列表
*/
public static List<KuGou> audioIdList(String musicName, long timestamp, KuGouHand hand) throws IOException {
List<KuGou> list=new ArrayList<>();
String sign = md5SignSearch(String.valueOf(timestamp), musicName,hand);
LinkedHashMap<String, String> param = new LinkedHashMap<>();
param.put("callback", hand.getCallback());
param.put("srcappid", hand.getSrcappid());
param.put("clientver", "1000");
param.put("clienttime", String.valueOf(timestamp));
param.put("mid", hand.getMid());
param.put("uuid", hand.getUuid());
param.put("dfid",hand.getDfid());
param.put("keyword", musicName);
param.put("page", hand.getPage());
param.put("pagesize", hand.getPagesize());
param.put("bitrate", hand.getBitrate());
param.put("isfuzzy", hand.getIsfuzzy());
param.put("inputtype", hand.getInputtype());
param.put("platform", hand.getPlatform());
param.put("userid", hand.getUserid());
param.put("iscorrection", hand.getIscorrection());
param.put("privilege_filter", hand.getPrivilegefilter());
param.put("filter", hand.getFilter());
param.put("token", hand.getToken());
param.put("appid", hand.getAppid());
param.put("signature", sign);
OkHttpClient client = new OkHttpClient();
String url = "https://complexsearch.kugou.com/v2/search/song" + GetParams(param);
Request request = new Request.Builder()
.url(url)
// .headers(headers)
.build();
Response response = client.newCall(request).execute();
String responseBody = response.body().string();
if (response.isSuccessful()) {
int startIndex = responseBody.indexOf("callback123(");
if (startIndex != -1) {
startIndex += "callback123(".length();
int endIndex = responseBody.lastIndexOf(")");
if (endIndex != -1) {
String result = responseBody.substring(startIndex, endIndex);
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Type type2 = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> map = gson.fromJson(result, type);
Map<String, Object> map2 = gson.fromJson(JSON.toJSONString(map.get("data")), type2);
List<KuGou> list2 = JSON.parseArray(JSON.toJSONString(map2.get("lists")), KuGou.class);
return list2;
}
}
return list;
} else {
throw new IOException("No matching results found");
}
}
(4)Dto 实体类KuGouHand
import lombok.Data;
@Data
public class KuGouHand {
//固定 返回名称
private String callback="callback123";
//固定 密匙id
private String srcappid = "2919";
//固定 appid
private String appid = "1014";
//固定
private String platid = "4";
//分页
private String page = "1";
//分页返回数量
private String pagesize="30";
//固定
private String bitrate ="0";
//固定
private String isfuzzy="0";
//固定
private String inputtype="0";
//固定
private String platform="WebFilter";
//固定
private String iscorrection="1";
//固定
private String privilegefilter= "0";
//固定
private String filter= "10";
// 验签方法
private String signature;
// token
private String token = "";
// 用户userId
private String userid = "";
// mid
private String mid = "";
// uuid
private String uuid = "";
// dfif
private String dfid = "";
}
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
@Data
public class KuGou {
@SerializedName("ID")
@NotNull(message = "ID不能为空!")
private String id;
@SerializedName("FileName")
private String fileName;
@SerializedName("EMixSongID")
@NotNull(message = "歌曲ID不能为空!")
private String eMixSongId;
@SerializedName("AlbumName")
private String albumName;
@SerializedName("SingerName")
private String singerName;
@SerializedName("AlbumID")
private String albumId;
@SerializedName("Duration")
private Integer duration;
@SerializedName("Singers")
private Object singers;
@SerializedName("MvHash")
private String mvHash;
@SerializedName("Type")
private String type;
@SerializedName("Image")
private String image;
@SerializedName("Suffix")
private String suffix;
@SerializedName("trans_param")
private HashMap<String,Object> transParam;
//时间戳
@NotNull(message = "原时间戳不能为空!")
private long timestamp;
//是否有Mv视频
private Boolean isHaveMv = false;
//播放时长
private String playDuration;
//播放地址
private String playUrl;
//播放hash
private String hash;
//歌词
private String lyrics;
}
(5)工具类
/**
* 参数装换GET
*/
public static String GetParams(Map<String, String> params) {
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (result.length() > 0) {
result.append("&");
}
result.append(entry.getKey()).append("=").append(entry.getValue());
}
return "?"+result.toString();
}