Skip to main content

letterboxdpy

A Python library for Letterboxd data
Simple, modern, and easy-to-use toolkit for movies, users, and more.

PyPI version Python Version License Downloads Weekly DOM Health Check


Installation

From PyPI

You can easily install the stable version of letterboxdpy from PyPI using pip:

pip install letterboxdpy

From GitHub Repository

Alternatively, if you wish to access the latest (potentially unstable) version directly from the GitHub repository, you can execute the following command:

pip install git+https://github.com/nmcassa/letterboxdpy.git

Local Installation (for Development)

If you have cloned the repository locally and want to make changes to the code, it is recommended to install it in "editable" mode. This allows you to run the library files directly and see your changes reflected immediately:

pip install -e .

# Or with example dependencies
pip install -e ".[examples]"

Core Objects

User Object

Explore the file | Functions Documentation

from letterboxdpy.user import User
user_instance = User("nmcassa")
print(user_instance)
Click to expand User object response
{
  "username": "nmcassa",
  "url": "https://letterboxd.com/nmcassa",
  "id": 1500306,
  "is_hq": false,
  "display_name": "nmcassa",
  "bio": null,
  "location": null,
  "website": null,
  "watchlist_length": 76,
  "stats": {
    "films": 702,
    "this_year": 7,
    "lists": 2,
    "following": 8,
    "followers": 8
  },
  "favorites": {
    "51794": {
      "slug": "the-king-of-comedy",
      "name": "The King of Comedy",
      "url": "https://letterboxd.com/film/the-king-of-comedy/",
      "year": 1982,
      "log_url": "https://letterboxd.com/nmcassa/film/the-king-of-comedy/activity/"
    },
    "...": "..."
  },
  "avatar": {
    "exists": true,
    "upscaled": true,
    "url": "https://a.ltrbxd.com/resized/avatar/upload/1/5/0/0/3/0/6/shard/avtr-0-1000-0-1000-crop.jpg"
  },
  "recent": {
    "watchlist": {
      "703077": {
        "id": "703077",
        "slug": "magazine-dreams",
        "name": "Magazine Dreams",
        "year": 2023
      },
      "...": "..."
    },
    "diary": {
      "months": {
        "1": {
          "31": [
            {
              "name": "If I Had Legs I'd Kick You",
              "slug": "if-i-had-legs-id-kick-you"
            }
          ],
          "...": "..."
        }
      }
    }
  }
}

Movie Object

Explore the file | Functions Documentation

from letterboxdpy.movie import Movie

# lookup by slug
movie_instance = Movie("v-for-vendetta")

# lookup by external ids
movie_instance = Movie(tmdb=752)
movie_instance = Movie(imdb="tt0434409")

# or using factory methods
movie_instance = Movie.from_tmdb(752)
movie_instance = Movie.from_imdb("tt0434409")

print(movie_instance)
Click to expand Movie object response
{
  "url": "https://letterboxd.com/film/v-for-vendetta",
  "slug": "v-for-vendetta",
  "id": "51400",
  "title": "V for Vendetta",
  "original_title": null,
  "runtime": 132,
  "rating": 3.84,
  "year": 2005,
  "tmdb_link": "https://www.themoviedb.org/movie/752/",
  "tmdb_id": "752",
  "imdb_link": "http://www.imdb.com/title/tt0434409/maindetails",
  "imdb_id": "tt0434409",
  "poster": "https://a.ltrbxd.com/resized/film-poster/5/1/4/0/0/51400-v-for-vendetta-0-230-0-345-crop.jpg",
  "banner": "https://a.ltrbxd.com/resized/sm/upload/mx/jg/tz/ni/v-for-vendetta-1920-1920-1080-1080-crop-000000.jpg",
  "tagline": "People should not be afraid of their governments. Governments should be afraid of their people.",
  "description": "In a world in which Great Britain has become a fascist state...",
  "trailer": {
    "id": "3ge0navn9E0",
    "link": "https://www.youtube.com/watch?v=3ge0navn9E0",
    "embed_url": "https://www.youtube.com/embed/3ge0navn9E0"
  },
  "alternative_titles": [
    "Vendetta \u00fc\u00e7\u00fcn V",
    "O za osvetu",...
  ],
  "details": [
    {
      "type": "studio",
      "name": "Virtual Studios",
      "slug": "virtual-studios",
      "url": "https://letterboxd.com/studio/virtual-studios/"
    },
    "..."
  ],
  "genres": [
    {
      "type": "genre",
      "name": "Thriller",
      "slug": "thriller",
      "url": "https://letterboxd.com/films/genre/thriller/"
    },
    "..."
  ],
  "cast": [
    {
      "name": "Natalie Portman",
      "role_name": "Evey Hammond",
      "slug": "natalie-portman",
      "url": "https://letterboxd.com/actor/natalie-portman/"
    },
    "..."
  ],
  "crew": {
    "director": [
      {
        "name": "James McTeigue",
        "slug": "james-mcteigue",
        "url": "https://letterboxd.com/director/james-mcteigue/"
      }
    ],
    "...": "..."
  },
  "popular_reviews": [
    {
      "user": {
        "username": "zoeyluke",
        "display_name": "zoey luke"
      },
      "link": "https://letterboxd.com/zoeyluke/film/v-for-vendetta/3/",
      "rating": 4.5,
      "review": "I love natalie Portman and I hate the government"
    },
    "...": "..."
  ]
}

Explore the file | Functions Documentation

from letterboxdpy.search import Search
search_instance = Search("V for Vendetta", 'films')
print(search_instance.get_results(5))
Click to expand Search object response
{
  "available": true,
  "query": "V%20for%20Vendetta",
  "filter": "films",
  "end_page": 1,
  "count": 5,
  "results": [
    {
      "no": 1,
      "page": 1,
      "type": "film",
      "slug": "v-for-vendetta",
      "name": "V for Vendetta",
      "year": 2005,
      "url": "https://letterboxd.com/film/v-for-vendetta/",
      "poster": "https://s.ltrbxd.com/static/img/empty-poster-70-BSf-Pjrh.png",
      "directors": [
        {
          "name": "James McTeigue",
          "slug": "james-mcteigue",
          "url": "https://letterboxd.com/director/james-mcteigue/"
        }
      ]
    },
    {
      "no": 2,
      "page": 1,
      "type": "film",
      "slug": "lady-vengeance",
      "name": "Lady Vengeance",
      "year": 2005,
      "url": "https://letterboxd.com/film/lady-vengeance/",
      "poster": null,
      "directors": [
        {
          "name": "Park Chan-wook",
          "slug": "park-chan-wook",
          "url": "https://letterboxd.com/director/park-chan-wook/"
        }
      ]
    },...
  ]
}

List Object

Explore the file

from letterboxdpy.list import List
list_instance = List("nmcassa", "movies-to-watch-with-priscilla-park")
list_instance.movies # fetch movies (lazy loading)
print(list_instance)
Click to expand List object response
{
  "username": "nmcassa",
  "slug": "movies-to-watch-with-priscilla-park",
  "url": "https://letterboxd.com/nmcassa/list/movies-to-watch-with-priscilla-park",
  "list_id": "31052453",
  "title": "Movies to Watch with Priscilla Park",
  "author": "nmcassa",
  "count": 2,
  "date_created": "2024-05-18T16:44:57.013000Z",
  "date_updated": "2024-05-20T14:58:06.486000Z",
  "description": null,
  "tags": [],
  "_movies": {
    "240344": {
      "slug": "la-la-land",
      "name": "La La Land",
      "year": 2016,
      "url": "https://letterboxd.com/film/la-la-land/"
    },
    "...": "..."
  }
}

Members Object

Explore the file | Functions Documentation

from letterboxdpy.members import Members
members_instance = Members(max=5)
print(members_instance.members)
Click to expand Members object response
[
  "schaffrillas",
  "kurstboy",
  "demiadejuyigbe",
  "zoerosebryant",
  "jaragon23"
]

Films Object

Explore the file | Functions Documentation

from letterboxdpy.films import Films
films_instance = Films("https://letterboxd.com/films/popular/", max=3)
print(films_instance.movies)
Click to expand Films object response
{
  "1197499": {
    "slug": "marty-supreme",
    "name": "Marty Supreme",
    "rating": 4.21,
    "url": "https://letterboxd.com/film/marty-supreme/"
  },
  "772232": {
    "slug": "hamnet",
    "name": "Hamnet",
    "rating": 4.22,
    "url": "https://letterboxd.com/film/hamnet/"
  },
  "1116600": {
    "slug": "sinners-2025",
    "name": "Sinners",
    "rating": 4.11,
    "url": "https://letterboxd.com/film/sinners-2025/"
  }
}

Watchlist Object

Explore the file

from letterboxdpy.watchlist import Watchlist
watchlist = Watchlist("nmcassa")
watchlist.movies # fetch movies (lazy loading)
print(watchlist)
Click to expand Watchlist object response
{
  "username": "nmcassa",
  "url": "https://letterboxd.com/nmcassa/watchlist",
  "count": 134,
  "movies": {
    "51315": {
      "slug": "videodrome",
      "name": "Videodrome",
      "year": 1983,
      "url": "https://letterboxd.com/film/videodrome/"
    },
    "...": "..."
  }
}

Advanced Features

Authentication & Sessions

Explore the file

The UserSession module unlocks account-specific features like profile customization and settings management. It handles login securely and persists your session, so you don't have to sign in every time.

from letterboxdpy.auth import UserSession

# Logs in if no session exists, or loads the saved session automatically
session = UserSession.ensure()

# 2. Programmatic login
# session = UserSession.login("username", "password")

# 3. Manual load from custom path
# session = UserSession.load(Path(".cookie/session.json"))

print(f"Authenticated as: {session.username}")

User Settings

Explore the file

The UserSettings module allows reading and updating user profile and notification settings. Requires an authenticated session.

from letterboxdpy.account.settings import UserSettings

settings = UserSettings(session)

# Get current profile data
profile = settings.get_profile()
print(f"Current Bio: {profile['bio']}")

# Update specific profile fields
settings.update_profile({
    "location": "New York, USA",
    "website": "https://example.com",
    "bio": "Just another movie lover."
})

# Manage notifications
notifs = settings.get_notifications()
settings.update_notifications({"emailEditorial": True, "pushFollowers": False})

Development

Requirements

This project requires Python 3.10 or higher.

# Core installation
pip install letterboxdpy

# With example dependencies
pip install "letterboxdpy[examples]"

Examples

Example scripts demonstrating various features are available in the examples/ directory.

See examples/README.md for detailed usage instructions.

Linting

This project uses Ruff for linting and formatting, configured in pyproject.toml.

# Check for issues
ruff check .

# Auto-fix issues
ruff check --fix .

# Format code
ruff format .

Testing

Run the full test suite using pytest:

python -m pytest tests

Or run a specific test file:

python -m pytest tests/test_movie.py

Pre-commit Hooks

Pre-commit hooks automatically run Ruff and the test suite before every commit, ensuring no broken or non-compliant code enters the repository.

# Install hooks (one-time setup)
pre-commit install

# Run manually against all files
pre-commit run --all-files

CI Pipeline

GitHub Actions automatically runs linting and tests on every push and pull request against the main branch, across all supported Python versions.

See .github/workflows/ci.yml for the full pipeline configuration.


Contributors


License

MIT License — Free to use, modify, and share.


Stargazers over time:
Stargazers over time
Built by the Letterboxdpy community

Metadata

Release files for letterboxdpy 6.5.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for letterboxdpy 6.5.8
File Size Uploaded
letterboxdpy-6.5.8.tar.gz 171.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for letterboxdpy 6.5.8
File Interpreter ABI Platform
letterboxdpy-6.5.8-py3-none-any.whl Python 3 none any Details

Total release size: 262.1 kB

Release files / letterboxdpy-6.5.8.tar.gz

Download URL letterboxdpy-6.5.8.tar.gz
Size 171.0 kB
Tags Source
SHA-256 checksum
How to use checksums
293d5cbdde185474fa9044d3d0fc39b4ecafd5543b04b77736e2b658d48b0158
BLAKE2b-256 checksum
How to use checksums
902e9c78cf66c193ee6a5c66c981884f333cb4818446e780885edf0057e6d1dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / letterboxdpy-6.5.8-py3-none-any.whl

Download URL letterboxdpy-6.5.8-py3-none-any.whl
Size 91.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c896acb3e1aefc1899277bc8c0e6a5838fc92a73861f9fb0951747be20ca5d6d
BLAKE2b-256 checksum
How to use checksums
6eca1c75425403b247db28f261cc65579a9e7e9780ffc9864048baf20635a69c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

6.5.9

2 release files

This release

6.5.8 This release

2 release files

6.5.7

2 release files

6.5.6

2 release files

6.5.5

2 release files

6.5.4

2 release files

6.5.3

2 release files

6.5.2

2 release files

6.5.1

2 release files

6.5.0

2 release files

6.4.1

2 release files

6.4.0

2 release files

6.3.0

2 release files

6.2.0

2 release files

6.1.0

2 release files

6.0.0

2 release files

5.3.7

2 release files

5.1.1

2 release files

5.1

2 release files

5.0

2 release files

4.5

2 release files

4.2

2 release files

4.1

2 release files

4.0

2 release files

3.17

2 release files

3.15

2 release files

3.1

2 release files

3

2 release files

2.75

2 release files

2.5

2 release files

2.2

2 release files

2.1

2 release files

2

2 release files

1.8

2 release files

1.7

2 release files

1.6

2 release files

1.5

1 release file

1.4

1 release file

1.3

1 release file

1.2

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page