index.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import axios from "axios";
  2. import dayjs = require("dayjs");
  3. import CryptoJs = require("crypto-js");
  4. function formatMusicItem(_) {
  5. return {
  6. id: _.id ?? _.trackId,
  7. artist: _.nickname,
  8. title: _.title,
  9. album: _.albumTitle,
  10. duration: _.duration,
  11. artwork: _.coverPath?.startsWith("//")
  12. ? `https:${_.coverPath}`
  13. : _.coverPath,
  14. };
  15. }
  16. function formatAlbumItem(_) {
  17. return {
  18. id: _.albumId ?? _.id,
  19. artist: _.nickname,
  20. title: _.title,
  21. artwork: _.coverPath?.startsWith("//")
  22. ? `https:${_.coverPath}`
  23. : _.coverPath,
  24. description: _.intro ?? _.description,
  25. date: _.updatedAt ? dayjs(_.updatedAt).format("YYYY-MM-DD") : null,
  26. };
  27. }
  28. function formatArtistItem(_) {
  29. return {
  30. name: _.nickname,
  31. id: _.uid,
  32. fans: _.followersCount,
  33. description: _.description,
  34. avatar: _.logoPic,
  35. worksNum: _.tracksCount,
  36. };
  37. }
  38. function paidAlbumFilter(raw) {
  39. return !raw.priceTypes?.length;
  40. }
  41. function paidMusicFilter(raw) {
  42. return raw.tag === 0 || raw.isPaid === false || parseFloat(raw.price) === 0;
  43. }
  44. async function searchBase(query: string, page: number, core: string) {
  45. return (
  46. await axios.get("https://www.ximalaya.com/revision/search/main", {
  47. params: {
  48. kw: query,
  49. page: page,
  50. spellchecker: true,
  51. condition: "relation",
  52. rows: 20,
  53. device: "iPhone",
  54. core,
  55. paidFilter: true,
  56. },
  57. })
  58. ).data;
  59. }
  60. async function searchMusic(query: string, page: number) {
  61. const res = (await searchBase(query, page, "track")).data.track;
  62. return {
  63. isEnd: page >= res.totalPage,
  64. data: res.docs.filter(paidMusicFilter).map(formatMusicItem),
  65. };
  66. }
  67. async function searchAlbum(query: string, page: number) {
  68. const res = (await searchBase(query, page, "album")).data.album;
  69. return {
  70. isEnd: page >= res.totalPage,
  71. data: res.docs.filter(paidAlbumFilter).map(formatAlbumItem),
  72. };
  73. }
  74. async function searchArtist(query: string, page: number) {
  75. const res = (await searchBase(query, page, "user")).data.user;
  76. return {
  77. isEnd: page >= res.totalPage,
  78. data: res.docs.map(formatArtistItem),
  79. };
  80. }
  81. async function getAlbumInfo(albumItem: IAlbum.IAlbumItem, page: number = 1) {
  82. const res = await axios.get(
  83. "https://www.ximalaya.com/revision/album/v1/getTracksList",
  84. {
  85. params: {
  86. albumId: albumItem.id,
  87. pageNum: page,
  88. pageSize: 50,
  89. },
  90. }
  91. );
  92. return {
  93. isEnd: page * 50 >= res.data.data.trackTotalCount,
  94. albumItem: {
  95. worksNum: res.data.data.trackTotalCount,
  96. },
  97. musicList: res.data.data.tracks.filter(paidMusicFilter).map((_) => {
  98. const r = formatMusicItem(_);
  99. r.artwork = albumItem.artwork;
  100. r.artist = albumItem.artist;
  101. return r;
  102. }),
  103. };
  104. }
  105. async function search(query, page, type: ICommon.SupportMediaType) {
  106. if (type === "music") {
  107. return searchMusic(query, page);
  108. } else if (type === "album") {
  109. return searchAlbum(query, page);
  110. } else if (type === "artist") {
  111. return searchArtist(query, page);
  112. }
  113. }
  114. async function getMediaSource(
  115. musicItem: IMusic.IMusicItem,
  116. quality: IMusic.IQualityKey
  117. ) {
  118. if (quality !== "standard") {
  119. return;
  120. }
  121. const info = (
  122. await axios.get(
  123. `https://www.ximalaya.com/mobile-playpage/track/v3/baseInfo/${Date.now()}?device=www&trackId=${
  124. musicItem.id
  125. }&trackQualityLevel=1`
  126. )
  127. ).data;
  128. const trackInfo = info.trackInfo;
  129. const { playUrlList } = trackInfo;
  130. const encodeText = playUrlList[0].url;
  131. const url = CryptoJs.AES.decrypt(
  132. // @ts-ignore
  133. {
  134. ciphertext: CryptoJs.enc.Base64url.parse(encodeText),
  135. },
  136. CryptoJs.enc.Hex.parse("aaad3e4fd540b0f79dca95606e72bf93"),
  137. {
  138. mode: CryptoJs.mode.ECB,
  139. padding: CryptoJs.pad.Pkcs7,
  140. }
  141. ).toString(CryptoJs.enc.Utf8);
  142. return {
  143. url,
  144. };
  145. }
  146. async function getArtistWorks(artistItem, page, type) {
  147. if (type === "music") {
  148. const res = (
  149. await axios.get("https://www.ximalaya.com/revision/user/track", {
  150. params: {
  151. page,
  152. pageSize: 30,
  153. uid: artistItem.id,
  154. },
  155. })
  156. ).data.data;
  157. return {
  158. isEnd: res.page * res.pageSize >= res.totalCount,
  159. data: res.trackList.filter(paidMusicFilter).map((_) => ({
  160. ...formatMusicItem(_),
  161. artist: artistItem.name,
  162. })),
  163. };
  164. } else {
  165. const res = (
  166. await axios.get("https://www.ximalaya.com/revision/user/pub", {
  167. params: {
  168. page,
  169. pageSize: 30,
  170. uid: artistItem.id,
  171. },
  172. })
  173. ).data.data;
  174. return {
  175. isEnd: res.page * res.pageSize >= res.totalCount,
  176. data: res.albumList.filter(paidAlbumFilter).map((_) => ({
  177. ...formatAlbumItem(_),
  178. artist: artistItem.name,
  179. })),
  180. };
  181. }
  182. }
  183. module.exports = {
  184. platform: "喜马拉雅",
  185. version: "0.1.5",
  186. supportedSearchType: ["music", "album", "artist"],
  187. srcUrl:
  188. "https://gitee.com/maotoumao/MusicFreePlugins/raw/v0.1/dist/xmly/index.js",
  189. cacheControl: "no-cache",
  190. search,
  191. getAlbumInfo,
  192. getMediaSource,
  193. getArtistWorks,
  194. };