refactor: merge ncm with 163 (#11891)

* feat(route): 支持网易云音乐用户动态 (#11270)

* feat(route): add 网易云音乐用户动态

* docs(route/ncm): 用户动态文档

* feat(route/ncm): 支持 radar.js

* feat(route/ncm): description 中添加图片

(但未增加歌曲、专辑、节目等)

* refactor: merge ncm with 163

* fix: throw playlist if cookie is not set

---------

Co-authored-by: Hash <master-hash@outlook.com>
This commit is contained in:
Tony 2023-02-16 19:21:11 +01:00 committed by GitHub
parent 45883a94b3
commit 6bdf67c69e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 285 additions and 203 deletions

View File

@ -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',

View File

@ -1628,23 +1628,27 @@ JavDB 有多个备用域名,本路由默认使用永久域名 <https://javdb.c
### 歌单歌曲
<Route author="DIYgod" example="/ncm/playlist/35798529" path="/ncm/playlist/:id" :paramsDesc="['歌单 id, 可在歌单页 URL 中找到']" radar="1" />
<Route author="DIYgod" example="/163/music/playlist/35798529" path="/163/music/playlist/:id" :paramsDesc="['歌单 id, 可在歌单页 URL 中找到']" radar="1" />
### 用户歌单
<Route author="DIYgod" example="/ncm/user/playlist/45441555" path="/ncm/user/playlist/:uid" :paramsDesc="['用户 uid, 可在用户主页 URL 中找到']" radar="1" />
<Route author="DIYgod" example="/163/music/user/playlist/45441555" path="/163/music/user/playlist/:uid" :paramsDesc="['用户 uid, 可在用户主页 URL 中找到']" radar="1" />
### 用户听歌排行
<Route author="alfredcai" example="/ncm/user/playrecords/45441555/1" path="/ncm/user/playrecords/:uid/:type?" :paramsDesc="['用户 uid, 可在用户主页 URL 中找到','排行榜类型0所有时间(默认)1最近一周']" />
<Route author="alfredcai" example="/163/music/user/playrecords/45441555/1" path="/163/music/user/playrecords/:uid/:type?" :paramsDesc="['用户 uid, 可在用户主页 URL 中找到','排行榜类型0所有时间(默认)1最近一周']" />
### 用户动态
<Route author="Master-Hash" example="/163/music/user/events/585804522" path="/163/music/user/events/:uid" :paramsDesc="['用户 uid, 可在用户主页 URL 中找到']" rader="1" />
### 歌手专辑
<Route author="metowolf" example="/ncm/artist/2116" path="/ncm/artist/:id" :paramsDesc="[' 歌手 id, 可在歌手详情页 URL 中找到']" radar="1" />
<Route author="metowolf" example="/163/music/artist/2116" path="/163/music/artist/:id" :paramsDesc="[' 歌手 id, 可在歌手详情页 URL 中找到']" radar="1" />
### 电台节目
<Route author="magic-akari" example="/ncm/djradio/347317067" path="/ncm/djradio/:id" :paramsDesc="['节目 id, 可在电台节目页 URL 中找到']" supportPodcast="1" radar="1" />
<Route author="magic-akari" example="/163/music/djradio/347317067" path="/163/music/djradio/:id" :paramsDesc="['节目 id, 可在电台节目页 URL 中找到']" supportPodcast="1" radar="1" />
## 西瓜视频

View File

@ -470,7 +470,7 @@ path="/ctfhub/upcoming/:limit?"
### 精品课程
<Route author="hoilc" example="/open163/vip" path="/open163/vip" radar="1" rssbud="1"/>
<Route author="hoilc" example="/163/open/vip" path="/163/open/vip" radar="1" rssbud="1"/>
## 下厨房

View File

@ -395,73 +395,6 @@ module.exports = {
},
],
},
'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: [

View File

@ -62,11 +62,11 @@ router.get('/benedictevans', lazyloadRouteHandler('./routes/benedictevans/recent
// router.get('/tieba/user/:uid', lazyloadRouteHandler('./routes/tieba/user'));
// 网易云音乐
router.get('/ncm/playlist/:id', lazyloadRouteHandler('./routes/ncm/playlist'));
router.get('/ncm/user/playlist/:uid', lazyloadRouteHandler('./routes/ncm/userplaylist'));
router.get('/ncm/artist/:id', lazyloadRouteHandler('./routes/ncm/artist'));
router.get('/ncm/djradio/:id', lazyloadRouteHandler('./routes/ncm/djradio'));
router.get('/ncm/user/playrecords/:uid/:type?', lazyloadRouteHandler('./routes/ncm/userplayrecords'));
// router.get('/ncm/playlist/:id', lazyloadRouteHandler('./routes/ncm/playlist'));
// router.get('/ncm/user/playlist/:uid', lazyloadRouteHandler('./routes/ncm/userplaylist'));
// router.get('/ncm/artist/:id', lazyloadRouteHandler('./routes/ncm/artist'));
// router.get('/ncm/djradio/:id', lazyloadRouteHandler('./routes/ncm/djradio'));
// router.get('/ncm/user/playrecords/:uid/:type?', lazyloadRouteHandler('./routes/ncm/userplayrecords'));
// 掘金 migrated to v2
// router.get('/juejin/category/:category', lazyloadRouteHandler('./routes/juejin/category'));

View File

@ -1,45 +0,0 @@
const got = require('@/utils/got');
const config = require('@/config').value;
module.exports = async (ctx) => {
const id = ctx.params.id;
const response = await got({
method: 'post',
url: '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({
method: 'get',
url: `https://music.163.com/api/song/detail?ids=[${data.trackIds.slice(0, 201).map((item) => item.id)}]`,
headers: {
Referer: 'https://music.163.com',
},
});
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: `歌手:${singer}<br>专辑:${thissong.album.name}<br>发行日期:${new Date(thissong.album.publishTime).toLocaleDateString()}<br><img src="${thissong.album.picUrl}">`,
link: `https://music.163.com/#/song?id=${item.id}`,
pubDate: new Date(item.at),
author: singer,
};
}),
};
};

View File

@ -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'],

View File

@ -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}<br>专辑:${item.name}<br>日期:${new Date(item.publishTime).toLocaleDateString()}<br><img src="${item.picUrl}">`,
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),

View File

@ -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,

View File

@ -0,0 +1,3 @@
module.exports = {
'/user/events/:id': ['Master-Hash'],
};

View File

@ -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 <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>';
}
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,
};
}),
};
};

View File

@ -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,
};
}),
};
};

View File

@ -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 = `<img src=${pl.coverImgUrl} />`;
const description = `<div>${(pl.description || '')
.split('\n')
.map((p) => `<p>${p}</p>`)
.join('')}</div>`;
const src = `http://music.163.com/playlist/${pl.id}`;
const html = image + description + `<div><a href="${src}">查看歌单</a></div>`;
const html = art(path.join(__dirname, '../templates/music/userplaylist.art'), {
image: pl.coverImgUrl,
description: (pl.description || '').split('\n'),
src,
});
return {
title: pl.name,

View File

@ -1,5 +1,7 @@
const got = require('@/utils/got');
const config = require('@/config').value;
const { art } = require('@/utils/render');
const path = require('path');
const headers = {
cookie: config.ncm.cookies,
@ -17,18 +19,14 @@ function getItem(records) {
return records.map((record, index) => {
const song = record.song;
const album = song.al ? `<img src=${song.al.picUrl} />` : '';
const artists = song.ar.map((a) => `<a href="https://music.163.com/artist?id=${a.id}">${a.name}</a>`).join(`/`);
const artists_paintext = song.ar.map((a) => a.name).join('/');
const html = `<div>
排行${index + 1} 播放次数${record.playCount} 得分${record.score}<br>
歌曲<a href="http://music.163.com/song?id=${song.id}">${song.name}</a><br>
歌手${artists}<br>
歌曲图${album}<br>
</div>`;
const html = art(path.join(__dirname, '../templates/music/userplayrecords.art'), {
index,
record,
song,
});
return {
title: `[${index + 1}] ${song.name} - ${artists_paintext}`,
@ -43,14 +41,14 @@ module.exports = async (ctx) => {
const uid = ctx.params.uid;
const type = parseInt(ctx.params.type) || 0;
const url = `http://music.163.com/api/v1/play/record?uid=${uid}&type=${type}`;
const response = await got({ url, headers });
const url = `https://music.163.com/api/v1/play/record?uid=${uid}&type=${type}`;
const response = await got(url, { headers });
const records = type === 1 ? response.data.weekData : response.data.allData;
ctx.state.data = {
title: type === 1 ? `听歌榜单(最近一周)- ${uid}` : `听歌榜单(所有时间)- ${uid}`,
link: `http://music.163.com/user/home?id=${uid}`,
title: `${type === 1 ? '听歌榜单(最近一周)' : '听歌榜单(所有时间}'} - ${uid}}`,
link: `https://music.163.com/user/home?id=${uid}`,
updated: response.headers.date,
item: getItem(records),
};

View File

@ -35,6 +35,53 @@ module.exports = {
target: '/163/today',
},
],
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 ? `/163/music/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 ? `/163/music/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 ? `/163/music/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 ? `/163/music/djradio/${id}` : '';
},
},
{
title: '用户动态',
docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue-yong-hu-dong-tai',
source: ['/'],
target: (_, url) => {
const id = new URL(url).hash.match(/event\?id=(.*)/)[1];
return id ? `/163/music/user/events/${id}` : '';
},
},
],
news: [
{
title: '排行榜',
@ -65,5 +112,35 @@ module.exports = {
target: '/163/today',
},
],
'y.music': [
{
title: '云音乐 - 用户歌单',
docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue',
source: '/m/user',
target: (params, url) => `/163/music/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) => `/163/music/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) => `/163/music/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) => `/163/music/playlist/${new URL(url).searchParams.get('id')}`,
},
{
title: '用户动态',
docs: 'https://docs.rsshub.app/multimedia.html#wang-yi-yun-yin-yue-yong-hu-dong-tai',
},
],
},
};

View File

@ -3,6 +3,14 @@ module.exports = function (router) {
router.get('/ds/:id', require('./ds'));
router.get('/dy/:id', require('./dy'));
router.get('/dy2/:id', require('./dy2'));
router.get('/music/artist/:id', require('./music/artist'));
router.get('/music/djradio/:id', require('./music/djradio'));
router.get('/music/playlist/:id', require('./music/playlist'));
router.get('/music/user/events/:id', require('./music/userevents'));
router.get('/music/user/playlist/:uid', require('./music/userplaylist'));
router.get('/music/user/playrecords/:uid/:type?', require('./music/userplayrecords'));
router.get('/news/rank/:category?/:type?/:time?', require('./news/rank'));
router.get('/news/special/:type?', require('./news/special'));
router.get('/open/vip', require('./open/vip'));

View File

@ -0,0 +1,4 @@
歌手:{{ singer }}<br>
专辑:{{ album }}<br>
发行日期:{{ date }}<br>
<img src="{{ picUrl }}">

View File

@ -0,0 +1,7 @@
<p>
{{ each description.split('\n') }}
{{$value}}{{if $index !== description.split('\n').length - 1}}<br>{{/if}}
{{/each}}
{{ each pics }}
<img src="{{$value}}">
{{ /each }}</p>

View File

@ -0,0 +1,16 @@
{{ if image }}
<img src="{{ image }}">
{{ /if }}
{{ if description }}
<div>
{{ each description d }}
<p>{{ d }}</p>
{{ /each }}
</div>
{{ /if }}
{{ if src }}
<div><a href="{{ src }}">查看歌单</a></div>
{{ /if }}

View File

@ -0,0 +1,7 @@
<div>
排行:{{ index + 1 }} 播放次数:{{ record.playCount }} 得分:{{ record.score }}<br>
歌曲:<a href="http://music.163.com/song?id={{ song.id }}">{{ song.name }}</a><br>
歌手:{{ each song.ar a i }}<a href="https://music.163.com/artist?id={{ a.id }}">{{ a.name }}</a> {{ if i < song.ar.length - 1 }}/ {{ /if }}{{ /each }}
<br>
{{ if song.al }}歌曲图:<img src={{ song.al.picUrl }}><br>{{ /if }}
</div>