https://github.com/nichtlegacy/letterboxd-graph
Generates a GitHub-style contribution graph based on your Letterboxd diary. Uses Node.js to scrape data, process entries, and create daily updated SVG visuals via GitHub Actions.
https://github.com/nichtlegacy/letterboxd-graph
contribution-graph github-actions javascript letterboxd movies nodejs svg web-scraping
Last synced: 2 months ago
JSON representation
Generates a GitHub-style contribution graph based on your Letterboxd diary. Uses Node.js to scrape data, process entries, and create daily updated SVG visuals via GitHub Actions.
- Host: GitHub
- URL: https://github.com/nichtlegacy/letterboxd-graph
- Owner: nichtlegacy
- License: mit
- Created: 2025-03-25T23:40:56.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2026-04-11T02:36:45.000Z (3 months ago)
- Last Synced: 2026-04-11T04:25:54.827Z (3 months ago)
- Topics: contribution-graph, github-actions, javascript, letterboxd, movies, nodejs, svg, web-scraping
- Language: JavaScript
- Homepage:
- Size: 8.73 MB
- Stars: 8
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# 🎬 Letterboxd Contribution Graph
Transform your Letterboxd film diary into a beautiful GitHub-style contribution graph
---
## ✨ Features
| Feature | Description |
|---------|-------------|
| 🎨 **Light & Dark Themes** | Automatically adapts to GitHub's theme preference |
| 📊 **Activity Heatmap** | GitHub-style contribution graph showing film activity |
| 👤 **Profile Integration** | Shows profile picture, display name, stats, and member badge |
| 🏆 **Pro/Patron Badges** | Displays Letterboxd Pro (orange) or Patron (cyan) status |
| 📅 **Multi-Year Support** | Generate graphs spanning multiple years |
| 🎯 **Streak Highlighting** | Hover over "Day Streak" to highlight your longest streak |
| 💬 **Interactive Tooltips** | Hover over cells to see film details (in browser) |
| ⭐ **Rating Mode** | Color cells by average rating instead of watch count |
| 📦 **JSON Export** | Writes `images/letterboxd-data.json` for external widgets (e.g. Glance `custom-api`) |
| 🔄 **Daily Updates** | Automated updates via GitHub Actions |
---
## 🚀 Quick Start
### 1. Fork this Repository
Click the **Fork** button at the top-right of this page.
### 2. Update Your Username
Edit `.github/workflows/update-graph.yml`:
```yaml
- run: npm start YOUR_LETTERBOXD_USERNAME -o images/github-letterboxd
```
### 3. Enable GitHub Actions
Go to **Actions** tab → Enable workflows if prompted.
### 4. Run the Workflow
The graph updates daily at midnight UTC, or trigger manually via the **Actions** tab.
---
## 📸 Examples
### Patron User (Single Year)
### Pro User (Single Year)
### Multi-Year Graph
### Interactive Features
Hover over stats to reveal additional information (visible when opening the SVG in a browser):
Day Streak Highlight
Days Active Tooltip
Film Count Tooltip
---
## 📖 CLI Usage
```bash
# Install dependencies
npm install
# Basic usage
node src/cli.js
# With options
node src/cli.js [options]
```
### Arguments
| Flag | Description | Default |
|------|-------------|---------|
| `-y ` | Year(s) to generate, comma-separated (e.g. `2024,2023`) | Current year |
| `-w ` | Week start: `sunday` or `monday` | `sunday` |
| `-o ` | Output path (without extension) | `images/github-letterboxd` |
| `-g ` | Enable username gradient: `true` or `false` | `true` |
| `-p` | Export PNG files in addition to SVG | Disabled |
| `-m ` | Graph mode: `count` or `rating` | `count` |
### Examples
```bash
# Single year with custom output
node src/cli.js nichtlegacy -y 2025 -o images/my-graph
# Multiple years (2024 + 2025)
node src/cli.js nichtlegacy -y 2025,2024
# Start week on Monday, no gradient
node src/cli.js nichtlegacy -w monday -g false
# Rating mode with PNG export
node src/cli.js nichtlegacy -m rating -p
```
---
## 🔧 GitHub Actions Setup
### Workflow File
Create `.github/workflows/update-graph.yml`:
```yaml
name: Update Letterboxd Graph
# ╔════════════════════════════════════════════════════════════════╗
# ║ CONFIGURATION - Edit these values for your Letterboxd profile ║
# ╚════════════════════════════════════════════════════════════════╝
env:
LETTERBOXD_USERNAME: "YOUR_USERNAME" # Replace with your username
YEARS: "" # e.g. "2025,2024" or leave empty for current year
EXPORT_PNG: "false" # Set to "true" to also generate PNG files
WEEK_START: "sunday" # "sunday" or "monday"
GRADIENT: "true" # "true" for colored name, "false" for white
on:
schedule:
- cron: "0 0 * * *" # Daily at midnight UTC
workflow_dispatch: # Manual trigger
permissions:
contents: write
jobs:
update-graph:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Generate Graph
run: |
# Build command based on configuration
CMD="node src/cli.js ${{ env.LETTERBOXD_USERNAME }} -o images/github-letterboxd"
if [ -n "${{ env.YEARS }}" ]; then CMD="$CMD -y ${{ env.YEARS }}"; fi
if [ "${{ env.WEEK_START }}" = "monday" ]; then CMD="$CMD -w monday"; fi
if [ "${{ env.GRADIENT }}" = "false" ]; then CMD="$CMD -g false"; fi
if [ "${{ env.EXPORT_PNG }}" = "true" ]; then CMD="$CMD -p"; fi
echo "Running: $CMD"
eval $CMD
- name: Commit and Push
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
git add images/
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "Update Letterboxd graph"
git push
fi
```
### Configuration
You can customize the graph directly in the workflow file by editing the `env` section at the top:
- **LETTERBOXD_USERNAME**: Your Letterboxd profile name
- **YEARS**: Comma-separated list of years (e.g., `2025,2024`)
- **EXPORT_PNG**: Set to `true` if you want PNG versions alongside SVGs
- **WEEK_START**: Start week on `sunday` or `monday`
- **GRADIENT**: Toggle the username text gradient
---
### Glance Widgets (custom-api)
The generator also writes `images/letterboxd-data.json`, so you can build Glance widgets without running an extra backend container.
Raw URL format:
```
https://raw.githubusercontent.com//letterboxd-graph/main/images/letterboxd-data.json
```
Example payload shape:
```json
{
"user": "nichtlegacy",
"year": 2026,
"stats": { "films": 123, "daysActive": 80, "streak": 7 },
"cells": [
{
"date": "2026-02-16",
"count": 2,
"ratingAvg": 3.5,
"films": [
{ "title": "Film A", "year": "2024", "rating": 3.5, "url": "https://letterboxd.com/..." }
],
"url": "https://letterboxd.com//films/diary/for/2026/02/16/"
}
],
"recent": [
{ "date": "2026-02-16", "title": "Film A", "year": "2024", "rating": 3.5, "url": "https://letterboxd.com/..." }
]
}
```
You can use this to build:
- a compact heatmap widget (GitHub-like)
- a separate stats widget (`films`, `daysActive`, `streak`)
- an optional recent-watches list
## 📂 Project Structure
```
letterboxd-graph/
├── .github/
│ ├── assets/ # README images and examples
│ └── workflows/
│ └── update-graph.yml # GitHub Actions workflow
├── fonts/
│ ├── Inter-Bold.ttf
│ ├── Inter-Medium.ttf
│ ├── Inter-Regular.ttf
│ └── Inter-SemiBold.ttf # Primary font for text measurement
├── images/
│ ├── github-letterboxd-dark.svg # Generated dark theme
│ ├── github-letterboxd-light.svg # Generated light theme
│ └── letterboxd-data.json # Generated JSON data for widgets
├── src/
│ ├── cli.js # CLI entry point
│ ├── fetcher.js # Letterboxd data fetching
│ ├── generator.js # SVG generation
│ ├── stats.js # Statistics calculations
│ └── exporter.js # PNG export functionality
├── package.json
└── README.md
```
---
## 🖼️ Embed in Your README
Add this to your profile README to display the graph with automatic theme switching:
```html
```
Replace `YOUR_GITHUB_USERNAME` and `YOUR_LETTERBOXD_USERNAME` with your usernames.
---
## 🎨 Themes & Modes
### Graph Modes
| Mode | Description |
|------|-------------|
| **Count** (default) | Cell color intensity based on number of films watched |
| **Rating** | Cell color based on average rating of films that day |
### Member Badges
The graph automatically detects and displays your Letterboxd membership status:
| Status | Badge Color | Location |
|--------|-------------|----------|
| **Pro** | Orange (#ff8000) | Bottom-left of profile picture |
| **Patron** | Cyan (#40bcf4) | Bottom-left of profile picture |
---
## 🛠️ Requirements
- **Node.js** v18 or higher
- **Public Letterboxd profile** with diary entries
- **GitHub account** with Actions enabled (for automated updates)
---
## 🤝 Contributing
Contributions are welcome! Feel free to:
- 🐛 Report bugs
- 💡 Suggest features
- 🔧 Submit pull requests
---
## 📄 License
MIT License - see [LICENSE](LICENSE) for details.