mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-08-30 16:55:08 +08:00
feat(apnews): Mobile API (#18819)
* feat(apnews): Mobile API * . * 更新 mobile-api.ts * 更新 mobile-api.ts * .
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
import { Route, ViewType } from '@/types';
|
||||
import { fetchArticle } from './utils';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import timezone from '@/utils/timezone';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/api/:tags?',
|
||||
categories: ['traditional-media', 'popular'],
|
||||
example: '/apnews/api/apf-topnews',
|
||||
view: ViewType.Articles,
|
||||
parameters: {
|
||||
tags: {
|
||||
description: 'Getting a list of articles from a public API based on tags.',
|
||||
options: [
|
||||
{ value: 'apf-topnews', label: 'Top News' },
|
||||
{ value: 'apf-sports', label: 'Sports' },
|
||||
{ value: 'apf-politics', label: 'Politics' },
|
||||
{ value: 'apf-entertainment', label: 'Entertainment' },
|
||||
{ value: 'apf-usnews', label: 'US News' },
|
||||
{ value: 'apf-oddities', label: 'Oddities' },
|
||||
{ value: 'apf-Travel', label: 'Travel' },
|
||||
{ value: 'apf-technology', label: 'Technology' },
|
||||
{ value: 'apf-lifestyle', label: 'Lifestyle' },
|
||||
{ value: 'apf-business', label: 'Business' },
|
||||
{ value: 'apf-Health', label: 'Health' },
|
||||
{ value: 'apf-science', label: 'Science' },
|
||||
{ value: 'apf-intlnews', label: 'International News' },
|
||||
],
|
||||
default: 'apf-topnews',
|
||||
},
|
||||
},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['apnews.com/'],
|
||||
},
|
||||
],
|
||||
name: 'News',
|
||||
maintainers: ['dzx-dzx'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const { tags = 'apf-topnews' } = ctx.req.param();
|
||||
const apiRootUrl = 'https://afs-prod.appspot.com/api/v2/feed/tag';
|
||||
const url = `${apiRootUrl}?tags=${tags}`;
|
||||
const res = await ofetch(url);
|
||||
|
||||
const list = res.cards
|
||||
.map((e) => ({
|
||||
title: e.contents[0]?.headline,
|
||||
link: e.contents[0]?.localLinkUrl,
|
||||
pubDate: timezone(parseDate(e.publishedDate), 0),
|
||||
category: e.tagObjs.map((tag) => tag.name),
|
||||
updated: timezone(parseDate(e.contents[0]?.updated), 0),
|
||||
description: e.contents[0]?.storyHTML,
|
||||
author: e.contents[0]?.reporters.map((author) => ({ name: author.displayName })),
|
||||
}))
|
||||
.sort((a, b) => b.pubDate - a.pubDate)
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20);
|
||||
|
||||
const items = ctx.req.query('fulltext') === 'true' ? await Promise.all(list.map((item) => fetchArticle(item))) : list;
|
||||
|
||||
return {
|
||||
title: `${res.tagObjs[0].name} - AP News`,
|
||||
item: items,
|
||||
link: 'https://apnews.com',
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Route, ViewType } from '@/types';
|
||||
import { asyncPoolAll, fetchArticle } from './utils';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/mobile/:path{.+}?',
|
||||
categories: ['traditional-media'],
|
||||
example: '/apnews/mobile/ap-top-news',
|
||||
view: ViewType.Articles,
|
||||
parameters: {
|
||||
path: {
|
||||
description: 'Corresponding path from AP News website',
|
||||
default: 'ap-top-news',
|
||||
},
|
||||
},
|
||||
features: {
|
||||
requireConfig: false,
|
||||
requirePuppeteer: false,
|
||||
antiCrawler: false,
|
||||
supportBT: false,
|
||||
supportPodcast: false,
|
||||
supportScihub: false,
|
||||
},
|
||||
radar: [
|
||||
{
|
||||
source: ['apnews.com/'],
|
||||
},
|
||||
],
|
||||
name: 'News (from mobile client API)',
|
||||
maintainers: ['dzx-dzx'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const path = ctx.req.param('path') ? `/${ctx.req.param('path')}` : '/hub/ap-top-news';
|
||||
const apiRootUrl = 'https://apnews.com/graphql/delivery/ap/v1';
|
||||
const res = await ofetch(apiRootUrl, {
|
||||
query: {
|
||||
operationName: 'ContentPageQuery',
|
||||
variables: { path },
|
||||
extensions: { persistedQuery: { version: 1, sha256Hash: '3bc305abbf62e9e632403a74cc86dc1cba51156d2313f09b3779efec51fc3acb' } },
|
||||
},
|
||||
});
|
||||
|
||||
const screen = res.data.Screen;
|
||||
|
||||
const list = [...screen.main.filter((e) => e.__typename === 'ColumnContainer').flatMap((_) => _.columns), ...screen.main.filter((e) => e.__typename !== 'ColumnContainer')]
|
||||
.filter((e) => e.__typename !== 'GoogleDfPAdModule')
|
||||
.flatMap((e) => {
|
||||
switch (e.__typename) {
|
||||
case 'PageListModule':
|
||||
return e.items;
|
||||
case 'VideoPlaylistModule':
|
||||
return e.playlist;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.map((e) => {
|
||||
if (e.__typename === 'PagePromo') {
|
||||
return {
|
||||
title: e.title,
|
||||
link: e.url,
|
||||
pubDate: parseDate(e.publishDateStamp),
|
||||
category: e.category,
|
||||
description: e.description,
|
||||
guid: e.id,
|
||||
};
|
||||
} else if (e.__typename === 'VideoPlaylistItem') {
|
||||
return {
|
||||
title: e.title,
|
||||
link: e.url,
|
||||
description: e.description,
|
||||
guid: e.contentId,
|
||||
};
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.sort((a, b) => b.pubDate - a.pubDate)
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 20);
|
||||
|
||||
const items = ctx.req.query('fulltext') === 'true' ? await asyncPoolAll(10, list, (item) => fetchArticle(item)) : list;
|
||||
|
||||
return {
|
||||
title: screen.category ?? screen.title,
|
||||
item: items,
|
||||
link: 'https://apnews.com',
|
||||
};
|
||||
}
|
||||
@@ -38,6 +38,7 @@ export function fetchArticle(item) {
|
||||
$('div.Enhancement').remove();
|
||||
const section = $("meta[property='article:section']").attr('content');
|
||||
return {
|
||||
...item,
|
||||
title: ldjson.headline,
|
||||
pubDate: parseDate(ldjson.datePublished),
|
||||
updated: parseDate(ldjson.dateModified),
|
||||
@@ -45,7 +46,6 @@ export function fetchArticle(item) {
|
||||
category: [...(section ? [section] : []), ...(ldjson.keywords ?? [])],
|
||||
guid: $("meta[name='brightspot.contentId']").attr('content'),
|
||||
author: ldjson.author,
|
||||
...item,
|
||||
};
|
||||
} else {
|
||||
// Live
|
||||
@@ -56,11 +56,11 @@ export function fetchArticle(item) {
|
||||
const pubDate = url.hash ? parseDate(Number.parseInt($(url.hash).parent().attr('data-posted-date-timestamp'), 10)) : parseDate(ldjson.coverageStartTime);
|
||||
|
||||
return {
|
||||
...item,
|
||||
category: ldjson.keywords,
|
||||
pubDate,
|
||||
description,
|
||||
guid: $("meta[name='brightspot.contentId']").attr('content'),
|
||||
...item,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user