11import { Route } from '@/types' ;
2- import got from '@/utils/got' ;
3- import * as url from 'node:url' ;
2+ import ofetch from '@/utils/ofetch' ;
43import { load } from 'cheerio' ;
54
65export const route : Route = {
@@ -24,56 +23,55 @@ export const route: Route = {
2423 handler,
2524} ;
2625
26+ const getMediaApiToken = ( metaContent ) => {
27+ if ( ! metaContent ) {
28+ throw new Error ( 'Empty web experience config meta content' ) ;
29+ }
30+ const config = JSON . parse ( decodeURIComponent ( metaContent ) ) ;
31+ return config . MEDIA_API . token ;
32+ } ;
33+
2734async function handler ( ctx ) {
2835 const country = ctx . req . param ( 'country' ) ;
2936 const id = ctx . req . param ( 'id' ) ;
3037 const link = `https://apps.apple.com/${ country } /app/${ id } ` ;
31- const target = url . resolve ( link , '?mt=8#see-all/in-app-purchases' ) ;
3238
33- const res = await got . get ( target ) ;
34- const $ = load ( res . data ) ;
39+ const res = await ofetch ( link ) ;
40+ const $ = load ( res ) ;
3541 const lang = $ ( 'html' ) . attr ( 'lang' ) ;
42+ const mediaToken = getMediaApiToken ( $ ( 'meta[name="web-experience-app/config/environment"]' ) . attr ( 'content' ) ) ;
3643
37- const apiResponse = (
38- await got ( {
39- method : 'get' ,
40- url : `https://amp-api.apps.apple.com/v1/catalog/${ country } /apps/${ id . replace ( 'id' , '' ) } ?platform=web&include=Cmerchandised-in-apps%2Ctop-in-apps%2Ceula&l=${ lang } ` ,
41- headers : {
42- authorization :
43- 'Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkNSRjVITkJHUFEifQ.eyJpc3MiOiI4Q1UyNk1LTFM0IiwiaWF0IjoxNjA3MDMxMTcwLCJleHAiOjE2MTAwNTUxNzB9.qzq2PKkPBNDwHbShoBY3T7J2IjgWsR_MyAvTnZtQB5FZjsH_ZY5esBa0qXbA9kUiq_90GkRoNVMR03meOQQ7SQ' ,
44- authority : 'amp-api.apps.apple.com' ,
45- referer : target ,
46- } ,
47- } )
48- ) . data . data [ 0 ] ;
44+ const apiResponse = await ofetch ( `https://amp-api-edge.apps.apple.com/v1/catalog/${ country } /apps/${ id . replace ( 'id' , '' ) } ` , {
45+ query : {
46+ platform : 'web' ,
47+ include : 'merchandised-in-apps,top-in-apps,eula' ,
48+ l : lang ,
49+ } ,
50+ headers : {
51+ authorization : `Bearer ${ mediaToken } ` ,
52+ origin : 'https://apps.apple.com' ,
53+ } ,
54+ } ) ;
4955
50- const attributes = apiResponse . attributes ;
51- const titleTemp = attributes . name ;
56+ const appData = apiResponse . data [ 0 ] ;
57+ const attributes = appData . attributes ;
5258
5359 const platform = attributes . deviceFamilies . includes ( 'mac' ) ? 'macOS' : 'iOS' ;
54- let title ;
60+
5561 let item = [ ] ;
5662
57- const iap = apiResponse . relationships [ 'top-in-apps' ] . data ;
63+ const iap = appData . relationships [ 'top-in-apps' ] . data ;
5864 if ( iap ) {
59- title = `${ country === 'cn' ? '内购限免提醒' : 'IAP price watcher' } : ${ titleTemp } for ${ platform } ` ;
60-
61- item = iap . map ( ( e ) => {
62- const title = `${ e . attributes . name } is now ${ e . attributes . offers [ 0 ] . priceFormatted } ` ;
63-
64- const result = {
65- link,
66- guid : e . attributes . url ,
67- description : e . attributes . artwork ? e . attributes . description . standard + `<br><img src=${ e . attributes . artwork . url . replace ( '{w}x{h}{c}.{f}' , '320x0w.jpg' ) } >` : e . attributes . description . standard ,
68- title,
69- pubDate : new Date ( ) . toUTCString ( ) ,
70- } ;
71- return result ;
72- } ) ;
65+ item = iap . map ( ( { attributes } ) => ( {
66+ title : `${ attributes . name } is now ${ attributes . offers [ 0 ] . priceFormatted } ` ,
67+ link : attributes . url ,
68+ guid : `${ attributes . url } :${ attributes . offerName } :${ attributes . offers [ 0 ] . priceString } ` ,
69+ description : attributes . artwork ? attributes . description . standard + `<br><img src=${ attributes . artwork . url . replace ( '{w}x{h}{c}.{f}' , '3000x3000bb.webp' ) } >` : attributes . description . standard ,
70+ } ) ) ;
7371 }
7472
7573 return {
76- title,
74+ title : ` ${ country . toLowerCase ( ) === 'cn' ? '内购限免提醒' : 'IAP price watcher' } : ${ attributes . name } for ${ platform } ` ,
7775 link,
7876 item,
7977 } ;
0 commit comments