From 41a06a22bbab9f4c9941eacf29de5c254ff4a860 Mon Sep 17 00:00:00 2001 From: Outvi V <19144373+outloudvi@users.noreply.github.com> Date: Thu, 3 Feb 2022 00:09:01 +0800 Subject: [PATCH] feat(route): add dockerhub image new tag (#8965) * feat: /dockerhub/tags/:owner/:image fix #6916 * fix: update the doc link of /dockerhub/build * docs(en): /dockerhub/tag/:owner/:image * docs: fix typo * fix(dockerhub/tags): use parseDate() * docs: link docs to h2 instead of h3 * chore: move /dockerhub/build to v2 * docs: put warning inside * fix(dockerhub): use docker.com/hub as the radar path * fix(dockerhub/tag): add :limits? * feat(dockerhub): polish the GUID * fix(dockerhub/tag): stricter argument checks * fix(dockerhub/tag): handle NaN per Deepscan CI --- assets/radar-rules.js | 11 --------- docs/en/program-update.md | 16 ++++++++++++- docs/program-update.md | 16 ++++++++++++- lib/radar-rules.js | 11 --------- lib/router.js | 3 --- lib/{routes => v2}/dockerhub/build.js | 4 +++- lib/v2/dockerhub/maintainer.js | 4 ++++ lib/v2/dockerhub/radar.js | 19 +++++++++++++++ lib/v2/dockerhub/router.js | 4 ++++ lib/v2/dockerhub/tag.js | 33 +++++++++++++++++++++++++++ lib/v2/dockerhub/utils.js | 10 ++++++++ 11 files changed, 103 insertions(+), 28 deletions(-) rename lib/{routes => v2}/dockerhub/build.js (82%) create mode 100644 lib/v2/dockerhub/maintainer.js create mode 100644 lib/v2/dockerhub/radar.js create mode 100644 lib/v2/dockerhub/router.js create mode 100644 lib/v2/dockerhub/tag.js create mode 100644 lib/v2/dockerhub/utils.js 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 };