#!/usr/bin/env python3
"""
# Script bookmarks-in-days
## Metadata
**Language**: #python
**Parent**:: [[Executable Markdown File]]
## Synopsis
List bookmarks saved in the last N days.
## Script
```python
#"""
#!/usr/bin/env python3
"""
Read Raindrop backup CSV file and print bookmarks saved in the last N days as JSON.
Usage:
python bookmarks-in-days.md [-h] [--days DAYS] [csv_file]
The CSV file is assumed to be sorted from latest to oldest.
"""
import argparse
import csv
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
EXCLUDED_FOLDERS = set(["Automation / Obsidian"])
DEFAULT_CSV = Path.home() / "Dropbox" / "Apps" / "Raindrop.io" / "Export.csv"
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Filter Raindrop bookmarks by creation date and output as JSON."
)
parser.add_argument(
"csv_file",
nargs="?",
help="Path to the Raindrop backup CSV file (default: in Dropbox)",
default=str(DEFAULT_CSV),
)
parser.add_argument(
"--days",
"-d",
type=int,
default=7,
help="Number of days to look back (default: 7)",
)
return parser.parse_args()
def parse_iso_datetime(date_str):
"""Parse ISO 8601 datetime string to datetime object."""
# Handle both with and without milliseconds
try:
return datetime.fromisoformat(date_str.replace("Z", "+00:00"))
except ValueError:
return None
def filter_recent_bookmarks(csv_file, days):
"""Read CSV and filter bookmarks created in the last N days."""
now = datetime.now(timezone.utc)
cutoff_timestamp = now.timestamp() - (days * 24 * 60 * 60)
bookmarks = []
skipped_count = 0
with open(csv_file, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
created_str = row.get("created", "")
created_dt = parse_iso_datetime(created_str)
if row.get("folder", "") in EXCLUDED_FOLDERS:
continue
if created_dt is None:
skipped_count += 1
continue
if created_dt.timestamp() >= cutoff_timestamp:
bookmarks.append(row)
if skipped_count > 0:
print(
f"Warning: Skipped {skipped_count} row(s) with invalid or missing creation dates.",
file=sys.stderr,
)
return bookmarks
def main():
"""Main entry point."""
args = parse_args()
try:
bookmarks = filter_recent_bookmarks(args.csv_file, args.days)
print(json.dumps(bookmarks, indent=2))
except FileNotFoundError:
print(f"Error: File '{args.csv_file}' not found.", file=sys.stderr)
sys.exit(1)
except PermissionError:
print(f"Error: Permission denied to read '{args.csv_file}'.", file=sys.stderr)
sys.exit(1)
except csv.Error as e:
print(f"Error: Failed to parse CSV file: {e}", file=sys.stderr)
sys.exit(1)
except UnicodeDecodeError as e:
print(f"Error: Failed to decode file (encoding issue): {e}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
"""
# vim: ft=python
```
"""