{"id":27096206,"url":"https://github.com/nichtlegacy/letterboxd-graph","last_synced_at":"2026-04-17T10:07:43.042Z","repository":{"id":284450799,"uuid":"954987902","full_name":"nichtlegacy/letterboxd-graph","owner":"nichtlegacy","description":"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.","archived":false,"fork":false,"pushed_at":"2026-04-11T02:36:45.000Z","size":9150,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-11T04:25:54.827Z","etag":null,"topics":["contribution-graph","github-actions","javascript","letterboxd","movies","nodejs","svg","web-scraping"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nichtlegacy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-25T23:40:56.000Z","updated_at":"2026-04-11T02:36:49.000Z","dependencies_parsed_at":"2025-04-10T02:21:51.687Z","dependency_job_id":"974ac8e5-8e41-4323-a181-fe50e9e96133","html_url":"https://github.com/nichtlegacy/letterboxd-graph","commit_stats":null,"previous_names":["nichtlegacy/letterboxd-graph"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/nichtlegacy/letterboxd-graph","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichtlegacy%2Fletterboxd-graph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichtlegacy%2Fletterboxd-graph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichtlegacy%2Fletterboxd-graph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichtlegacy%2Fletterboxd-graph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nichtlegacy","download_url":"https://codeload.github.com/nichtlegacy/letterboxd-graph/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nichtlegacy%2Fletterboxd-graph/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31924408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T09:10:15.403Z","status":"ssl_error","status_checked_at":"2026-04-17T09:10:14.455Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["contribution-graph","github-actions","javascript","letterboxd","movies","nodejs","svg","web-scraping"],"created_at":"2025-04-06T09:34:59.127Z","updated_at":"2026-04-17T10:07:43.036Z","avatar_url":"https://github.com/nichtlegacy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎬 Letterboxd Contribution Graph\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/nichtlegacy/letterboxd-graph/update-graph.yml?label=action\u0026style=flat-square\" alt=\"GitHub Workflow Status\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/release/nichtlegacy/letterboxd-graph.svg?style=flat-square\" alt=\"GitHub Release\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Made%20with-Node.js-green?style=flat-square\" alt=\"Made with Node.js\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/JavaScript-ES6+-yellow?style=flat-square\" alt=\"JavaScript\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-blue?style=flat-square\" alt=\"License\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eTransform your Letterboxd film diary into a beautiful GitHub-style contribution graph\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://letterboxd.com/nichtlegacy/\" target=\"_blank\"\u003e\n    \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/nichtlegacy/letterboxd-graph/blob/main/images/github-letterboxd-dark.svg\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://github.com/nichtlegacy/letterboxd-graph/blob/main/images/github-letterboxd-light.svg\"\u003e\n      \u003cimg alt=\"Letterboxd contribution graph\" src=\"https://github.com/nichtlegacy/letterboxd-graph/blob/main/images/github-letterboxd-light.svg\" width=\"100%\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## ✨ Features\n\n| Feature | Description |\n|---------|-------------|\n| 🎨 **Light \u0026 Dark Themes** | Automatically adapts to GitHub's theme preference |\n| 📊 **Activity Heatmap** | GitHub-style contribution graph showing film activity |\n| 👤 **Profile Integration** | Shows profile picture, display name, stats, and member badge |\n| 🏆 **Pro/Patron Badges** | Displays Letterboxd Pro (orange) or Patron (cyan) status |\n| 📅 **Multi-Year Support** | Generate graphs spanning multiple years |\n| 🎯 **Streak Highlighting** | Hover over \"Day Streak\" to highlight your longest streak |\n| 💬 **Interactive Tooltips** | Hover over cells to see film details (in browser) |\n| ⭐ **Rating Mode** | Color cells by average rating instead of watch count |\n| 📦 **JSON Export** | Writes `images/letterboxd-data.json` for external widgets (e.g. Glance `custom-api`) |\n| 🔄 **Daily Updates** | Automated updates via GitHub Actions |\n\n---\n\n## 🚀 Quick Start\n\n### 1. Fork this Repository\n\nClick the **Fork** button at the top-right of this page.\n\n### 2. Update Your Username\n\nEdit `.github/workflows/update-graph.yml`:\n\n```yaml\n- run: npm start YOUR_LETTERBOXD_USERNAME -o images/github-letterboxd\n```\n\n### 3. Enable GitHub Actions\n\nGo to **Actions** tab → Enable workflows if prompted.\n\n### 4. Run the Workflow\n\nThe graph updates daily at midnight UTC, or trigger manually via the **Actions** tab.\n\n---\n\n## 📸 Examples\n\n### Patron User (Single Year)\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/behaind-dark.svg\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Pro User (Single Year)\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/rufus_firefly-dark.svg\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Multi-Year Graph\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\".github/assets/nichtlegacy-dark.svg\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n### Interactive Features\n\nHover over stats to reveal additional information (visible when opening the SVG in a browser):\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eDay Streak Highlight\u003c/th\u003e\n    \u003cth\u003eDays Active Tooltip\u003c/th\u003e\n    \u003cth\u003eFilm Count Tooltip\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\".github/assets/hover-streak.png\" width=\"250\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\".github/assets/hover-days-active.png\" width=\"250\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg src=\".github/assets/hover-films.png\" width=\"250\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n## 📖 CLI Usage\n\n```bash\n# Install dependencies\nnpm install\n\n# Basic usage\nnode src/cli.js \u003cusername\u003e\n\n# With options\nnode src/cli.js \u003cusername\u003e [options]\n```\n\n### Arguments\n\n| Flag | Description | Default |\n|------|-------------|---------|\n| `-y \u003cyears\u003e` | Year(s) to generate, comma-separated (e.g. `2024,2023`) | Current year |\n| `-w \u003cday\u003e` | Week start: `sunday` or `monday` | `sunday` |\n| `-o \u003cpath\u003e` | Output path (without extension) | `images/github-letterboxd` |\n| `-g \u003cbool\u003e` | Enable username gradient: `true` or `false` | `true` |\n| `-p` | Export PNG files in addition to SVG | Disabled |\n| `-m \u003cmode\u003e` | Graph mode: `count` or `rating` | `count` |\n\n### Examples\n\n```bash\n# Single year with custom output\nnode src/cli.js nichtlegacy -y 2025 -o images/my-graph\n\n# Multiple years (2024 + 2025)\nnode src/cli.js nichtlegacy -y 2025,2024\n\n# Start week on Monday, no gradient\nnode src/cli.js nichtlegacy -w monday -g false\n\n# Rating mode with PNG export\nnode src/cli.js nichtlegacy -m rating -p\n```\n\n---\n\n## 🔧 GitHub Actions Setup\n\n### Workflow File\n\nCreate `.github/workflows/update-graph.yml`:\n\n```yaml\nname: Update Letterboxd Graph\n\n# ╔════════════════════════════════════════════════════════════════╗\n# ║  CONFIGURATION - Edit these values for your Letterboxd profile ║\n# ╚════════════════════════════════════════════════════════════════╝\nenv:\n  LETTERBOXD_USERNAME: \"YOUR_USERNAME\" # Replace with your username\n  YEARS: \"\"                            # e.g. \"2025,2024\" or leave empty for current year\n  EXPORT_PNG: \"false\"                  # Set to \"true\" to also generate PNG files\n  WEEK_START: \"sunday\"                 # \"sunday\" or \"monday\"\n  GRADIENT: \"true\"                     # \"true\" for colored name, \"false\" for white\n\non:\n  schedule:\n    - cron: \"0 0 * * *\"   # Daily at midnight UTC\n  workflow_dispatch:       # Manual trigger\n\npermissions:\n  contents: write\n\njobs:\n  update-graph:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      \n      - uses: actions/setup-node@v4\n        with:\n          node-version: '20'\n          cache: 'npm'\n      \n      - run: npm ci\n      \n      - name: Generate Graph\n        run: |\n          # Build command based on configuration\n          CMD=\"node src/cli.js ${{ env.LETTERBOXD_USERNAME }} -o images/github-letterboxd\"\n          \n          if [ -n \"${{ env.YEARS }}\" ]; then CMD=\"$CMD -y ${{ env.YEARS }}\"; fi\n          if [ \"${{ env.WEEK_START }}\" = \"monday\" ]; then CMD=\"$CMD -w monday\"; fi\n          if [ \"${{ env.GRADIENT }}\" = \"false\" ]; then CMD=\"$CMD -g false\"; fi\n          if [ \"${{ env.EXPORT_PNG }}\" = \"true\" ]; then CMD=\"$CMD -p\"; fi\n          \n          echo \"Running: $CMD\"\n          eval $CMD\n\n      - name: Commit and Push\n        run: |\n          git config --global user.name 'github-actions[bot]'\n          git config --global user.email 'github-actions[bot]@users.noreply.github.com'\n          git add images/\n          \n          if git diff --staged --quiet; then\n            echo \"No changes to commit\"\n          else\n            git commit -m \"Update Letterboxd graph\"\n            git push\n          fi\n```\n\n### Configuration\n\nYou can customize the graph directly in the workflow file by editing the `env` section at the top:\n\n- **LETTERBOXD_USERNAME**: Your Letterboxd profile name\n- **YEARS**: Comma-separated list of years (e.g., `2025,2024`)\n- **EXPORT_PNG**: Set to `true` if you want PNG versions alongside SVGs\n- **WEEK_START**: Start week on `sunday` or `monday`\n- **GRADIENT**: Toggle the username text gradient\n\n---\n\n\n### Glance Widgets (custom-api)\n\nThe generator also writes `images/letterboxd-data.json`, so you can build Glance widgets without running an extra backend container.\n\nRaw URL format:\n\n```\nhttps://raw.githubusercontent.com/\u003cgithub-user\u003e/letterboxd-graph/main/images/letterboxd-data.json\n```\n\nExample payload shape:\n\n```json\n{\n  \"user\": \"nichtlegacy\",\n  \"year\": 2026,\n  \"stats\": { \"films\": 123, \"daysActive\": 80, \"streak\": 7 },\n  \"cells\": [\n    {\n      \"date\": \"2026-02-16\",\n      \"count\": 2,\n      \"ratingAvg\": 3.5,\n      \"films\": [\n        { \"title\": \"Film A\", \"year\": \"2024\", \"rating\": 3.5, \"url\": \"https://letterboxd.com/...\" }\n      ],\n      \"url\": \"https://letterboxd.com/\u003cuser\u003e/films/diary/for/2026/02/16/\"\n    }\n  ],\n  \"recent\": [\n    { \"date\": \"2026-02-16\", \"title\": \"Film A\", \"year\": \"2024\", \"rating\": 3.5, \"url\": \"https://letterboxd.com/...\" }\n  ]\n}\n```\n\nYou can use this to build:\n\n- a compact heatmap widget (GitHub-like)\n- a separate stats widget (`films`, `daysActive`, `streak`)\n- an optional recent-watches list\n\n## 📂 Project Structure\n\n```\nletterboxd-graph/\n├── .github/\n│   ├── assets/               # README images and examples\n│   └── workflows/\n│       └── update-graph.yml  # GitHub Actions workflow\n├── fonts/\n│   ├── Inter-Bold.ttf\n│   ├── Inter-Medium.ttf\n│   ├── Inter-Regular.ttf\n│   └── Inter-SemiBold.ttf    # Primary font for text measurement\n├── images/\n│   ├── github-letterboxd-dark.svg    # Generated dark theme\n│   ├── github-letterboxd-light.svg   # Generated light theme\n│   └── letterboxd-data.json          # Generated JSON data for widgets\n├── src/\n│   ├── cli.js                # CLI entry point\n│   ├── fetcher.js            # Letterboxd data fetching\n│   ├── generator.js          # SVG generation\n│   ├── stats.js              # Statistics calculations\n│   └── exporter.js           # PNG export functionality\n├── package.json\n└── README.md\n```\n\n---\n\n## 🖼️ Embed in Your README\n\nAdd this to your profile README to display the graph with automatic theme switching:\n\n```html\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://letterboxd.com/YOUR_LETTERBOXD_USERNAME/\" target=\"_blank\"\u003e\n    \u003cpicture\u003e\n      \u003csource\n        media=\"(prefers-color-scheme: dark)\"\n        srcset=\"https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-dark.svg\"\n      /\u003e\n      \u003csource\n        media=\"(prefers-color-scheme: light)\"\n        srcset=\"https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-light.svg\"\n      /\u003e\n      \u003cimg\n        alt=\"Letterboxd contribution graph\"\n        src=\"https://github.com/YOUR_GITHUB_USERNAME/letterboxd-graph/blob/main/images/github-letterboxd-light.svg\"\n      /\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n```\n\nReplace `YOUR_GITHUB_USERNAME` and `YOUR_LETTERBOXD_USERNAME` with your usernames.\n\n---\n\n## 🎨 Themes \u0026 Modes\n\n### Graph Modes\n\n| Mode | Description |\n|------|-------------|\n| **Count** (default) | Cell color intensity based on number of films watched |\n| **Rating** | Cell color based on average rating of films that day |\n\n### Member Badges\n\nThe graph automatically detects and displays your Letterboxd membership status:\n\n| Status | Badge Color | Location |\n|--------|-------------|----------|\n| **Pro** | Orange (#ff8000) | Bottom-left of profile picture |\n| **Patron** | Cyan (#40bcf4) | Bottom-left of profile picture |\n\n---\n\n## 🛠️ Requirements\n\n- **Node.js** v18 or higher\n- **Public Letterboxd profile** with diary entries\n- **GitHub account** with Actions enabled (for automated updates)\n\n---\n\n## 🤝 Contributing\n\nContributions are welcome! Feel free to:\n\n- 🐛 Report bugs\n- 💡 Suggest features\n- 🔧 Submit pull requests\n\n---\n\n## 📄 License\n\nMIT License - see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnichtlegacy%2Fletterboxd-graph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnichtlegacy%2Fletterboxd-graph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnichtlegacy%2Fletterboxd-graph/lists"}