|
@@ -62,6 +62,10 @@ function buildTwitterUrl(url: string): string {
|
|
|
return new URL(url, 'https://twitter.com').toString();
|
|
|
}
|
|
|
|
|
|
+function buildTweetUrl(tweet: Tweet): string {
|
|
|
+ return buildTwitterUrl(`/${tweet.user.screen_name}/status/${tweet.id_str}`);
|
|
|
+}
|
|
|
+
|
|
|
function buildProxyUrl(url: string): string {
|
|
|
const search = new URLSearchParams({ target: url }).toString();
|
|
|
return `/__proxy?${search}`;
|
|
@@ -88,7 +92,12 @@ class TextFormatter {
|
|
|
text: tag('a', { href: url }, `#${text}`),
|
|
|
});
|
|
|
}
|
|
|
+ const quoteLink = tweet.quoted_status ? buildTweetUrl(tweet.quoted_status) : undefined;
|
|
|
for (const link of tweet.entities.urls) {
|
|
|
+ if (quoteLink && link.expanded_url === quoteLink) {
|
|
|
+ // skip links for quoted status that are displayed inline
|
|
|
+ continue;
|
|
|
+ }
|
|
|
const url = new URL(link.expanded_url).toString();
|
|
|
this.splices.push({
|
|
|
indices: link.indices,
|
|
@@ -150,7 +159,7 @@ class TextFormatter {
|
|
|
const imageUrl = new URL(this.tweet.user.profile_image_url_https).toString();
|
|
|
const imageSrc = this.useProxy ? buildProxyUrl(imageUrl) : imageUrl;
|
|
|
const profileUrl = buildTwitterUrl(`/${this.tweet.user.screen_name}`);
|
|
|
- const tweetUrl = buildTwitterUrl(`/${this.tweet.user.screen_name}/status/${this.tweet.id_str}`);
|
|
|
+ const tweetUrl = buildTweetUrl(this.tweet);
|
|
|
const html = [
|
|
|
tag('img', { loading: 'lazy', src: imageSrc, height: '24px', width: '24px' }),
|
|
|
' ',
|
|
@@ -165,9 +174,8 @@ class TextFormatter {
|
|
|
}
|
|
|
|
|
|
bodyHTML(): SafeString {
|
|
|
- const max = this.tweet.display_text_range[1];
|
|
|
const splices = this.splices
|
|
|
- .filter(({ indices }) => indices[0] < max && indices[1] <= max)
|
|
|
+ .filter(({ indices }) => indices[0] && indices[1])
|
|
|
.sort((a, b) => a.indices[0] - b.indices[0]);
|
|
|
|
|
|
let index = 0;
|
|
@@ -260,7 +268,7 @@ export function timelineAsJSON(username: string, tweets: Tweet[]): string {
|
|
|
return {
|
|
|
id: tweet.id_str,
|
|
|
title: unescapeHTML(tweet.full_text.split('\n')[0]),
|
|
|
- url: buildTwitterUrl(`/${tweet.user.screen_name}/status/${tweet.id_str}`),
|
|
|
+ url: buildTweetUrl(tweet),
|
|
|
content_html: html,
|
|
|
date_published: new Date(tweet.created_at).toISOString(),
|
|
|
authors: [{
|