yun.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import axios from "axios";
  2. import CryptoJS from "crypto-js";
  3. class YunDrive {
  4. constructor() {
  5. this.regex = /https:\/\/yun.139.com\/shareweb\/#\/w\/i\/([^&]+)/
  6. this.x = CryptoJS.enc.Utf8.parse("PVGDwmcvfs1uV3d1");
  7. this.baseUrl = 'https://share-kd-njs.yun.139.com/yun-share/richlifeApp/devapp/IOutLink/';
  8. this.baseHeader = {
  9. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  10. 'Accept': 'application/json, text/plain, */*',
  11. 'Content-Type': 'application/json',
  12. 'hcy-cool-flag': '1',
  13. 'x-deviceinfo': '||3|12.27.0|chrome|131.0.0.0|5c7c68368f048245e1ce47f1c0f8f2d0||windows 10|1536X695|zh-CN|||'
  14. }
  15. this.linkID = '';
  16. }
  17. encrypt(data) {
  18. let t = CryptoJS.lib.WordArray.random(16)
  19. , n = "";
  20. if ("string" == typeof data) {
  21. const o = CryptoJS.enc.Utf8.parse(data);
  22. n = CryptoJS.AES.encrypt(o, this.x, {
  23. iv: t,
  24. mode: CryptoJS.mode.CBC,
  25. padding: CryptoJS.pad.Pkcs7
  26. })
  27. } else if (typeof data === 'object' && data !== null) {
  28. const a = JSON.stringify(data)
  29. , s = CryptoJS.enc.Utf8.parse(a);
  30. n = CryptoJS.AES.encrypt(s, this.x, {
  31. iv: t,
  32. mode: CryptoJS.mode.CBC,
  33. padding: CryptoJS.pad.Pkcs7
  34. })
  35. }
  36. return CryptoJS.enc.Base64.stringify(t.concat(n.ciphertext))
  37. }
  38. decrypt(data) {
  39. const t = CryptoJS.enc.Base64.parse(data)
  40. , n = t.clone()
  41. , i = n.words.splice(4);
  42. n.init(n.words),
  43. t.init(i);
  44. const o = CryptoJS.enc.Base64.stringify(t)
  45. , a = CryptoJS.AES.decrypt(o, this.x, {
  46. iv: n,
  47. mode: CryptoJS.mode.CBC,
  48. padding: CryptoJS.pad.Pkcs7
  49. })
  50. , s = a.toString(CryptoJS.enc.Utf8);
  51. return s.toString()
  52. }
  53. async getShareID(url) {
  54. const matches = this.regex.exec(url)
  55. if (matches && matches[1]) {
  56. this.linkID = matches[1]
  57. } else {
  58. const matches = /https:\/\/caiyun.139.com\/m\/i\?([^&]+)/.exec(url);
  59. if (matches && matches[1]) {
  60. this.linkID = matches[1]
  61. }
  62. }
  63. }
  64. async getShareInfo(pCaID) {
  65. let data = JSON.stringify(this.encrypt(JSON.stringify({
  66. "getOutLinkInfoReq":
  67. {
  68. "account": "",
  69. "linkID": this.linkID,
  70. "passwd": "",
  71. "caSrt": 0,
  72. "coSrt": 0,
  73. "srtDr": 1,
  74. "bNum": 1,
  75. "pCaID": pCaID,
  76. "eNum": 200
  77. }, "commonAccountInfo": {"account": "", "accountType": 1}
  78. })))
  79. return await axios.post(this.baseUrl + 'getOutLinkInfoV6', data, {
  80. headers: this.baseHeader
  81. })
  82. }
  83. async getShareData(url) {
  84. if (!url) {
  85. return;
  86. }
  87. const isValidUrl = url.startsWith('http');
  88. let pCaID = isValidUrl ? 'root' : url;
  89. if (isValidUrl) {
  90. await this.getShareID(url);
  91. }
  92. let file = {}
  93. let fileInfo = await this.getShareFile(pCaID)
  94. if (fileInfo && Array.isArray(fileInfo)) {
  95. await Promise.all(fileInfo.map(async (item) => {
  96. if (!(item.name in file)) {
  97. file[item.name] = [];
  98. }
  99. let filelist = await this.getShareUrl(item.path);
  100. if (filelist && filelist.length > 0) {
  101. file[item.name].push(...filelist);
  102. }
  103. }));
  104. }
  105. for (let key in file) {
  106. if (file[key].length === 0) {
  107. delete file[key];
  108. }
  109. }
  110. if (Object.keys(file).length === 0) {
  111. file['root'] = await this.getShareFile(url)
  112. if (file['root'] && Array.isArray(file['root'])) {
  113. file['root'] = file['root'].filter(item => item && Object.keys(item).length > 0);
  114. }
  115. }
  116. return file
  117. }
  118. async getShareFile(pCaID) {
  119. if (!pCaID) {
  120. return;
  121. }
  122. try {
  123. const isValidUrl = pCaID.startsWith('http');
  124. pCaID = isValidUrl ? 'root' : pCaID;
  125. const resp = await this.getShareInfo(pCaID);
  126. if (resp.status !== 200) {
  127. return null;
  128. }
  129. const json = JSON.parse(this.decrypt(resp.data)).data;
  130. if (!json || !json.caLst) {
  131. return null;
  132. }
  133. const caLst = json?.caLst;
  134. const names = caLst.map(it => it.caName);
  135. const rootPaths = caLst.map(it => it.path);
  136. const filterRegex = /App|活动中心|免费|1T空间|免流/;
  137. const videos = [];
  138. if (caLst && caLst.length > 0) {
  139. names.forEach((name, index) => {
  140. if (!filterRegex.test(name)) {
  141. videos.push({
  142. name: name,
  143. path: rootPaths[index]
  144. });
  145. }
  146. });
  147. let result = await Promise.all(rootPaths.map(async (path) => this.getShareFile(path)));
  148. result = result.filter(item => item !== undefined && item !== null);
  149. return [...videos, ...result.flat()];
  150. }
  151. } catch (error) {
  152. console.error('Error processing share data:', error);
  153. return null;
  154. }
  155. }
  156. async getShareUrl(pCaID) {
  157. try {
  158. let resp = await this.getShareInfo(pCaID);
  159. if (resp.status !== 200) {
  160. return null;
  161. }
  162. const json = JSON.parse(this.decrypt(resp.data)).data;
  163. if (!json || !('coLst' in json)) {
  164. return null;
  165. }
  166. const caLst = json.caLst;
  167. const coLst = json.coLst;
  168. if (coLst !== null) {
  169. const filteredItems = coLst.filter(it => it && it.coType === 3);
  170. return filteredItems.map(it => ({
  171. name: it.coName,
  172. contentId: it.coID,
  173. linkID: this.linkID
  174. }));
  175. } else if (caLst !== null) {
  176. const rootPaths = caLst.map(it => it.path);
  177. let result = await Promise.all(rootPaths.map(path => this.getShareUrl(path)));
  178. result = result.filter(item => item && item.length > 0);
  179. return result.flat();
  180. }
  181. } catch (error) {
  182. console.error('Error processing share URL:', error);
  183. return null;
  184. }
  185. }
  186. async getSharePlay(contentId, linkID) {
  187. let data = {
  188. "getContentInfoFromOutLinkReq": {
  189. "contentId": contentId,
  190. "linkID": linkID,
  191. "account": ""
  192. },
  193. "commonAccountInfo": {
  194. "account": "",
  195. "accountType": 1
  196. }
  197. };
  198. let resp = await axios.post(this.baseUrl + 'getContentInfoFromOutLink', data, {
  199. headers: {
  200. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
  201. 'Accept': 'application/json, text/plain, */*',
  202. 'Accept-Encoding': 'gzip, deflate, br, zstd',
  203. 'Content-Type': 'application/json'
  204. }
  205. })
  206. if (resp.status === 200) {
  207. let data = resp.data
  208. return data.data.contentInfo.presentURL
  209. }
  210. }
  211. }
  212. export const Yun = new YunDrive()