From 355d473ca9177bde548eb992f1cf4367425a9e0d Mon Sep 17 00:00:00 2001 From: WilliamGates <3852641+williamgateszhao@users.noreply.github.com> Date: Mon, 8 Sep 2025 05:16:54 +0800 Subject: [PATCH] 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 --------- --- lib/routes/radio-canada/latest.ts | 47 ++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/routes/radio-canada/latest.ts b/lib/routes/radio-canada/latest.ts index 7c44933f5..90f786204 100644 --- a/lib/routes/radio-canada/latest.ts +++ b/lib/routes/radio-canada/latest.ts @@ -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`, '
'); + .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 = `
${headerImg?.alt ?? ''}
${headerImg?.legend ?? ''}
`; + 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 = ``; + const picture = attachment?.picture; + const imageUrl = picture?.pattern ? picture?.pattern.replace('/q_auto,w_{width}', '').replace('{ratio}', attachment?.dimensionRatio ?? '16x9') : ''; + bodyWithImg = bodyWithImg.replace(placeholder, `
${picture?.alt ?? ''}
${picture?.legend ?? ''}
`); + } + return header + primer + bodyWithImg; +};