add S3 browser section to bib_explorer notebook

refs #94

New section 10 connects to the zotero S3 bucket via s3fs and lists
files synced from Zotero through the WebDAV-to-S3 bridge. Shows
both the bucket root and the zotero/zotero/ sync directory.
This commit is contained in:
kert
2026-03-22 02:55:46 -04:00
parent bf7049962f
commit 5b362d85d7

View File

@@ -716,6 +716,95 @@ def _(library_df, mo):
return
@app.cell(hide_code=True)
def _(mo):
mo.md("""
## 10. Zotero WebDAV Storage (S3)
Browse files synced from Zotero to the WebDAV-backed S3 bucket.
The `webdav` service (rclone) serves the `zotero` bucket in RustFS.
""")
return
@app.cell(hide_code=True)
def _(mo):
import os
import s3fs
_endpoint = os.environ.get("S3_ENDPOINT", "http://rustfs:9000")
_key = os.environ.get("RUSTFS_ACCESS_KEY", "")
_secret = os.environ.get("RUSTFS_SECRET_KEY", "")
fs = s3fs.S3FileSystem(
key=_key,
secret=_secret,
endpoint_url=_endpoint,
client_kwargs={"region_name": "us-east-1"},
)
try:
_files = fs.ls("zotero/", detail=True)
_rows = [
{
"path": f["Key"].removeprefix("zotero/"),
"size_kb": round(f.get("size", f.get("Size", 0)) / 1024, 1),
"modified": str(f.get("LastModified", "")),
}
for f in _files
if f.get("type", f.get("StorageClass", "")) != "directory"
]
except Exception as e:
_rows = []
mo.md(f"Could not list S3 bucket: `{e}`")
import polars as _pl
s3_df = _pl.DataFrame(_rows) if _rows else _pl.DataFrame()
if s3_df.height > 0:
mo.md(f"**{s3_df.height}** files in `s3://zotero/`")
else:
mo.md("No files in `s3://zotero/` yet. Sync from Zotero to populate.")
return (fs, s3_df)
@app.cell(hide_code=True)
def _(mo, s3_df):
mo.ui.table(s3_df, label="Zotero S3 Files") if s3_df.height > 0 else mo.md("")
return
@app.cell(hide_code=True)
def _(fs, mo):
_zotero_dir = []
try:
_zotero_dir = fs.ls("zotero/zotero/", detail=True)
except Exception:
pass
_sync_rows = [
{
"file": f["Key"].removeprefix("zotero/zotero/"),
"size_kb": round(f.get("size", f.get("Size", 0)) / 1024, 1),
}
for f in _zotero_dir
if f.get("type", f.get("StorageClass", "")) != "directory"
]
import polars as _pl
_sync_df = _pl.DataFrame(_sync_rows) if _sync_rows else _pl.DataFrame()
if _sync_df.height > 0:
mo.md(f"### Zotero Sync Directory\n\n**{_sync_df.height}** synced items")
mo.ui.table(_sync_df, label="Synced Files")
else:
mo.md("No synced files in `zotero/zotero/` yet.")
return
@app.cell(hide_code=True)
def _(mo):
mo.md("""