AppImage video fix, proper import posts, first-run chooser, file pickers
- bundleMediaFramework: true — bundles full GStreamer plugin set in AppImage. Fixes WebKit hang on video/audio (missing appsink/autoaudiosink plugins). MSDK/VA plugins removed post-build to avoid Ubuntu DMA assertion crash. - Import creates complete posts: BlobHeader, VisibilityIntent, pinned blobs, self-follow. Imported posts now indistinguishable from locally created ones. - First-run chooser: Start Fresh or Import Identity on fresh install only. Profile setup shown for existing identities without display name. - File pickers: native Browse buttons on export (folder) and import (ZIP) via tauri-plugin-dialog. - Export path: relative paths resolved against home dir. - Lightbox close: only on overlay/image click, not inner form content. - Growth loop skips self as N2 candidate. - Node shutdown on identity switch (prevents zombie background tasks). - media-src CSP includes asset protocol. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ec731fdb4b
commit
cba30a1bb3
7 changed files with 186 additions and 11 deletions
|
|
@ -150,26 +150,57 @@ pub async fn import_public_posts(
|
|||
let mut imported = 0usize;
|
||||
let mut blobs_imported = 0usize;
|
||||
|
||||
info!(post_count = parsed.posts.len(), skipped = parsed.skipped, "Import phase 2: storing to DB");
|
||||
|
||||
// Ensure we follow ourselves so imported posts appear in feed
|
||||
{
|
||||
let s = storage.get().await;
|
||||
let _ = s.add_follow(our_node_id);
|
||||
}
|
||||
|
||||
let now = now_ms();
|
||||
|
||||
for (new_post, _vis, blob_data) in &parsed.posts {
|
||||
let new_id = compute_post_id(new_post);
|
||||
|
||||
let s = storage.get().await;
|
||||
if s.get_post(&new_id).ok().flatten().is_some() {
|
||||
continue; // duplicate
|
||||
drop(s);
|
||||
debug!(post = hex::encode(new_id), "Import: skipping duplicate post");
|
||||
continue;
|
||||
}
|
||||
s.store_post_with_visibility(&new_id, new_post, &PostVisibility::Public)?;
|
||||
drop(s);
|
||||
// Store post with intent (matches create_post_with_visibility behavior)
|
||||
s.store_post_with_intent(&new_id, new_post, &PostVisibility::Public, &crate::types::VisibilityIntent::Public)?;
|
||||
|
||||
// Store blobs + record them, matching normal post creation
|
||||
for (att, data) in blob_data {
|
||||
if !blob_store.has(&att.cid) {
|
||||
blob_store.store(&att.cid, data)?;
|
||||
let s = storage.get().await;
|
||||
let _ = s.record_blob(&att.cid, &new_id, our_node_id, data.len() as u64, &att.mime_type, att.size_bytes);
|
||||
blobs_imported += 1;
|
||||
}
|
||||
s.record_blob(&att.cid, &new_id, our_node_id, data.len() as u64, &att.mime_type, att.size_bytes)?;
|
||||
let _ = s.pin_blob(&att.cid);
|
||||
blobs_imported += 1;
|
||||
}
|
||||
|
||||
// Create BlobHeader (matches what engagement/sync expects)
|
||||
let header = crate::types::BlobHeader {
|
||||
post_id: new_id,
|
||||
author: *our_node_id,
|
||||
reactions: vec![],
|
||||
comments: vec![],
|
||||
policy: crate::types::CommentPolicy::default(),
|
||||
updated_at: now,
|
||||
thread_splits: vec![],
|
||||
receipt_slots: vec![],
|
||||
comment_slots: vec![],
|
||||
prior_author: None,
|
||||
};
|
||||
let header_json = serde_json::to_string(&header).unwrap_or_default();
|
||||
let _ = s.store_blob_header(&new_id, our_node_id, &header_json, now);
|
||||
drop(s);
|
||||
|
||||
imported += 1;
|
||||
debug!(imported, post = hex::encode(new_id), "Import: stored post");
|
||||
}
|
||||
|
||||
info!(imported, skipped = parsed.skipped, blobs = blobs_imported, "Public post import complete");
|
||||
|
|
|
|||
|
|
@ -1561,6 +1561,10 @@ impl Network {
|
|||
};
|
||||
|
||||
let (candidate_id, score) = match candidate {
|
||||
Some((nid, score)) if nid == self.our_node_id => {
|
||||
debug!("Growth loop: skipping self as candidate");
|
||||
continue;
|
||||
}
|
||||
Some(c) => c,
|
||||
None => {
|
||||
debug!("Growth loop: no N2 candidates available");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue