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.9

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.9
File Size Uploaded
letterboxdpy-6.5.9.tar.gz 171.0 kB Details

Built distribution (wheel)

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

Total release size: 262.3 kB

Release files / letterboxdpy-6.5.9.tar.gz

Download URL letterboxdpy-6.5.9.tar.gz
Size 171.0 kB
Tags Source
SHA-256 checksum
How to use checksums
208ceceb6208e6e6da859368ff3c3ee9717ea6cc45c6ad81d736b6a451bc95a7
BLAKE2b-256 checksum
How to use checksums
ad13fe80adfc7be415e79ae567b3f8948676f2b9a281b54efb09734e26c7f244
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.9-py3-none-any.whl

Download URL letterboxdpy-6.5.9-py3-none-any.whl
Size 91.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5f583d1739ac007bc6c417cca90b782dc76b62519ef2cd7ab67dc0e632693974
BLAKE2b-256 checksum
How to use checksums
24ec0fa171531918f2a67ebc56edb93895c817a54dba4794b0f9e08328bd72cd
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

This release

6.5.9 This release

2 release files

6.5.8

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