Skip to content

Instantly share code, notes, and snippets.

@dctanner
Created July 15, 2025 15:40
Show Gist options
  • Save dctanner/e0e00b32d4df6936a8a19ac7da89a056 to your computer and use it in GitHub Desktop.
Save dctanner/e0e00b32d4df6936a8a19ac7da89a056 to your computer and use it in GitHub Desktop.

Revisions

  1. dctanner revised this gist Jul 15, 2025. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions pocket_to_pinboard_standalone.py
    Original file line number Diff line number Diff line change
    @@ -6,11 +6,11 @@
    To run this script with uv in a single command:
    uv run --with pinboard https://gist.github.com/YOUR_USERNAME/GIST_ID/raw/pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
    uv run --with pinboard https://gist.github.com/dctanner/e0e00b32d4df6936a8a19ac7da89a056/raw/pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
    Or download first and run:
    curl -O https://gist.github.com/YOUR_USERNAME/GIST_ID/raw/pocket_to_pinboard_standalone.py
    curl -O https://gist.github.com/dctanner/e0e00b32d4df6936a8a19ac7da89a056/raw/pocket_to_pinboard_standalone.py
    uv run --with pinboard pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
    Requirements:
  2. dctanner created this gist Jul 15, 2025.
    126 changes: 126 additions & 0 deletions pocket_to_pinboard_standalone.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,126 @@
    #!/usr/bin/env python3
    """
    Pocket to Pinboard Import Script
    This script imports bookmarks from a Pocket export CSV file to Pinboard.
    To run this script with uv in a single command:
    uv run --with pinboard https://gist.github.com/YOUR_USERNAME/GIST_ID/raw/pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
    Or download first and run:
    curl -O https://gist.github.com/YOUR_USERNAME/GIST_ID/raw/pocket_to_pinboard_standalone.py
    uv run --with pinboard pocket_to_pinboard_standalone.py pocket_export.csv username:api_token
    Requirements:
    - uv (install from https://github.com/astral-sh/uv)
    - A Pocket export CSV file (export from https://getpocket.com/export)
    - A Pinboard API token (get from https://pinboard.in/settings/password)
    Usage:
    python pocket_to_pinboard_standalone.py <pocket_csv_file> <pinboard_api_token>
    Arguments:
    pocket_csv_file Path to the Pocket export CSV file
    pinboard_api_token Pinboard API token in username:token format
    Example:
    python pocket_to_pinboard_standalone.py pocket_export.csv myusername:1234567890ABCDEF
    Note: The script respects Pinboard's rate limiting (3 seconds between requests).
    """

    import csv
    import argparse
    import time
    from datetime import datetime
    import pinboard


    def parse_pocket_csv(csv_file):
    """Parse Pocket export CSV and return list of bookmarks."""
    bookmarks = []

    with open(csv_file, 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
    # Skip items without URLs
    if not row.get('url'):
    continue

    bookmark = {
    'url': row['url'],
    'description': row.get('title', ''),
    'tags': row.get('tags', '').split(',') if row.get('tags') else [],
    'time': datetime.fromtimestamp(int(row.get('time_added', 0))) if row.get('time_added') else None,
    'toread': row.get('status') == 'unread'
    }
    bookmarks.append(bookmark)

    return bookmarks


    def import_to_pinboard(bookmarks, api_token):
    """Import bookmarks to Pinboard."""
    pb = pinboard.Pinboard(api_token)

    total = len(bookmarks)
    successful = 0
    failed = 0

    print(f"Starting import of {total} bookmarks...")

    for i, bookmark in enumerate(bookmarks, 1):
    try:
    # Pinboard API has rate limiting (1 request per 3 seconds)
    if i > 1:
    time.sleep(3)

    pb.posts.add(
    url=bookmark['url'],
    description=bookmark['description'],
    tags=' '.join(bookmark['tags']),
    dt=bookmark['time'],
    toread=bookmark['toread']
    )

    successful += 1
    print(f"[{i}/{total}] Added: {bookmark['description'][:50]}...")

    except Exception as e:
    failed += 1
    print(f"[{i}/{total}] Failed to add {bookmark['url']}: {str(e)}")

    print(f"\nImport complete!")
    print(f"Successful: {successful}")
    print(f"Failed: {failed}")


    def main():
    parser = argparse.ArgumentParser(description='Import Pocket bookmarks to Pinboard')
    parser.add_argument('csv_file', help='Path to Pocket export CSV file')
    parser.add_argument('api_token', help='Pinboard API token (username:token format)')

    args = parser.parse_args()

    # Parse CSV
    try:
    bookmarks = parse_pocket_csv(args.csv_file)
    print(f"Parsed {len(bookmarks)} bookmarks from CSV")
    except Exception as e:
    print(f"Error reading CSV file: {e}")
    return 1

    # Import to Pinboard
    try:
    import_to_pinboard(bookmarks, args.api_token)
    except Exception as e:
    print(f"Error during import: {e}")
    return 1

    return 0


    if __name__ == '__main__':
    exit(main())