diff --git a/docs/en/social-media.md b/docs/en/social-media.md
index bc8b99f3e7..e7b8c6997c 100644
--- a/docs/en/social-media.md
+++ b/docs/en/social-media.md
@@ -48,10 +48,14 @@ These feed do not include boosts (a.k.a. reblogs). RSSHub provides a feed for us
-### Timeline
+### Instance timeline (local)
+### Instance timeline (federated)
+
+
+
### User timeline (backup)
diff --git a/docs/social-media.md b/docs/social-media.md
index aa83544338..d6ceaf1e6e 100644
--- a/docs/social-media.md
+++ b/docs/social-media.md
@@ -337,10 +337,14 @@ Tiny Tiny RSS 会给所有 iframe 元素添加 `sandbox="allow-scripts"` 属性
-### 实例公共时间线
+### 实例公共时间线(本站)
+### 实例公共时间线(跨站)
+
+
+
### 用户公共时间线(备用)
diff --git a/lib/router.js b/lib/router.js
index e2761a9aa4..c9a60cb41c 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -2297,7 +2297,8 @@ router.get('/ikea/uk/new', require('./routes/ikea/uk/new'));
router.get('/ikea/uk/offer', require('./routes/ikea/uk/offer'));
// Mastodon
-router.get('/mastodon/timeline/:site/:only_media?', require('./routes/mastodon/timeline'));
+router.get('/mastodon/timeline/:site/:only_media?', require('./routes/mastodon/timeline_local'));
+router.get('/mastodon/remote/:site/:only_media?', require('./routes/mastodon/timeline_remote'));
router.get('/mastodon/account_id/:site/:account_id/statuses/:only_media?', require('./routes/mastodon/account_id'));
router.get('/mastodon/acct/:acct/statuses/:only_media?', require('./routes/mastodon/acct'));
diff --git a/lib/routes/mastodon/timeline.js b/lib/routes/mastodon/timeline_local.js
similarity index 100%
rename from lib/routes/mastodon/timeline.js
rename to lib/routes/mastodon/timeline_local.js
diff --git a/lib/routes/mastodon/timeline_remote.js b/lib/routes/mastodon/timeline_remote.js
new file mode 100644
index 0000000000..ce60b0e6af
--- /dev/null
+++ b/lib/routes/mastodon/timeline_remote.js
@@ -0,0 +1,18 @@
+const got = require('@/utils/got');
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const site = ctx.params.site;
+ const only_media = ctx.params.only_media ? 'true' : 'false';
+
+ const url = `http://${site}/api/v1/timelines/public?remote=true&only_media=${only_media}`;
+
+ const response = await got.get(url);
+ const list = response.data;
+
+ ctx.state.data = {
+ title: `Federated Public${ctx.params.only_media ? ' Media' : ''} Timeline on ${site}`,
+ link: `http://${site}`,
+ item: utils.parseStatuses(list),
+ };
+};
diff --git a/lib/routes/mastodon/utils.js b/lib/routes/mastodon/utils.js
index b07bfecfd2..3af05b9419 100644
--- a/lib/routes/mastodon/utils.js
+++ b/lib/routes/mastodon/utils.js
@@ -10,13 +10,16 @@ const parseStatuses = (data) =>
.map((item) => {
switch (item.type) {
case 'gifv':
- return `
`;
+ return `
`;
case 'video':
- return `
`;
+ return `
`;
case 'image':
- return `
`;
+ return `
`;
+ case 'audio':
+ return `
`;
+ case 'unknown':
default:
- return '';
+ return `
${item.remote_url}`;
}
})
.join('');
@@ -33,7 +36,7 @@ const parseStatuses = (data) =>
titleAuthor = `@${item.account.username}`;
media = mediaParse(item.media_attachments);
}
- const titleText = item.sentitive === true ? `(CW) ${item.spoiler_text}` : contentRemovedHtml;
+ const titleText = item.sensitive === true ? `(CW) ${item.spoiler_text}` : contentRemovedHtml;
return {
title: `${titleAuthor}: "${titleText}"`,