diff --git a/assets/radar-rules.js b/assets/radar-rules.js
index 01f701b6f1..4733c75678 100644
--- a/assets/radar-rules.js
+++ b/assets/radar-rules.js
@@ -312,17 +312,6 @@
},
'wineyun.com': { _name: '酒云网', www: [{ title: '最新商品', docs: 'https://docs.rsshub.app/other.html#jiu-yun-wang', source: ['/:category'], target: '/wineyun/:category' }] },
'epicgames.com': { _name: 'Epic Games', www: [{ title: '每周免费游戏', docs: 'https://docs.rsshub.app/game.html#epicgames-freegame', source: '/store/zh-CN/free-games', target: '/epicgames/freegames' }] },
- 'docker.com': {
- _name: 'Docker',
- hub: [
- {
- title: '镜像有新 Build',
- docs: 'https://docs.rsshub.app/program-update.html#docker-hub',
- source: ['/r/:owner/:image', '/r/:owner/:image/tags', '/_/:image'],
- target: (params) => `/dockerhub/build/${params.owner ? params.owner : 'library'}/${params.image}`,
- },
- ],
- },
'nga.cn': {
_name: 'NGA',
bbs: [
diff --git a/docs/en/program-update.md b/docs/en/program-update.md
index dd0a673164..e174eaa5bf 100644
--- a/docs/en/program-update.md
+++ b/docs/en/program-update.md
@@ -112,7 +112,7 @@ For example: `https://www.curseforge.com/sc2/assets/taylor-mouses-stuff/files` t
### Image New Build
-
+
::: warning
@@ -120,6 +120,20 @@ The owner of the official image fills in the library, for example: https://rsshu
:::
+
+
+### Image New Tag
+
+
+
+::: warning
+
+Use `library` as the `owner` for official images, such as
+
+:::
+
+
+
## Eagle
### Changelog
diff --git a/docs/program-update.md b/docs/program-update.md
index f94a79b0d6..eac0cd60cd 100644
--- a/docs/program-update.md
+++ b/docs/program-update.md
@@ -150,7 +150,7 @@ pageClass: routes
### 镜像有新 Build
-
+
::: warning 注意
@@ -158,6 +158,20 @@ pageClass: routes
:::
+
+
+### 镜像有新 Tag
+
+
+
+::: warning 注意
+
+官方镜像的 owner 填写 library, 如:
+
+:::
+
+
+
## Eagle
### 更新日志
diff --git a/lib/radar-rules.js b/lib/radar-rules.js
index 172a99f586..d139a277f4 100644
--- a/lib/radar-rules.js
+++ b/lib/radar-rules.js
@@ -786,17 +786,6 @@ module.exports = {
},
],
},
- 'docker.com': {
- _name: 'Docker',
- hub: [
- {
- title: '镜像有新 Build',
- docs: 'https://docs.rsshub.app/program-update.html#docker-hub',
- source: ['/r/:owner/:image', '/r/:owner/:image/tags', '/_/:image'],
- target: (params) => `/dockerhub/build/${params.owner ? params.owner : 'library'}/${params.image}`,
- },
- ],
- },
'nga.cn': {
_name: 'NGA',
bbs: [
diff --git a/lib/router.js b/lib/router.js
index 53f3d821dc..0da6266b4c 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1376,9 +1376,6 @@ router.get('/meipai/user/:uid', lazyloadRouteHandler('./routes/meipai/user'));
// 多知网
router.get('/duozhi', lazyloadRouteHandler('./routes/duozhi'));
-// Docker Hub
-router.get('/dockerhub/build/:owner/:image/:tag?', lazyloadRouteHandler('./routes/dockerhub/build'));
-
// 人人都是产品经理
router.get('/woshipm/popular', lazyloadRouteHandler('./routes/woshipm/popular'));
router.get('/woshipm/wen', lazyloadRouteHandler('./routes/woshipm/wen'));
diff --git a/lib/routes/dockerhub/build.js b/lib/v2/dockerhub/build.js
similarity index 82%
rename from lib/routes/dockerhub/build.js
rename to lib/v2/dockerhub/build.js
index da6897369b..7f9611fdbd 100644
--- a/lib/routes/dockerhub/build.js
+++ b/lib/v2/dockerhub/build.js
@@ -1,4 +1,5 @@
const got = require('@/utils/got');
+const { hash } = require('./utils');
module.exports = async (ctx) => {
const { owner, image, tag = 'latest' } = ctx.params;
@@ -22,7 +23,8 @@ module.exports = async (ctx) => {
link: `https://hub.docker.com/layers/docker/${namespace}/${tag}/images/${item.images[0].digest.replace(':', '-')}`,
author: owner,
pubDate: new Date(item.last_updated).toUTCString(),
- guid: item.last_updated,
+ // only check for different images hashes (considering varients of all arches), since the tag name is already fixed
+ guid: hash(item.images),
},
],
};
diff --git a/lib/v2/dockerhub/maintainer.js b/lib/v2/dockerhub/maintainer.js
new file mode 100644
index 0000000000..67edecf56d
--- /dev/null
+++ b/lib/v2/dockerhub/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/build/:owner/:image/:tag?': ['HenryQW'],
+ '/tag/:owner/:image': ['outloudvi'],
+};
diff --git a/lib/v2/dockerhub/radar.js b/lib/v2/dockerhub/radar.js
new file mode 100644
index 0000000000..f2a9a1587a
--- /dev/null
+++ b/lib/v2/dockerhub/radar.js
@@ -0,0 +1,19 @@
+module.exports = {
+ 'docker.com': {
+ _name: 'Docker Hub',
+ hub: [
+ {
+ title: '镜像有新 Build',
+ docs: 'https://docs.rsshub.app/program-update.html#docker-hub',
+ source: ['/r/:owner/:image', '/r/:owner/:image/tags', '/_/:image'],
+ target: (params) => `/dockerhub/build/${params.owner ? params.owner : 'library'}/${params.image}`,
+ },
+ {
+ title: '镜像有新 Tag',
+ docs: 'https://docs.rsshub.app/program-update.html#docker-hub',
+ source: ['/r/:owner/:image', '/r/:owner/:image/tags', '/_/:image'],
+ target: (params) => `/dockerhub/tag/${params.owner ? params.owner : 'library'}/${params.image}`,
+ },
+ ],
+ },
+};
diff --git a/lib/v2/dockerhub/router.js b/lib/v2/dockerhub/router.js
new file mode 100644
index 0000000000..ff340b7451
--- /dev/null
+++ b/lib/v2/dockerhub/router.js
@@ -0,0 +1,4 @@
+module.exports = function (router) {
+ router.get('/build/:owner/:image/:tag?', require('./build'));
+ router.get('/tag/:owner/:image/:limits?', require('./tag'));
+};
diff --git a/lib/v2/dockerhub/tag.js b/lib/v2/dockerhub/tag.js
new file mode 100644
index 0000000000..a59fe53a2b
--- /dev/null
+++ b/lib/v2/dockerhub/tag.js
@@ -0,0 +1,33 @@
+const got = require('@/utils/got');
+const { parseDate } = require('@/utils/parse-date');
+const { hash } = require('./utils');
+
+module.exports = async (ctx) => {
+ const { owner, image, limits } = ctx.params;
+
+ const namespace = `${owner}/${image}`;
+ const link = `https://hub.docker.com/r/${namespace}`;
+
+ const pageSize = !isNaN(parseInt(limits)) ? parseInt(limits) : 10;
+
+ const data = await got.get(`https://hub.docker.com/v2/repositories/${namespace}/tags/?page_size=${pageSize}`);
+ const metadata = await got.get(`https://hub.docker.com/v2/repositories/${namespace}/`);
+
+ const tags = data.data.results;
+
+ ctx.state.data = {
+ title: `${namespace} tags`,
+ description: metadata.data.description,
+ link,
+ language: 'en',
+ item: tags.map((item) => ({
+ title: `${namespace}:${item.name} was updated`,
+ description: `${namespace}:${item.name} was updated, supporting the architectures of ${item.images.map((img) => `${img.os}/${img.architecture}`).join(', ')}`,
+ link: `https://hub.docker.com/layers/${owner === 'library' ? `${image}/` : ''}${namespace}/${item.name}/images/${item.images[0].digest.replace(':', '-')}`,
+ author: owner,
+ pubDate: parseDate(item.tag_last_pushed),
+ // check for (1) different tag names and (2) different image hashes, considering varients of all arches
+ guid: `${namespace}:${item.name}@${hash(item.images)}`,
+ })),
+ };
+};
diff --git a/lib/v2/dockerhub/utils.js b/lib/v2/dockerhub/utils.js
new file mode 100644
index 0000000000..e6ad13b55a
--- /dev/null
+++ b/lib/v2/dockerhub/utils.js
@@ -0,0 +1,10 @@
+const md5 = require('@/utils/md5');
+
+function hash(images) {
+ const entries = Object.entries(images)
+ .map((x) => [`${x.os}/${x.architecture}`, x.digest])
+ .sort((a, b) => a[0] - b[0]);
+ return md5(entries.map((x) => x.join(',')).join('|'));
+}
+
+module.exports = { hash };