diff --git a/docs/en/program-update.md b/docs/en/program-update.md
index f86246dbc3..9325fd5e2b 100644
--- a/docs/en/program-update.md
+++ b/docs/en/program-update.md
@@ -96,6 +96,12 @@ For example: `https://www.curseforge.com/sc2/assets/taylor-mouses-stuff/files` t
+## Ditto clipboard manager
+
+### Changes
+
+
+
## Docker Hub
### Image New Build
diff --git a/docs/program-update.md b/docs/program-update.md
index 0562c219c8..6065614d5e 100644
--- a/docs/program-update.md
+++ b/docs/program-update.md
@@ -152,6 +152,12 @@ pageClass: routes
+## Ditto clipboard manager
+
+### Changes
+
+
+
## Docker Hub
### 镜像有新 Build
diff --git a/lib/router.js b/lib/router.js
index ae1c425816..262be7d908 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -3733,10 +3733,14 @@ router.get('/dayone/blog', require('./routes/dayone/blog'));
// 滴答清单
router.get('/dida365/habit/checkins', require('./routes/dida365/habit-checkins'));
+// Ditto clipboard manager
+router.get('/ditto/changes/:type?', require('./routes/ditto/changes'));
+
// iDaily 每日环球视野
router.get('/idaily/today', require('./routes/idaily/index'));
// 北屋
router.get('/northhouse/:category?', require('./routes/northhouse/index'));
+
module.exports = router;
diff --git a/lib/routes/ditto/changes.js b/lib/routes/ditto/changes.js
new file mode 100644
index 0000000000..4f33908f24
--- /dev/null
+++ b/lib/routes/ditto/changes.js
@@ -0,0 +1,36 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx) => {
+ const type = ctx.params.type || '';
+
+ const rootUrl = 'https://ditto-cp.sourceforge.io';
+ const currentUrl = `${rootUrl}/${type === '' ? 'changeHistory.php' : `${type}/changes.php`}`;
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(type === '' ? response.data : `
${response.data.split('\r\n').join('
')}
`);
+
+ const items = $('.post')
+ .map((_, item) => {
+ item = $(item);
+
+ const title = type === '' ? item.find('.title').text() : item.text();
+
+ return {
+ title,
+ link: currentUrl,
+ pubDate: new Date(title.split(' ')[type === '' ? 1 : 0]).toUTCString(),
+ description: type === '' ? item.find('.entry').html() : `${item.text()}
`,
+ };
+ })
+ .get();
+
+ ctx.state.data = {
+ title: `Ditto clipboard manager ${type === '' ? '' : `(${type}) `}changes`,
+ link: currentUrl,
+ item: items,
+ };
+};