diff --git a/docs/en/travel.md b/docs/en/travel.md
index c052ced98b54c5..5b198a85e1dd78 100644
--- a/docs/en/travel.md
+++ b/docs/en/travel.md
@@ -20,6 +20,14 @@ If the city name contains a space like `Mexico City`, replace the space with `%2
+## Brooklyn Museum
+
+
+
## Hopper
### Flight Deals
@@ -31,3 +39,27 @@ This route returns a list of flight deals (in most cases, 6 flight deals) for a
For airport IATA code please refer to [Wikipedia List of airports by IATA code](https://en.wikipedia.org/wiki/List_of_airports_by_IATA_code:_A)
+
+## Museum of Contemporary Art Chicago
+
+
+
+## New Museum
+
+
+
+## Solomon R. Guggenheim Museum
+
+
+
+## The Jewish Museum
+
+
+
+## The Metropolitan Museum of Art
+
+
diff --git a/docs/travel.md b/docs/travel.md
index 5753924d7fd3c5..b362e8d2d7d7b0 100644
--- a/docs/travel.md
+++ b/docs/travel.md
@@ -114,6 +114,38 @@ IATA 国际航空运输协会机场代码,参见[维基百科 国际航空运
+## 纽约布鲁克林博物馆
+
+
+
+## 纽约大都会美术馆
+
+
+
+## 纽约古根海姆基金会
+
+
+
+## 纽约新美术馆
+
+
+
+## 纽约犹太人博物馆
+
+
+
+## 芝加哥当代艺术博物馆
+
+
+
## 中国美术馆
### 美术馆新闻
diff --git a/lib/v2/brooklynmuseum/exhibitions.js b/lib/v2/brooklynmuseum/exhibitions.js
new file mode 100644
index 00000000000000..2dfa5a9fd15dac
--- /dev/null
+++ b/lib/v2/brooklynmuseum/exhibitions.js
@@ -0,0 +1,27 @@
+const buildData = require('@/utils/common-config');
+
+module.exports = async (ctx) => {
+ let link;
+ const state = ctx.params.state;
+
+ switch (state) {
+ case undefined:
+ case 'current':
+ link = 'https://www.brooklynmuseum.org/exhibitions/';
+ break;
+ default:
+ link = `https://www.brooklynmuseum.org/exhibitions/${state}`;
+ }
+
+ ctx.state.data = await buildData({
+ link,
+ url: link,
+ title: 'Brooklyn Museum - Exhibitions',
+ item: {
+ item: '.exhibitions .image-card',
+ title: `$('h2 > a, h3 > a').text()`,
+ link: `$('h2 > a, h3 > a').attr('href')`,
+ description: `$('h6').text()`,
+ },
+ });
+};
diff --git a/lib/v2/brooklynmuseum/maintainer.js b/lib/v2/brooklynmuseum/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/brooklynmuseum/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/brooklynmuseum/radar.js b/lib/v2/brooklynmuseum/radar.js
new file mode 100644
index 00000000000000..7a518af6b297e9
--- /dev/null
+++ b/lib/v2/brooklynmuseum/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'brooklynmuseum.org': {
+ _name: 'Brooklyn Museum',
+ www: [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#brooklyn-museum',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/brooklynmuseum/router.js b/lib/v2/brooklynmuseum/router.js
new file mode 100644
index 00000000000000..3b6bc4063e9c62
--- /dev/null
+++ b/lib/v2/brooklynmuseum/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions/:state?', require('./exhibitions'));
+};
diff --git a/lib/v2/guggenheim/exhibitions.js b/lib/v2/guggenheim/exhibitions.js
new file mode 100644
index 00000000000000..150152604d8e80
--- /dev/null
+++ b/lib/v2/guggenheim/exhibitions.js
@@ -0,0 +1,29 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx) => {
+ const link = 'https://www.guggenheim.org/exhibitions';
+
+ const response = await got({
+ url: link,
+ method: 'GET',
+ });
+
+ const code = cheerio.load(response.data)('#app-js-extra').html();
+ const data = JSON.parse(code.match(/var bootstrap = ([^\n]*);/)[1]);
+ const exhibitions = data.initial.main.posts.featuredExhibitions;
+ const items = [].concat(exhibitions.past.items ?? [], exhibitions.on_view.items ?? [], exhibitions.upcoming.items ?? []);
+
+ ctx.state.data = {
+ link,
+ url: link,
+ title: 'The Guggenheim Museums and Foundation - Exhibitions',
+ item: items.map((ex) => ({
+ title: ex.title,
+ link: `https://www.guggenheim.org/exhibition/${ex.slug}`,
+ description: ex.excerpt,
+ pubDate: ex.dates ? parseDate(`${ex.dates.start.month} ${ex.dates.start.day}, ${ex.dates.start.year}`, 'MMMM D, YYYY') : null,
+ })),
+ };
+};
diff --git a/lib/v2/guggenheim/maintainer.js b/lib/v2/guggenheim/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/guggenheim/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/guggenheim/radar.js b/lib/v2/guggenheim/radar.js
new file mode 100644
index 00000000000000..7d69aedeba0f67
--- /dev/null
+++ b/lib/v2/guggenheim/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'guggenheim.org': {
+ _name: 'Solomon R. Guggenheim Museum',
+ www: [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#solomon-r-guggenheim-museum',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/guggenheim/router.js b/lib/v2/guggenheim/router.js
new file mode 100644
index 00000000000000..d98b7c8845a250
--- /dev/null
+++ b/lib/v2/guggenheim/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions', require('./exhibitions'));
+};
diff --git a/lib/v2/jewishmuseum/exhibitions.js b/lib/v2/jewishmuseum/exhibitions.js
new file mode 100644
index 00000000000000..ae5bc01cc4ee81
--- /dev/null
+++ b/lib/v2/jewishmuseum/exhibitions.js
@@ -0,0 +1,16 @@
+const buildData = require('@/utils/common-config');
+
+module.exports = async (ctx) => {
+ const link = 'https://thejewishmuseum.org/exhibitions';
+
+ ctx.state.data = await buildData({
+ link,
+ url: link,
+ title: 'Jewish Museums - Exhibitions',
+ item: {
+ item: '#current article.exhibition, #upcoming article, #past article.exhibition',
+ title: `$('article.exhibition h3').text()`,
+ link: `$('article.exhibition > a').attr('href')`,
+ },
+ });
+};
diff --git a/lib/v2/jewishmuseum/maintainer.js b/lib/v2/jewishmuseum/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/jewishmuseum/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/jewishmuseum/radar.js b/lib/v2/jewishmuseum/radar.js
new file mode 100644
index 00000000000000..223b1a7af374f1
--- /dev/null
+++ b/lib/v2/jewishmuseum/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'thejewishmuseum.org': {
+ _name: 'Jewish Museum',
+ '.': [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#the-jewish-museum',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/jewishmuseum/router.js b/lib/v2/jewishmuseum/router.js
new file mode 100644
index 00000000000000..d98b7c8845a250
--- /dev/null
+++ b/lib/v2/jewishmuseum/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions', require('./exhibitions'));
+};
diff --git a/lib/v2/mcachicago/exhibitions.js b/lib/v2/mcachicago/exhibitions.js
new file mode 100644
index 00000000000000..9fe1e4b41ea71b
--- /dev/null
+++ b/lib/v2/mcachicago/exhibitions.js
@@ -0,0 +1,17 @@
+const buildData = require('@/utils/common-config');
+
+module.exports = async (ctx) => {
+ const link = 'https://mcachicago.org/exhibitions';
+
+ ctx.state.data = await buildData({
+ link,
+ url: link,
+ title: 'MCA Chicago - Exhibitions',
+ item: {
+ item: '#exhibitions .card',
+ title: `$('.title').text()`,
+ link: `$('a').attr('href')`,
+ // description: `$('a').html()`,
+ },
+ });
+};
diff --git a/lib/v2/mcachicago/maintainer.js b/lib/v2/mcachicago/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/mcachicago/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/mcachicago/radar.js b/lib/v2/mcachicago/radar.js
new file mode 100644
index 00000000000000..8d24a4852f5e2e
--- /dev/null
+++ b/lib/v2/mcachicago/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'mcachicago.org': {
+ _name: 'MCA Chicago',
+ '.': [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#museum-of-contemporary-art-chicago',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/mcachicago/router.js b/lib/v2/mcachicago/router.js
new file mode 100644
index 00000000000000..d98b7c8845a250
--- /dev/null
+++ b/lib/v2/mcachicago/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions', require('./exhibitions'));
+};
diff --git a/lib/v2/metmuseum/exhibitions.js b/lib/v2/metmuseum/exhibitions.js
new file mode 100644
index 00000000000000..6297491490a0f5
--- /dev/null
+++ b/lib/v2/metmuseum/exhibitions.js
@@ -0,0 +1,31 @@
+const got = require('@/utils/got');
+const { parseDate } = require('@/utils/parse-date');
+
+function generateExhibitionItem(result) {
+ return {
+ title: result.title,
+ link: `https://www.metmuseum.org${result.url}`,
+ description: result.description,
+ pubDate: parseDate(result.startDate),
+ guid: result.id,
+ };
+}
+
+module.exports = async (ctx) => {
+ const searchType = ctx.params.state ?? 'current';
+
+ const url = `https://www.metmuseum.org/ghidorah/ExhibitionListing/Search?searchType=${searchType}`;
+
+ const response = await got({
+ url,
+ method: 'GET',
+ });
+
+ const data = response.data.data;
+
+ ctx.state.data = {
+ title: 'The Metropolitan Museum of Art - Exhibitions',
+ link: 'https://www.metmuseum.org/exhibitions',
+ item: data.results.map(generateExhibitionItem),
+ };
+};
diff --git a/lib/v2/metmuseum/maintainer.js b/lib/v2/metmuseum/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/metmuseum/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/metmuseum/radar.js b/lib/v2/metmuseum/radar.js
new file mode 100644
index 00000000000000..c7154582d81ab3
--- /dev/null
+++ b/lib/v2/metmuseum/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'metmuseum.org': {
+ _name: 'The Metropolitan Museum of Art',
+ www: [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#the-metropolitan-museum-of-art',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/metmuseum/router.js b/lib/v2/metmuseum/router.js
new file mode 100644
index 00000000000000..3b6bc4063e9c62
--- /dev/null
+++ b/lib/v2/metmuseum/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions/:state?', require('./exhibitions'));
+};
diff --git a/lib/v2/newmuseum/exhibitions.js b/lib/v2/newmuseum/exhibitions.js
new file mode 100644
index 00000000000000..7798526cc883c0
--- /dev/null
+++ b/lib/v2/newmuseum/exhibitions.js
@@ -0,0 +1,27 @@
+const buildData = require('@/utils/common-config');
+
+module.exports = async (ctx) => {
+ let link;
+ const state = ctx.query.state;
+
+ switch (state) {
+ case undefined:
+ case 'current':
+ link = 'https://www.newmuseum.org/exhibitions/';
+ break;
+ default:
+ link = `https://www.newmuseum.org/exhibitions/${state}`;
+ }
+
+ ctx.state.data = await buildData({
+ link,
+ url: link,
+ title: 'New Museum - Exhibitions',
+ item: {
+ item: '.exh',
+ title: `$('.exh .title').text()`,
+ link: `$('.exh > a').attr('href')`,
+ description: `$('.exh .body-reveal').text()`,
+ },
+ });
+};
diff --git a/lib/v2/newmuseum/maintainer.js b/lib/v2/newmuseum/maintainer.js
new file mode 100644
index 00000000000000..2b582f7fce773b
--- /dev/null
+++ b/lib/v2/newmuseum/maintainer.js
@@ -0,0 +1,3 @@
+module.exports = {
+ '/exhibitions': ['chazeon'],
+};
diff --git a/lib/v2/newmuseum/radar.js b/lib/v2/newmuseum/radar.js
new file mode 100644
index 00000000000000..483b923139b570
--- /dev/null
+++ b/lib/v2/newmuseum/radar.js
@@ -0,0 +1,11 @@
+module.exports = {
+ 'newmuseum.org': {
+ _name: 'New Museum',
+ www: [
+ {
+ title: 'Exhibitions',
+ docs: 'https://docs.rsshub.app/en/travel.html#new-museum',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/newmuseum/router.js b/lib/v2/newmuseum/router.js
new file mode 100644
index 00000000000000..d98b7c8845a250
--- /dev/null
+++ b/lib/v2/newmuseum/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/exhibitions', require('./exhibitions'));
+};