diff --git a/docs/bbs.md b/docs/bbs.md
index 05fc4fb2865616..003f265bd8fb45 100644
--- a/docs/bbs.md
+++ b/docs/bbs.md
@@ -218,16 +218,6 @@ pageClass: routes
-## Quicker
-
-### 讨论区
-
-
-
-### 用户动作更新
-
-
-
## RF 技术社区
### 文章
diff --git a/docs/program-update.md b/docs/program-update.md
index 3423f36b2e1bab..b3ce8e2b337884 100644
--- a/docs/program-update.md
+++ b/docs/program-update.md
@@ -382,7 +382,7 @@ pageClass: routes
### 版本更新
-
+
## RescueTime
diff --git a/docs/programming.md b/docs/programming.md
index 8f0cb9097a5be0..36de6faaeff0dc 100644
--- a/docs/programming.md
+++ b/docs/programming.md
@@ -503,6 +503,58 @@ GitHub 官方也提供了一些 RSS:
+## Quicker
+
+### 动作分享
+
+
+
+| 动作库最新更新 | 动作库最多赞 | 动作库新动作 | 动作库最近赞 |
+| ------- | ----------- | ---------- | ----------- |
+| Recent | Recommended | NewActions | RecentLiked |
+
+| 子程序 | 扩展热键 | 文本指令 |
+| ----------- | --------- | ------------ |
+| SubPrograms | PowerKeys | TextCommands |
+
+
+
+### 讨论区
+
+
+
+分类
+
+| 使用问题 | 动作开发 | BUG 反馈 | 功能建议 |
+| ---- | ---- | ------ | ---- |
+| 1 | 9 | 3 | 4 |
+
+| 动作需求 | 经验创意 | 动作推荐 | 信息发布 |
+| ---- | ---- | ---- | ---- |
+| 6 | 2 | 7 | 5 |
+
+| 随便聊聊 | 异常报告 | 全部 |
+| ---- | ---- | --- |
+| 8 | 10 | all |
+
+状态
+
+| 全部 | 精华 | 已归档 |
+| -- | ------ | ------- |
+| | digest | achived |
+
+
+
+### 用户更新
+
+
+
+| 动作 | 子程序 | 动作单 |
+| ------- | ----------- | ----------- |
+| Actions | SubPrograms | ActionLists |
+
+
+
## react
### react-native
diff --git a/lib/router.js b/lib/router.js
index d66ab24a5055ff..ae3caefb7bd754 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -25,10 +25,10 @@ const lazyloadRouteHandler = (routeHandlerPath) => (ctx) => {
router.get('/1draw', lazyloadRouteHandler('./routes/1draw/index'));
// quicker
-router.get('/quicker/qa', lazyloadRouteHandler('./routes/quicker/qa.js'));
-router.get('/quicker/update', lazyloadRouteHandler('./routes/quicker/update.js'));
-router.get('/quicker/user/action/:uid/:person', lazyloadRouteHandler('./routes/quicker/person.js'));
-router.get('/quicker/user/:uid/:person', lazyloadRouteHandler('./routes/quicker/person.js'));
+// router.get('/quicker/qa', lazyloadRouteHandler('./routes/quicker/qa.js'));
+// router.get('/quicker/update', lazyloadRouteHandler('./routes/quicker/update.js'));
+// router.get('/quicker/user/action/:uid/:person', lazyloadRouteHandler('./routes/quicker/person.js'));
+// router.get('/quicker/user/:uid/:person', lazyloadRouteHandler('./routes/quicker/person.js'));
// Benedict Evans
router.get('/benedictevans', lazyloadRouteHandler('./routes/benedictevans/recent.js'));
diff --git a/lib/routes/quicker/person.js b/lib/routes/quicker/person.js
deleted file mode 100644
index 03ce82096a5fa9..00000000000000
--- a/lib/routes/quicker/person.js
+++ /dev/null
@@ -1,32 +0,0 @@
-const cheerio = require('cheerio');
-const got = require('@/utils/got');
-
-module.exports = async (ctx) => {
- const person = ctx.params.person;
- const uid = ctx.params.uid;
- const response = await got({
- method: 'get',
- url: `https://getquicker.net/User/${uid}/${person}`,
- });
- const data = response.data;
- const $ = cheerio.load(data);
- const list = $('.align-middle:nth-child(2) a:nth-child(1)');
-
- const out = list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.text(),
- description: item.next().text(),
- guid: item.text(),
- link: item.attr('href'),
- };
- })
- .get();
-
- ctx.state.data = {
- title: '用户动作 - Quicker',
- link: 'https://getquicker.net/Help/Versions',
- item: out,
- };
-};
diff --git a/lib/routes/quicker/qa.js b/lib/routes/quicker/qa.js
deleted file mode 100644
index 183f902d6dde04..00000000000000
--- a/lib/routes/quicker/qa.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const cheerio = require('cheerio');
-const got = require('@/utils/got');
-
-module.exports = async (ctx) => {
- const response = await got({
- method: 'get',
- url: 'https://getquicker.net/QA',
- });
- const data = response.data;
- const $ = cheerio.load(data);
- const list = $('div.question-title > a');
-
- const out = await Promise.all(
- list
- .map(async (index, item) => {
- item = $(item);
- const response_item = await got({
- method: 'get',
- url: 'https://getquicker.net' + item.attr('href'),
- });
- const a = cheerio.load(response_item.data);
- return Promise.resolve({
- title: item.text(),
- description: `作者:${a('.user-link').first().text()}
描述:${a('.user-content').first().html()}`,
- pubDate:
- a('.user-content span')
- .last()
- .text()
- .match(/最后更新于\s*\S+/) || '1900/1/1',
- link: item.attr('href'),
- });
- })
- .get()
- );
-
- ctx.state.data = {
- title: '讨论区 - Quicker',
- link: 'https://getquicker.net/QA',
- item: out,
- };
-};
diff --git a/lib/routes/quicker/update.js b/lib/routes/quicker/update.js
deleted file mode 100644
index e47b382e69a7f5..00000000000000
--- a/lib/routes/quicker/update.js
+++ /dev/null
@@ -1,30 +0,0 @@
-const cheerio = require('cheerio');
-const got = require('@/utils/got');
-
-module.exports = async (ctx) => {
- const response = await got({
- method: 'get',
- url: 'https://getquicker.net/Help/Versions',
- });
- const data = response.data;
- const $ = cheerio.load(data);
- const list = $('div.version-list > div');
-
- const out = list
- .map((index, item) => {
- item = $(item);
- return {
- title: item.find('h2 > a').text(),
- description: item.find('div.article-content').html(),
- pubDate: item.find('div > span.text-secondary.d-lg-block.mb-2').text() || '1900/1/1',
- link: item.find('h2 > a').attr('href'),
- };
- })
- .get();
-
- ctx.state.data = {
- title: '版本更新 - Quicker',
- link: 'https://getquicker.net/Help/Versions',
- item: out,
- };
-};
diff --git a/lib/v2/quicker/maintainer.js b/lib/v2/quicker/maintainer.js
new file mode 100644
index 00000000000000..d5e7b8dd533d36
--- /dev/null
+++ b/lib/v2/quicker/maintainer.js
@@ -0,0 +1,7 @@
+module.exports = {
+ '/qa/:category?/:state?': ['Cesaryuan', 'nczitzk'],
+ '/share/:category?': ['nczitzk'],
+ '/update': ['Cesaryuan', 'nczitzk'],
+ '/user/:category/:id': ['Cesaryuan', 'nczitzk'],
+ '/versions': ['Cesaryuan', 'nczitzk'],
+};
diff --git a/lib/v2/quicker/qa.js b/lib/v2/quicker/qa.js
new file mode 100644
index 00000000000000..1fd2037920a8fb
--- /dev/null
+++ b/lib/v2/quicker/qa.js
@@ -0,0 +1,65 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const timezone = require('@/utils/timezone');
+const { parseDate, parseRelativeDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category ?? 'all';
+ const state = ctx.params.state ?? '';
+
+ const rootUrl = 'https://getquicker.net';
+ const currentUrl = `${rootUrl}/QA${category !== 'all' ? `?category=${category}` : ''}${state ? `?state=${state}` : ''}`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('a.question-title')
+ .slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 25)
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ return {
+ title: item.text(),
+ link: `${rootUrl}${item.attr('href')}`,
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+
+ const content = cheerio.load(detailResponse.data);
+
+ content('div[data-note="最后更新人信息"]').remove();
+
+ const pubDate = content('.info-text')
+ .first()
+ .text()
+ .replace(/创建于 /, '')
+ .trim();
+
+ item.description = content('.topic-body').html();
+ item.author = content('.user-link').first().text();
+ item.pubDate = timezone(/-/.test(pubDate) ? parseDate(pubDate) : parseRelativeDate(pubDate), +8);
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ allowEmpty: true,
+ };
+};
diff --git a/lib/v2/quicker/radar.js b/lib/v2/quicker/radar.js
new file mode 100644
index 00000000000000..6333917e396d34
--- /dev/null
+++ b/lib/v2/quicker/radar.js
@@ -0,0 +1,31 @@
+module.exports = {
+ 'getquicker.net': {
+ _name: 'Quicker',
+ '.': [
+ {
+ title: '动作分享',
+ docs: 'https://docs.rsshub.app/programming.html#quicker-dong-zuo-fen-xiang',
+ source: ['/Share/:category', '/'],
+ target: '/quicker/share/:category?',
+ },
+ {
+ title: '讨论区',
+ docs: 'https://docs.rsshub.app/programming.html#quicker-tao-lun-qu',
+ source: ['/QA', '/'],
+ target: (params, url) => `/quicker/qa/${new URL(url).searchParams.get('category') ?? ''}/${new URL(url).searchParams.get('state') ?? ''}`,
+ },
+ {
+ title: '用户动作更新',
+ docs: 'https://docs.rsshub.app/programming.html#quicker-yong-hu-dong-zuo-geng-xin',
+ source: ['/QA', '/'],
+ target: (params, url) => `/quicker/qa/${new URL(url).searchParams.get('category') ?? ''}/${new URL(url).searchParams.get('state') ?? ''}`,
+ },
+ {
+ title: '版本更新',
+ docs: 'https://docs.rsshub.app/programming.html#quicker-ban-ben-geng-xin',
+ source: ['/Help/Versions', '/'],
+ target: '/quicker/versions',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/quicker/router.js b/lib/v2/quicker/router.js
new file mode 100644
index 00000000000000..6415b5e41cca66
--- /dev/null
+++ b/lib/v2/quicker/router.js
@@ -0,0 +1,7 @@
+module.exports = function (router) {
+ router.get('/qa/:category?/:state?', require('./qa'));
+ router.get('/share/:category?', require('./share'));
+ router.get('/update', require('./versions'));
+ router.get('/user/:category/:id', require('./user'));
+ router.get('/versions', require('./versions'));
+};
diff --git a/lib/v2/quicker/share.js b/lib/v2/quicker/share.js
new file mode 100644
index 00000000000000..d17cb5c320cbce
--- /dev/null
+++ b/lib/v2/quicker/share.js
@@ -0,0 +1,61 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const timezone = require('@/utils/timezone');
+const { parseDate, parseRelativeDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category ?? 'Recent';
+
+ const rootUrl = 'https://getquicker.net';
+ const currentUrl = `${rootUrl}/Share/${category}`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('table tbody tr')
+ .slice(1, ctx.query.limit ? parseInt(ctx.query.limit) : 25)
+ .toArray()
+ .map((item) => {
+ item = $(item).find('td a').first();
+
+ return {
+ title: item.text(),
+ link: `${rootUrl}${item.attr('href')}`,
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+
+ const content = cheerio.load(detailResponse.data);
+
+ content('section').last().remove();
+ content('#app').children().slice(0, 2).remove();
+
+ const pubDate = content('.text-secondary a').not('.text-secondary').first().text()?.trim().replace(/\s*/g, '') || content('div.note-text').find('span').eq(3).text();
+
+ item.author = content('.user-link').first().text();
+ item.description = content('div[data-info="动作信息"]').html() ?? content('#app').html() ?? content('.row').eq(1).html();
+ item.pubDate = timezone(/-/.test(pubDate) ? parseDate(pubDate) : parseRelativeDate(pubDate), +8);
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ allowEmpty: true,
+ };
+};
diff --git a/lib/v2/quicker/user.js b/lib/v2/quicker/user.js
new file mode 100644
index 00000000000000..cdd64c19f90dd6
--- /dev/null
+++ b/lib/v2/quicker/user.js
@@ -0,0 +1,62 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const timezone = require('@/utils/timezone');
+const { parseDate, parseRelativeDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category;
+ const id = ctx.params.id;
+
+ const rootUrl = 'https://getquicker.net';
+ const currentUrl = `${rootUrl}/User/${category}/${id}`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('table tbody tr')
+ .slice(1, ctx.query.limit ? parseInt(ctx.query.limit) : 25)
+ .toArray()
+ .map((item) => {
+ item = $(item).find('td a').first();
+
+ return {
+ title: item.text(),
+ link: `${rootUrl}${item.attr('href')}`,
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+
+ const content = cheerio.load(detailResponse.data);
+
+ content('section').last().remove();
+ content('#app').children().slice(0, 2).remove();
+
+ const pubDate = content('.text-secondary a').not('.text-secondary').first().text()?.trim().replace(/\s*/g, '') || content('div.note-text').find('span').eq(3).text();
+
+ item.author = content('.user-link').first().text();
+ item.description = content('div[data-info="动作信息"]').html() ?? content('#app').html() ?? content('.row').eq(1).html();
+ item.pubDate = timezone(/-/.test(pubDate) ? parseDate(pubDate) : parseRelativeDate(pubDate), +8);
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ allowEmpty: true,
+ };
+};
diff --git a/lib/v2/quicker/versions.js b/lib/v2/quicker/versions.js
new file mode 100644
index 00000000000000..ece5f7a0e3ca3e
--- /dev/null
+++ b/lib/v2/quicker/versions.js
@@ -0,0 +1,36 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const rootUrl = 'https://getquicker.net';
+ const currentUrl = `${rootUrl}/Help/Versions`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ const items = $('.version')
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ const a = item.find('h2 a');
+
+ return {
+ title: a.text().trim(),
+ link: `${rootUrl}${a.attr('href')}`,
+ description: item.find('.article-content').html(),
+ pubDate: parseDate(item.find('.text-secondary').first().text()),
+ };
+ });
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ };
+};