fix(route): radio-canada (#19987)
* fix(radio-canada): Repair description fetching after site update
The previous method for fetching the item description broke due to a change in the target website's format.
This commit resolves the issue by extracting the description directly from the main HTML content of the article page. This restores functionality to the feed and provides a more robust parsing method.
* refactor(radio-canada): Parse article content from internal JSON state
This change refactors the content fetching logic to parse a JSON object (`window._rcState_`) from the page. This approach allows for the full reconstruction of the article, including the header image, primer text, and all body attachments (images), by replacing placeholders in the HTML with the correct media.
* fix(radio-canada): Improve content parsing with fallback mechanism
Adds a fallback to the previous HTML scraping method in case the JSON state object is not found. This ensures greater resilience against site changes and improves the chances of successfully retrieving content.
* refactor(radio-canada): Extract content parsing logic into a helper function
To address a "Complex Method" warning from CodeFactor, the logic for parsing the article description from the JSON state has been extracted into a dedicated `parseDescriptionFromState` function.
This change improves code readability and maintainability by simplifying the main handler and isolating the content parsing logic. The `if/else` block was also converted to a ternary operator for conciseness.
* fix(radio-canada): Update image URL parsing to remove width placeholder for header and body attachments
---------
This commit is contained in:
parent
22200f2fc0
commit
355d473ca9
|
|
@ -1,6 +1,6 @@
|
|||
import { Route } from '@/types';
|
||||
import cache from '@/utils/cache';
|
||||
import got from '@/utils/got';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
import { load } from 'cheerio';
|
||||
|
||||
|
|
@ -37,12 +37,9 @@ async function handler(ctx) {
|
|||
const apiRootUrl = 'https://services.radio-canada.ca';
|
||||
const currentUrl = `${apiRootUrl}/neuro/sphere/v1/rci/${language}/continuous-feed?pageSize=50`;
|
||||
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
const response = await ofetch(currentUrl);
|
||||
|
||||
const list = response.data.data.lineup.items.map((item) => ({
|
||||
const list = response.data.lineup.items.map((item) => ({
|
||||
title: item.title,
|
||||
category: item.kicker,
|
||||
link: `${rootUrl}${item.url}`,
|
||||
|
|
@ -52,18 +49,15 @@ async function handler(ctx) {
|
|||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const detailResponse = await ofetch(item.link);
|
||||
|
||||
const $ = load(detailResponse);
|
||||
|
||||
const $ = load(detailResponse.data);
|
||||
const rcState = $('script:contains("window._rcState_ = ")')
|
||||
.text()
|
||||
.match(/window\._rcState_ = (.*);/)[1];
|
||||
const rcStateJson = JSON.parse(rcState);
|
||||
const news = Object.values(rcStateJson.pagesV2.pages)[0];
|
||||
item.description = news.data.newsStory.body.html.replaceAll(String.raw`\n`, '<br>');
|
||||
.match(/window\._rcState_ = (.*);/)?.[1];
|
||||
|
||||
item.description = rcState ? parseDescriptionFromState(rcState) : ($(`div[data-testid="newsStoryMedia"]`).html() ?? '') + ($('article > main').html() ?? '');
|
||||
|
||||
return item;
|
||||
})
|
||||
|
|
@ -71,8 +65,27 @@ async function handler(ctx) {
|
|||
);
|
||||
|
||||
return {
|
||||
title: response.data.meta.title,
|
||||
link: response.data.metric.metrikContent.omniture.url,
|
||||
title: response.meta.title,
|
||||
link: response.metric.metrikContent.omniture.url,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
||||
const parseDescriptionFromState = (rcState) => {
|
||||
const rcStateJson = JSON.parse(rcState);
|
||||
const news = Object.values(rcStateJson?.pages?.pages ?? {})[0] as any;
|
||||
|
||||
const headerImg = news?.data?.newsStory?.headerMultimediaItem?.picture;
|
||||
const headerImgUrl = headerImg?.pattern ? headerImg?.pattern.replace('/q_auto,w_{width}', '').replace('{ratio}', '16x9') : '';
|
||||
const header = `<figure><picture><img src="${headerImgUrl}" alt="${headerImg?.alt ?? ''}"></picture><figcaption>${headerImg?.legend ?? ''}</figcaption></figure>`;
|
||||
const primer = news?.data?.newsStory?.primer?.replaceAll(String.raw`\n`, '') ?? '';
|
||||
const body = news?.data?.newsStory?.body?.html?.replaceAll(String.raw`\n`, '') ?? '';
|
||||
let bodyWithImg = body;
|
||||
for (const [index, attachment] of (news?.data?.newsStory?.body?.attachments ?? []).entries()) {
|
||||
const placeholder = `<!--body:attachment:${index}-->`;
|
||||
const picture = attachment?.picture;
|
||||
const imageUrl = picture?.pattern ? picture?.pattern.replace('/q_auto,w_{width}', '').replace('{ratio}', attachment?.dimensionRatio ?? '16x9') : '';
|
||||
bodyWithImg = bodyWithImg.replace(placeholder, `<figure><picture><img src="${imageUrl}" alt="${picture?.alt ?? ''}"></picture><figcaption>${picture?.legend ?? ''}</figcaption></figure>`);
|
||||
}
|
||||
return header + primer + bodyWithImg;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue