diff --git a/netease_music/sql/structure.sql b/netease_music/sql/structure.sql index 9b37c9f..cac2c7e 100644 --- a/netease_music/sql/structure.sql +++ b/netease_music/sql/structure.sql @@ -2,11 +2,27 @@ CREATE DATABASE `neteaseMusic` CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ USE `neteaseMusic`; CREATE TABLE `song` ( `song_id` int(10) unsigned NOT NULL COMMENT '歌曲id', - `title` varchar(200) NOT NULL COMMENT '歌曲名', - `image` varchar(200) NOT NULL COMMENT '封面图 http://p1.music.126.net/ 后面的部分', - `pub_date` varchar(100) NOT NULL COMMENT '发布日期', + `title` varchar(200)NOT NULL COMMENT '歌曲名', + `type` tinyint(4) NOT NULL COMMENT ' 0: 一般类型 1: 通过云盘上传的音乐,网易云不存在公开对应 2: 通过云盘上传的音乐,网易云存在公开对应', + `alias` json DEFAULT NULL COMMENT '歌曲别名(JSON格式数组)', + `pop` float DEFAULT NULL COMMENT '歌曲热度', + `fee` tinyint(4) DEFAULT NULL COMMENT '版权 0: 免费或无版权 1: VIP 歌曲 4: 购买专辑 8: 非会员可免费播放低音质,会员可播放高音质及下载 fee 为 1 或 8 的歌曲均可单独购买 2 元单曲', + `quality` varchar(500)NOT NULL COMMENT '高/中/低/无损质量文件信息', + `cd` varchar(255) NOT NULL COMMENT 'None或如"04", "1/2", "3", "null"的字符串,表示歌曲属于专辑中第几张CD,对应音频文件的Tag', + `no` int(10) unsigned DEFAULT NULL COMMENT '表示歌曲属于CD中第几曲,0表示没有这个字段,对应音频文件的Tag', + `dj_id` int(10) unsigned DEFAULT NULL COMMENT '0: 不是DJ节目 其他:是DJ节目,表示DJ ID', + `s_id` int(10) unsigned DEFAULT NULL COMMENT '对于t == 2的歌曲,表示匹配到的公开版本歌曲ID', + `origin_cover_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0: 未知 1: 原曲 2: 翻唱', + `image` varchar(200)DEFAULT NULL COMMENT '封面图 http://p1.music.126.net/ 后面的部分', + `pub_date` varchar(100)DEFAULT NULL COMMENT '发布日期(弃用)', + `pub_time` bigint(20) unsigned DEFAULT NULL COMMENT '发布日期 毫秒为单位的Unix时间戳', + `no_copyright_rcmd` varchar(255) DEFAULT NULL COMMENT 'None表示可以播,非空表示无版权', + `mv` int(10) unsigned DEFAULT NULL COMMENT '非零表示有MV ID', + `single` tinyint(4) DEFAULT NULL COMMENT '0: 有专辑信息或者是DJ节目 1: 未知专辑', + `version` int(10) unsigned NOT NULL DEFAULT '1' COMMENT '歌曲版本信息', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '爬取时间', `modify_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间', + `data_version` tinyint(4) NOT NULL DEFAULT '1' COMMENT '数据记录版本(如果有字段调整则整体+1)', PRIMARY KEY (`song_id`), KEY `song_id` (`song_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; diff --git a/netease_music/src/getInfo/songInfoUtils.js b/netease_music/src/getInfo/songInfoUtils.js index a72416e..af64f8b 100644 --- a/netease_music/src/getInfo/songInfoUtils.js +++ b/netease_music/src/getInfo/songInfoUtils.js @@ -1,11 +1,12 @@ const fs = require('fs'); const path = require('path'); -const requestUtils = require('../../../utils/requestUtils'); const sleepUtils = require('../../../utils/sleepUtils'); const dbUtils = global.dbUtils; +const { song_detail } = require('NeteaseCloudMusicApi'); + // 从数据库中查出还缺少的歌曲,并进行爬取 async function fetchAll({ args = {} }) { console.log("start fetching songs ..."); @@ -20,6 +21,10 @@ async function fetchAll({ args = {} }) { ${args.order ? `ORDER BY song_id ${args.order}` : ''} ${args.limit ? `LIMIT ${args.limit}` : ''} `; + // 更新现有数据 + sql = `SELECT song_id FROM song WHERE data_version = 1`; + // 测试用 + // sql = `SELECT song_id FROM song_artist_relation group by song_id limit 10`; console.log(sql); var songIds = await dbUtils.query(sql, []); @@ -27,7 +32,7 @@ async function fetchAll({ args = {} }) { // 0 - 100, 200 - 399, 400 - ..., ... - songIds.length-1 // 0 1 2 count-1 - var step = 270; + var step = 1000; var total = songIds.length; var count = Math.ceil(total / step); for (let i = 0; i < count; i++) { @@ -45,56 +50,67 @@ async function fetchAll({ args = {} }) { // 获取音乐详情 async function fetch({ songIdArray, debug = false }) { - let result = await dbUtils.query('SELECT count(*) as count FROM song WHERE song_id = ?', [songId]); - if (result[0].count > 0 && !debug) { - console.log(`数据库中已有数据,跳过 songId: ${songId}`); - return; - } - // https://neteasecloudmusicapi-docs.4everland.app/#/?id=%e8%8e%b7%e5%8f%96%e6%ad%8c%e6%9b%b2%e8%af%a6%e6%83%85 try { - // 每一次大概可以取到270条以上 - var songResult = await song_detail({ - ids: ["64956", "64956"].join(','), - }); - fs.writeFileSync(path.join(__dirname, "../../temp", `song-${playlistId}.json`), JSON.stringify(playlistResult)); + // 每一次大概可以取到1000条以上 + var songResult = await song_detail({ ids: songIdArray.join(',') }); + // fs.writeFileSync(path.join(__dirname, "../../temp", `song-${songIdArray[0]}-${songIdArray[songIdArray.length - 1]}.json`), JSON.stringify(songResult)); } catch (errors) { console.error(errors); return; } + // console.log(songResult.body.songs.map(item => JSON.stringify(item))); - // console.log(playlistResult); + let songAlbumRel = [], songArtistRel = []; + let songInfoList = songResult.body.songs.map(song => { + song.ar.forEach(item => songArtistRel.push([song.id, item.id])); + songAlbumRel.push([song.id, song.al.id || 0]) + return { + title: song.name, // 歌曲标题 + id: song.id, // 歌曲ID + type: song.t, // 0: 一般类型 1: 通过云盘上传的音乐,网易云不存在公开对应 2: 通过云盘上传的音乐,网易云存在公开对应 + alias: JSON.stringify(song.alia), // 别名列表,第一个别名会被显示作副标题 + pop: song.pop, // 小数,常取[0.0, 100.0]中离散的几个数值, 表示歌曲热度 + fee: song.fee, // 版权 0: 免费或无版权 1: VIP 歌曲 4: 购买专辑 8: 非会员可免费播放低音质,会员可播放高音质及下载 fee 为 1 或 8 的歌曲均可单独购买 2 元单曲 + duration: song.dt, // 歌曲时长 + quality: JSON.stringify({ h: song.h, m: song.m, l: song.l, sq: song.sq }), // 高/中/低/无损质量文件信息 + version: song.version, // 歌曲版本信息 + cd: song.cd, // None或如"04", "1/2", "3", "null"的字符串,表示歌曲属于专辑中第几张CD,对应音频文件的Tag + no: song.no, // 表示歌曲属于CD中第几曲,0表示没有这个字段,对应音频文件的Tag + djId: song.djId, // 0: 不是DJ节目 其他:是DJ节目,表示DJ ID + sId: song.s_id, // 对于t == 2的歌曲,表示匹配到的公开版本歌曲ID + originCoverType: song.originCoverType, // 0: 未知 1: 原曲 2: 翻唱 + image: "", + pubTime: song.publishTime, // 毫秒为单位的Unix时间戳 + mv: song.mv, // 非零表示有MV ID + single: song.single, // 0: 有专辑信息或者是DJ节目 1: 未知专辑 + noCopyrightRcmd: song.noCopyrightRcmd ? JSON.stringify(song.noCopyrightRcmd) : "", // None表示可以播,非空表示无版权 - let songInfo = { - songId: songId, - title: title, - image: image, - pubDate: songInfoDict.pubDate, - artist: artist, - artistIds: artistIds, - album: album || null, - albumId: albumId || null, - duration: duration, - }; - // console.log("songInfo", songInfo); - if (albumId != null) - dbUtils.query('INSERT IGNORE INTO song_album_relation SET ?', { - song_id: songInfo.songId, - album_id: songInfo.albumId, - }); - artistIds.forEach(function (artistId) { - dbUtils.query('INSERT IGNORE INTO song_artist_relation SET ?', { - song_id: songInfo.songId, - artist_id: artistId, - }); + artist: song.ar.map(item => item.id), // 歌手列表 + album: song.al.id || 0, // 专辑,如果是DJ节目(dj_type != 0)或者无专辑信息(single == 1),则专辑id为0 + }; }); - dbUtils.query('INSERT IGNORE INTO song SET ?', { - song_id: songInfo.songId, - title: songInfo.title, - image: songInfo.image, - pub_date: songInfo.pubDate, - }); - return songInfo; + + // console.log("songAlbumRel, songArtistRel", songAlbumRel, songArtistRel); + // console.log("songInfoList", songInfoList); + + await dbUtils.query('INSERT IGNORE INTO song_album_relation (song_id, album_id) VALUES ?', [songAlbumRel]); + await dbUtils.query('INSERT IGNORE INTO song_artist_relation (song_id, artist_id) VALUES ?', [songArtistRel]); + await dbUtils.query(` + INSERT INTO song ( + song_id, title, type, alias, pop, fee, quality, cd, + no, dj_id, s_id, origin_cover_type, pub_time, + no_copyright_rcmd, mv, single, version, data_version + ) VALUES ? ON DUPLICATE KEY UPDATE + title = VALUES(title), type = VALUES(type), alias = VALUES(alias), pop = VALUES(pop), fee = VALUES(fee), quality = VALUES(quality), cd = VALUES(cd), + no = VALUES(no), dj_id = VALUES(dj_id), s_id = VALUES(s_id), origin_cover_type = VALUES(origin_cover_type), pub_time = VALUES(pub_time), + no_copyright_rcmd = VALUES(no_copyright_rcmd), mv = VALUES(mv), single = VALUES(single), version = VALUES(version), data_version = VALUES(data_version) + `, [songInfoList.map(songInfo => [ + songInfo.id, songInfo.title, songInfo.type, songInfo.alias, songInfo.pop, songInfo.fee, songInfo.quality, songInfo.cd, + songInfo.no, songInfo.djId, songInfo.sId, songInfo.originCoverType, songInfo.pubTime, + songInfo.noCopyrightRcmd, songInfo.mv, songInfo.single, songInfo.version, 2 + ])]); + // image 因为接口没有返回,所以不更新 } module.exports = { diff --git a/netease_music/src/index.js b/netease_music/src/index.js index 37d7a74..f3ae84c 100644 --- a/netease_music/src/index.js +++ b/netease_music/src/index.js @@ -31,6 +31,8 @@ async function test() { // 不是所有歌手都有个人主页 例如 https://music.163.com/#/artist?id=1079075 + // let res = await songInfoUtils.fetchAll({ args: {} }); + // let res = await albumInfoUtils.fetch({ albumId: "9156", debug: true }); // let res = await artistInfoUtils.fetch({ artistId: "12023508" }); // let res = await songInfoUtils.fetch({ songId: "437608327" }); @@ -40,8 +42,6 @@ async function test() { // let res = await artistInfoUtils.getFromDatabase({ artistId: "12023508" }); // let res = await songInfoUtils.getFromDatabase({ songId: "437608327" }); - let res = await dbUtils.query('INSERT IGNORE INTO song (`song_id`, `title`, `image`, `pub_date`) VALUES ?', - [[[100, '4', '3', '4'], [200, '23', '4', '5']]]); console.log(res); }