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: Added Route for 30secondsofcode (DIYgod#18045)
* init * comment fixes --------- Co-authored-by: rjnishant530 <[email protected]>
- Loading branch information
1 parent
38ec24d
commit 2f4653b
Showing
4 changed files
with
167 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,65 @@ | ||
import { Data, Route } from '@/types'; | ||
import { load } from 'cheerio'; | ||
import ofetch from '@/utils/ofetch'; | ||
import { processList } from './utils'; | ||
export const route: Route = { | ||
path: '/category/:category?/:subCategory?', | ||
categories: ['programming'], | ||
example: '/category/css/interactivity', | ||
parameters: { | ||
category: { | ||
description: 'Main Category. For Complete list visit site "https://www.30secondsofcode.org/collections/p/1/"', | ||
options: [ | ||
{ value: 'js', label: 'Javascript' }, | ||
{ value: 'css', label: 'CSS' }, | ||
{ value: 'algorithm', label: 'JavaScript Algorithms' }, | ||
{ value: 'react', label: 'React' }, | ||
], | ||
}, | ||
subCategory: { | ||
description: 'Filter within Category. Visit Individual Category site for subCategories', | ||
}, | ||
}, | ||
features: { | ||
requireConfig: false, | ||
requirePuppeteer: false, | ||
antiCrawler: false, | ||
supportBT: false, | ||
supportPodcast: false, | ||
supportScihub: false, | ||
}, | ||
radar: [ | ||
{ | ||
source: ['30secondsofcode.org/:category/:subCategory/', '30secondsofcode.org/:category/'], | ||
target: '/category/:category/:subCategory', | ||
}, | ||
], | ||
name: 'Category and Subcategory', | ||
maintainers: ['Rjnishant530'], | ||
handler, | ||
}; | ||
|
||
async function handler(ctx) { | ||
const category = ctx.req.param('category') ?? ''; | ||
const subCategory = ctx.req.param('subCategory') ?? ''; | ||
|
||
const rootUrl = 'https://www.30secondsofcode.org'; | ||
const currentUrl = `${rootUrl}${category ? `/${category}` : ''}${subCategory ? `/${subCategory}` : ''}${category || subCategory ? '/p/1/' : ''}`; | ||
|
||
const response = await ofetch(currentUrl); | ||
const $ = load(response); | ||
const heroElement = $('section.hero'); | ||
const heading = heroElement.find('div > h1').text(); | ||
const description = heroElement.find('div > p').text(); | ||
const image = heroElement.find('img').attr('src'); | ||
|
||
const fullList = $('section.preview-list > ul > li').toArray(); | ||
const items = await processList(fullList); | ||
return { | ||
title: heading, | ||
description, | ||
image: `${rootUrl}${image}`, | ||
link: rootUrl, | ||
item: items, | ||
} 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,7 @@ | ||
import type { Namespace } from '@/types'; | ||
|
||
export const namespace: Namespace = { | ||
name: '30 Seconds of code', | ||
url: 'www.30secondsofcode.org', | ||
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,41 @@ | ||
import { Data, Route } from '@/types'; | ||
import { load } from 'cheerio'; | ||
import { processList, rootUrl } from './utils'; | ||
import ofetch from '@/utils/ofetch'; | ||
|
||
export const route: Route = { | ||
path: '/latest', | ||
categories: ['programming'], | ||
example: '/latest', | ||
features: { | ||
requireConfig: false, | ||
requirePuppeteer: false, | ||
antiCrawler: false, | ||
supportBT: false, | ||
supportPodcast: false, | ||
supportScihub: false, | ||
}, | ||
radar: [ | ||
{ | ||
source: ['30secondsofcode.org'], | ||
target: '/latest', | ||
}, | ||
], | ||
name: 'New & Popular Snippets', | ||
maintainers: ['Rjnishant530'], | ||
handler, | ||
}; | ||
|
||
async function handler() { | ||
const response = await ofetch(rootUrl); | ||
|
||
const $ = load(response); | ||
const fullList = $('section.preview-list > ul > li').toArray(); | ||
const items = await processList(fullList); | ||
return { | ||
title: 'New & Popular Snippets', | ||
description: 'Discover short code snippets for all your development needs.', | ||
link: rootUrl, | ||
item: items, | ||
} 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,54 @@ | ||
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.30secondsofcode.org'; | ||
|
||
export async function processList(listElements) { | ||
const items = await Promise.allSettled( | ||
listElements.map((item) => { | ||
const $ = load(item); | ||
const link = $(' article > h3 > a').attr('href'); | ||
const date = $(' article > small > time').attr('datetime'); | ||
return processItem({ link, date }); | ||
}) | ||
); | ||
return items.map((item) => (item.status === 'fulfilled' ? item.value : ({ title: 'Error Reading Item' } as DataItem))); | ||
} | ||
|
||
async function processItem({ link: articleLink, date }) { | ||
return await cache.tryGet(`30secondsofcode:${articleLink}`, async () => { | ||
const finalLink = `${rootUrl}${articleLink}`; | ||
const response = await ofetch(finalLink); | ||
const $ = load(response); | ||
const tags = $.root() | ||
.find('body > main > nav > ol > li:not(:first-child):not(:last-child)') | ||
.toArray() | ||
.map((tag) => $(tag).find('a').text()); | ||
const article = $('main > article'); | ||
const title = article.find('h1').text(); | ||
article.find('img').each((_, element) => { | ||
const img = $(element); | ||
const src = img.attr('src'); | ||
if (src?.startsWith('/')) { | ||
img.attr('src', `${rootUrl}${src}`); | ||
} | ||
}); | ||
const image = article.find('img').attr('src'); | ||
const description = article.clone().find('h1, script').remove().end().html(); | ||
|
||
return { | ||
title, | ||
link: finalLink, | ||
pubDate: parseDate(date), | ||
description, | ||
author: '30 Seconds of Code', | ||
category: tags, | ||
image: `${rootUrl}${image}`, | ||
banner: `${rootUrl}${image}`, | ||
language: 'en-us', | ||
} as DataItem; | ||
}); | ||
} |