feat(route): add alternativeto.net (#13320)
* feat(route): add alternativeto.net * Update website/docs/routes/programming.md * Update website/docs/routes/programming.md ---------
This commit is contained in:
parent
aba9c21290
commit
b9604caaef
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
'/software/:name/:routeParams?': ['JimenezLi'],
|
||||
'/platform/:name/:routeParams?': ['JimenezLi'],
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
const { baseURL, puppeteerGet } = require('./utils');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const name = ctx.params.name;
|
||||
const query = new URLSearchParams(ctx.params.routeParams);
|
||||
const link = `https://alternativeto.net/platform/${name}/?${query.toString()}`;
|
||||
|
||||
// use Puppeteer due to the obstacle by cloudflare challenge
|
||||
const html = await puppeteerGet(link, ctx.cache);
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
ctx.state.data = {
|
||||
title: $('.Heading_h1___Cf5Y').text().trim(),
|
||||
description: $('.intro-text').text().trim(),
|
||||
link,
|
||||
item: $('.AppListItem_appInfo__h9cWP')
|
||||
.toArray()
|
||||
.map((element) => {
|
||||
const item = $(element);
|
||||
const title = item.find('.Heading_h2___LwQD').text().trim();
|
||||
const link = `${baseURL}${item.find('.Heading_h2___LwQD a').attr('href')}`;
|
||||
const description = item.find('.AppListItem_description__wtODK').text().trim();
|
||||
|
||||
return {
|
||||
title,
|
||||
link,
|
||||
description,
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
module.exports = {
|
||||
'alternativeto.net': {
|
||||
_name: 'AlternativeTo',
|
||||
www: [
|
||||
{
|
||||
title: 'Software Alternatives',
|
||||
docs: 'https://docs.rsshub.app/routes/programming#alternativeto-software-alternatives',
|
||||
source: '/software/:name',
|
||||
target: '/software/:name',
|
||||
},
|
||||
{
|
||||
title: 'Platform Software',
|
||||
docs: 'https://docs.rsshub.app/routes/programming#alternativeto-platform-software',
|
||||
source: '/platform/:name',
|
||||
target: '/platform/:name',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = (router) => {
|
||||
router.get('/software/:name/:routeParams?', require('./software'));
|
||||
router.get('/platform/:name/:routeParams?', require('./platform'));
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
const { baseURL, puppeteerGet } = require('./utils');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const name = ctx.params.name;
|
||||
const query = new URLSearchParams(ctx.params.routeParams);
|
||||
const link = `https://alternativeto.net/software/${name}/?${query.toString()}`;
|
||||
|
||||
// use Puppeteer due to the obstacle by cloudflare challenge
|
||||
const html = await puppeteerGet(link, ctx.cache);
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
ctx.state.data = {
|
||||
title: $('.Heading_h1___Cf5Y').text().trim(),
|
||||
description: $('.intro-text').text().trim(),
|
||||
link,
|
||||
item: $('.AppListItem_appInfo__h9cWP')
|
||||
.toArray()
|
||||
.map((element) => {
|
||||
const item = $(element);
|
||||
const title = item.find('.Heading_h2___LwQD').text().trim();
|
||||
const link = `${baseURL}${item.find('.Heading_h2___LwQD a').attr('href')}`;
|
||||
const description = item.find('.AppListItem_description__wtODK').text().trim();
|
||||
|
||||
return {
|
||||
title,
|
||||
link,
|
||||
description,
|
||||
};
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
const baseURL = 'https://alternativeto.net';
|
||||
|
||||
const puppeteerGet = (url, cache) =>
|
||||
cache.tryGet(url, async () => {
|
||||
const browser = await require('@/utils/puppeteer')();
|
||||
const page = await browser.newPage();
|
||||
await page.setRequestInterception(true);
|
||||
page.on('request', (request) => {
|
||||
request.resourceType() === 'document' ? request.continue() : request.abort();
|
||||
});
|
||||
await page.goto(url, {
|
||||
waitUntil: 'domcontentloaded',
|
||||
});
|
||||
const html = await page.evaluate(() => document.documentElement.innerHTML);
|
||||
browser.close();
|
||||
return html;
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
baseURL,
|
||||
puppeteerGet,
|
||||
};
|
||||
|
|
@ -82,6 +82,24 @@ You have the option to utilize the main heading or use individual categories as
|
|||
|
||||
</Route>
|
||||
|
||||
## AlternativeTo {#alternativeto}
|
||||
|
||||
### Software Alternatives {#alternativeto-software-alternatives}
|
||||
|
||||
<Route author="JimenezLi" example="/alternativeto/software/cpp" path="/alternativeto/software/:name/:routeParams?" paramsDesc={['Software name', 'Filters of software type']} puppeteer="1" radar="1">
|
||||
|
||||
> routeParms can be copied from original site URL, example: `/alternativeto/software/cpp/license=opensource&platform=windows`
|
||||
|
||||
</Route>
|
||||
|
||||
### Platform Software {#alternativeto-platform-software}
|
||||
|
||||
<Route author="JimenezLi" example="/alternativeto/platform/firefox" path="/alternativeto/platform/:name/:routeParams?" paramsDesc={['Platform name', 'Filters of software type']} puppeteer="1" radar="1">
|
||||
|
||||
> routeParms can be copied from original site URL, example: `/alternativeto/platform/firefox/license=free`
|
||||
|
||||
</Route>
|
||||
|
||||
## AtCoder {#atcoder}
|
||||
|
||||
### Present Contests {#atcoder-present-contests}
|
||||
|
|
|
|||
Loading…
Reference in New Issue