diff --git a/assets/radar-rules.js b/assets/radar-rules.js
index 23d9f2e7e..bd7dca853 100644
--- a/assets/radar-rules.js
+++ b/assets/radar-rules.js
@@ -164,53 +164,6 @@
'steampowered.com': { _name: 'Steam', store: [{ title: 'search', docs: 'https://docs.rsshub.app/game.html#steam', source: '/search/', target: (params, url) => `/steam/search/${new URL(url).searchParams}` }] },
// 'baijingapp.com': { _name: '白鲸出海', www: [{ title: '文章', docs: 'https://docs.rsshub.app/new-media.html#bai-jing-chu-hai', source: '', target: '/baijing' }] },
'xiaomi.cn': { _name: '小米社区', www: [{ title: '圈子', docs: 'https://docs.rsshub.app/bbs.html#xiao-mi-she-qu', source: '/board/:boardId', target: '/mi/bbs/board/:boardId' }] },
- '163.com': {
- _name: '网易',
- music: [
- {
- title: '云音乐 - 用户歌单',
- docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue',
- source: '/',
- target: (params, url) => {
- const id = new URL(url).hash.match(/home\?id=(.*)/)[1];
- return id ? `/ncm/user/playlist/${id}` : '';
- },
- },
- {
- title: '云音乐 - 歌单歌曲',
- docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue',
- source: '/',
- target: (params, url) => {
- const id = new URL(url).hash.match(/playlist\?id=(.*)/)[1];
- return id ? `/ncm/playlist/${id}` : '';
- },
- },
- {
- title: '云音乐 - 歌手专辑',
- docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue',
- source: '/',
- target: (params, url) => {
- const id = new URL(url).hash.match(/album\?id=(.*)/)[1];
- return id ? `/ncm/artist/${id}` : '';
- },
- },
- {
- title: '云音乐 - 电台节目',
- docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue',
- source: '/',
- target: (params, url) => {
- const id = new URL(url).hash.match(/djradio\?id=(.*)/)[1];
- return id ? `/ncm/djradio/${id}` : '';
- },
- },
- ],
- 'y.music': [
- { title: '云音乐 - 用户歌单', docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue', source: '/m/user', target: (params, url) => `/ncm/playlist/${new URL(url).searchParams.get('id')}` },
- { title: '云音乐 - 歌单歌曲', docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue', source: '/m/playlist', target: (params, url) => `/ncm/playlist/${new URL(url).searchParams.get('id')}` },
- { title: '云音乐 - 歌手专辑', docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue', source: '/m/album', target: (params, url) => `/ncm/playlist/${new URL(url).searchParams.get('id')}` },
- { title: '云音乐 - 播单声音', docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue', source: ['/m/radio', '/m/djradio'], target: (params, url) => `/ncm/playlist/${new URL(url).searchParams.get('id')}` },
- ],
- },
'suzhou.gov.cn': { _name: '苏州市政府', www: [{ title: '政府新闻', docs: 'https://docs.rsshub.app/government.html#su-zhou-shi-ren-min-zheng-fu', source: '/szsrmzf/:uid/nav_list.shtml', target: '/gov/suzhou/news/:uid' }] },
'mqube.net': {
_name: 'MQube',
diff --git a/docs/multimedia.md b/docs/multimedia.md
index cf75faacf..224a1564a 100644
--- a/docs/multimedia.md
+++ b/docs/multimedia.md
@@ -1628,23 +1628,27 @@ JavDB 有多个备用域名,本路由默认使用永久域名
专辑:${thissong.album.name}
发行日期:${new Date(thissong.album.publishTime).toLocaleDateString()}`,
- link: `https://music.163.com/#/song?id=${item.id}`,
- pubDate: new Date(item.at),
- author: singer,
- };
- }),
- };
-};
diff --git a/lib/v2/163/maintainer.js b/lib/v2/163/maintainer.js
index c5168ec4b..d6fddf203 100644
--- a/lib/v2/163/maintainer.js
+++ b/lib/v2/163/maintainer.js
@@ -3,6 +3,14 @@ module.exports = {
'/ds/:id': ['luyuhuang'],
'/dy/:id': ['HendricksZheng'],
'/dy2/:id': ['mjysci'],
+
+ '/music/artist/:id': ['metowolf'],
+ '/music/djradio/:id': ['magic-akari'],
+ '/music/playlist/:id': ['DIYgod'],
+ '/music/user/events/:id': ['Master-Hash'],
+ '/music/user/playlist/:uid': ['DIYgod'],
+ '/music/user/playrecords/:uid/:type?': ['alfredcai'],
+
'/news/rank/:category?/:type?/:time?': ['nczitzk'],
'/news/special/:type?': ['nczitzk'],
'/open/vip': ['hoilc'],
diff --git a/lib/routes/ncm/artist.js b/lib/v2/163/music/artist.js
similarity index 65%
rename from lib/routes/ncm/artist.js
rename to lib/v2/163/music/artist.js
index 87932b0f8..1430d298b 100644
--- a/lib/routes/ncm/artist.js
+++ b/lib/v2/163/music/artist.js
@@ -1,11 +1,11 @@
const got = require('@/utils/got');
+const { art } = require('@/utils/render');
+const path = require('path');
module.exports = async (ctx) => {
const id = ctx.params.id;
- const response = await got({
- method: 'get',
- url: `https://music.163.com/api/artist/albums/${id}`,
+ const response = await got(`https://music.163.com/api/artist/albums/${id}`, {
headers: {
Referer: 'https://music.163.com/',
},
@@ -17,11 +17,17 @@ module.exports = async (ctx) => {
title: data.artist.name,
link: `https://music.163.com/#/artist/album?id=${id}`,
description: `网易云音乐歌手专辑 - ${data.artist.name}`,
+ image: data.artist.img1v1Url || data.artist.picUrl,
item: data.hotAlbums.map((item) => {
const singer = item.artists.length === 1 ? item.artists[0].name : item.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
return {
title: `${item.name} - ${singer}`,
- description: `歌手:${singer}
专辑:${item.name}
日期:${new Date(item.publishTime).toLocaleDateString()}`,
+ description: art(path.join(__dirname, '../templates/music/playlist.art'), {
+ singer,
+ album: item.name,
+ date: new Date(item.publishTime).toLocaleDateString(),
+ picUrl: item.picUrl,
+ }),
link: `https://music.163.com/#/album?id=${item.id}`,
pubDate: new Date(item.publishTime),
published: new Date(item.publishTime),
diff --git a/lib/routes/ncm/djradio.js b/lib/v2/163/music/djradio.js
similarity index 92%
rename from lib/routes/ncm/djradio.js
rename to lib/v2/163/music/djradio.js
index a6ca1d3b2..4056445e4 100644
--- a/lib/routes/ncm/djradio.js
+++ b/lib/v2/163/music/djradio.js
@@ -7,9 +7,7 @@ module.exports = async (ctx) => {
const id = ctx.params.id;
const ProcessFeed = (limit, offset) =>
- got({
- method: 'post',
- url: 'https://music.163.com/api/dj/program/byradio',
+ got.post('https://music.163.com/api/dj/program/byradio', {
headers: {
Referer: 'https://music.163.com/',
},
@@ -40,7 +38,7 @@ module.exports = async (ctx) => {
const duration = ~~(pg.duration / 1000);
const mm_ss_duration = `${(duration / 60).toFixed(0).padStart(2, '0')}:${(duration % 60).toFixed(0).padStart(2, '0')}`;
- const html = art(path.join(__dirname, 'templates/djradio-content.art'), {
+ const html = art(path.join(__dirname, '../templates/music/djradio-content.art'), {
pg,
description,
itunes_duration: mm_ss_duration,
diff --git a/lib/v2/163/music/maintainer.js b/lib/v2/163/music/maintainer.js
new file mode 100644
index 000000000..464796cda
--- /dev/null
+++ b/lib/v2/163/music/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/user/events/:id': ['Master-Hash'],
+};
diff --git a/lib/v2/163/music/playlist.js b/lib/v2/163/music/playlist.js
new file mode 100644
index 000000000..722804899
--- /dev/null
+++ b/lib/v2/163/music/playlist.js
@@ -0,0 +1,55 @@
+const got = require('@/utils/got');
+const config = require('@/config').value;
+const { art } = require('@/utils/render');
+const path = require('path');
+
+module.exports = async (ctx) => {
+ if (!config.ncm || !config.ncm.cookies) {
+ throw '163 Music RSS is disabled due to the lack of relevant config';
+ }
+
+ const id = ctx.params.id;
+
+ const response = await got.post('https://music.163.com/api/v3/playlist/detail', {
+ headers: {
+ Referer: 'https://music.163.com/',
+ Cookie: config.ncm.cookies,
+ },
+ form: {
+ id,
+ },
+ });
+
+ const data = response.data.playlist;
+ const songinfo = await got('https://music.163.com/api/song/detail', {
+ headers: {
+ Referer: 'https://music.163.com',
+ },
+ searchParams: {
+ ids: `[${data.trackIds.slice(0, 201).map((item) => item.id)}]`,
+ },
+ });
+ const songs = songinfo.data.songs;
+
+ ctx.state.data = {
+ title: data.name,
+ link: `https://music.163.com/#/playlist?id=${id}`,
+ description: `网易云音乐歌单 - ${data.name}`,
+ item: data.trackIds.slice(0, 201).map((item) => {
+ const thisSong = songs.find((element) => element.id === item.id);
+ const singer = thisSong.artists.length === 1 ? thisSong.artists[0].name : thisSong.artists.reduce((prev, cur) => (prev.name || prev) + '/' + cur.name);
+ return {
+ title: `${thisSong.name} - ${singer}`,
+ description: art(path.join(__dirname, '../templates/music/playlist.art'), {
+ singer,
+ album: thisSong.album.name,
+ date: new Date(thisSong.album.publishTime).toLocaleDateString(),
+ picUrl: thisSong.album.picUrl,
+ }),
+ link: `https://music.163.com/#/song?id=${item.id}`,
+ pubDate: new Date(item.at),
+ author: singer,
+ };
+ }),
+ };
+};
diff --git a/lib/v2/163/music/userevents.js b/lib/v2/163/music/userevents.js
new file mode 100644
index 000000000..6344fc473
--- /dev/null
+++ b/lib/v2/163/music/userevents.js
@@ -0,0 +1,52 @@
+const path = require('path');
+const got = require('@/utils/got');
+const { art } = require('@/utils/render');
+const renderDescription = (info) => art(path.join(__dirname, '../templates/music/userevents.art'), info);
+
+module.exports = async (ctx) => {
+ const { id } = ctx.params;
+
+ const response = await got(`https://music.163.com/api/event/get/${id}`, {
+ headers: {
+ Referer: 'https://music.163.com/',
+ },
+ });
+
+ const { data } = response;
+ const { nickname, signature, avatarUrl } = data.events[0].user;
+
+ ctx.state.data = {
+ title: `${nickname}的云村动态`,
+ link: `https://music.163.com/#/user/event?id=${id}`,
+ description: `网易云音乐用户动态 - ${signature}`,
+ icon: avatarUrl,
+ image: avatarUrl,
+ item: data.events.map((item) => {
+ const title = item.info.commentThread.resourceTitle;
+ const userId = item.user.userId;
+ const description = JSON.parse(item.json).msg;
+ const pics = item.pics.map(({ originUrl }) => originUrl);
+ const eventId = item.id;
+
+ /**
+ * @todo 根据 `item.info.commentThread.resourceInfo.eventType` 生成 Media
+ * 17 分享节目
+ * 18 分享单曲
+ * 19 分享专辑
+ * 35 空
+ * 因为我不需要,我就不写了。
+ * 因为 api 并没有 mp3 URL,生成 `media` 字段会有困难。
+ */
+ return {
+ title,
+ description: renderDescription({ description, pics }),
+ link: `https://music.163.com/#/event?id=${eventId}&uid=${userId}`,
+ pubDate: new Date(item.eventTime),
+ published: new Date(item.eventTime),
+ author: nickname,
+ upvotes: item.info.likedCount,
+ comments: item.info.commentCount,
+ };
+ }),
+ };
+};
diff --git a/lib/routes/ncm/userplaylist.js b/lib/v2/163/music/userplaylist.js
similarity index 71%
rename from lib/routes/ncm/userplaylist.js
rename to lib/v2/163/music/userplaylist.js
index 62547cb33..bebbe6aec 100644
--- a/lib/routes/ncm/userplaylist.js
+++ b/lib/v2/163/music/userplaylist.js
@@ -1,11 +1,11 @@
const got = require('@/utils/got');
+const { art } = require('@/utils/render');
+const path = require('path');
module.exports = async (ctx) => {
const uid = ctx.params.uid;
- const response = await got({
- method: 'post',
- url: 'http://music.163.com/api/user/playlist',
+ const response = await got.post('https://music.163.com/api/user/playlist', {
headers: {
Referer: 'https://music.163.com/',
},
@@ -24,23 +24,21 @@ module.exports = async (ctx) => {
ctx.state.data = {
title: `${nickname} 的所有歌单`,
- link: `http://music.163.com/user/home?id=${uid}`,
+ link: `https://music.163.com/user/home?id=${uid}`,
subtitle: signature,
description: signature,
author: nickname,
updated: response.headers.date,
icon: avatarUrl,
+ image: avatarUrl,
item: playlist.map((pl) => {
- const image = `
`;
-
- const description = `
${p}
`) - .join('')}
+{{ each description.split('\n') }}
+ {{$value}}{{if $index !== description.split('\n').length - 1}}
{{/if}}
+{{/each}}
+{{ each pics }}
+
+{{ /each }}
{{ d }}
+ {{ /each }} +