Skip to content

Instantly share code, notes, and snippets.

@gsquire
Created June 8, 2025 19:19
Show Gist options
  • Save gsquire/f2b572da529e7aed1227c51fee1cc130 to your computer and use it in GitHub Desktop.
Save gsquire/f2b572da529e7aed1227c51fee1cc130 to your computer and use it in GitHub Desktop.
Export your Pocket CSV to a NETSCAPE bookmark file that linkhut can import
[package]
name = "pocket2linkhut"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0"
argh = "0.1"
csv = "1.3"
serde = { version = "1.0", features = ["derive"] }
use std::fs::File;
use std::io::Write;
use std::path::Path;
use anyhow::Result;
use argh::FromArgs;
use csv::Reader;
use serde::Deserialize;
#[derive(FromArgs)]
/// Create a NETSCAPE bookmark file to import to linkhut.
struct App {
/// whether or not the links should be public
#[argh(switch)]
public: bool,
/// the exported Pocket CSV file
#[argh(positional)]
file: String,
}
#[derive(Debug, Deserialize)]
struct Bookmark {
title: String,
url: String,
time_added: u64,
tags: Option<String>,
#[allow(unused)]
status: String,
}
fn read_pocket_export<P: AsRef<Path>>(path: P, public: bool) -> Result<()> {
const BOOKMARKS_FILE: &str = "bookmarks.html";
const HEADER: &str = r#"<!DOCTYPE NETSCAPE-Bookmark-file-1>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<!-- This is an automatically generated file.
It will be read and overwritten.
Do Not Edit! -->
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
"#;
const FOOTER: &str = "</DL><p>\n";
let mut f = File::create(BOOKMARKS_FILE)?;
f.write_all(HEADER.as_bytes())?;
let mut rdr = Reader::from_path(path)?;
for record in rdr.deserialize() {
let bookmark: Bookmark = record?;
write_bookmark(&mut f, bookmark, public)?;
}
f.write_all(FOOTER.as_bytes())?;
Ok(())
}
fn write_bookmark(f: &mut File, bookmark: Bookmark, public: bool) -> Result<()> {
let entry = format!(
"<DT><A HREF=\"{}\" ADD_DATE=\"{}\" PRIVATE=\"{}\" TAGS=\"{}\">{}</A>\n<DD>\n\n",
bookmark.url,
bookmark.time_added,
!public,
bookmark.tags.unwrap_or_default(),
bookmark.title
);
f.write_all(entry.as_bytes())?;
Ok(())
}
fn main() {
let args: App = argh::from_env();
if let Err(e) = read_pocket_export(args.file, args.public) {
eprintln!("error: {e}");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment