├── Media ├── PlayParse │ ├── MediaPlayParse - Netease.as │ ├── MediaPlayParse - Netease.ico │ └── Netease_Config.json └── UrlList │ ├── MediaUrlList - Netease.as │ └── MediaUrlList - Netease.ico ├── README.md └── public └── img ├── album.png ├── artist_mv.png ├── artist_song.png ├── mv.png ├── my_playlist.png ├── playlist.png ├── radio.png ├── song.png └── video_playlist.png /Media/PlayParse/MediaPlayParse - Netease.as: -------------------------------------------------------------------------------- 1 | /* 2 | Netease media parse 3 | author: chen310 4 | link: https://github.com/chen310/NeteasePotPlayer 5 | */ 6 | 7 | // void OnInitialize() 8 | // void OnFinalize() 9 | // string GetTitle() -> get title for UI 10 | // string GetVersion -> get version for manage 11 | // string GetDesc() -> get detail information 12 | // string GetLoginTitle() -> get title for login dialog 13 | // string GetLoginDesc() -> get desc for login dialog 14 | // string GetUserText() -> get user text for login dialog 15 | // string GetPasswordText() -> get password text for login dialog 16 | // string ServerCheck(string User, string Pass) -> server check 17 | // string ServerLogin(string User, string Pass) -> login 18 | // void ServerLogout() -> logout 19 | //------------------------------------------------------------------------------------------------ 20 | // bool PlayitemCheck(const string &in) -> check playitem 21 | // array PlayitemParse(const string &in) -> parse playitem 22 | // bool PlaylistCheck(const string &in) -> check playlist 23 | // array PlaylistParse(const string &in) -> parse playlist 24 | 25 | Config ConfigData; 26 | string host = "https://music.163.com"; 27 | 28 | string GetTitle() { 29 | 30 | return "NeteaseCloudMusic"; 31 | } 32 | 33 | string GetVersion() { 34 | 35 | return "1.3"; 36 | } 37 | 38 | string GetDesc() { 39 | 40 | return "https://music.163.com"; 41 | } 42 | 43 | string GetLoginTitle() 44 | { 45 | return "请输入配置文件所在位置"; 46 | } 47 | 48 | string GetLoginDesc() 49 | { 50 | return "请输入配置文件所在位置"; 51 | } 52 | 53 | string GetUserText() 54 | { 55 | return "配置文件路径"; 56 | } 57 | 58 | string GetPasswordText() 59 | { 60 | return ""; 61 | } 62 | 63 | string ServerCheck(string User, string Pass) { 64 | if (User.empty()) { 65 | return "未填写配置文件路径"; 66 | } 67 | if (!isFileExists(User)) { 68 | return "配置文件不存在"; 69 | } 70 | if (ConfigData.cookie.empty()) { 71 | return "未填写cookie"; 72 | } 73 | string info = ""; 74 | JsonReader reader; 75 | JsonValue root; 76 | string res = post("/api/user/level"); 77 | if (reader.parse(res, root) && root.isObject()) { 78 | if (root["code"].asInt() != 200) { 79 | return "无法获取用户信息"; 80 | } 81 | JsonValue data = root["data"]; 82 | if (data.isObject()) { 83 | info += "登录成功\n"; 84 | info += "用户ID: " + data["userId"].asString() + "\n"; 85 | } 86 | } 87 | return info; 88 | } 89 | 90 | string ServerLogin(string User, string Pass) 91 | { 92 | if (User.empty()) return "路径不可为空"; 93 | if (!isFileExists(User)) { 94 | return "配置文件不存在"; 95 | } 96 | ConfigData = ReadConfigFile(User); 97 | if (!ConfigData.cookie.empty() && ConfigData.cookie.find("os=") < 0) { 98 | ConfigData.cookie += "; os=pc; appver=3.1.6.203622"; 99 | } 100 | if (!ConfigData.VIPCookie.empty() && ConfigData.VIPCookie.find("os=") < 0) { 101 | ConfigData.VIPCookie += "; os=pc; appver=3.1.6.203622"; 102 | } 103 | if (ConfigData.debug) { 104 | HostOpenConsole(); 105 | } 106 | 107 | return "配置文件读取成功,填写完配置后需要重启 PotPlayer 才能生效"; 108 | } 109 | 110 | bool isFileExists(string path) { 111 | return HostFileOpen(path) > 0; 112 | } 113 | 114 | class Config { 115 | string fullConfig; 116 | string cookie; 117 | string VIPCookie; 118 | string ip; 119 | string musicQuality = "hires"; 120 | string videoQesolution = "1080"; 121 | bool skipUnavailable = true; 122 | bool useNeteaseApi = false; 123 | string NeteaseApi; 124 | string lyricApi = "https://neteaselyric.chen310.repl.co"; 125 | bool debug = false; 126 | }; 127 | 128 | Config ReadConfigFile(string file) { 129 | Config config; 130 | config.fullConfig = HostFileRead(HostFileOpen(file), 10000); 131 | JsonReader reader; 132 | JsonValue root; 133 | if (reader.parse(config.fullConfig, root) && root.isObject()) { 134 | if (root["cookie"].isString() && !root["cookie"].asString().empty()) { 135 | config.cookie = root["cookie"].asString(); 136 | } 137 | if (root["VIPCookie"].isString() && !root["VIPCookie"].asString().empty()) { 138 | config.VIPCookie = root["VIPCookie"].asString(); 139 | } 140 | if (root["X-Real-IP"].isString() && !root["X-Real-IP"].asString().empty()) { 141 | config.ip = root["X-Real-IP"].asString(); 142 | } 143 | if (root["musicQuality"].isString() && !root["musicQuality"].asString().empty()) { 144 | config.musicQuality = root["musicQuality"].asString(); 145 | } 146 | if (root["videoQesolution"].isString() && !root["videoQesolution"].asString().empty()) { 147 | config.videoQesolution = root["videoQesolution"].asString(); 148 | } 149 | if (root["skipUnavailable"].isBool()) { 150 | config.skipUnavailable = root["skipUnavailable"].asBool(); 151 | } 152 | if (root["useNeteaseApi"].isBool()) { 153 | config.useNeteaseApi = root["useNeteaseApi"].asBool(); 154 | } 155 | if (root["NeteaseApi"].isString() && !root["NeteaseApi"].asString().empty()) { 156 | config.NeteaseApi = root["NeteaseApi"].asString(); 157 | } 158 | if (root["lyricApi"].isString() && !root["lyricApi"].asString().empty()) { 159 | config.lyricApi = root["lyricApi"].asString(); 160 | } 161 | if (root["debug"].isBool()) { 162 | config.debug = root["debug"].asBool(); 163 | } 164 | } 165 | return config; 166 | } 167 | 168 | void log(string item) { 169 | if (!ConfigData.debug) { 170 | return; 171 | } 172 | HostPrintUTF8(item); 173 | } 174 | 175 | void log(string item, string info) { 176 | log(item + ": " + info); 177 | } 178 | 179 | void log(string item, int info) { 180 | log(item + ": " + info); 181 | } 182 | 183 | string post(string api, string data="", bool isInCloudDrive=false) { 184 | string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"; 185 | string url; 186 | string Headers; 187 | if (ConfigData.useNeteaseApi) { 188 | Headers = "Accept: */*\r\nConnection: keep-alive\r\n"; 189 | url = ConfigData.NeteaseApi + api; 190 | } else { 191 | Headers = "Accept: */*\r\nConnection: keep-alive\r\nHost: music.163.com\r\nReferer: https://music.163.com\r\n"; 192 | url = host + api; 193 | } 194 | if (!ConfigData.ip.empty()) { 195 | Headers += "X-Real-IP: " + ConfigData.ip + "\r\n"; 196 | } 197 | if (!isInCloudDrive && !ConfigData.VIPCookie.empty() && (api.find("/api/song/enhance/player/url/v1") >= 0 || api.find("/song/url") >= 0)) { 198 | Headers += "Cookie: " + ConfigData.VIPCookie + "\r\n"; 199 | } else if (!ConfigData.cookie.empty()) { 200 | Headers += "Cookie: " + ConfigData.cookie + "\r\n"; 201 | } 202 | log("request", url); 203 | return HostUrlGetStringWithAPI(url, UserAgent, Headers, data, true); 204 | } 205 | 206 | array Album(string id) { 207 | string res; 208 | if (ConfigData.useNeteaseApi) { 209 | res = post("/album?id=" + id); 210 | } else { 211 | res = post("/api/v1/album/" + id); 212 | } 213 | array songs; 214 | if (!res.empty()) { 215 | JsonReader Reader; 216 | JsonValue Root; 217 | if (Reader.parse(res, Root) && Root.isObject()) { 218 | if (Root["code"].asInt() == 200) { 219 | JsonValue data = Root["songs"]; 220 | if (data.isArray()) { 221 | for (int i = 0; i < data.size(); i++) { 222 | JsonValue item = data[i]; 223 | if (item.isObject()) { 224 | // 填写了 VIPCookie 后不会跳过 VIP 歌曲 225 | if ((ConfigData.skipUnavailable && item["privilege"]["pl"].asInt() == 0 && (ConfigData.VIPCookie.empty() || item["privilege"]["fee"].asInt() != 1))) { 226 | continue; 227 | } 228 | dictionary song; 229 | song["title"] = item["name"].asString(); 230 | song["duration"] = item["dt"].asInt(); 231 | song["url"] = host + "/song?id=" + item["id"].asString(); 232 | song["thumbnail"] = item["al"]["picUrl"].asString(); 233 | song["author"] = item["ar"][0]["name"].asString(); 234 | songs.insertLast(song); 235 | } 236 | } 237 | } 238 | } 239 | } 240 | } 241 | return songs; 242 | } 243 | 244 | array Playlist(string id) { 245 | string res; 246 | if (ConfigData.useNeteaseApi) { 247 | res = post("/playlist/detail?id=" + id); 248 | } else { 249 | res = post("/api/v6/playlist/detail?id=" + id + "&n=100000&s=8"); 250 | } 251 | array songs; 252 | bool isVideoPlaylist; 253 | if (!res.empty()) { 254 | JsonReader Reader; 255 | JsonValue Root; 256 | if (Reader.parse(res, Root) && Root.isObject()) { 257 | if (Root["code"].asInt() == 200) { 258 | isVideoPlaylist = Root["playlist"]["specialType"].asInt() == 200; 259 | // 视频歌单 260 | if (isVideoPlaylist) { 261 | JsonValue data = Root["playlist"]["videos"]; 262 | if (data.isArray()) { 263 | for (int i = 0; i < data.size(); i++) { 264 | JsonValue item = data[i]; 265 | if (item.isObject()) { 266 | dictionary song; 267 | song["title"] = item["mlogBaseData"]["text"].asString(); 268 | song["duration"] = item["mlogBaseData"]["duration"].asInt(); 269 | string vid = item["mlogBaseData"]["id"].asString(); 270 | int videoType = item["mlogBaseData"]["type"].asInt(); 271 | // videoType: 1: video, 2: mlog, 3: mv 272 | if (videoType == 1) { 273 | song["url"] = host + "/#/video?id=" + vid; 274 | } else if (videoType == 2) { 275 | song["url"] = "https://st.music.163.com/mlog/mlog.html?id=" + vid; 276 | } else { 277 | song["url"] = host + "/mv?id=" + vid; 278 | } 279 | song["thumbnail"] = item["mlogBaseData"]["coverUrl"].asString(); 280 | if (item["mlogExtVO"].isObject() && item["mlogExtVO"]["artistName"].isString()) { 281 | song["author"] = item["mlogExtVO"]["artistName"].asString(); 282 | } 283 | songs.insertLast(song); 284 | } 285 | } 286 | } 287 | } else { 288 | JsonValue data = Root["playlist"]["tracks"]; 289 | JsonValue privileges = Root["privileges"]; 290 | if (data.isArray()) { 291 | for (int i = 0; i < data.size(); i++) { 292 | JsonValue item = data[i]; 293 | JsonValue privilege = privileges[i]; 294 | if (item.isObject()) { 295 | if ((ConfigData.skipUnavailable && privilege["pl"].asInt() == 0 && (ConfigData.VIPCookie.empty() || privilege["fee"].asInt() != 1))) { 296 | continue; 297 | } 298 | dictionary song; 299 | song["title"] = item["name"].asString(); 300 | song["duration"] = item["dt"].asInt(); 301 | song["url"] = host + "/song?id=" + item["id"].asString(); 302 | song["thumbnail"] = item["al"]["picUrl"].asString(); 303 | song["author"] = item["ar"][0]["name"].asString(); 304 | songs.insertLast(song); 305 | } 306 | 307 | } 308 | } 309 | } 310 | } 311 | } 312 | } 313 | return songs; 314 | } 315 | 316 | array RecommendSongs() { 317 | string res; 318 | if (ConfigData.useNeteaseApi) { 319 | res = post("/recommend/songs"); 320 | } else { 321 | res = post("/api/v2/discovery/recommend/songs"); 322 | } 323 | array songs; 324 | if (!res.empty()) { 325 | JsonReader Reader; 326 | JsonValue Root; 327 | if (Reader.parse(res, Root) && Root.isObject()) { 328 | if (Root["code"].asInt() == 200) { 329 | JsonValue data = Root["recommend"]; 330 | if (data.isArray()) { 331 | for (int i = 0; i < data.size(); i++) { 332 | JsonValue item = data[i]; 333 | if (item.isObject()) { 334 | if ((ConfigData.skipUnavailable && item["privilege"]["pl"].asInt() == 0 && (ConfigData.VIPCookie.empty() || item["privilege"]["fee"].asInt() != 1))) { 335 | continue; 336 | } 337 | dictionary song; 338 | song["title"] = item["name"].asString(); 339 | song["duration"] = item["duration"].asInt(); 340 | song["url"] = host + "/song?id=" + item["id"].asString(); 341 | song["thumbnail"] = item["album"]["picUrl"].asString(); 342 | song["author"] = item["artists"][0]["name"].asString(); 343 | songs.insertLast(song); 344 | } 345 | } 346 | } 347 | } 348 | } 349 | } 350 | return songs; 351 | } 352 | 353 | array ArtistSong(string id) { 354 | string res; 355 | if (ConfigData.useNeteaseApi) { 356 | res = post("/artist/songs?id=" + id + "&limit=1000"); 357 | } else { 358 | res = post("/api/v1/artist/songs?id=" + id + "&offset=0&limit=1000&private_cloud=true&work_type=1&order=hot"); 359 | } 360 | array songs; 361 | if (!res.empty()) { 362 | JsonReader Reader; 363 | JsonValue Root; 364 | if (Reader.parse(res, Root) && Root.isObject()) { 365 | if (Root["code"].asInt() == 200) { 366 | JsonValue data = Root["songs"]; 367 | if (data.isArray()) { 368 | for (int i = 0; i < data.size(); i++) { 369 | JsonValue item = data[i]; 370 | if (item.isObject()) { 371 | if ((ConfigData.skipUnavailable && item["privilege"]["pl"].asInt() == 0 && (ConfigData.VIPCookie.empty() || item["privilege"]["fee"].asInt() != 1))) { 372 | continue; 373 | } 374 | dictionary song; 375 | song["title"] = item["name"].asString(); 376 | song["duration"] = item["dt"].asInt(); 377 | song["url"] = host + "/song?id=" + item["id"].asString(); 378 | song["thumbnail"] = item["al"]["picUrl"].asString(); 379 | song["author"] = item["ar"][0]["name"].asString(); 380 | songs.insertLast(song); 381 | } 382 | } 383 | } 384 | } 385 | } 386 | } 387 | return songs; 388 | } 389 | 390 | array ArtistMV(string id) { 391 | string res; 392 | if (ConfigData.useNeteaseApi) { 393 | res = post("/artist/mv?id=" + id + "&offset=0&limit=1000"); 394 | } else { 395 | res = post("/api/artist/mvs?artistId=" + id + "&offset=0&limit=1000"); 396 | } 397 | array mvs; 398 | if (!res.empty()) { 399 | JsonReader Reader; 400 | JsonValue Root; 401 | if (Reader.parse(res, Root) && Root.isObject()) { 402 | if (Root["code"].asInt() == 200) { 403 | JsonValue data = Root["mvs"]; 404 | if (data.isArray()) { 405 | for (int i = 0; i < data.size(); i++) { 406 | JsonValue item = data[i]; 407 | if (item.isObject()) { 408 | dictionary mv; 409 | mv["title"] = item["name"].asString(); 410 | mv["duration"] = item["duration"].asInt(); 411 | mv["url"] = host + "/mv?id=" + item["id"].asString(); 412 | mv["thumbnail"] = item["imgurl"].asString(); 413 | mv["author"] = item["artist"]["name"].asString(); 414 | mvs.insertLast(mv); 415 | } 416 | 417 | } 418 | } 419 | } 420 | } 421 | } 422 | return mvs; 423 | } 424 | 425 | array MVSublist() { 426 | string res; 427 | if (ConfigData.useNeteaseApi) { 428 | res = post("/mv/sublist"); 429 | } else { 430 | res = post("/api/cloudvideo/allvideo/sublist"); 431 | } 432 | array mvs; 433 | if (!res.empty()) { 434 | JsonReader Reader; 435 | JsonValue Root; 436 | if (Reader.parse(res, Root) && Root.isObject()) { 437 | if (Root["code"].asInt() == 200) { 438 | JsonValue data = Root["data"]; 439 | if (data.isArray()) { 440 | for (int i = 0; i < data.size(); i++) { 441 | JsonValue item = data[i]; 442 | if (item.isObject()) { 443 | dictionary mv; 444 | int videoType = item["type"].asInt(); 445 | mv["title"] = item["title"].asString(); 446 | mv["duration"] = item["durationms"].asInt(); 447 | if (videoType == 1) { 448 | mv["url"] = host + "/#/video?id=" + item["vid"].asString(); 449 | } else if (videoType == 0) { 450 | mv["url"] = host + "/mv?id=" + item["vid"].asString(); 451 | } 452 | mv["thumbnail"] = item["coverUrl"].asString(); 453 | mv["author"] = item["creator"][0]["userName"].asString(); 454 | mvs.insertLast(mv); 455 | } 456 | } 457 | } 458 | } 459 | } 460 | } 461 | return mvs; 462 | } 463 | 464 | string MlogUrl(string id, const string &in path, dictionary &MetaData, array &QualityList) { 465 | string res; 466 | if (ConfigData.useNeteaseApi) { 467 | res = post("/mlog/url?id=" + id + "&res=" + ConfigData.videoQesolution); 468 | } else { 469 | res = post("/api/mlog/detail/v1?type=1&id=" + id + "&resolution=" + ConfigData.videoQesolution); 470 | } 471 | if (!res.empty()) { 472 | JsonReader Reader; 473 | JsonValue Root; 474 | if (Reader.parse(res, Root) && Root.isObject()) { 475 | if (Root["code"].asInt() == 200) { 476 | JsonValue item = Root["data"]["resource"]["content"]; 477 | MetaData["title"] = item["title"].asString(); 478 | MetaData["webUrl"] = path; 479 | MetaData["content"] = item["title"].asString(); 480 | return item["video"]["urlInfo"]["url"].asString(); 481 | } else { 482 | return ""; 483 | } 484 | } 485 | } 486 | return ""; 487 | } 488 | 489 | string VideoUrl(string id, const string &in path, dictionary &MetaData, array &QualityList) { 490 | string res; 491 | if (ConfigData.useNeteaseApi) { 492 | res = post("/video/detail?id=" + id); 493 | } else { 494 | res = post("/api/cloudvideo/v1/video/detail?id=" + id); 495 | } 496 | if (!res.empty()) { 497 | JsonReader Reader; 498 | JsonValue Root; 499 | if (Reader.parse(res, Root) && Root.isObject()) { 500 | if (Root["code"].asInt() == 200) { 501 | JsonValue item = Root["data"]; 502 | MetaData["title"] = item["title"].asString(); 503 | MetaData["author"] = item["creator"]["nickname"].asString(); 504 | MetaData["content"] = item["description"].asString(); 505 | MetaData["webUrl"] = path; 506 | } else { 507 | return ""; 508 | } 509 | } 510 | } 511 | if (ConfigData.useNeteaseApi) { 512 | res = post("/video/url?id" + id + "&res=" + ConfigData.videoQesolution); 513 | } else { 514 | res = post("/api/cloudvideo/playurl?ids=%5B%22" + id + "%22%5D&resolution=" + ConfigData.videoQesolution); 515 | } 516 | if (!res.empty()) { 517 | JsonReader Reader; 518 | JsonValue Root; 519 | if (Reader.parse(res, Root) && Root.isObject()) { 520 | if (Root["code"].asInt() == 200) { 521 | JsonValue data = Root["urls"]; 522 | if (data.size() == 0) { 523 | return ""; 524 | } 525 | JsonValue item = data[0]; 526 | if (item.isObject()) { 527 | JsonValue url = item["url"]; 528 | if (url.isString() && !url.asString().empty()) { 529 | return url.asString(); 530 | } 531 | } 532 | } else { 533 | return ""; 534 | } 535 | } 536 | } 537 | return ""; 538 | } 539 | 540 | 541 | string MVUrl(string id, const string &in path, dictionary &MetaData, array &QualityList) { 542 | string res; 543 | if (ConfigData.useNeteaseApi) { 544 | res = post("/mv/detail?mvid=" + id); 545 | } else { 546 | res = post("/api/v1/mv/detail?id=" + id); 547 | } 548 | if (!res.empty()) { 549 | JsonReader Reader; 550 | JsonValue Root; 551 | if (Reader.parse(res, Root) && Root.isObject()) { 552 | if (Root["code"].asInt() == 200) { 553 | JsonValue item = Root["data"]; 554 | MetaData["title"] = item["name"].asString(); 555 | MetaData["author"] = item["artistName"].asString(); 556 | MetaData["content"] = item["name"].asString(); 557 | MetaData["webUrl"] = path; 558 | } else { 559 | return ""; 560 | } 561 | } 562 | } 563 | if (ConfigData.useNeteaseApi) { 564 | res = post("/mv/url?id=" + id + "&r=" + ConfigData.videoQesolution); 565 | } else { 566 | res = post("/api/song/enhance/play/mv/url?id=" + id + "&r=" + ConfigData.videoQesolution); 567 | } 568 | if (!res.empty()) 569 | { 570 | JsonReader Reader; 571 | JsonValue Root; 572 | if (Reader.parse(res, Root) && Root.isObject()) 573 | { 574 | if (Root["code"].asInt() == 200) 575 | { 576 | JsonValue item = Root["data"]; 577 | if (item.isObject()) 578 | { 579 | JsonValue url = item["url"]; 580 | if (url.isString() && !url.asString().empty()) 581 | { 582 | return url.asString(); 583 | } 584 | } 585 | } else { 586 | return ""; 587 | } 588 | } 589 | } 590 | return ""; 591 | } 592 | 593 | array Djradio(string id) { 594 | string res; 595 | if (ConfigData.useNeteaseApi) { 596 | res = post("/dj/program?rid=" + id + "&limit=1000"); 597 | } else { 598 | res = post("/api/dj/program/byradio?radioId=" + id + "&offset=0&limit=1000"); 599 | } 600 | array songs; 601 | if (!res.empty()) { 602 | JsonReader Reader; 603 | JsonValue Root; 604 | if (Reader.parse(res, Root) && Root.isObject()) { 605 | if (Root["code"].asInt() == 200) { 606 | JsonValue data = Root["programs"]; 607 | if (data.isArray()) { 608 | for (int i = 0; i < data.size(); i++) { 609 | JsonValue item = data[i]; 610 | if (item.isObject()) { 611 | dictionary song; 612 | song["title"] = item["name"].asString(); 613 | song["duration"] = item["duration"].asInt(); 614 | song["url"] = host + "#/program?id=" + item["id"].asString(); 615 | song["thumbnail"] = item["album"]["picUrl"].asString(); 616 | song["author"] = item["artists"][0]["name"].asString(); 617 | songs.insertLast(song); 618 | } 619 | } 620 | } 621 | } 622 | } 623 | } 624 | return songs; 625 | } 626 | 627 | array GetSongUrl(string id, bool isInCloudDrive) { 628 | string res; 629 | if (ConfigData.useNeteaseApi) { 630 | res = post("/song/url/v1?id=" + id + "&level=" + ConfigData.musicQuality, "", isInCloudDrive); 631 | } else { 632 | if (ConfigData.musicQuality == "dolby") { 633 | res = post("/api/song/enhance/player/url/v1?ids=%5B" + id + "%5D&level=hires&effects=%5B%22dolby%22%5D&encodeType=mp4", "", isInCloudDrive); 634 | } 635 | res = post("/api/song/enhance/player/url/v1?ids=%5B" + id + "%5D&level=" + ConfigData.musicQuality + "&encodeType=mp4", "", isInCloudDrive); 636 | } 637 | array output; 638 | if (!res.empty()) 639 | { 640 | JsonReader Reader; 641 | JsonValue Root; 642 | if (Reader.parse(res, Root) && Root.isObject()) { 643 | if (Root["code"].asInt() == 200) { 644 | JsonValue data = Root["data"]; 645 | if (data.isArray()) { 646 | JsonValue item = data[0]; 647 | if (item.isObject()) { 648 | JsonValue url = item["url"]; 649 | if (url.isString() && !url.asString().empty()) { 650 | output.insertLast(url.asString()); 651 | if (item["level"].isString() && !item["level"].asString().empty()) { 652 | output.insertLast(item["level"].asString()); 653 | } 654 | return output; 655 | } 656 | } 657 | } 658 | } else { 659 | output.insertLast(""); 660 | return output; 661 | } 662 | } 663 | } 664 | output.insertLast(""); 665 | return output; 666 | } 667 | 668 | string getQuality(string level) { 669 | array levelList = { "standard", "higher", "exhigh", "lossless", "hires", "jyeffect", "sky", "jymaster", "dolby" }; 670 | array qualityList = { "标准", "较高", "极高", "无损", "Hi-Res", "高清环绕声", "沉浸环绕声", "超清母带", "杜比全景声"}; 671 | int idx = levelList.find(level); 672 | if (idx >= 0) { 673 | return qualityList[idx]; 674 | } 675 | return level; 676 | } 677 | 678 | string SongUrl(string id, const string &in path, dictionary &MetaData, array &QualityList) { 679 | string res; 680 | if (ConfigData.useNeteaseApi) { 681 | res = post("/song/detail?ids=" + id); 682 | } else { 683 | res = post("/api/v3/song/detail?c=[{\"id\":" + id +"}]"); 684 | } 685 | bool isInCloudDrive = false; 686 | if (!res.empty()) { 687 | JsonReader Reader; 688 | JsonValue Root; 689 | if (Reader.parse(res, Root) && Root.isObject()) { 690 | if (Root["code"].asInt() == 200) { 691 | JsonValue data = Root["songs"]; 692 | if (data.isArray()) { 693 | JsonValue item = data[0]; 694 | if (item.isObject()) { 695 | if (!item["name"].asString().empty()) { 696 | MetaData["title"] = item["name"].asString(); 697 | MetaData["content"] = item["name"].asString(); 698 | MetaData["author"] = item["ar"][0]["name"].asString(); 699 | } 700 | MetaData["webUrl"] = path; 701 | if (!ConfigData.lyricApi.empty()){ 702 | array subtitle; 703 | dictionary dic; 704 | dic["name"] = item["name"].asString(); 705 | dic["url"] = ConfigData.lyricApi + "/lyric?id=" + id; 706 | subtitle.insertLast(dic); 707 | MetaData["subtitle"] = subtitle; 708 | } 709 | if (item["pc"].isObject()) { 710 | isInCloudDrive = true; 711 | } 712 | } 713 | } 714 | } else { 715 | return ""; 716 | } 717 | } 718 | } 719 | array output = GetSongUrl(id, isInCloudDrive); 720 | if (output[0].empty()) { 721 | return ""; 722 | } 723 | if (@QualityList !is null) { 724 | dictionary qualityitem1; 725 | string quality = getQuality(output[1]); 726 | if (isInCloudDrive) { 727 | qualityitem1["quality"] = quality + " (云盘)"; 728 | } else { 729 | qualityitem1["quality"] = quality; 730 | } 731 | qualityitem1["qualityDetail"] = qualityitem1["quality"]; 732 | qualityitem1["url"] = output[0]; 733 | qualityitem1["itag"] = 0; 734 | QualityList.insertLast(qualityitem1); 735 | 736 | dictionary qualityitem2; 737 | qualityitem2["quality"] = "-"; 738 | qualityitem2["qualityDetail"] = qualityitem2["quality"]; 739 | qualityitem2["url"] = output[0]; 740 | qualityitem2["itag"] = 1; 741 | QualityList.insertLast(qualityitem2); 742 | } 743 | return output[0]; 744 | } 745 | 746 | array BoughtSongs() { 747 | string res; 748 | if (ConfigData.useNeteaseApi) { 749 | res = post("/song/purchased?offset=0&limit=1000"); 750 | } else { 751 | res = post("/api/single/mybought/song/list?offset=0&limit=1000"); 752 | } 753 | array songs; 754 | if (!res.empty()) { 755 | JsonReader Reader; 756 | JsonValue Root; 757 | if (Reader.parse(res, Root) && Root.isObject()) { 758 | if (Root["code"].asInt() == 200) { 759 | JsonValue data = Root["data"]["list"]; 760 | if (data.isArray()) { 761 | for (int i = 0; i < data.size(); i++) { 762 | JsonValue item = data[i]; 763 | if (item.isObject()) { 764 | dictionary song; 765 | song["title"] = item["name"].asString(); 766 | song["url"] = host + "/song?id=" + item["songId"].asString(); 767 | song["thumbnail"] = item["picUrl"].asString(); 768 | song["author"] = item["artistName"].asString(); 769 | songs.insertLast(song); 770 | } 771 | } 772 | } 773 | } 774 | } 775 | } 776 | return songs; 777 | } 778 | 779 | string parseArtists(JsonValue list, string sep) { 780 | if (!list.isArray() || list.size() == 0) { 781 | return ""; 782 | } 783 | string res = list[0]["name"].asString(); 784 | for (int i = 1; i < list.size(); i++) { 785 | res += sep; 786 | res += list[i]["name"].asString(); 787 | } 788 | return res; 789 | } 790 | 791 | array Search(string path) { 792 | string res; 793 | string kw; 794 | if (path.find("?WithCaption") >= 0) { 795 | path.replace("?WithCaption", ""); 796 | kw = HostUrlEncode(parse(path, "s")); 797 | } else { 798 | kw = parse(path, "s"); 799 | } 800 | string type = parse(path, "type"); 801 | if (type != "1" and type != "1004" and type != "1006" and type != "1014") { 802 | type = "1"; 803 | } 804 | if (ConfigData.useNeteaseApi) { 805 | res = post("/cloudsearch?keywords=" + kw + "&type=" + type + "&offsest=0&limit=100&total=true"); 806 | } else { 807 | res = post("/api/cloudsearch/pc?s=" + kw + "&type=" + type + "&offsest=0&limit=100&total=true"); 808 | } 809 | array songs; 810 | if (!res.empty()) { 811 | JsonReader Reader; 812 | JsonValue Root; 813 | if (Reader.parse(res, Root) && Root.isObject()) { 814 | if (Root["code"].asInt() == 200) { 815 | JsonValue data = Root["result"]["songs"]; 816 | if (data.isArray()) { 817 | for (int i = 0; i < data.size(); i++) { 818 | JsonValue item = data[i]; 819 | if (item.isObject()) { 820 | JsonValue privilege = item["privilege"]; 821 | if (privilege.isObject()) { 822 | if ((ConfigData.skipUnavailable && privilege["pl"].asInt() == 0 && (ConfigData.VIPCookie.empty() || privilege["fee"].asInt() != 1))) { 823 | continue; 824 | } 825 | } 826 | dictionary song; 827 | song["title"] = item["name"].asString(); 828 | song["duration"] = item["dt"].asInt(); 829 | song["url"] = host + "/song?id=" + item["id"].asString(); 830 | song["thumbnail"] = item["al"]["picUrl"].asString(); 831 | song["author"] = parseArtists(item["ar"], "/"); 832 | songs.insertLast(song); 833 | } 834 | } 835 | } 836 | data = Root["result"]["videos"]; 837 | if (data.isArray()) { 838 | for (int i = 0; i < data.size(); i++) { 839 | JsonValue item = data[i]; 840 | if (item.isObject()) { 841 | dictionary video; 842 | video["title"] = item["title"].asString(); 843 | if (item["vid"].asString().length() >= 32) { 844 | video["url"] = host + "/#/video?id=" + item["vid"].asString(); 845 | } else { 846 | video["url"] = host + "/mv?id=" + item["vid"].asString(); 847 | } 848 | video["thumbnail"] = item["coverUrl"].asString(); 849 | video["author"] = item["creator"][0]["userName"].asString(); 850 | songs.insertLast(video); 851 | } 852 | } 853 | } 854 | data = Root["result"]["mvs"]; 855 | if (data.isArray()) { 856 | for (int i = 0; i < data.size(); i++) { 857 | JsonValue item = data[i]; 858 | if (item.isObject()) { 859 | dictionary mv; 860 | mv["title"] = item["name"].asString(); 861 | mv["url"] = host + "/mv?id=" + item["id"].asString(); 862 | mv["thumbnail"] = item["cover"].asString(); 863 | mv["author"] = item["artists"][0]["name"].asString(); 864 | songs.insertLast(mv); 865 | } 866 | } 867 | } 868 | } 869 | } 870 | } 871 | return songs; 872 | } 873 | 874 | string Program(string id, const string &in path, dictionary &MetaData, array &QualityList) { 875 | string res; 876 | if (ConfigData.useNeteaseApi) { 877 | res = post("/dj/program/detail?id=" + id); 878 | } else { 879 | res = post("/api/dj/program/detail?id=" + id); 880 | } 881 | string songId = "0"; 882 | if (!res.empty()) { 883 | JsonReader Reader; 884 | JsonValue Root; 885 | if (Reader.parse(res, Root) && Root.isObject()) { 886 | if (Root["code"].asInt() == 200) { 887 | JsonValue item = Root["program"]["mainSong"]; 888 | if (item.isObject()) { 889 | songId = item["id"].asString(); 890 | MetaData["title"] = item["name"].asString(); 891 | MetaData["url"] = path; 892 | if (!ConfigData.lyricApi.empty()){ 893 | array subtitle; 894 | dictionary dic; 895 | dic["name"] = item["name"].asString(); 896 | dic["url"] = ConfigData.lyricApi + "/lyric?id=" + id; 897 | subtitle.insertLast(dic); 898 | MetaData["subtitle"] = subtitle; 899 | } 900 | } 901 | } else { 902 | return ""; 903 | } 904 | } 905 | } 906 | return GetSongUrl(songId, false)[0]; 907 | } 908 | 909 | string parse(string url, string key, string defaultValue="") { 910 | string value = HostRegExpParse(url, "\\?" + key + "=([^&]+)"); 911 | if (!value.empty()) { 912 | return value; 913 | } 914 | value = HostRegExpParse(url, "&" + key + "=([^&]+)"); 915 | if (!value.empty()) { 916 | return value; 917 | } 918 | 919 | value = defaultValue; 920 | return value; 921 | } 922 | 923 | bool PlayitemCheck(const string &in path) { 924 | if (path.find("music.163.com") < 0) { 925 | return false; 926 | } 927 | 928 | if (path.find("/song") >= 0) { 929 | return true; 930 | } 931 | 932 | if (path.find("/video") >= 0) { 933 | return true; 934 | } 935 | 936 | if (path.find("/mlog") >= 0) { 937 | return true; 938 | } 939 | 940 | if (path.find("#/mv") >= 0 || path.find("music.163.com/mv") >= 0) { 941 | return true; 942 | } 943 | 944 | if (path.find("/program") >= 0) { 945 | return true; 946 | } 947 | 948 | return false; 949 | } 950 | 951 | bool PlaylistCheck(const string &in path) { 952 | if (path.find("music.163.com") < 0) { 953 | return false; 954 | } 955 | 956 | if (path.find("/playlist") >= 0) { 957 | return true; 958 | } 959 | 960 | if (path.find("/artist?") >= 0) { 961 | return true; 962 | } 963 | 964 | if (path.find("/artist/mv") >= 0) { 965 | return true; 966 | } 967 | 968 | if (path.find("/album") >= 0) { 969 | return true; 970 | } 971 | 972 | if (path.find("/djradio") >= 0 or path.find("/radio") >= 0) { 973 | return true; 974 | } 975 | 976 | if (path.find("/discover/toplist") >= 0) { 977 | return true; 978 | } 979 | 980 | if (path.find("/recommend/taste") >= 0) { 981 | return true; 982 | } 983 | 984 | if (path.find("/purchasedsong") >= 0) { 985 | return true; 986 | } 987 | 988 | if (path.find("/music/mv") >= 0) { 989 | return true; 990 | } 991 | 992 | if (path.find("/search") >= 0) { 993 | return true; 994 | } 995 | 996 | return false; 997 | } 998 | 999 | string parseId(string url) { 1000 | string id = HostRegExpParse(url, "\\?id=([a-zA-Z0-9]+)"); 1001 | if (!id.empty()) { 1002 | return id; 1003 | } 1004 | id = HostRegExpParse(url, "&id=([a-zA-Z0-9]+)"); 1005 | if (!id.empty()) { 1006 | return id; 1007 | } 1008 | return ""; 1009 | } 1010 | 1011 | array PlaylistParse(const string &in path) { 1012 | array result; 1013 | 1014 | if (path.find("/recommend/taste") >= 0) { 1015 | return RecommendSongs(); 1016 | } 1017 | 1018 | if (path.find("/purchasedsong") >= 0) { 1019 | return BoughtSongs(); 1020 | } 1021 | 1022 | if (path.find("/music/mv") >= 0) { 1023 | return MVSublist(); 1024 | } 1025 | 1026 | string id = parseId(path); 1027 | if (id.empty()) { 1028 | // 飙升榜 1029 | if (path.find("/discover/toplist") >= 0) { 1030 | id = "19723756"; 1031 | } else if (path.find("/search") >= 0) { 1032 | return Search(path); 1033 | } else { 1034 | return result; 1035 | } 1036 | } 1037 | 1038 | if (path.find("/artist/mv") >= 0) { 1039 | return ArtistMV(id); 1040 | } 1041 | 1042 | if (path.find("/playlist") >= 0) { 1043 | return Playlist(id); 1044 | } 1045 | 1046 | if (path.find("/album") >= 0) { 1047 | return Album(id); 1048 | } 1049 | 1050 | if (path.find("/artist?") >= 0) { 1051 | return ArtistSong(id); 1052 | } 1053 | 1054 | if (path.find("/djradio") >= 0 or path.find("/radio") >= 0) { 1055 | return Djradio(id); 1056 | } 1057 | 1058 | if (path.find("/discover/toplist") >= 0) { 1059 | return Playlist(id); 1060 | } 1061 | 1062 | return result; 1063 | } 1064 | 1065 | string PlayitemParse(const string &in path, dictionary &MetaData, array &QualityList) { 1066 | string id = parseId(path); 1067 | if (id.empty()) { 1068 | return ""; 1069 | } 1070 | 1071 | if (path.find("/song") >= 0) { 1072 | return SongUrl(id, path, MetaData, QualityList); 1073 | } 1074 | 1075 | if (path.find("/mv") >= 0) { 1076 | return MVUrl(id, path, MetaData, QualityList); 1077 | } 1078 | 1079 | if (path.find("/mlog") >= 0) { 1080 | return MlogUrl(id, path, MetaData, QualityList); 1081 | } 1082 | 1083 | if (path.find("/video") >= 0) { 1084 | return VideoUrl(id, path, MetaData, QualityList); 1085 | } 1086 | 1087 | if (path.find("/program") >= 0) { 1088 | return Program(id, path, MetaData, QualityList); 1089 | } 1090 | 1091 | return path; 1092 | } 1093 | -------------------------------------------------------------------------------- /Media/PlayParse/MediaPlayParse - Netease.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/Media/PlayParse/MediaPlayParse - Netease.ico -------------------------------------------------------------------------------- /Media/PlayParse/Netease_Config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cookie": "", 3 | "VIPCookie": "", 4 | "X-Real-IP": "", 5 | "musicQuality": "hires", 6 | "videoQesolution": "1080", 7 | "skipUnavailable": true, 8 | "useNeteaseApi": false, 9 | "NeteaseApi": "", 10 | "lyricApi": "", 11 | "debug": false 12 | } -------------------------------------------------------------------------------- /Media/UrlList/MediaUrlList - Netease.as: -------------------------------------------------------------------------------- 1 | /* 2 | media url search by netease 3 | author: chen310 4 | link: https://github.com/chen310/NeteasePotPlayer 5 | */ 6 | 7 | // void OnInitialize() 8 | // void OnFinalize() 9 | // string GetTitle() -> get title for UI 10 | // string GetVersion -> get version for manage 11 | // string GetDesc() -> get detail information 12 | // string GetLoginTitle() -> get title for login dialog 13 | // string GetLoginDesc() -> get desc for login dialog 14 | // string GetUserText() -> get user text for login dialog 15 | // string GetPasswordText() -> get password text for login dialog 16 | // string ServerCheck(string User, string Pass) -> server check 17 | // string ServerLogin(string User, string Pass) -> login 18 | // void ServerLogout() -> logout 19 | //------------------------------------------------------------------------------------------------ 20 | // array GetCategorys() -> get category list 21 | // string GetSorts(string Category, string Extra, string PathToken, string Query) -> get sort option 22 | // array GetUrlList(string Category, string Extra, string PathToken, string Query, string PageToken) -> get url list for Category 23 | 24 | // ******************** 设置开始 ******************** 25 | 26 | // 填写 Cookie 27 | string cookie = ""; 28 | // 填写用户 id 29 | string uid = ""; 30 | // 是否使用第三方 API 地址,如为 true,则需在下方填写 API 地址,否则使用官方 API 31 | bool useNeteaseApi = false; 32 | // 第三方 API 地址,详见 https://github.com/Binary/NeteaseCloudMusicApi 33 | string NeteaseApi = ""; 34 | 35 | // ******************** 设置结束 ******************** 36 | 37 | string host = "https://music.163.com"; 38 | 39 | string GetTitle() 40 | { 41 | return "NeteaseCloudMusic"; 42 | } 43 | 44 | string GetVersion() 45 | { 46 | return "1.1"; 47 | } 48 | 49 | string GetDesc() 50 | { 51 | return "https://music.163.com"; 52 | } 53 | 54 | string post(string api, string data="") { 55 | string UserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"; 56 | string url; 57 | string Headers; 58 | if (useNeteaseApi) { 59 | Headers = "Accept: */*\r\nConnection: keep-alive\r\n"; 60 | url = NeteaseApi + api; 61 | } else { 62 | Headers = "Accept: */*\r\nConnection: keep-alive\r\nHost: music.163.com\r\nReferer: https://music.163.com\r\n"; 63 | url = host + api; 64 | } 65 | if (!cookie.empty()) { 66 | Headers += "Cookie: " + cookie + "\r\n"; 67 | } 68 | return HostUrlGetStringWithAPI(url, UserAgent, Headers, data, true); 69 | } 70 | 71 | array MyPlaylist() { 72 | array ret; 73 | if (uid.empty()) { 74 | return ret; 75 | } 76 | string res; 77 | if (useNeteaseApi) { 78 | res = post("/user/playlist?uid=" + uid + "&limit=1000"); 79 | } else { 80 | res = post("/api/user/playlist?uid=" + uid + "&offse=0&limit=1000&includeVideo=true"); 81 | } 82 | if (!res.empty()) { 83 | JsonReader Reader; 84 | JsonValue Root; 85 | if (Reader.parse(res, Root) && Root.isObject()) { 86 | if (Root["code"].asInt() == 200) { 87 | JsonValue data = Root["playlist"]; 88 | if (data.isArray()) { 89 | for (uint i = 0; i < data.size(); i++) { 90 | JsonValue item = data[i]; 91 | if (item.isObject()) { 92 | dictionary playlist; 93 | playlist["title"] = item["name"].asString(); 94 | playlist["url"] = host + "/#/playlist?id=" + item["id"].asString(); 95 | ret.insertLast(playlist); 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | return ret; 103 | } 104 | 105 | array RecommendPlaylist() { 106 | array ret; 107 | if (uid.empty() or cookie.empty()) { 108 | return ret; 109 | } 110 | 111 | dictionary recommendSongs; 112 | recommendSongs["title"] = "每日推荐歌曲"; 113 | recommendSongs["url"] = host + "/#/discover/recommend/taste"; 114 | ret.insertLast(recommendSongs); 115 | 116 | string res; 117 | if (useNeteaseApi) { 118 | res = post("/recommend/resource"); 119 | } else { 120 | res = post("/api/v1/discovery/recommend/resource"); 121 | } 122 | if (!res.empty()) { 123 | JsonReader Reader; 124 | JsonValue Root; 125 | if (Reader.parse(res, Root) && Root.isObject()) { 126 | if (Root["code"].asInt() == 200) { 127 | JsonValue data = Root["recommend"]; 128 | if (data.isArray()) { 129 | for (int i = 0; i < data.size(); i++) { 130 | JsonValue item = data[i]; 131 | if (item.isObject()) { 132 | dictionary playlist; 133 | playlist["title"] = item["name"].asString(); 134 | playlist["url"] = host + "/#/playlist?id=" + item["id"].asString(); 135 | ret.insertLast(playlist); 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | return ret; 143 | } 144 | 145 | array GetCategorys() 146 | { 147 | array ret; 148 | 149 | dictionary item1; 150 | item1["title"] = "我的歌单"; 151 | item1["Category"] = "MyPlaylist"; 152 | ret.insertLast(item1); 153 | 154 | dictionary item2; 155 | item2["title"] = "推荐歌单"; 156 | item2["Category"] = "RecommendPlaylist"; 157 | ret.insertLast(item2); 158 | 159 | return ret; 160 | } 161 | 162 | array GetUrlList(string Category, string Extra, string PathToken, string Query, string PageToken) 163 | { 164 | if (Category == "MyPlaylist") 165 | return MyPlaylist(); 166 | 167 | if (Category == "RecommendPlaylist") 168 | return RecommendPlaylist(); 169 | 170 | array ret; 171 | return ret; 172 | } 173 | -------------------------------------------------------------------------------- /Media/UrlList/MediaUrlList - Netease.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/Media/UrlList/MediaUrlList - Netease.ico -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NeteasePotPlayer 2 | 3 | 适用于 PotPlayer 的网易云音乐插件。如果配合[油猴脚本](https://greasyfork.org/zh-CN/scripts/443047-neteasepotplayer),可以直接在网页打开 PotPlayer 进行播放 4 | 5 | ## 安装插件 6 | 7 | 将项目 `Media/PlayParse` 路径下的 `MediaPlayParse - Netease.as`、 `MediaPlayParse - Netease.ico` 和 `Netease_Config.json` 三个文件复制到 `{PotPlayer 安装路径}\Extension\Media\PlayParse` 文件夹下。 8 | 9 | 将项目 `Media/UrlList` 路径下的 `MediaUrlList - Netease.as` 和 `MediaUrlList - Netease.ico` 两个文件复制到 `{PotPlayer 安装路径}\Extension\Media\UrlList` 文件夹下。 10 | 11 | 比如,如果 PotPlayer 安装路径为 `D:\DAUM\PotPlayer`,则将 `MediaPlayParse - Netease.as`、 `MediaPlayParse - Netease.ico` 和 `Netease_Config.json` 三个文件复制到 `D:\DAUM\PotPlayer\Extension\Media\PlayParse` 文件夹下,将 `MediaUrlList - Netease.as` 和 `MediaUrlList - Netease.ico` 两个文件复制到 `D:\DAUM\PotPlayer\Extension\Media\UrlList` 文件夹下。 12 | 13 | 然后打开 `Netease_Config.json` 文件进行设置。 14 | 15 | ```json5 16 | { 17 | // 填写账号 Cookie 18 | "cookie": "", 19 | // 有多个账号可填写,用来获取歌曲播放链接。可不填 20 | "VIPCookie": "", 21 | "X-Real-IP": "", 22 | // 歌曲音质,可用 standard | higher | exhigh | lossless | hires | jyeffect | sky | jymaster | dolby 23 | "musicQuality": "hires", 24 | // 视频画质 25 | "videoQesolution": "1080", 26 | // 是否跳过不能播放的歌曲 27 | "skipUnavailable": true, 28 | // 是否使用第三方 API 地址,如为 true,则需在下方填写 API 地址,否则使用官方 API 29 | "useNeteaseApi": false, 30 | // 第三方 API 地址,详见 https://github.com/Binary/NeteaseCloudMusicApi 31 | "NeteaseApi": "", 32 | // 歌词 API 33 | "lyricApi": "", 34 | "debug": false 35 | } 36 | ``` 37 | 38 | 填写 cookie 后,则可以播放云盘歌曲,如果是黑胶账号,还能播放 VIP 歌曲。如果不填写 cookie,则只能播放免费歌曲。 39 | 40 | 如果无法访问 vercel,可以自己搭建歌词 API 并填写服务器地址: [NeteaseLyric](https://github.com/chen310/NeteaseLyric) 41 | 42 | 插件默认使用的是官方 API,如果要使用自己搭建的 API,请将 `useNeteaseApi` 变量的值设置为 true,并在 `NeteaseApi` 中填写服务器地址。服务器搭建方法详见 [NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 43 | 44 | 按 F5 打开选项,点击扩展功能下的媒体播放列表/项目,再点击 `NeteaseCloudMusic`,然后打开 `账号设置`,在 `配置文件路径` 中填写配置文件 `Netease_Config.json` 的路径,如 `D:\DAUM\PotPlayer\Extension\Media\PlayParse\Netease_Config.json`,之后可以点击测试按钮进行测试。 45 | 46 | 如果不使用 ctrl + U 的列表功能,后面的设置可不填写:打开 `MediaUrlList - Netease.as` 文件进行设置。 47 | 48 | ```AngelScript 49 | // 填写 Cookie 50 | string cookie = ""; 51 | // 填写用户 id 52 | string uid = ""; 53 | // 是否使用第三方 API 地址,如为 true,则需在下方填写 API 地址,否则使用官方 API 54 | bool useNeteaseApi = false; 55 | // 第三方 API 地址,详见 https://github.com/Binary/NeteaseCloudMusicApi 56 | string NeteaseApi = ""; 57 | ``` 58 | 59 | 需要填写自己的用户 id。如果不填写 cookie,则无法查看隐私歌单。 60 | 61 | ## 在列表中显示缩略图 62 | 63 | 按 F6 打开播放列表,点击鼠标右键,点击`样式`,选择显示缩略图,即可显示缩略图。 64 | 65 | ## 使用 66 | 67 | 使用 PotPlayer 打开网易云链接(快捷键为 ctrl + U),即可播放。 68 | 69 | ### 播放 MV 70 | 71 | 示例链接 72 | 73 | ``` 74 | https://music.163.com/mv?id=482078 75 | ``` 76 | 77 | ![MV](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/mv.png) 78 | 79 | ### 播放歌曲 80 | 81 | 示例链接 82 | 83 | ``` 84 | https://music.163.com/song?id=186331 85 | ``` 86 | 87 | ![Song](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/song.png) 88 | 89 | ### 播放歌单 90 | 91 | 示例链接 92 | 93 | ``` 94 | https://music.163.com/playlist?id=492068610 95 | ``` 96 | 97 | ![Playlist](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/playlist.png) 98 | 99 | ### 播放视频歌单 100 | 101 | 示例链接 102 | 103 | ``` 104 | https://music.163.com/playlist?id=6642773122 105 | ``` 106 | 107 | ![VideoPlaylist](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/video_playlist.png) 108 | 109 | ### 播放专辑 110 | 111 | 示例链接 112 | 113 | ``` 114 | https://music.163.com/#/album?id=6491 115 | ``` 116 | 117 | ![Album](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/album.png) 118 | 119 | ### 播放歌手 MV 120 | 121 | 示例链接 122 | 123 | ``` 124 | https://music.163.com/#/artist/mv?id=7763 125 | ``` 126 | 127 | ![ArtistMV](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/artist_mv.png) 128 | 129 | ### 播放歌手歌曲 130 | 131 | 示例链接 132 | 133 | ``` 134 | https://music.163.com/#/artist?id=2116 135 | ``` 136 | 137 | ![ArtistSong](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/artist_song.png) 138 | 139 | ### 播放电台 140 | 141 | 示例链接 142 | 143 | ``` 144 | https://music.163.com/#/djradio?id=966559685 145 | ``` 146 | 147 | ![Radio](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/radio.png) 148 | 149 | ### 已购单曲 150 | 151 | 示例链接 152 | 153 | ``` 154 | https://music.163.com/#/member/purchasedsong 155 | ``` 156 | 157 | ### 每日歌曲推荐 158 | 159 | 示例链接 160 | 161 | ``` 162 | https://music.163.com/#/discover/recommend/taste 163 | ``` 164 | 165 | ### 排行榜 166 | 167 | 示例链接 168 | 169 | ``` 170 | https://music.163.com/#/discover/toplist 171 | https://music.163.com/#/discover/toplist?id=3779629 172 | ``` 173 | 174 | ### 收藏的视频 175 | 176 | 示例链接 177 | 178 | ``` 179 | https://music.163.com/#/my/m/music/mv 180 | ``` 181 | 182 | ### 我的歌单 183 | 184 | 按 ctrl + U,选择 `NeteaseCloudMusic 我的歌单`,即可得到歌单列表,选择想要播放的歌单,双击即可播放。 185 | 186 | ![MyPlaylist](https://cdn.jsdelivr.net/gh/chen310/NeteasePotPlayer/public/img/my_playlist.png) 187 | -------------------------------------------------------------------------------- /public/img/album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/album.png -------------------------------------------------------------------------------- /public/img/artist_mv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/artist_mv.png -------------------------------------------------------------------------------- /public/img/artist_song.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/artist_song.png -------------------------------------------------------------------------------- /public/img/mv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/mv.png -------------------------------------------------------------------------------- /public/img/my_playlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/my_playlist.png -------------------------------------------------------------------------------- /public/img/playlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/playlist.png -------------------------------------------------------------------------------- /public/img/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/radio.png -------------------------------------------------------------------------------- /public/img/song.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/song.png -------------------------------------------------------------------------------- /public/img/video_playlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chen310/NeteasePotPlayer/f4ed2c75867005571d4840834282f93735e650da/public/img/video_playlist.png --------------------------------------------------------------------------------