Support media envelopes and feed w/o transparent shares
This commit is contained in:
		
							parent
							
								
									0f7af7c13a
								
							
						
					
					
						commit
						95f6887eda
					
				| 
						 | 
					@ -17,6 +17,7 @@ ports to use for development and deployment.
 | 
				
			||||||
- [x] RSS feeds for projects
 | 
					- [x] RSS feeds for projects
 | 
				
			||||||
- [x] Index page explaining what's going on
 | 
					- [x] Index page explaining what's going on
 | 
				
			||||||
- [x] Better support for transparent shares
 | 
					- [x] Better support for transparent shares
 | 
				
			||||||
 | 
					    - [x] Add feed without shares
 | 
				
			||||||
- [ ] More robust parsing (defaults for all!)
 | 
					- [ ] More robust parsing (defaults for all!)
 | 
				
			||||||
- [ ] RSS feeds for tags
 | 
					- [ ] RSS feeds for tags
 | 
				
			||||||
- [x] Atom Extension pagination support
 | 
					- [x] Atom Extension pagination support
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,14 +44,9 @@ pub struct CohostPost {
 | 
				
			||||||
        default
 | 
					        default
 | 
				
			||||||
    )]
 | 
					    )]
 | 
				
			||||||
    pub url: String,
 | 
					    pub url: String,
 | 
				
			||||||
    #[serde(
 | 
					    #[serde(deserialize_with = "deserialize_null_default", default)]
 | 
				
			||||||
        deserialize_with = "deserialize_null_default",
 | 
					 | 
				
			||||||
        default
 | 
					 | 
				
			||||||
    )]
 | 
					 | 
				
			||||||
    pub blocks: Vec<CohostPostBlock>,
 | 
					    pub blocks: Vec<CohostPostBlock>,
 | 
				
			||||||
    #[serde(
 | 
					    #[serde(rename = "transparentShareOfPostId")]
 | 
				
			||||||
        rename = "transparentShareOfPostId",
 | 
					 | 
				
			||||||
    )]
 | 
					 | 
				
			||||||
    pub transparent_share_of_post_id: Option<u64>,
 | 
					    pub transparent_share_of_post_id: Option<u64>,
 | 
				
			||||||
    #[serde(rename = "postingProject")]
 | 
					    #[serde(rename = "postingProject")]
 | 
				
			||||||
    pub poster: CohostPostingProject,
 | 
					    pub poster: CohostPostingProject,
 | 
				
			||||||
| 
						 | 
					@ -93,7 +88,6 @@ pub struct CohostPostLink {
 | 
				
			||||||
    pub t_type: String,
 | 
					    pub t_type: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Deserialize)]
 | 
					#[derive(Debug, Clone, Deserialize)]
 | 
				
			||||||
pub struct CohostPostBlock {
 | 
					pub struct CohostPostBlock {
 | 
				
			||||||
    pub attachment: Option<CohostPostAttachment>,
 | 
					    pub attachment: Option<CohostPostAttachment>,
 | 
				
			||||||
| 
						 | 
					@ -101,7 +95,11 @@ pub struct CohostPostBlock {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Deserialize)]
 | 
					#[derive(Debug, Clone, Deserialize)]
 | 
				
			||||||
pub struct CohostPostAttachment {
 | 
					pub struct CohostPostAttachment {
 | 
				
			||||||
    #[serde(rename = "fileURL", deserialize_with = "deserialize_null_default", default)]
 | 
					    #[serde(
 | 
				
			||||||
 | 
					        rename = "fileURL",
 | 
				
			||||||
 | 
					        deserialize_with = "deserialize_null_default",
 | 
				
			||||||
 | 
					        default
 | 
				
			||||||
 | 
					    )]
 | 
				
			||||||
    pub file_url: String,
 | 
					    pub file_url: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										20
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
					@ -194,12 +194,22 @@ async fn get_project_data(project_id: String) -> Result<CohostAccount, ErrorResp
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[get("/<project>/originals.rss")]
 | 
				
			||||||
 | 
					async fn syndication_originals_rss_route(project: String) -> Result<RssResponse, ErrorResponse> {
 | 
				
			||||||
 | 
					    let project_data = get_project_data(project.clone()).await?;
 | 
				
			||||||
 | 
					    let page_data = get_full_post_data(project.clone()).await?;
 | 
				
			||||||
 | 
					    Ok(RssResponse {
 | 
				
			||||||
 | 
					        inner: syndication::channel_for_posts_page(project.clone(), project_data, page_data, true)
 | 
				
			||||||
 | 
					            .to_string(),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[get("/<project>/feed.rss")]
 | 
					#[get("/<project>/feed.rss")]
 | 
				
			||||||
async fn syndication_rss_route(project: String) -> Result<RssResponse, ErrorResponse> {
 | 
					async fn syndication_rss_route(project: String) -> Result<RssResponse, ErrorResponse> {
 | 
				
			||||||
    let project_data = get_project_data(project.clone()).await?;
 | 
					    let project_data = get_project_data(project.clone()).await?;
 | 
				
			||||||
    let page_data = get_full_post_data(project.clone()).await?;
 | 
					    let page_data = get_full_post_data(project.clone()).await?;
 | 
				
			||||||
    Ok(RssResponse {
 | 
					    Ok(RssResponse {
 | 
				
			||||||
        inner: syndication::channel_for_posts_page(project.clone(), project_data, page_data)
 | 
					        inner: syndication::channel_for_posts_page(project.clone(), project_data, page_data, false)
 | 
				
			||||||
            .to_string(),
 | 
					            .to_string(),
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -244,7 +254,13 @@ async fn main() -> Result<(), Box<dyn Error>> {
 | 
				
			||||||
    let _rocket = rocket::build()
 | 
					    let _rocket = rocket::build()
 | 
				
			||||||
        .mount(
 | 
					        .mount(
 | 
				
			||||||
            &ARGS.base_url,
 | 
					            &ARGS.base_url,
 | 
				
			||||||
            routes![index, webfinger_route, syndication_rss_route, post_md_route],
 | 
					            routes![
 | 
				
			||||||
 | 
					                index,
 | 
				
			||||||
 | 
					                webfinger_route,
 | 
				
			||||||
 | 
					                syndication_rss_route,
 | 
				
			||||||
 | 
					                syndication_originals_rss_route,
 | 
				
			||||||
 | 
					                post_md_route
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .ignite()
 | 
					        .ignite()
 | 
				
			||||||
        .await?
 | 
					        .await?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,11 +22,16 @@ pub fn channel_for_posts_page(
 | 
				
			||||||
    project_name: impl AsRef<str>,
 | 
					    project_name: impl AsRef<str>,
 | 
				
			||||||
    project: CohostAccount,
 | 
					    project: CohostAccount,
 | 
				
			||||||
    mut page: CohostPostsPage,
 | 
					    mut page: CohostPostsPage,
 | 
				
			||||||
 | 
					    originals_only: bool,
 | 
				
			||||||
) -> Channel {
 | 
					) -> Channel {
 | 
				
			||||||
    let project_name = project_name.as_ref().clone();
 | 
					    let project_name = project_name.as_ref().clone();
 | 
				
			||||||
    let mut builder = rss::ChannelBuilder::default();
 | 
					    let mut builder = rss::ChannelBuilder::default();
 | 
				
			||||||
    builder
 | 
					    builder
 | 
				
			||||||
        .title(format!("{} Cohost Posts", project.display_name))
 | 
					        .title(format!(
 | 
				
			||||||
 | 
					            "{} Cohost Posts{}",
 | 
				
			||||||
 | 
					            project.display_name,
 | 
				
			||||||
 | 
					            if originals_only { "" } else { " and Shares" }
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
        .description(project.description)
 | 
					        .description(project.description)
 | 
				
			||||||
        .generator(Some(format!(
 | 
					        .generator(Some(format!(
 | 
				
			||||||
            "{} {}",
 | 
					            "{} {}",
 | 
				
			||||||
| 
						 | 
					@ -73,7 +78,13 @@ pub fn channel_for_posts_page(
 | 
				
			||||||
        let mut body_text = String::new();
 | 
					        let mut body_text = String::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if let Some(shared_post_id) = item.transparent_share_of_post_id {
 | 
					        if let Some(shared_post_id) = item.transparent_share_of_post_id {
 | 
				
			||||||
            body_text.push_str(&format!("(share of post {} without any commentary)\n\n---\n\n", shared_post_id));
 | 
					            if originals_only {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            body_text.push_str(&format!(
 | 
				
			||||||
 | 
					                "(share of post {} without any commentary)\n\n---\n\n",
 | 
				
			||||||
 | 
					                shared_post_id
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
        } else if item.share_tree.len() == 1 {
 | 
					        } else if item.share_tree.len() == 1 {
 | 
				
			||||||
            body_text.push_str("(in reply to another post)\n\n---\n\n")
 | 
					            body_text.push_str("(in reply to another post)\n\n---\n\n")
 | 
				
			||||||
        } else if item.share_tree.len() > 1 {
 | 
					        } else if item.share_tree.len() > 1 {
 | 
				
			||||||
| 
						 | 
					@ -113,9 +124,16 @@ pub fn channel_for_posts_page(
 | 
				
			||||||
        item_builder.content(html_output);
 | 
					        item_builder.content(html_output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for attachment in item.blocks.into_iter().filter_map(|block| block.attachment) {
 | 
					        for attachment in item.blocks.into_iter().filter_map(|block| block.attachment) {
 | 
				
			||||||
            use rss::EnclosureBuilder;
 | 
					 | 
				
			||||||
            use mime_guess::from_path as guess_mime_from_path;
 | 
					            use mime_guess::from_path as guess_mime_from_path;
 | 
				
			||||||
            let enclosure = EnclosureBuilder::default().mime_type(guess_mime_from_path(&attachment.file_url).first_or_octet_stream().to_string()).url(attachment.file_url).build();
 | 
					            use rss::EnclosureBuilder;
 | 
				
			||||||
 | 
					            let enclosure = EnclosureBuilder::default()
 | 
				
			||||||
 | 
					                .mime_type(
 | 
				
			||||||
 | 
					                    guess_mime_from_path(&attachment.file_url)
 | 
				
			||||||
 | 
					                        .first_or_octet_stream()
 | 
				
			||||||
 | 
					                        .to_string(),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .url(attachment.file_url)
 | 
				
			||||||
 | 
					                .build();
 | 
				
			||||||
            item_builder.enclosure(enclosure);
 | 
					            item_builder.enclosure(enclosure);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,8 +52,9 @@
 | 
				
			||||||
    <h2>Standard Data from Cohost Posts and Projects</h2>
 | 
					    <h2>Standard Data from Cohost Posts and Projects</h2>
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
        <h3>Project RSS Feeds</h3>
 | 
					        <h3>Project RSS Feeds</h3>
 | 
				
			||||||
        Go to <code>/project_name/feed.rss</code> to get a feed for a project.
 | 
					        Go to <code>/project_name/feed.rss</code> to get a feed for a project, or <code>/project_name/originals.rss</code> for just original posts (including shared posts with commentary).
 | 
				
			||||||
        For example, <a href="/noracodes/feed.rss"><code>/noracodes/feed.rss</code></a> will give you the feed for my page.
 | 
					        For example, <a href="/noracodes/feed.rss"><code>/noracodes/feed.rss</code></a> will give you the feed for my page,
 | 
				
			||||||
 | 
					        or <a href="/noracodes/original.rss"><code>/noracodes/feed.rss</code></a> for just my original posts.
 | 
				
			||||||
    </p>
 | 
					    </p>
 | 
				
			||||||
    <p>
 | 
					    <p>
 | 
				
			||||||
        <h3>Markdown Extraction</h3>
 | 
					        <h3>Markdown Extraction</h3>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue