From 6deef181c5cf943c52464408d1effb7674efa467 Mon Sep 17 00:00:00 2001
From: quiniapiezoelectricity
<73748843+quiniapiezoelectricity@users.noreply.github.com>
Date: Tue, 8 Oct 2024 16:34:34 +0100
Subject: [PATCH] feat: Add L'Orient-Le Jour Route (#17030)
* feat: Add L'Orient-Le Jour Route
* fix codefactor
* fix codefactor
---
lib/config.ts | 10 +
lib/routes/lorientlejour/index.ts | 173 ++++++++++++++++++
lib/routes/lorientlejour/namespace.ts | 7 +
.../lorientlejour/templates/description.art | 18 ++
4 files changed, 208 insertions(+)
create mode 100644 lib/routes/lorientlejour/index.ts
create mode 100644 lib/routes/lorientlejour/namespace.ts
create mode 100644 lib/routes/lorientlejour/templates/description.art
diff --git a/lib/config.ts b/lib/config.ts
index 2d9292702f..e2e0e162f8 100644
--- a/lib/config.ts
+++ b/lib/config.ts
@@ -183,6 +183,11 @@ export type Config = {
lightnovel: {
cookie?: string;
};
+ lorientlejour: {
+ token?: string;
+ username?: string;
+ password?: string;
+ };
malaysiakini: {
email?: string;
password?: string;
@@ -567,6 +572,11 @@ const calculateValue = () => {
lightnovel: {
cookie: envs.SECURITY_KEY,
},
+ lorientlejour: {
+ token: envs.LORIENTLEJOUR_TOKEN,
+ username: envs.LORIENTLEJOUR_USERNAME,
+ password: envs.LORIENTLEJOUR_PASSWORD,
+ },
malaysiakini: {
email: envs.MALAYSIAKINI_EMAIL,
password: envs.MALAYSIAKINI_PASSWORD,
diff --git a/lib/routes/lorientlejour/index.ts b/lib/routes/lorientlejour/index.ts
new file mode 100644
index 0000000000..74e9d612c4
--- /dev/null
+++ b/lib/routes/lorientlejour/index.ts
@@ -0,0 +1,173 @@
+import { Route } from '@/types';
+import cache from '@/utils/cache';
+import got from '@/utils/got';
+import { config } from '@/config';
+import { FetchError } from 'ofetch';
+import { load } from 'cheerio';
+import { art } from '@/utils/render';
+import { getCurrentPath } from '@/utils/helpers';
+import path from 'node:path';
+import timezone from '@/utils/timezone';
+import { parseDate } from '@/utils/parse-date';
+
+const __dirname = getCurrentPath(import.meta.url);
+
+export const route: Route = {
+ path: '/:category?',
+ categories: ['traditional-media'],
+ example: '/lorientlejour/977-lebanon',
+ parameters: {
+ category: 'Category from the last segment of the URL of the corresponding site, see below for more information, /977-Lebanon by default',
+ },
+ features: {
+ requirePuppeteer: false,
+ antiCrawler: false,
+ supportBT: false,
+ supportPodcast: false,
+ supportScihub: false,
+ requireConfig: [
+ {
+ name: 'LORIENTLEJOUR_USERNAME',
+ optional: true,
+ description: `L'Orient-Le Jour/L'Orient Today Email or Username`,
+ },
+ {
+ name: 'LORIENTLEJOUR_PASSWORD',
+ optional: true,
+ description: `L'Orient-Le Jour/L'Orient Today Password`,
+ },
+ {
+ name: 'LORIENTLEJOUR_TOKEN',
+ optional: true,
+ description: `To obtain a token, log into L'Orient-Le Jour/L'Orient Today App and inspect the connection request to find the token parameter from the request URL`,
+ },
+ ],
+ },
+ name: 'Category',
+ maintainers: ['quiniapiezoelectricity'],
+ handler,
+ description: ` :::tip
+ For example, the path for the sites https://today.lorientlejour.com/section/977-lebanon and https://www.lorientlejour.com/rubrique/1-liban would be /lorientlejour/977-lebanon and /lorientlejour/1-liban respectively.
+ :::`,
+ radar: [
+ {
+ source: ['www.lorientlejour.com/*/:category'],
+ target: '/:category',
+ },
+ {
+ source: ['www.lorientlejour.com'],
+ target: '/1-Liban',
+ },
+ {
+ source: ['today.lorientlejour.com/*/:category'],
+ target: '/:category',
+ },
+ {
+ source: ['today.lorientlejour.com'],
+ target: '/977-Lebanon',
+ },
+ ],
+};
+
+async function handler(ctx) {
+ const category = ctx.req.param('category') ?? '977-Lebanon';
+ const limit = ctx.req.param('limit') ?? 25;
+
+ const categoryId = category.match(/^(\d+)/i)[0] ?? category;
+
+ const key = '3d5_f6A(S$G_FD=2S(Dr6%7BW_h37@rE';
+
+ let token;
+ const cacheIn = await cache.get('lorientlejour:token');
+ if (cacheIn) {
+ token = cacheIn;
+ } else if (config.lorientlejour.token) {
+ token = config.lorientlejour.token;
+ cache.set('lorientlejour:token', token);
+ } else if (config.lorientlejour.username && config.lorientlejour.password) {
+ const loginUrl = `https://www.lorientlejour.com/cmsapi/visitors.php?key=${key}&action=login&loginName=${config.lorientlejour.username}&password=${config.lorientlejour.password}`;
+ const loginResponse = await got(loginUrl);
+ token = loginResponse.data.data.token;
+ cache.set('lorientlejour:token', token);
+ }
+
+ if (token) {
+ try {
+ await got(`https://www.lorientlejour.com/cmsapi/visitors.php?key=${key}&action=login_token&token=${token}`);
+ } catch (error) {
+ if (error instanceof FetchError && error.statusCode === 403) {
+ await cache.set('lorientlejour:token', '');
+ }
+ throw error;
+ }
+ }
+
+ let categoryUrl = `https://www.lorientlejour.com/cmsapi/categories.php?key=${key}&action=view&categoryId=${categoryId}`;
+ if (token) {
+ categoryUrl = categoryUrl + `&token=${token}`;
+ }
+ const categoryResponse = await cache.tryGet(
+ categoryUrl,
+ async () =>
+ await got({
+ method: 'get',
+ url: categoryUrl,
+ }),
+ config.cache.routeExpire,
+ false
+ );
+ const categoryInfo = categoryResponse.data.data[0];
+ let language = '';
+ if (categoryInfo.typeId.locale) {
+ language = categoryInfo.typeId.locale;
+ }
+ if (language === '') {
+ language = categoryInfo.typeId.name === 'English' ? 'en-US' : 'fr-FR';
+ }
+ let title = `L'Orient Le Jour`;
+ if (language === 'en-US') {
+ title = `L'Orient Today`;
+ }
+
+ let url = `https://www.lorientlejour.com/cmsapi/content.php?text=clean&key=${key}&action=search&category=${categoryId}&limit=${limit}&text=false&page=1&includeSubcategories=1`;
+ if (token) {
+ url = url + `&token=${token}`;
+ }
+ const response = await got(url);
+ const items = response.data.data.map((item) => {
+ item.link = item.url;
+ item.author = item.authors.map((author) => author.name).join(', ');
+ item.pubDate = timezone(parseDate(item.firstPublished), +3);
+ item.updated = timezone(parseDate(item.lastUpdate), +3);
+ item.category = item.categories.map((itemCategory) => itemCategory.name);
+ const contents = item.contents;
+ const $ = load(contents);
+ const article = $('html');
+ article.find('.inline-embeded-article').remove();
+ article.find('.relatedArticles').remove();
+ if (item.inline_attachments) {
+ article.find('.inlineImage').each(function () {
+ const inlineImageSrc = $(this).attr('src');
+ const inlineAttachment = item.inline_attachments.find((inlineAttachment) => inlineAttachment.url === inlineImageSrc);
+ if (inlineAttachment && inlineAttachment.description) {
+ $(this).wrap('
{{@ summary }}+{{ /if }} +{{ if attachments}} + {{ each attachments }} + {{if $value.url }} +