Metadata-Version: 2.4
Name: pinterest-downloader
Version: 4.1.0
Summary: Unofficial Python library to download and interact with Pinterest content (pins, videos, GIFs, profiles, and boards). No API key required.
Home-page: https://github.com/x7007x/PinterestDownloader
Author: Ahmed Negm
License: MIT
Project-URL: Bug Tracker, https://github.com/x7007x/PinterestDownloader/issues
Project-URL: PyPI, https://pypi.org/project/pinterest-downloader/
Keywords: pinterest,downloader,pins,boards,profiles,media,images,videos,gifs,scraper,unofficial-api
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Video
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: beautifulsoup4>=4.10.0
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: project-url
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# pinterest-downloader

Unofficial Python library to download and interact with Pinterest content —
pins, videos, GIFs, profiles, and boards — without an API key.

## Features

- 🔎 **Search pins & videos** — paginated keyword search with bookmark support
  (`search`, `search_all`)
- 📁 **Search boards** — find boards by keyword (`search_boards`)
- 📌 **Fetch single pins** — full metadata for images, videos, and GIFs
  (direct MP4 + HLS links, posters, embed data, source attribution)
- 🗂️ **Board feeds** — list every pin saved to a board (`get_board_pins`)
- 👤 **User pins** — list every pin created by a user (`get_user_pins`)
- 👤 **User profiles** — follower/following counts, pin counts, bio, boards
- 📁 **Boards** — board metadata, cover images, and full board lists per user
- ⬇️ **Downloads** — save pin media or an entire board to disk
  (`download_pin`, `download_board`)
- 🛡️ **Graceful errors** — every method returns a dict with an `ok` flag and a
  descriptive `error.message`; no exceptions are raised by the library itself
- 🚀 **No API key required** — works with public Pinterest data

## Install

```bash
pip install pinterest-downloader
```

Dependencies (`requests`, `beautifulsoup4`) are installed automatically.

## Quick Start

```python
from pinterest_downloader import Pinterest

p = Pinterest()

# Get a pin (image / video / gif)
pin = p.get_pin("https://pin.it/xxxxx")
if pin["ok"]:
    print(pin["pin"]["media_type"])  # "image", "video", or "gif"

# Get user profile
profile = p.get_profile("username_or_url_or_id")

# Get board info
board = p.get_board("https://www.pinterest.com/username/board-name/")

# Search for pins
result = p.search("cute cats")
for pin in result["pins"]:
    print(pin["id"], pin["media_type"])
```

All functions return a dictionary with an `"ok"` key (`True` on success,
`False` on error). If `ok` is `False`, an `error` key contains a message.

## API Reference

### `get_pin(url_or_id)`

Retrieves all available data for a single pin.

**Accepts:** full pin URL, short `pin.it` link, or numeric pin ID.

```python
{
    "ok": True,
    "pin": {
        "id": "123456789",
        "title": "...",
        "description": "...",
        "url": "https://www.pinterest.com/pin/123456789/",
        "source_url": "https://...",
        "external_link": "https://...",
        "media_type": "image" | "video" | "gif",
        "images": {
            "170x": {"url": "...", "width": 236, "height": 132},
            "236x": {"url": "...", "width": 236, "height": 132},
            "474x": {"url": "...", "width": 474, "height": 266},
            "736x": {"url": "...", "width": 736, "height": 414},
            "orig": {"url": "...", "width": 1200, "height": 675}
        },
        "created_at": "Thu, 30 Oct 2025 04:39:43 +0000",
        "is_uploaded": False,
        "domain": "...",
        "dominant_color": "#615c67",
        "video": {                        # only for videos
            "formats": [
                {
                    "quality": "V_720P",
                    "url": "https://...mp4",
                    "width": 1920,
                    "height": 1080,
                    "duration": 11378,
                    "thumbnail": "https://..."
                }
            ],
            "mp4_available": True,
            "poster": "https://..."
        },
        "embed": {                        # if available
            "src": "...",
            "width": 290,
            "height": 374,
            "type": "gif"
        },
        "attribution": { ... },           # if available
        "source": {                       # if available
            "url": "...",
            "site_name": "Cheezburger",
            "display_name": "...",
            "type_name": "article"
        }
    },
    "author": {
        "id": "...",
        "username": "...",
        "full_name": "...",
        "image_url": "..."
    },
    "board": {
        "id": "...",
        "name": "...",
        "url": "..."
    },
    "media": {                            # legacy flat media info
        "type": "video",
        "url": "...",
        "video_formats": [...],
        "poster": "..."
    },
    "engagement": {
        "reactions": 96,
        "reactions_detail": {"like": 96},
        "comment_count": 0
    }
}
```

- Reaction labels are descriptive: `like`, `love`, `wow`, `funny`, etc.
- Videos include both HLS (`.m3u8`) and direct MP4 links when available
  (`mp4_available` flag).

### `search(query, page_size=25, bookmark=None, scope="pins")`

Searches for pins and returns a page of results.

- `query` – search keywords.
- `page_size` – number of results per page (max 25).
- `bookmark` – used for pagination; pass the `"bookmark"` value from a
  previous response to get the next page.
- `scope` – `"pins"` (default) or `"videos"` to restrict the results.

```python
{
    "ok": True,
    "query": "cute cats",
    "bookmark": "Y2JVS...",    # for the next page
    "pins": [
        { ... },               # each pin has the same structure as get_pin() minus the full wrapper
        ...
    ]
}
```

### `search_all(query, max_pages=5)`

Convenience method that fetches multiple pages of search results automatically.

```python
{
    "ok": True,
    "query": "cute cats",
    "total": 42,
    "pins": [ ... ]
}
```

### `get_profile(identifier)`

Retrieves a user's public profile and their boards.

**Accepts:** username, `pinterest.com/username` URL, or user ID.

```python
{
    "ok": True,
    "resolved_url": "https://www.pinterest.com/username/",
    "profile": {
        "username": "...",
        "profile_url": "...",
        "full_name": "...",
        "follower_count": 1193,
        "following_count": 101,
        "pin_count": 480,
        "about": "...",
        "id": "123456789",
        "image_url": "...",
        "website_url": "..."
    },
    "boards": [
        {
            "id": "...",
            "name": "Cute Animals",
            "board_url": "https://www.pinterest.com/username/cute-animals/",
            "cover_url": "..."
        },
        ...
    ]
}
```

### `search_boards(query, page_size=25, bookmark=None)`

Searches for boards instead of pins.

```python
{
    "ok": True,
    "query": "cute cats",
    "bookmark": "...",
    "boards": [
        {
            "id": "123",
            "name": "Cute Cats",
            "description": "...",
            "url": "https://www.pinterest.com/wagpets/cute-cats/",
            "pin_count": 1591,
            "cover_url": "...",
            "owner": {"id": "...", "username": "wagpets", "full_name": "Wag Pets"}
        }
    ]
}
```

### `get_board_pins(url_or_id, page_size=25, bookmark=None)`

Retrieves the pins saved to a board, with pagination via `bookmark`.

**Accepts:** a board URL or a numeric board ID.

```python
{
    "ok": True,
    "board": {"id": "...", "name": "...", "url": "..."},
    "bookmark": "...",          # pass to get the next page
    "pins": [ ... ]             # each pin has the same structure as get_pin()
}
```

### `get_user_pins(username, page_size=25, bookmark=None)`

Retrieves the pins created by a user, with pagination via `bookmark`.

```python
{
    "ok": True,
    "username": "...",
    "bookmark": "...",
    "pins": [ ... ]
}
```

### `get_boards(identifier)`

Returns a detailed list of all boards for a user.

**Accepts:** same as `get_profile`.

```python
{
    "ok": True,
    "resolved_url": "...",
    "username": "...",
    "boards": [
        {
            "id": "...",
            "name": "...",
            "description": "...",
            "category": "...",
            "privacy": "public",
            "pin_count": 463,
            "cover_url": "...",
            "board_url": "https://www.pinterest.com/username/board-name/",
            "owner": {"id": "...", "username": "..."}
        }
    ]
}
```

### `get_board(url)`

Retrieves a specific board and also returns the user's full board list.

**Accepts:** board URL (required).

```python
{
    "ok": True,
    "resolved_url": "...",
    "user": {"username": "...", "id": "...", "full_name": "..."},
    "board_slug": "board-name",
    "board": {
        "id": "...",
        "name": "Board Name",
        "description": "...",
        "category": "...",
        "privacy": "public",
        "pin_count": 25,
        "follower_count": 100,
        "board_url": "...",
        "cover_url": "...",
        "owner": {"username": "...", "id": "..."}
    },
    "boards": [ ... ]   # all user boards
}
```

### `download_pin(url_or_id, path=".")`

Downloads a pin's media to disk. Images and GIFs are saved at their original
resolution; videos are saved as the highest-quality MP4 when available
(falling back to the poster image). Files are named `<pin_id>.<ext>`.

```python
{
    "ok": True,
    "path": "./123456789.jpg",
    "filename": "123456789.jpg",
    "url": "https://i.pinimg.com/originals/...",
    "media_type": "image"
}
```

### `download_board(url_or_id, path=".", limit=None)`

Downloads the media of every pin in a board. Walks all pages of the board
feed; pass `limit` to cap the number of pins downloaded.

```python
{
    "ok": True,
    "board": {"id": "...", "name": "..."},
    "downloaded": 25,
    "failed": 0,
    "total_pins": 25,
    "files": ["./123.jpg", ...]
}
```

## Error Handling

When something goes wrong, every method returns:

```python
{"ok": False, "error": {"message": "description of the problem"}}
```

No exceptions are raised by the library itself. Always check the `"ok"` key.

## Development

Run the live smoke tests (requires network access):

```bash
pip install requests beautifulsoup4
python3 test_live.py
```

## License

MIT — Ahmed Negm
