diff --git a/docs/en/multimedia.md b/docs/en/multimedia.md
index 6d94e5074..cb2a7b083 100644
--- a/docs/en/multimedia.md
+++ b/docs/en/multimedia.md
@@ -30,6 +30,16 @@ Full transcript support for better user experience.
+## Coomer
+
+### Artist
+
+
+
+### Recent Posts
+
+
+
## EZTV
::: tip
diff --git a/docs/multimedia.md b/docs/multimedia.md
index 68f879d4b..e5a8ee2a9 100644
--- a/docs/multimedia.md
+++ b/docs/multimedia.md
@@ -303,6 +303,16 @@ BT 之家的域名会变更,本路由以 为默认
+## Coomer
+
+### Artist
+
+
+
+### Recent Posts
+
+
+
## E-Hentai
### 分类
diff --git a/lib/v2/coomer/artist.js b/lib/v2/coomer/artist.js
new file mode 100644
index 000000000..9000e4c27
--- /dev/null
+++ b/lib/v2/coomer/artist.js
@@ -0,0 +1,9 @@
+const fetchItems = require('./utils');
+
+module.exports = async (ctx) => {
+ const id = ctx.params.id;
+
+ const currentUrl = `onlyfans/user/${id}`;
+
+ ctx.state.data = await fetchItems(ctx, currentUrl);
+};
diff --git a/lib/v2/coomer/maintainer.js b/lib/v2/coomer/maintainer.js
new file mode 100644
index 000000000..2e27c59ca
--- /dev/null
+++ b/lib/v2/coomer/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/artist/:id': ['nczitzk'],
+ '/posts': ['nczitzk'],
+};
diff --git a/lib/v2/coomer/posts.js b/lib/v2/coomer/posts.js
new file mode 100644
index 000000000..26d56a0d2
--- /dev/null
+++ b/lib/v2/coomer/posts.js
@@ -0,0 +1,7 @@
+const fetchItems = require('./utils');
+
+module.exports = async (ctx) => {
+ const currentUrl = 'posts';
+
+ ctx.state.data = await fetchItems(ctx, currentUrl);
+};
diff --git a/lib/v2/coomer/radar.js b/lib/v2/coomer/radar.js
new file mode 100644
index 000000000..d048b3e5b
--- /dev/null
+++ b/lib/v2/coomer/radar.js
@@ -0,0 +1,19 @@
+module.exports = {
+ 'coomer.party': {
+ _name: 'Coomer',
+ '.': [
+ {
+ title: 'Artist',
+ docs: 'https://docs.rsshub.app/multimedia.html#coomer-artist',
+ source: ['/onlyfans/user/:id', '/'],
+ target: '/coomer/artist/:id',
+ },
+ {
+ title: 'Recent Posts',
+ docs: 'https://docs.rsshub.app/multimedia.html#coomer-recent-posts',
+ source: ['/posts', '/'],
+ target: '/coomer/posts',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/coomer/router.js b/lib/v2/coomer/router.js
new file mode 100644
index 000000000..b6507d2eb
--- /dev/null
+++ b/lib/v2/coomer/router.js
@@ -0,0 +1,4 @@
+module.exports = function (router) {
+ router.get('/artist/:id', require('./artist'));
+ router.get('/posts', require('./posts'));
+};
diff --git a/lib/v2/coomer/utils.js b/lib/v2/coomer/utils.js
new file mode 100644
index 000000000..4914dfd66
--- /dev/null
+++ b/lib/v2/coomer/utils.js
@@ -0,0 +1,53 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const { parseDate } = require('@/utils/parse-date');
+
+module.exports = async (ctx, currentUrl) => {
+ const rootUrl = 'https://coomer.party';
+ currentUrl = `${rootUrl}/${currentUrl}`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ let items = $('.post-card__link .fancy-link')
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ return {
+ 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('.ad-container').remove();
+
+ item.author = content('.post__user-name').text();
+ item.title = content('.post__title span').first().text();
+ item.pubDate = parseDate(content('.timestamp').attr('datetime'));
+ item.description = content('.post__body').html();
+
+ return item;
+ })
+ )
+ );
+
+ return {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ };
+};