winther blog

How I made a static website of my Letterboxd reviews

I have several hundred movie reviews on Letterboxd and while I like the site and will continue to use it, it is also nice to have a backup plan and make sure I own and control what I have written. The good thing is that Letterboxd has an export function, that is just a zip file full of CSV files with everything in your profile. I wanted to simply convert the contents of the reviews.csv file and turn it into Markdown files I could then use to build a static site. I have done this using Jekyll but the process could be applied to most similar working Markdown based static site generators.

I wrote a quick and dirty Python script to make Markdown files from the CSV file:

import os
import csv
import slugify

with open('reviews.csv') as csvfile:

    reader = csv.DictReader(csvfile)

    for row in reader:
        entry_date = row['Watched Date']
        entry_year = entry_date.split("-")[0]
        url = row['Letterboxd URI']
        title = row['Name']
        slug = slugify.slugify(title)
        year = row["Year"]
        review = row['Review']
        rating = row['Rating']
        text = f'{title}\n{review}\n{url}'
        filename = f'_posts/{entry_year}/{entry_date}-{slug}.md'
        os.makedirs(os.path.dirname(filename), exist_ok=True)
        with open(filename, 'w') as md_file:
            md_file.write('---\n')
            md_file.write('layout: post\n')
            md_file.write(f'title: "{title} ({year})"\n')
            md_file.write(f'date: {entry_date}\n')
            md_file.write('---\n')
            md_file.write('\n')
            md_file.write(review)
            md_file.write('\n')
            md_file.write('\n')
            md_file.write('---\n\n')
            md_file.write(f'Rating: {rating}\n\n')
            md_file.write(f'[Letterboxd link]({url})')

This gave me a _posts folder I could easily integrate into a very basic Jekyll site. I wanted to have just one page listing all movie reviews in alphabetical order with some easy navigation:

{% assign all_posts = site.posts | sort_natural: "title" %}
{% assign topics_by_letter = all_posts | group_by_exp: "post", "post.title | upcase | slice: 0, 1" %}
<p>
{% for letter in topics_by_letter %}
<a href="#{{ letter.name }}">{{ letter.name }}</a>
{% endfor %}
</p>
{% for letter in topics_by_letter %}
<h2 id="{{ letter.name}}">{{ letter.name }}</h2>
<ul>
    {% for post in letter.items %}
        <li><a href="{{ post.url | relative_url }}">{{ post.title }}</a></li>
    {% endfor %}
</ul>
<a href="#top">back to top</a>
{% endfor %}

It is a bit messy and hacky with the grouping by first letter, but I think the result worked out all right.

While this takes a bit of technical knowledge, I encourage everyone to at least consider using any option of exporting your data from whatever service you currently use. We have seen how otherwise good platforms can turn to shit and if you have invested a lot of time in adding something to that platform, if possible - it is nice to still have that data and maybe use it for something in the future on your own terms.

#tech