| 
					
				 | 
			
			
				@@ -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: [{ 
			 |