forked from DIYgod/RSSHub
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(joshwcomeau): add new Routes josh w comeau (DIYgod#18071)
* init * Update lib/routes/joshwcomeau/latest.ts Co-authored-by: Tony <[email protected]> * Update lib/routes/joshwcomeau/popular.ts Co-authored-by: Tony <[email protected]> * remove date sorting * update date --------- Co-authored-by: Rjnishant530 <[email protected]>
- Loading branch information
1 parent
d359da4
commit 30061eb
Showing
4 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { Data, Route } from '@/types'; | ||
import { getRelativeUrlList, processList, rootUrl } from './utils'; | ||
|
||
export const route: Route = { | ||
path: '/latest/:category?', | ||
categories: ['programming'], | ||
example: '/joshwcomeau/latest/css', | ||
features: { | ||
requireConfig: false, | ||
requirePuppeteer: false, | ||
antiCrawler: false, | ||
supportBT: false, | ||
supportPodcast: false, | ||
supportScihub: false, | ||
}, | ||
parameters: { | ||
category: { | ||
description: 'Category', | ||
options: [ | ||
{ value: 'css', label: 'CSS' }, | ||
{ value: 'react', label: 'React' }, | ||
{ value: 'animation', label: 'Animation' }, | ||
{ value: 'javascript', label: 'JavaScript' }, | ||
{ value: 'career', label: 'Career' }, | ||
{ value: 'blog', label: 'Blog' }, | ||
], | ||
}, | ||
}, | ||
radar: [ | ||
{ | ||
source: ['joshwcomeau.com/'], | ||
target: '/latest', | ||
}, | ||
{ | ||
source: ['joshwcomeau.com/:category'], | ||
target: '/latest/:category', | ||
}, | ||
], | ||
name: 'Articles and Tutorials', | ||
maintainers: ['Rjnishant530'], | ||
handler, | ||
}; | ||
|
||
async function handler(ctx) { | ||
const category: string = ctx.req.param('category') || ''; | ||
const currentUrl = category ? `${rootUrl}/${category}` : rootUrl; | ||
const selector = category ? 'div > article > a:first-child' : 'article[data-include-enter-animation="false"] > a:first-child'; | ||
const { heading, urls } = await getRelativeUrlList(currentUrl, selector); | ||
const items = await processList(urls); | ||
const title = category ? `${heading} | ` : ''; | ||
return { | ||
title: `${title}Articles and Tutorials | Josh W. Comeau`, | ||
description: `Friendly tutorials for developers. Focus on ${category ? title : 'React, CSS, Animation, and more!'}`, | ||
link: currentUrl, | ||
item: items, | ||
icon: `${rootUrl}/favicon.png`, | ||
logo: `${rootUrl}/favicon.png`, | ||
} as Data; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import type { Namespace } from '@/types'; | ||
|
||
export const namespace: Namespace = { | ||
name: 'Josh W Comeau', | ||
url: 'www.joshwcomeau.com', | ||
categories: ['programming'], | ||
lang: 'en', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { Data, Route } from '@/types'; | ||
import { getRelativeUrlList, processList, rootUrl } from './utils'; | ||
|
||
export const route: Route = { | ||
path: '/popular', | ||
categories: ['programming'], | ||
example: '/joshwcomeau/popular', | ||
features: { | ||
requireConfig: false, | ||
requirePuppeteer: false, | ||
antiCrawler: false, | ||
supportBT: false, | ||
supportPodcast: false, | ||
supportScihub: false, | ||
}, | ||
radar: [ | ||
{ | ||
source: ['joshwcomeau.com/'], | ||
target: '/popular', | ||
}, | ||
], | ||
name: 'Popular Content', | ||
maintainers: ['Rjnishant530'], | ||
handler, | ||
}; | ||
|
||
async function handler() { | ||
const { urls } = await getRelativeUrlList(rootUrl, 'section > ol > li > a'); | ||
const items = await processList(urls); | ||
return { | ||
title: 'Popular Content | Josh W. Comeau', | ||
description: 'Friendly tutorials for developers. Focus on React, CSS, Animation, and more!', | ||
link: rootUrl, | ||
item: items, | ||
icon: `${rootUrl}/favicon.png`, | ||
logo: `${rootUrl}/favicon.png`, | ||
} as Data; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { DataItem } from '@/types'; | ||
import { load } from 'cheerio'; | ||
import ofetch from '@/utils/ofetch'; | ||
import { parseDate } from '@/utils/parse-date'; | ||
import cache from '@/utils/cache'; | ||
|
||
export const rootUrl = 'https://www.joshwcomeau.com'; | ||
|
||
export async function getRelativeUrlList(url, selector) { | ||
const response = await ofetch(url); | ||
const $ = load(response); | ||
const heading = $('header>h1').text(); | ||
const urls = $(selector) | ||
.toArray() | ||
.map((element) => { | ||
const itemRelativeUrl = $(element).attr('href'); | ||
const cardTitle = $(element).find('span').text(); | ||
return { url: itemRelativeUrl as string, cardTitle }; | ||
}); | ||
return { heading, urls }; | ||
} | ||
|
||
export async function processList(list) { | ||
const listPromise = await Promise.allSettled(list.map(async (item) => await cache.tryGet(`joshwcomeau:${item.url}`, async () => await getPostContent(item)))); | ||
return listPromise.map((item, index) => (item.status === 'fulfilled' ? item.value : ({ title: 'Error Reading Item', link: `${rootUrl}${list[index]?.url}` } as DataItem))); | ||
} | ||
|
||
export async function getPostContent({ url, cardTitle }) { | ||
if (url.startsWith('https')) { | ||
return { | ||
title: cardTitle ?? 'External Content', | ||
description: 'Read it on external Site', | ||
link: url, | ||
} as DataItem; | ||
} | ||
const response = await ofetch(`${rootUrl}${url}`); | ||
const $ = load(response); | ||
const title = $('meta[property="og:title"]').attr('content')?.replace('• Josh W. Comeau', ''); | ||
const summary = $('meta[property="og:description"]').attr('content'); | ||
const author = $('meta[name="author"]').attr('content'); | ||
const dateDiv = $('div[data-parent-layout]'); | ||
const tag = dateDiv.find('dl:first-child > dd > a').text(); | ||
const pubDate = dateDiv.find('dl:first-child > dd:has(span):not(:last-child)').text(); | ||
const updateDate = dateDiv.find('dl:last-child > dd:has(span):not(:last-child)').text(); | ||
const description = $('main > article').html(); | ||
return { | ||
title, | ||
description, | ||
author, | ||
pubDate: processDate(pubDate), | ||
updated: processDate(updateDate), | ||
link: `${rootUrl}${url}`, | ||
content: { html: description, text: summary }, | ||
category: [tag], | ||
} as DataItem; | ||
} | ||
|
||
function processDate(date: string) { | ||
const dateWithSlash = date.trim().replaceAll(' ', '/').replace(',', ''); | ||
return parseDate(dateWithSlash, 'MMMM/Do/YYYY', 'en'); | ||
} |