|
1 | 1 | import { Route } from '@/types'; |
2 | 2 |
|
3 | | -import got from '@/utils/got'; |
| 3 | +import ofetch from '@/utils/ofetch'; |
4 | 4 | import { parseDate } from '@/utils/parse-date'; |
5 | 5 | import { art } from '@/utils/render'; |
6 | 6 | import path from 'node:path'; |
7 | | -import CryptoJS from 'crypto-js'; |
| 7 | +import timezone from '@/utils/timezone'; |
8 | 8 |
|
9 | 9 | const audio_types = { |
10 | 10 | m3u8: 'x-mpegURL', |
@@ -39,79 +39,70 @@ export const route: Route = { |
39 | 39 | }; |
40 | 40 |
|
41 | 41 | async function handler(ctx) { |
42 | | - const KEY = 'f0fc4c668392f9f9a447e48584c214ee'; |
43 | | - |
44 | 42 | const id = ctx.req.param('id'); |
45 | | - const size = ctx.req.query('limit') ?? '100'; |
46 | | - |
47 | | - const rootUrl = 'https://www.radio.cn'; |
48 | | - |
49 | | - const currentUrl = `${rootUrl}/pc-portal/sanji/detail.html?columnId=${id}`; |
50 | | - const apiRootUrl = 'https://ytmsout.radio.cn'; |
51 | | - |
52 | | - const timestamp = Date.now(); |
53 | | - const id_params = `id=${id}`; |
54 | | - const detailApiUrl = `${apiRootUrl}/web/appAlbum/detail/${id}?${id_params}`; |
55 | | - |
56 | | - const details = await got({ |
57 | | - method: 'get', |
58 | | - url: detailApiUrl, |
59 | | - headers: { |
60 | | - sign: CryptoJS.MD5(`${id_params}×tamp=${timestamp}&key=${KEY}`).toString().toUpperCase(), |
61 | | - timestamp, |
62 | | - 'Content-Type': 'application/json', |
63 | | - equipmentId: '0000', |
64 | | - platformCode: 'WEB', |
65 | | - }, |
66 | | - }); |
67 | 43 |
|
68 | | - const params = `albumId=${id}&pageNo=0&pageSize=${size}`; |
69 | | - const apiUrl = `${apiRootUrl}/web/appSingle/pageByAlbum?${params}`; |
| 44 | + const rootUrl = 'https://ytweb.radio.cn'; |
| 45 | + const currentUrl = `${rootUrl}/share/albumDetail?columnId=${id}`; |
| 46 | + const apiRootUrl = 'https://ytapi.radio.cn'; |
70 | 47 |
|
71 | | - const response = await got({ |
72 | | - method: 'get', |
73 | | - url: apiUrl, |
| 48 | + const response = await ofetch(`${apiRootUrl}/ytsrv/srv/wifimusicbox/demand/detail`, { |
| 49 | + method: 'POST', |
74 | 50 | headers: { |
75 | | - sign: CryptoJS.MD5(`${params}×tamp=${timestamp}&key=${KEY}`).toString().toUpperCase(), |
76 | | - timestamp, |
77 | | - 'Content-Type': 'application/json', |
78 | | - equipmentId: '0000', |
79 | | - platformCode: 'WEB', |
| 51 | + accept: 'application/json, text/plain, */*', |
| 52 | + 'content-type': 'application/x-www-form-urlencoded', |
| 53 | + equipmentSource: 'WEB', // only this header is mandatory |
| 54 | + equipmentType: '3', |
| 55 | + platformCode: 'H5', |
| 56 | + productId: '1605403829833195520', |
| 57 | + providerCode: '25010', |
| 58 | + referer: 'https://ytweb.radio.cn/', |
| 59 | + timestamp: String(Date.now()), |
| 60 | + version: '4.0.0', |
80 | 61 | }, |
| 62 | + body: new URLSearchParams({ |
| 63 | + pageIndex: '0', |
| 64 | + sortType: '', |
| 65 | + mobileId: '', |
| 66 | + providerCode: '25010', |
| 67 | + pid: id, |
| 68 | + paySongFlag: '1', |
| 69 | + richText: '1', |
| 70 | + h5flag: '1', |
| 71 | + }), |
| 72 | + parseResponse: JSON.parse, |
81 | 73 | }); |
82 | 74 |
|
83 | | - const data = response.data.data.data; |
84 | | - const items = data.map((item) => { |
85 | | - let enclosure_url = item.playUrlHigh ?? item.playUrlLow; |
| 75 | + const items = response.con.map((item) => { |
| 76 | + let enclosure_url = item.playUrlHigh ?? item.playUrlMedium ?? item.playUrlLow ?? item.playUrl; |
86 | 77 | enclosure_url = /\.m3u8$/.test(enclosure_url) ? item.downloadUrl : enclosure_url; |
87 | 78 |
|
88 | | - const file_ext = new URL(enclosure_url).pathname.split('.').pop(); |
89 | | - const enclosure_type = file_ext ? `audio/${audio_types[file_ext]}` : ''; |
| 79 | + const fileExt = new URL(enclosure_url).pathname.split('.').pop(); |
| 80 | + const enclosure_type = fileExt ? `audio/${audio_types[fileExt]}` : ''; |
90 | 81 |
|
91 | 82 | return { |
92 | 83 | guid: item.id, |
93 | 84 | title: item.name, |
94 | | - link: enclosure_url, |
| 85 | + link: `${rootUrl}/share/albumPlay?correlateId=${item.id}&columnId=${id}`, |
95 | 86 | description: art(path.join(__dirname, 'templates/description.art'), { |
96 | | - description: item.des, |
97 | 87 | enclosure_url, |
98 | 88 | enclosure_type, |
99 | 89 | }), |
100 | | - pubDate: parseDate(item.publishTime), |
| 90 | + pubDate: timezone(parseDate(item.createTime), +8), |
101 | 91 | enclosure_url, |
102 | 92 | enclosure_type, |
103 | 93 | enclosure_length: item.fileSize, |
104 | 94 | itunes_duration: item.duration, |
105 | | - itunes_item_image: details.data.data.image, |
| 95 | + itunes_item_image: item.logoUrl, |
106 | 96 | }; |
107 | 97 | }); |
108 | 98 |
|
109 | 99 | return { |
110 | | - title: `云听 - ${details.data.data.name}`, |
| 100 | + title: `云听 - ${response.columnName}`, |
111 | 101 | link: currentUrl, |
112 | 102 | item: items, |
113 | | - image: details.data.data.image, |
114 | | - description: details.data.data.des ?? details.data.data.desSimple, |
115 | | - itunes_author: details.data.data.ownerNickName || 'radio.cn', |
| 103 | + image: response.posterInfo.imgUrl, |
| 104 | + logo: response.logoUrl, |
| 105 | + description: response.descriptions ?? response.descriptionSimple, |
| 106 | + itunes_author: response.ownerNickName || 'radio.cn', |
116 | 107 | }; |
117 | 108 | } |
0 commit comments