Movie Tracking

Published 2024-01-06 Link to heading

For the last few years I’ve watched somewhere around 60-80 films a year. In 2020 I started tracking my movie watching in a pretty rudimentary way - I just have a note in Google Keep with an ordered list of all the movies, like:

1. Movie One (1945)
2. Movie Two (2022)
...

At some point it’d be nice to move everything over to Letterboxd, but I don’t really use the information for anything, and this method is extremely fast - no log-ins or searching required. I mainly keep the list because I have a hard time remembering what exactly I’ve watched lately, and it’s nice to figure out if I did see a particular film several years later (and it’s interesting - somewhat - to know how many I’ve watched in a year vs the last).

One thing I did want to understand was the distribution of release years represented and if that’s changed over time. I’ve always really liked action/sci-fi films from the 80s and 90s, and I expected to see a fall-off on either side - though the past two years I’ve watched a lot more films from the 1970s (or did I? only the data will tell).

I wanted to use Observable (observablehq.com) to show this - I worked with D3 a long time ago, so I thought I could come up to speed quickly, and it’s nice to be able to embed charts. Turns out Observable is very complex! Rather than sit down and read the docs, I just forked an existing chart that looked like the one I wanted and bashed the code till I go to a stable point.

To get the data into an easy JSON format, I built a simple go script to parse that note format above and spit out a JSON array like:

[ { title: "title", year_watched: 2022, year_released: 1975 }, ...]

I don’t actually use the title in the graph, but maybe I will later. Here’s the entire Go script - which was mostly written by ChatGPT:

movie_format.go ``` package main
import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "regexp"
    "strings"
)

func main() {

    // Check if a file location argument is provided
    if len(os.Args) != 3 {
        fmt.Println("Usage: go run main.go <year> <file_location>")
        return
    }

    // Read the file location from the command-line argument
    yearWatched := os.Args[1]
    fileLocation := os.Args[2]

    // Read the content of the text file into a string
    fileContent, err := ioutil.ReadFile(fileLocation)
    if err != nil {
        fmt.Println("Error reading the file:", err)
        return
    }

    // Convert the file content to a string
    input := string(fileContent)

    // Split the input into lines
    lines := strings.Split(input, "\n")

    // Initialize an empty slice to hold the movie objects
    movies := []map[string]interface{}{}

    // Define a regular expression to match the movie names and years
    re := regexp.MustCompile(`(\d+)\.\s+(.*?)\s+\((\d+)\)`)

    // Iterate through each line and extract movie details
    for _, line := range lines {
        matches := re.FindStringSubmatch(line)
        if len(matches) == 4 {
            movie := map[string]interface{}{
                "year_watched":  yearWatched,
                "title":         matches[2],
                "year_released": matches[3],
            }
            movies = append(movies, movie)
        }
    }

    // Convert the movie slice to JSON
    jsonData, err := json.Marshal(movies)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }

    // Print the JSON
    fmt.Println(string(jsonData))
}
```

After that, I just had to set up the data sources in Observable and format the chart appropriately.

You can see it on the site, but the code itself ends up being pretty simple:

Observable Plot
   moviePlot = Plot.plot({
   y: {tickFormat: "s", grid: true},
   x: {interval: 1, tickFormat: (num) => num.toString()},
   color: {scheme: "observable10", legend: true},
   grid: true,
   marks: [
       Plot.rectY(data, {y: "count" ,
       x: "year_released", fill: "year_watched", fy: "year_watched"
       }),
       Plot.ruleY([0])
   ]
   })

I thought at first it should be a grouped bar chart - like this - but I think there are too many years to make that readable. (You can see the output on the site - the bars are tiny). Luckily I found the facet ability: https://observablehq.com/plot/features/facets which lets you separate out the data into little charts.

Lessons Link to heading

  1. Observable is very powerful and has a pretty steep learning curve. I hope to find more reasons to use it so I’m a little more comfortable - the underlying D3 concepts of scales and transforms came back, but the sheer number of concepts is a bit overwhelming.
  2. In 2021 I watched a ton of new movies - this was when Warner announced they would release all 16 of their films same-day to both theaters and the streaming service formerly known as HBO Max, and I decided to watch all of them 1. Yes, even Tom & Jerry, which I enjoyed more than most critics.
  3. Movies from the new millenium (2000-2020) continue to be a dead-zone for what I like watching now. No surprise and unlikely to change.
  4. The 70s are really growing in interest over time - I like Criterion Channel, which has had a few collections of 70s Horror and 70s Sci-fi 2, and since then I’ve enjoyed diving into conspiracy thrillers (Three Days of the Condor, The Parallax View, etc). It’s probably tied with the 80s now for my favorite decade in film.

What’s Next? Link to heading

  • I’m planning on reading some books about The New Hollywood movement - Pictures at a Revolution, this new one on Francis Ford Coppola.
  • I’d like to write a service that takes the list of movies on my “want to watch-list” (again, another Google note) and automatically alerts me when they’re available to stream. I think https://www.justwatch.com/ does this, but it’s a good exercise to practice Go.