···
use lexica::app_bsky::actor::ProfileViewBasic;
use lexica::app_bsky::embed::Embed;
use lexica::app_bsky::feed::{
-
BlockedAuthor, FeedViewPost, PostView, PostViewerState, ReplyRef, ReplyRefPost, ThreadgateView,
use lexica::app_bsky::graph::ListViewBasic;
use lexica::app_bsky::RecordStats;
···
-
author: ProfileViewBasic,
-
labels: Vec<models::Label>,
-
threadgate: Option<ThreadgateView>,
-
viewer: Option<PostViewerState>,
-
stats: Option<PostStats>,
.map(|stats| RecordStats {
···
let threadgate = self.hydrate_threadgate(threadgate).await;
let labels = self.get_label(&post.at_uri).await;
post, author, labels, embed, threadgate, viewer, stats,
-
pub async fn hydrate_posts(&self, posts: Vec<String>) -> HashMap<String, PostView> {
let stats = self.loaders.post_stats.load_many(posts.clone()).await;
let posts = self.loaders.posts.load_many(posts).await;
···
.unzip::<_, _, Vec<_>, Vec<_>>();
let authors = self.hydrate_profiles_basic(authors).await;
-
let post_labels = self.get_label_many(&post_uris).await;
-
let viewer_data = self.get_post_viewer_states(&post_uris).await;
···
let threadgates = self.hydrate_threadgates(threadgates).await;
-
let embeds = self.hydrate_embeds(post_uris).await;
.filter_map(|(uri, (post, threadgate))| {
-
let author = authors.get(&post.did)?;
-
let embed = embeds.get(&uri).cloned();
let threadgate = threadgate.and_then(|tg| threadgates.get(&tg.at_uri).cloned());
-
let labels = post_labels.get(&uri).cloned().unwrap_or_default();
let stats = stats.get(&uri).cloned();
-
let viewer = viewer_data.get(&uri).cloned();
pub async fn hydrate_feed_posts(
author_threads_only: bool,
-
) -> HashMap<String, FeedViewPost> {
-
let stats = self.loaders.post_stats.load_many(posts.clone()).await;
-
let posts = self.loaders.posts.load_many(posts).await;
-
let (authors, post_uris) = posts
-
.map(|(post, _)| (post.did.clone(), post.at_uri.clone()))
-
.unzip::<_, _, Vec<_>, Vec<_>>();
-
let authors = self.hydrate_profiles_basic(authors).await;
-
let post_labels = self.get_label_many(&post_uris).await;
-
let viewer_data = self.get_post_viewer_states(&post_uris).await;
-
let embeds = self.hydrate_embeds(post_uris.clone()).await;
// we shouldn't show the parent when the post violates a threadgate.
-
.filter(|(post, _)| !post.violates_threadgate)
-
.flat_map(|(post, _)| [post.parent_uri.clone(), post.root_uri.clone()])
let reply_posts = self.hydrate_posts(reply_refs).await;
-
// hydrate all the posts.
-
.filter_map(|(post_uri, (raw, _))| {
-
let root = raw.root_uri.clone();
-
let parent = raw.parent_uri.clone();
-
let author = authors.get(&raw.did)?;
-
let embed = embeds.get(&post_uri).cloned();
-
let labels = post_labels.get(&post_uri).cloned().unwrap_or_default();
-
let stats = stats.get(&post_uri).cloned();
-
let viewer = viewer_data.get(&post_uri).cloned();
-
build_postview(raw, author.to_owned(), labels, embed, None, viewer, stats);
-
Some((post_uri, (post, root, parent)))
-
.collect::<HashMap<_, _>>();
-
.filter_map(|post_uri| {
-
let item = if author_threads_only {
-
compile_feed_authors_threads_only(&post_uri, &mut posts)?
-
compile_feed(&post_uri, &mut posts, &reply_posts)?
···
-
type FeedViewPartData = (PostView, Option<String>, Option<String>);
-
// this is the 'normal' one that runs in most places
-
posts: &mut HashMap<String, FeedViewPartData>,
-
reply_posts: &HashMap<String, PostView>,
-
) -> Option<FeedViewPost> {
-
let (post, root_uri, parent_uri) = posts.remove(uri)?;
-
let root = root_uri.as_ref().and_then(|uri| reply_posts.get(uri));
-
let parent = parent_uri.as_ref().and_then(|uri| reply_posts.get(uri));
-
let reply = if parent_uri.is_some() && root_uri.is_some() {
-
.map(postview_to_replyref)
-
.unwrap_or(ReplyRefPost::NotFound {
-
uri: root_uri.as_ref().unwrap().clone(),
-
.map(postview_to_replyref)
-
.unwrap_or(ReplyRefPost::NotFound {
-
uri: parent_uri.as_ref().unwrap().clone(),
-
grandparent_author: None,
-
// and this one runs in getAuthorFeed when filter=PostsAndAuthorThreads
-
fn compile_feed_authors_threads_only(
-
posts: &mut HashMap<String, FeedViewPartData>,
-
) -> Option<FeedViewPost> {
-
let (post, root_uri, parent_uri) = posts.get(uri)?.clone();
-
let root = root_uri.as_ref().and_then(|root| posts.get(root));
-
let parent = parent_uri.as_ref().and_then(|parent| posts.get(parent));
-
let reply = if parent_uri.is_some() && root_uri.is_some() {
-
.map(|(post, _, _)| postview_to_replyref(post))?,
-
.map(|(post, _, _)| postview_to_replyref(post))?,
-
grandparent_author: None,
···
use lexica::app_bsky::actor::ProfileViewBasic;
use lexica::app_bsky::embed::Embed;
use lexica::app_bsky::feed::{
+
BlockedAuthor, FeedReasonRepost, FeedViewPost, FeedViewPostReason, PostView, PostViewerState,
+
ReplyRef, ReplyRefPost, ThreadgateView,
use lexica::app_bsky::graph::ListViewBasic;
use lexica::app_bsky::RecordStats;
···
+
type HydratePostsRet = (
+
Option<ThreadgateView>,
+
Option<PostViewerState>,
+
(post, author, labels, embed, threadgate, viewer, stats): HydratePostsRet,
.map(|stats| RecordStats {
···
let threadgate = self.hydrate_threadgate(threadgate).await;
let labels = self.get_label(&post.at_uri).await;
post, author, labels, embed, threadgate, viewer, stats,
+
async fn hydrate_posts_inner(&self, posts: Vec<String>) -> HashMap<String, HydratePostsRet> {
let stats = self.loaders.post_stats.load_many(posts.clone()).await;
let posts = self.loaders.posts.load_many(posts).await;
···
.unzip::<_, _, Vec<_>, Vec<_>>();
let authors = self.hydrate_profiles_basic(authors).await;
+
let mut post_labels = self.get_label_many(&post_uris).await;
+
let mut viewer_data = self.get_post_viewer_states(&post_uris).await;
···
let threadgates = self.hydrate_threadgates(threadgates).await;
+
let mut embeds = self.hydrate_embeds(post_uris).await;
.filter_map(|(uri, (post, threadgate))| {
+
let author = authors.get(&post.did)?.clone();
+
let embed = embeds.remove(&uri);
let threadgate = threadgate.and_then(|tg| threadgates.get(&tg.at_uri).cloned());
+
let labels = post_labels.remove(&uri).unwrap_or_default();
let stats = stats.get(&uri).cloned();
+
let viewer = viewer_data.remove(&uri);
+
(post, author, labels, embed, threadgate, viewer, stats),
+
pub async fn hydrate_posts(&self, posts: Vec<String>) -> HashMap<String, PostView> {
+
self.hydrate_posts_inner(posts)
+
.map(|(uri, data)| (uri, build_postview(data)))
pub async fn hydrate_feed_posts(
+
posts: Vec<RawFeedItem>,
author_threads_only: bool,
+
) -> Vec<FeedViewPost> {
+
.map(|item| item.post_uri().to_string())
+
let mut posts_hyd = self.hydrate_posts_inner(post_uris).await;
// we shouldn't show the parent when the post violates a threadgate.
+
let reply_refs = posts_hyd
+
.filter(|(post, ..)| !post.violates_threadgate)
+
.flat_map(|(post, ..)| [post.parent_uri.clone(), post.root_uri.clone()])
let reply_posts = self.hydrate_posts(reply_refs).await;
+
let repost_profiles = posts
+
.filter_map(|item| item.repost_by())
+
let profiles_hydrated = self.hydrate_profiles_basic(repost_profiles).await;
+
let post = posts_hyd.remove(item.post_uri())?;
+
let context = item.context();
+
let reply = if let RawFeedItem::Post { .. } = item {
+
let root_uri = post.0.root_uri.as_ref();
+
let parent_uri = post.0.parent_uri.as_ref();
+
let (root, parent) = if author_threads_only {
+
if root_uri.is_some() && parent_uri.is_some() {
+
let root = root_uri.and_then(|uri| posts_hyd.get(uri))?;
+
let parent = parent_uri.and_then(|uri| posts_hyd.get(uri))?;
+
let root = build_postview(root.clone());
+
let parent = build_postview(parent.clone());
+
(Some(root), Some(parent))
+
let root = root_uri.and_then(|uri| reply_posts.get(uri)).cloned();
+
let parent = parent_uri.and_then(|uri| reply_posts.get(uri)).cloned();
+
if root_uri.is_some() || parent_uri.is_some() {
+
root: root.map(postview_to_replyref).unwrap_or(
+
ReplyRefPost::NotFound {
+
uri: root_uri.unwrap().to_owned(),
+
parent: parent.map(postview_to_replyref).unwrap_or(
+
ReplyRefPost::NotFound {
+
uri: parent_uri.unwrap().to_owned(),
+
grandparent_author: None,
+
let reason = match item {
+
RawFeedItem::Repost { uri, by, at, .. } => {
+
Some(FeedViewPostReason::Repost(FeedReasonRepost {
+
by: profiles_hydrated.get(&by).cloned()?,
+
RawFeedItem::Pin { .. } => Some(FeedViewPostReason::Pin),
+
let post = build_postview(post);
···
+
context: Option<String>,
+
context: Option<String>,
+
at: chrono::DateTime<chrono::Utc>,
+
context: Option<String>,
+
fn post_uri(&self) -> &str {
+
RawFeedItem::Pin { uri, .. } => uri,
+
RawFeedItem::Post { uri, .. } => uri,
+
RawFeedItem::Repost { post, .. } => post,
+
fn repost_by(&self) -> Option<String> {
+
RawFeedItem::Repost { by, .. } => Some(by.clone()),
+
fn context(&self) -> Option<String> {
+
RawFeedItem::Pin { context, .. } => context.clone(),
+
RawFeedItem::Post { context, .. } => context.clone(),
+
RawFeedItem::Repost { context, .. } => context.clone(),