rsshub
Version:
Make RSS Great Again!
396 lines (395 loc) • 10.4 kB
JavaScript
import { t as rofetch } from "./ofetch-C3ts-Hud.mjs";
import { load } from "cheerio";
//#region lib/routes/afr/query.ts
const pageByNavigationPathQuery = `
query pageByNavigationPath($input: PageByNavigationPathInput!, $firstStories: Int, $afterStories: Cursor) {
pageByNavigationPath(input: $input) {
error {
message
type {
class
... on ErrorTypeInvalidRequest {
fields {
field
message
}
}
}
}
page {
ads {
suppress
}
description
id
latestStoriesConnection(first: $firstStories, after: $afterStories) {
edges {
node {
byline {
...AssetBylineFragment
}
headlines {
headline
}
ads {
sponsor {
name
}
}
overview {
about
label
}
type
dates {
firstPublished
published
}
id
publicId
images {
...AssetImagesFragmentAudience
}
tags {
primary {
...TagFragmentAudience
}
secondary {
...TagFragmentAudience
}
}
urls {
...AssetUrlsAudienceFragment
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
name
seo {
canonical {
brand {
key
}
}
description
title
}
social {
image {
height
url
width
}
}
}
redirect
}
}
fragment AssetBylineFragment on AssetByline {
type
... on AssetBylineAuthor {
author {
name
publicId
profile {
avatar
bio
body
canonical {
brand {
key
}
}
email
socials {
facebook {
publicId
}
twitter {
publicId
}
}
title
}
}
}
... on AssetBylineName {
name
}
}
fragment AssetImagesFragmentAudience on ImageRenditions {
landscape16x9 {
...ImageFragmentAudience
}
landscape3x2 {
...ImageFragmentAudience
}
portrait2x3 {
...ImageFragmentAudience
}
square1x1 {
...ImageFragmentAudience
}
}
fragment ImageFragmentAudience on ImageRendition {
altText
animated
caption
credit
crop {
offsetX
offsetY
width
zoom
}
mediaId
mimeType
source
type
}
fragment AssetUrlsAudienceFragment on AssetURLs {
canonical {
brand {
key
}
path
}
external {
url
}
published {
brand {
key
}
path
}
}
fragment TagFragmentAudience on Tag {
company {
exchangeCode
stockCode
}
context {
name
}
description
displayName
externalEntities {
google {
placeId
}
wikipedia {
publicId
url
}
}
id
location {
latitude
longitude
postalCode
state
}
name
publicId
seo {
description
title
}
urls {
canonical {
brand {
key
}
path
}
published {
brand {
key
}
path
}
}
}
`;
const assetsConnectionByCriteriaQuery = `
query assetsConnectionByCriteria($after: ID, $brand: Brand!, $categories: [Int!], $first: Int!, $render: Render!, $types: [AssetType!]!) {
assetsConnectionByCriteria(after: $after, brand: $brand, categories: $categories, first: $first, render: $render, types: $types) {
edges {
cursor
node {
...AssetFragment
sponsor {
name
}
}
}
error {
message
type {
class
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
fragment AssetFragment on Asset {
asset {
about
byline
duration
headlines {
headline
}
live
}
assetType
dates {
firstPublished
modified
published
}
id
featuredImages {
landscape16x9 {
...ImageFragment
}
landscape3x2 {
...ImageFragment
}
portrait2x3 {
...ImageFragment
}
square1x1 {
...ImageFragment
}
}
label
tags {
primary: primaryTag {
...AssetTag
}
secondary {
...AssetTag
}
}
urls {
...AssetURLs
}
}
fragment AssetTag on AssetTagDetails {
...AssetTagAudience
shortID
slug
}
fragment AssetTagAudience on AssetTagDetails {
company {
exchangeCode
stockCode
}
context
displayName
id
name
urls {
canonical {
brand
path
}
published {
afr {
path
}
}
}
}
fragment AssetURLs on AssetURLs {
canonical {
brand
path
}
published {
afr {
path
}
}
}
fragment ImageFragment on Image {
data {
altText
aspect
autocrop
caption
cropWidth
id
offsetX
offsetY
zoom
}
}
`;
//#endregion
//#region lib/routes/afr/utils.ts
const getItem = async (item) => {
const $ = load(await rofetch(item.link));
const content = JSON.parse($("script#__REDUX_STATE__").text().replaceAll(":undefined", ":null").match("__REDUX_STATE__=(.*);")?.[1] || "{}").page.content;
const asset = content.asset;
switch (content.assetType) {
case "liveArticle":
item.description = asset.posts.map((post) => `<h2>${post.asset.headlines.headline}</h2>${post.asset.body}`).join("");
break;
case "article":
case "featureArticle":
item.description = renderArticle(asset, item.link);
break;
default: throw new Error(`Unknown asset type: ${content.assetType} in ${item.link}`);
}
return item;
};
const renderArticle = (asset, link) => {
const $ = load(asset.body, null, false);
$("x-placeholder").each((_, el) => {
const $el = $(el);
const id = $el.attr("id");
if (!id) $el.replaceWith("");
const placeholder = asset.bodyPlaceholders[id];
switch (placeholder?.type) {
case "callout":
case "relatedStory":
$el.replaceWith("");
break;
case "iframe":
$el.replaceWith(`<iframe src="${placeholder.data.url}" frameborder="0" allowfullscreen></iframe>`);
break;
case "image":
$el.replaceWith(`<img src="https://static.ffx.io/images/${placeholder.data.fileName}" alt="${placeholder.data.altText}" />`);
break;
case "linkArticle":
$el.replaceWith(placeholder.data.text);
break;
case "linkExternal":
$el.replaceWith(`<a href="${placeholder.data.url}" target="_blank" rel="noopener">${placeholder.data.text}</a>`);
break;
case "quote":
$el.replaceWith(placeholder.data.markup);
break;
case "scribd":
$el.replaceWith(`<a href="${placeholder.data.url}" target="_blank" rel="noopener">View on Scribd</a>`);
break;
case "twitter":
$el.replaceWith(`<a href="${placeholder.data.url}">${placeholder.data.url}</a>`);
break;
default: throw new Error(`Unknown placeholder type: ${placeholder?.type} in ${link}`);
}
});
return $.html();
};
//#endregion
export { assetsConnectionByCriteriaQuery as n, pageByNavigationPathQuery as r, getItem as t };