douban_open.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import { dayjs, Crypto, Uri, _ } from 'assets://js/lib/cat.js';
  2. let key = 'douban';
  3. let domain = 'https://frodo.douban.com';
  4. let device = {};
  5. let siteKey = '';
  6. let siteType = 0;
  7. function sig(link) {
  8. link += `&udid=${device.id}&uuid=${device.id}&&rom=android&apikey=0dad551ec0f84ed02907ff5c42e8ec70&s=rexxar_new&channel=Yingyongbao_Market&timezone=Asia/Shanghai&device_id=${device.id}&os_rom=android&apple=c52fbb99b908be4d026954cc4374f16d&mooncake=0f607264fc6318a92b9e13c65db7cd3c&sugar=0`;
  9. const u = new Uri(link);
  10. const ts = dayjs().unix().toString();
  11. let sha1 = Crypto.HmacSHA1('GET&' + encodeURIComponent(u.path()) + '&' + ts, 'bf7dddc7c9cfe6f7');
  12. let signa = Crypto.enc.Base64.stringify(sha1);
  13. return link + '&_sig=' + encodeURIComponent(signa) + '&_ts=' + ts;
  14. }
  15. async function request(reqUrl, ua) {
  16. const resp = await req(reqUrl, {
  17. method: 'get',
  18. headers: {
  19. 'User-Agent': ua || device.ua,
  20. },
  21. });
  22. const text = resp.content;
  23. return JSON.parse(text);
  24. }
  25. async function init(cfg) {
  26. siteKey = cfg.skey;
  27. siteType = cfg.stype;
  28. const deviceKey = 'device';
  29. const deviceInfo = await local.get(key, deviceKey);
  30. if (deviceInfo && deviceInfo.length > 0) {
  31. try {
  32. device = JSON.parse(deviceInfo);
  33. } catch (error) {}
  34. }
  35. if (_.isEmpty(device)) {
  36. device.id = randStr(40).toLowerCase();
  37. device.ua = `Rexxar-Core/0.1.3 api-client/1 com.douban.frodo/7.9.0(216) Android/28 product/Xiaomi11 rom/android network/wifi udid/${device.id} platform/mobile com.douban.frodo/7.9.0(216) Rexxar/1.2.151 platform/mobile 1.2.151`;
  38. await local.set(key, deviceKey, JSON.stringify(device));
  39. }
  40. }
  41. const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
  42. function randStr(len, withNum) {
  43. var _str = '';
  44. let containsNum = withNum === undefined ? true : withNum;
  45. for (var i = 0; i < len; i++) {
  46. let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
  47. _str += charStr[idx];
  48. }
  49. return _str;
  50. }
  51. async function home(filter) {
  52. const link = sig(domain + '/api/v2/movie/tag?sort=U&start=0&count=30&q=全部形式,全部类型,全部地区,全部年代&score_rang=0,10');
  53. const data = await request(link);
  54. let classes = [
  55. {
  56. type_id: 't1',
  57. type_name: '热播',
  58. },
  59. {
  60. type_id: 't2',
  61. type_name: '片库',
  62. },
  63. {
  64. type_id: 't250',
  65. type_name: 'Top250',
  66. },
  67. {
  68. type_id: 't3',
  69. type_name: '榜单',
  70. ratio: 1,
  71. },
  72. {
  73. type_id: 't4',
  74. type_name: '片单',
  75. ratio: 1,
  76. },
  77. ];
  78. let filterObj = {};
  79. filterObj['t1'] = [
  80. {
  81. key: 'u',
  82. name: '',
  83. init: 'movie/hot_gaia',
  84. value: [
  85. { n: '电影', v: 'movie/hot_gaia' },
  86. { n: '电视剧', v: 'subject_collection/tv_hot/items' },
  87. { n: '国产剧', v: 'subject_collection/tv_domestic/items' },
  88. { n: '美剧', v: 'subject_collection/tv_american/items' },
  89. { n: '日剧', v: 'subject_collection/tv_japanese/items' },
  90. { n: '韩剧', v: 'subject_collection/tv_korean/items' },
  91. { n: '动漫', v: 'subject_collection/tv_animation/items' },
  92. { n: '综艺', v: 'subject_collection/show_hot/items' },
  93. ],
  94. },
  95. ];
  96. filterObj['t4'] = [
  97. {
  98. key: 'type',
  99. name: '',
  100. init: '',
  101. value: [
  102. { n: '全部', v: '' },
  103. { n: '电影', v: 'movie' },
  104. { n: '电视剧', v: 'tv' },
  105. ],
  106. },
  107. {
  108. key: 'cate',
  109. name: '',
  110. init: 'all',
  111. value: [
  112. { n: '全部', v: 'all' },
  113. { n: '豆瓣片单', v: 'official' },
  114. { n: '精选', v: 'selected' },
  115. { n: '经典', v: 'classical' },
  116. { n: '获奖', v: 'prize' },
  117. { n: '高分', v: 'high_score' },
  118. { n: '榜单', v: 'movie_list' },
  119. { n: '冷门佳片', v: 'dark_horse' },
  120. { n: '主题', v: 'topic' },
  121. { n: '导演', v: 'director' },
  122. { n: '演员', v: 'actor' },
  123. { n: '系列', v: 'series' },
  124. ],
  125. },
  126. {
  127. key: 'cate',
  128. name: '',
  129. init: 'all',
  130. value: [
  131. { n: '华语', v: 'chinese' },
  132. { n: '欧美', v: 'western' },
  133. { n: '日本', v: 'japanese' },
  134. { n: '韩国', v: 'korea' },
  135. ],
  136. },
  137. {
  138. key: 'cate',
  139. name: '',
  140. init: 'all',
  141. value: [
  142. { n: '喜剧', v: 'comedy' },
  143. { n: '动作', v: 'action' },
  144. { n: '爱情', v: 'love' },
  145. { n: '科幻', v: 'science_fiction' },
  146. { n: '动画', v: 'cartoon' },
  147. { n: '悬疑', v: 'mystery' },
  148. { n: '惊悚', v: 'panic' },
  149. { n: '恐怖', v: 'horrible' },
  150. { n: '犯罪', v: 'criminal' },
  151. { n: '同性', v: 'lgbt' },
  152. { n: '战争', v: 'war' },
  153. { n: '奇幻', v: 'fantasy' },
  154. { n: '情色', v: 'erotica' },
  155. { n: '音乐', v: 'music' },
  156. { n: '纪录片', v: 'documentary' },
  157. { n: '治愈', v: 'cure' },
  158. { n: '艺术', v: 'art' },
  159. { n: '黑色幽默', v: 'dark_humor' },
  160. { n: '青春', v: 'youth' },
  161. { n: '女性', v: 'female' },
  162. { n: '真实事件改编', v: 'real_event' },
  163. { n: '暴力', v: 'violence' },
  164. { n: '黑白', v: 'black_white' },
  165. { n: '美食', v: 'food' },
  166. { n: '旅行', v: 'travel' },
  167. { n: '儿童', v: 'child' },
  168. { n: '人性', v: 'humanity' },
  169. { n: '家庭', v: 'family' },
  170. { n: '文艺', v: 'literary_art' },
  171. { n: '小说改编', v: 'novel' },
  172. { n: '感人', v: 'moving' },
  173. { n: '励志', v: 'inspiration' },
  174. ],
  175. },
  176. ];
  177. let filterAll = [];
  178. for (const tag of data.tags) {
  179. if (tag.type == '特色') continue;
  180. let f = {
  181. key: tag.type,
  182. name: '',
  183. init: tag.data[0],
  184. };
  185. let fValues = [];
  186. if (tag.type == '年代' && tag.data.indexOf(dayjs().year().toString()) < 0) {
  187. tag.data.splice(1, 0, dayjs().year().toString());
  188. if (tag.data.indexOf((dayjs().year() - 1).toString()) < 0) {
  189. tag.data.splice(2, 0, (dayjs().year() - 1).toString());
  190. }
  191. }
  192. for (const v of tag.data) {
  193. let n = v;
  194. if (v.indexOf('全部') >= 0) n = '全部';
  195. fValues.push({ n: n, v: v });
  196. }
  197. f['value'] = fValues;
  198. filterAll.push(f);
  199. }
  200. let sort = {
  201. key: 'sort',
  202. name: '',
  203. init: data.sorts[0].name,
  204. };
  205. let sortValues = [];
  206. for (const sort of data.sorts) {
  207. sortValues.push({ n: sort.text, v: sort.name });
  208. }
  209. sort['value'] = sortValues;
  210. filterAll.push(sort);
  211. filterObj['t2'] = filterAll;
  212. return JSON.stringify({
  213. class: classes,
  214. filters: filterObj,
  215. });
  216. }
  217. async function category(tid, pg, filter, extend) {
  218. let page = pg || 1;
  219. if (page == 0) page = 1;
  220. if (tid == 't1') {
  221. const link = sig(`${domain}/api/v2/${extend.u || 'movie/hot_gaia'}?area=全部&sort=recommend&playable=0&loc_id=0&start=${(page - 1) * 30}&count=30`);
  222. const data = await request(link);
  223. let videos = [];
  224. for (const vod of data.items || data.subject_collection_items) {
  225. let score = (vod.rating ? vod.rating.value || '' : '').toString();
  226. videos.push({
  227. vod_id: 'msearch:'+vod.id,
  228. vod_name: vod.title,
  229. vod_pic: vod.pic.normal || vod.pic.large,
  230. vod_remarks: score.length > 0 ? '评分:' + score : '',
  231. });
  232. }
  233. return JSON.stringify({
  234. page: parseInt(page),
  235. pagecount: Math.ceil(data.total / 30),
  236. list: videos,
  237. });
  238. } else if (tid == 't250') {
  239. const link = sig(`${domain}/api/v2/subject_collection/movie_top250/items?area=全部&sort=recommend&playable=0&loc_id=0&start=${(page - 1) * 30}&count=30`);
  240. const data = await request(link);
  241. let videos = [];
  242. for (const vod of data.items || data.subject_collection_items) {
  243. let score = (vod.rating ? vod.rating.value || '' : '').toString();
  244. videos.push({
  245. vod_id: 'msearch:'+vod.id,
  246. vod_name: vod.title,
  247. vod_pic: vod.pic.normal || vod.pic.large,
  248. vod_remarks: score.length > 0 ? '评分:' + score : '',
  249. });
  250. }
  251. return JSON.stringify({
  252. page: parseInt(page),
  253. pagecount: Math.ceil(data.total / 30),
  254. list: videos,
  255. });
  256. } else if (tid == 't2') {
  257. const link = sig(`${domain}/api/v2/movie/tag?sort=${extend.sort || 'U'}&start=${(page - 1) * 30}&count=30&q=${extend['形式'] || '全部形式'},${extend['类型'] || '全部类型'},${extend['地区'] || '全部地区'},${extend['年代'] || '全部年代'}&score_rang=0,10`);
  258. const data = await request(link);
  259. let videos = [];
  260. for (const vod of data.data) {
  261. let score = (vod.rating ? vod.rating.value || '' : '').toString();
  262. videos.push({
  263. vod_id: 'msearch:'+vod.id,
  264. vod_name: vod.title,
  265. vod_pic: vod.pic.normal || vod.pic.large,
  266. vod_remarks: score.length > 0 ? '评分:' + score : '',
  267. });
  268. }
  269. return JSON.stringify({
  270. page: parseInt(page),
  271. pagecount: Math.ceil(data.total / 30),
  272. list: videos,
  273. });
  274. } else if (tid == 't3') {
  275. let link = sig(`${domain}/api/v2/movie/category_ranks?count=30&category=recent_hot`);
  276. let data = await request(link);
  277. let videos = [];
  278. for (const vod of data.selected_collections) {
  279. videos.push({
  280. vod_id: 'msearch:'+'cr_' + vod.id,
  281. vod_name: vod.short_name || vod.title,
  282. vod_pic: vod.cover_url,
  283. vod_remarks: '',
  284. cate: {},
  285. });
  286. }
  287. link = sig(`${domain}/api/v2/tv/category_ranks?count=30&category=recent_hot`);
  288. data = await request(link);
  289. for (const vod of data.selected_collections) {
  290. videos.push({
  291. vod_id: 'msearch:'+'cr_' + vod.id,
  292. vod_name: vod.short_name || vod.title,
  293. vod_pic: vod.cover_url,
  294. vod_remarks: '',
  295. cate: {},
  296. });
  297. }
  298. return JSON.stringify({
  299. page: 1,
  300. pagecount: 1,
  301. list: videos,
  302. });
  303. } else if (tid == 't4') {
  304. const link = sig(`${domain}/api/v2/skynet/new_playlists?subject_type=${extend['type'] || ''}&category=${extend['cate'] || 'all'}&loc_id=0&start=${(page - 1) * 30}&count=30`);
  305. const data = await request(link);
  306. let videos = [];
  307. for (const vod of data.data[0].items) {
  308. videos.push({
  309. vod_id: 'msearch:'+vod.owner ? 'dl_' + vod.id : 'cr_' + vod.id,
  310. vod_name: vod.title,
  311. vod_pic: vod.cover_url,
  312. vod_remarks: '',
  313. cate: {},
  314. });
  315. }
  316. return JSON.stringify({
  317. page: parseInt(page),
  318. pagecount: Math.ceil(data.total / 30),
  319. list: videos,
  320. });
  321. } else if (tid.startsWith('cr_')) {
  322. const link = sig(`${domain}/api/v2/subject_collection/${tid.substring(3)}/items?start=${(page - 1) * 30}&count=30&updated_at=&items_only=1`);
  323. const data = await request(link);
  324. let videos = [];
  325. for (const vod of data.subject_collection_items) {
  326. let score = (vod.rating ? vod.rating.value || '' : '').toString();
  327. videos.push({
  328. vod_id: 'msearch:'+vod.id,
  329. vod_name: vod.title,
  330. vod_pic: vod.pic.normal || vod.pic.large,
  331. vod_remarks: score.length > 0 ? '评分:' + score : '',
  332. });
  333. }
  334. return JSON.stringify({
  335. page: parseInt(page),
  336. pagecount: Math.ceil(data.total / 30),
  337. list: videos,
  338. });
  339. } else if (tid.startsWith('dl_')) {
  340. const link = sig(`${domain}/api/v2/doulist/${tid.substring(3)}/posts?start=${(page - 1) * 30}&count=30&updated_at=&items_only=1`);
  341. const data = await request(link);
  342. let videos = [];
  343. for (const it of data.items) {
  344. const vod = it.content.subject;
  345. if (!vod) continue;
  346. let score = (vod.rating ? vod.rating.value || '' : '').toString();
  347. videos.push({
  348. vod_id: 'msearch:'+vod.id,
  349. vod_name: vod.title,
  350. vod_pic: vod.pic.normal || vod.pic.large,
  351. vod_remarks: score.length > 0 ? '评分:' + score : '',
  352. });
  353. }
  354. return JSON.stringify({
  355. page: parseInt(page),
  356. pagecount: Math.ceil(data.total / 30),
  357. list: videos,
  358. });
  359. }
  360. }
  361. async function detail(id) {
  362. return '{}';
  363. }
  364. async function play(flag, id, flags) {
  365. return '{}';
  366. }
  367. async function search(wd, quick, pg) {
  368. return '{}';
  369. }
  370. export function __jsEvalReturn() {
  371. return {
  372. init: init,
  373. home: home,
  374. category: category,
  375. detail: detail,
  376. play: play,
  377. search: search,
  378. };
  379. }