@@ -3,60 +3,114 @@ const cheerio = require('cheerio');
33const timezone = require ( '@/utils/timezone' ) ;
44const { parseDate, parseRelativeDate } = require ( '@/utils/parse-date' ) ;
55
6- const titles = {
7- '' : '最新报道' ,
8- 1 : '晚点独家' ,
9- 2 : '人物访谈' ,
10- 3 : '晚点早知道' ,
11- 4 : '长报道' ,
12- } ;
6+ /**
7+ * Convert an array into a dictionary object.
8+ * The keys of the dictionary object are the `id` properties of the elements in the array,
9+ * and the values are the remaining properties of each element.
10+ * @param {Array } arr - The array to be converted.
11+ * @returns {Object } - The converted dictionary object.
12+ */
13+ const arrayToDictionary = ( arr ) =>
14+ arr . reduce (
15+ ( dictionary , { id, ...rest } ) => ( {
16+ ...dictionary ,
17+ [ id ] : {
18+ ...rest ,
19+ } ,
20+ } ) ,
21+ { }
22+ ) ;
1323
1424module . exports = async ( ctx ) => {
15- const proma = ctx . params . proma ?? '' ;
25+ const { proma } = ctx . params ;
26+ const limit = ctx . query . limit ? parseInt ( ctx . query . limit , 10 ) : 5 ;
27+
28+ const title = '晚点' ;
29+ const defaultTitle = '最新报道' ;
30+ const exclusiveCategory = '晚点独家' ;
1631
1732 const rootUrl = 'https://www.latepost.com' ;
18- const currentUrl = `${ rootUrl } /${ proma ? 'site/index' : 'news/get-news-data' } ` ;
33+ const currentUrl = new URL ( proma ? `news/index?proma=${ proma } ` : '' , rootUrl ) . href ;
34+
35+ const apiColumnUrl = new URL ( 'site/get-column' , rootUrl ) . href ;
36+ const apiCommentUrl = new URL ( 'news/get-comment' , rootUrl ) . href ;
37+ const apiUrl = new URL ( proma ? 'site/index' : 'news/get-news-data' , rootUrl ) . href ;
1938
20- const response = await got ( {
21- method : 'post' ,
22- url : currentUrl ,
23- page : 1 ,
24- programa : proma ,
39+ const { data : columnResponse } = await got ( apiColumnUrl ) ;
40+ const columns = arrayToDictionary ( columnResponse ?. data ?? [ ] ) ;
41+
42+ const { data : response } = await got . post ( apiUrl , {
43+ json : {
44+ page : 1 ,
45+ limit,
46+ programa : parseInt ( proma , 10 ) ,
47+ } ,
2548 } ) ;
2649
27- let items = response . data . data . slice ( 0 , ctx . query . limit ? parseInt ( ctx . query . limit ) : 25 ) . map ( ( item ) => ( {
50+ let items = response . data . slice ( 0 , limit ) . map ( ( item ) => ( {
2851 title : item . title ,
29- link : `${ rootUrl } ${ item . detail_url } ` ,
30- category : item . label . map ( ( l ) => l . label ) ,
52+ link : new URL ( item . detail_url , rootUrl ) . href ,
53+ category : [ item . is_dj ? exclusiveCategory : undefined , item . programa ? columns [ item . programa ] . title : undefined , ...item . label . map ( ( c ) => c . label ) ] ,
54+ guid : item . id ,
55+ pubDate : parseDate ( item . release_time , [ 'MM月DD日' , 'YYYY年MM月DD日' ] ) ,
3156 } ) ) ;
3257
3358 items = await Promise . all (
3459 items . map ( ( item ) =>
3560 ctx . cache . tryGet ( item . link , async ( ) => {
36- const detailResponse = await got ( {
37- method : 'get' ,
38- url : item . link ,
61+ const { data : detailResponse } = await got ( item . link ) ;
62+
63+ const { data : commentResponse } = await got . post ( apiCommentUrl , {
64+ news_id : item . guid ,
65+ page : 1 ,
66+ limit : Infinity ,
67+ sort : 1 ,
68+ delete_num : 0 ,
3969 } ) ;
4070
41- const content = cheerio . load ( detailResponse . data ) ;
71+ const content = cheerio . load ( detailResponse ) ;
4272
43- content ( 'br' ) . each ( function ( ) {
44- content ( this ) . parent ( ) . remove ( ) ;
45- } ) ;
73+ item . title = item . title ?? content ( 'div.article-header-title' ) . text ( ) ;
74+ item . description = content ( '#select-main' )
75+ . html ( )
76+ . replace ( / < p > < b r > < \/ p > / g, '' ) ;
77+ item . author = content ( 'div.article-header-author div.author-link a.label' ) . first ( ) . text ( ) ;
78+ item . category = item . category . filter ( ( c ) => c ) ;
79+ item . guid = `latepost-${ item . guid } ` ;
4680
47- const pubDate = content ( '.article-header-date' ) . text ( ) ;
48- item . pubDate = timezone ( / 月 | 日 / . test ( pubDate ) ? parseDate ( ( / 年 / . test ( pubDate ) ? pubDate : `${ new Date ( ) . getFullYear ( ) } -${ pubDate } ` ) . replace ( / 年 | 月 / g, '-' ) . replace ( / 日 / g, '' ) ) : parseRelativeDate ( pubDate ) , + 8 ) ;
81+ const pubDate = content ( 'div.article-header-date' ) . text ( ) ;
4982
50- item . description = content ( '#select-main' ) . html ( ) ;
83+ if ( pubDate ) {
84+ if ( / \d + 月 \d + 日 / . test ( pubDate ) ) {
85+ item . pubDate = parseDate ( pubDate , [ 'MM月DD日 HH:mm' , 'YYYY年MM月DD日 HH:mm' ] ) ;
86+ } else {
87+ item . pubDate = parseRelativeDate ( pubDate ) ;
88+ }
89+ }
90+
91+ item . pubDate = timezone ( item . pubDate , + 8 ) ;
92+ item . comments = commentResponse . data ?. length ( ) ?? 0 ;
5193
5294 return item ;
5395 } )
5496 )
5597 ) ;
5698
99+ const icon = new URL ( 'favicon.ico' , rootUrl ) . href ;
100+
101+ const { data : currentResponse } = await got ( currentUrl ) ;
102+
103+ const $ = cheerio . load ( currentResponse ) ;
104+
57105 ctx . state . data = {
58- title : `${ titles [ proma ] } - 晚点` ,
59- link : currentUrl ,
60106 item : items ,
107+ title : `${ title } - ${ proma ? columns [ proma ] . title : defaultTitle } ` ,
108+ link : currentUrl ,
109+ description : $ ( 'div.logo-txt' ) . first ( ) . text ( ) ,
110+ language : 'zh-cn' ,
111+ image : new URL ( $ ( 'div.logo-txt img' ) . prop ( 'src' ) , rootUrl ) . href ,
112+ icon,
113+ logo : icon ,
114+ author : title ,
61115 } ;
62116} ;
0 commit comments