50 Commits
Author SHA1 Message Date
mnw 86e7768575 3 movies with new ChatGPT Process. 2026-05-11 18:40:15 +00:00
mnw b1b9cd27bc Images were in the wrong path. 2026-01-18 16:01:46 -06:00
mnw ca8fac2019 Forgot to toggle off draft mode. 2026-01-18 15:58:34 -06:00
mnw cfd9261a86 A post about The Unbelievable Truth and some images to go with it. 2026-01-18 15:56:52 -06:00
mnw 69d6b370b2 Add gopher documentation to README and execution notes
- Update README with gopher/phlog section, publishing commands, URLs,
  and first-time SDF setup instructions
- Add gopher workflow documentation to execution-notes.txt
- Include planning docs in docs/ directory
2026-01-14 16:24:42 -06:00
mnw b7ac21093a Fix import path issue in gopher scripts
Add script directory to sys.path so imports work when scripts are
called from remote_publish.sh. Also remove unused variable and
no-op regex.
2026-01-14 16:24:42 -06:00
mnw 80dfa5b585 Add phlog: true to existing posts for gopher (Phase 5)
Enable gopher publishing for:
- Is it me? (tech/meta post)
- Recovering Failed Ubuntu Upgrade (tech post)
- Megalopolis (movie review)
2026-01-14 16:24:42 -06:00
mnw ce3a948758 Add phlog prompt to post creation scripts (Phase 4)
All three post creation scripts now ask whether to publish to gopher
phlog and include the phlog field in generated frontmatter.
2026-01-14 16:24:09 -06:00
mnw 0fb8d32e45 Add gopher deployment to remote_publish.sh (Phase 3)
Add --gopher and --gopher-only flags to deploy blog posts to SDF
gopherspace. Builds gopher content locally then rsyncs to server.
2026-01-14 16:24:09 -06:00
mnw bd45fc9e82 Add gophermap generation scripts (Phase 2)
Create scripts for generating category gophermaps with ASCII art
headers and a blog index gophermap. Also includes root gophermap
template with "FROM THE WEB" section for blog integration.
2026-01-14 16:24:09 -06:00
mnw e087a6eb83 Add gopher integration core infrastructure (Phase 1)
Create scripts for converting Hugo blog posts to gopher-friendly
plain text format. Includes ASCII art assets for headers/footers
and markdown-to-gopher conversion with proper line wrapping.
2026-01-14 16:24:09 -06:00
mnw e293d2b528 Filling out the past years so that we have a dictionary of all the NFR movies and their short description 2026-01-04 18:22:08 -06:00
mnw ca0cb3db20 Created an animated gif for darkroom and updated the text of the series page. 2026-01-01 23:13:14 -06:00
mnw e61a7839f4 No matter the model these llm love to fix transcriptions with ; and — and other weird characters I never use. 2026-01-01 22:37:13 -06:00
mnw 53705128d5 Hugo Pagnination fix was getting deprecation warning 2026-01-01 22:29:40 -06:00
mnw fdba772b88 Publish the new NFR page now 2026-01-01 22:28:53 -06:00
mnw 3bcecdd7b5 Updated the metadata fetching script and wrote the first National Film Registry entry 2026-01-01 22:25:07 -06:00
mnw 82e01341c9 Dollar signs or something causing formatting issue 2025-12-31 23:58:40 -06:00
mnw 18af137472 Housemaid before midnight 2025-12-31 23:56:19 -06:00
mnw 259c73634f Ok maybe this time. 2025-12-25 22:23:43 -06:00
mnw eb0c6c35b5 Its fun testing and trial and erroring 2025-12-25 21:38:57 -06:00
mnw 31901b10ce Ok let's try again 2025-12-25 21:35:44 -06:00
mnw 25851414fe Trying to get the series links at the bottom to show up. I think its the wrong Taxonomies 2025-12-25 21:16:10 -06:00
mnw 01cbef4604 The Secret Agent, dictated and edited like 4 or 5 tries. I hope it makes sense. 2025-12-25 20:47:41 -06:00
mnw c4321633f5 I didnt like how the spacing with the hyphens looked did a little tidy real quick. 2025-12-25 18:35:40 -06:00
mnw b0e2cd52d8 Not a draft man. Oops. 2025-12-25 18:31:17 -06:00
Marcus Wilson 0a5054d79b Drafted, Dicated, Edited, Redictated and then setup the authoring scripts on my mac. Lets see if it works 2025-12-25 18:29:32 -06:00
mnw c9e223da40 Ooops had my API key in there. Rotating out and switching to an import py style secret 2025-12-24 22:14:07 -06:00
mnw e02a0af16f Deleted file 2025-12-24 21:50:46 -06:00
mnw 365d86051d I'll blog about this another day 2025-12-24 21:38:34 -06:00
mnw 15e32c49d2 Finishing up the trio of scripts for the various post types. 2025-12-24 21:31:24 -06:00
mnw 2fdff679f5 Mastodon Comments Activate. I'll need to actually post about my blog to mastodon to use it but I'll start soon I think. 2025-12-24 20:43:35 -06:00
mnw 87b70ad855 Oops forgot the summary and then the auto gen summary was funky. Default summary added so we dont do that again. 2025-12-24 19:50:32 -06:00
mnw 7fad7c319a Added homevideo kind of post since the Lethal Tender one was kind of awkward. Also updated the layout for the movie poster details like runtime and director. Oh yeah and commented out the email button since I need ot find that key or make a new one. 2025-12-24 19:34:44 -06:00
mnw db29743a9c New post should not be a draft to get published huh 2025-12-24 19:15:37 -06:00
mnw 1f66392a2b I remember the command by telling myself make home page but the command is mkhomepg 2025-12-24 19:12:49 -06:00
mnw c3eb9e3064 Wrote up Lethal Tender review 2025-12-24 19:01:38 -06:00
mnw b09b638dca Trying to automate the movie review pages 2025-12-24 17:14:39 -06:00
mnw a5782a3357 Lag on terminal caused paste issues 2025-12-23 00:04:18 -05:00
mnw 0caecb2369 Wrote up avatar fire and ash, remove draft flag 2025-12-23 04:42:02 +00:00
mnw de78bb34ba Wrote up avatar fire and ash 2025-12-23 04:38:59 +00:00
mnw f66fd4f745 Preparing for update 2024-12-13 17:46:29 +00:00
mnw 43258686e8 November updates 2024-11-20 02:14:25 +00:00
mnw 52a727af42 Commented out hit counter for now 2024-10-15 00:13:17 +00:00
mnw 859ec57f70 Short post about fixing a failed ubuntu upgrade 2024-10-07 23:28:49 +00:00
mnw b0e3126cbf Touched up the W-H post and then wrote a post about Joker 2 2024-10-07 16:46:15 +00:00
mnw 1c9cd3bd7e Updated brand image, added favicon, finished movie posts template 2024-10-06 23:05:36 +00:00
mnw 8f386c5b5a Set brand image to be a static url since the template didnt like the blog subdirectory 2024-10-02 02:18:08 +00:00
mnw a828238c58 updated archetype, fixed layout, and made a post about going to megalopolis, also fixed summmaries 2024-10-02 02:08:42 +00:00
mnw 73fe8534ca Updating to use Poison theme added bear call lists 2024-10-01 10:31:41 +00:00
134 changed files with 12603 additions and 49 deletions
+34
View File
@@ -0,0 +1,34 @@
# Build output
public/
resources/_gen/
# Hugo lock file
.hugo_build.lock
# Editor/IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Environment/secrets
.env
*.env
# Python
__pycache__/
*.pyc
.venv/
venv/
scripts/config.py
# Claude Code
.claude/
# Gopher build output
gopher_build/
+3
View File
@@ -1,3 +1,6 @@
[submodule "themes/hugo.386"]
path = themes/hugo.386
url = https://gitlab.com/jmfergeau/hugo.386
[submodule "themes/poison"]
path = themes/poison
url = https://github.com/lukeorth/poison.git
+90
View File
@@ -0,0 +1,90 @@
# marcus-web
Personal blog powered by Hugo with gopher/phlog support. Many references to I Saw The TV Glow its a fantastic movie.
## Clone
```bash
git clone ssh://git@git.sdf.org/mnw/marcus-web.git
cd marcus-web
```
## Setup
```bash
./scripts/setup.sh
source .venv/bin/activate
```
## Usage
See `scripts/execution-notes.txt` for full details, but the short version:
```bash
# Movies (Frank's Couch)
python scripts/import_letterboxd.py
# Beer Calls (Luna Juice)
python scripts/new_beercall.py
# Beer Events
python scripts/new_lunajuice.py
# Tech Posts (Fun Center)
python scripts/new_techpost.py
```
## Publishing
```bash
# Hugo site only
./scripts/remote_publish.sh
# Hugo + Gopher
./scripts/remote_publish.sh --gopher
# Gopher only
./scripts/remote_publish.sh --gopher-only
```
Hugo builds happen on SDF via git pull. Gopher content is built locally and rsynced to `~/gopher/blog/`.
## Gopher / Phlog
Posts can be published to SDF gopherspace by adding `phlog: true` to the frontmatter:
```yaml
---
title: 'My Post'
phlog: true
---
```
### First-Time Gopher Setup on SDF
Before the first gopher deploy, make sure the `blog/` directory exists on SDF:
```bash
ssh mnw@sdf.org "mkdir -p ~/gopher/blog"
```
Then run the initial deploy:
```bash
./scripts/remote_publish.sh --gopher-only
```
### Gopher URLs
| Location | URL |
|----------|-----|
| Gopher root | `gopher://sdf.org/1/users/mnw/` |
| Blog index | `gopher://sdf.org/1/users/mnw/blog/` |
| Frank's Couch | `gopher://sdf.org/1/users/mnw/blog/franks-couch/` |
| Fun Center | `gopher://sdf.org/1/users/mnw/blog/fun-center/` |
| Web proxy | [Floodgap Proxy](https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/) |
### References
- [SDF Gopher Setup](https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features)
- [Tilde.town Gopher Guide](https://tilde.town/wiki/editing-your-homepage/gopher.html)
+41
View File
@@ -0,0 +1,41 @@
---
title: '{{ replace .Name "-" " " | title }}'
date: {{ .Date }}
draft: true
series: "Found in the Darkroom"
summary: "TODO: Add a summary for the homepage"
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: ""
# Auto-filled by fetch_movie_data.py:
poster: ""
year:
runtime:
director: ""
genres: []
# National Film Registry info
nfr_year: 2024
letterboxd_url: ""
tags:
- national-film-registry
- home-video
---
{{< imdbposter >}}
| Date watched | |
|------------------------|-----------------------|
| TV or Computer | |
| Watched Multiple Times | |
| Added to NFR | {{ .Params.nfr_year }} |
| Letterboxd Rating | |
| Favorite Quote | |
{{< /imdbposter >}}
## Why It's in the National Film Registry
[Add information about why this film was selected for preservation]
## My Thoughts
This is where our review goes and we talk about the film, its historical significance, and how it holds up today.
+10 -5
View File
@@ -1,5 +1,10 @@
+++
title = '{{ replace .File.ContentBaseName "-" " " | title }}'
date = {{ .Date }}
draft = true
+++
---
title: '{{ replace .File.ContentBaseName "-" " " | title }}'
date: {{ .Date }}
draft: true
series: "Series name"
summary: "This is the custom summary"
tags:
- Tag A
- Tag B
---
+34
View File
@@ -0,0 +1,34 @@
---
title: '{{ replace .Name "-" " " | title }}'
date: {{ .Date }}
draft: true
series: "Frank's Couch"
summary: "TODO: Add a summary for the homepage"
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: ""
# Auto-filled by fetch_movie_data.py:
poster: ""
year:
runtime:
director: ""
genres: []
tags:
- home-video
- anticipated
- no-expectations
---
{{< imdbposter >}}
| Date watched | |
|------------------------|-----------------------|
| Format | |
| Watched Multiple Times | |
| Kept the Lights On | |
| Will It Stick With Me? | |
| Did You Cry? | |
| Letterboxd Rating | |
{{< /imdbposter >}}
This is where our review goes and we talk about life and stuff and how the world works.
+40
View File
@@ -0,0 +1,40 @@
---
title: '{{ replace .Name "-" " " | title }}'
date: {{ .Date }}
draft: true
series: "Frank's Couch"
summary: "TODO: Add a summary for the homepage"
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: ""
# Auto-filled by fetch_movie_data.py:
poster: ""
year:
runtime:
director: ""
genres: []
tags:
- gucci
- ghost theater
- marcel
- amc-south
- amc-lakeline
- anticipated
- no-expectations
- had pizza
---
{{< imdbposter >}}
| Date watched | |
|---------------------|-----------------------|
| Show Time | |
| Theater | |
| Theater Number | |
| Pizza | |
| Tickets | |
| Letterboxd Rating | |
| Crew | |
{{< /imdbposter >}}
This is where our review goes and we talk about life and stuff and how the world works.
+58
View File
@@ -0,0 +1,58 @@
---
title: Avatar Fire and Ash
date: 2025-12-23 03:44:12+00:00
draft: false
series: Frank's Couch
summary: James Cameron and the boys enjoy a hot winter evening.
imdb: tt1757678
tags:
- ghost theater
- anticipated
poster: /images/posters/avatar-fire-and-ash.jpg
runtime: 198
year: 2025
director: James Cameron
genres:
- Science Fiction
- Adventure
- Fantasy
---
{{< imdbposter >}}
| Date watched | December 20th |
|---------------------|-----------------------|
| Show Time | 3:30 pm |
| Theater | Ghost |
| Theater Number | 3 |
| Pizza | No |
| Tickets | Box Office |
| Letterboxd Rating | 4 |
| Crew | Me, Science Bro, and Coach T |
{{< /imdbposter >}}
Howdy, long time no blog. I wanted to take a second to say that I am going to try this again. We have still been going to see movies almost every week, but I have not been writing about them or really talking about them with anyone, and I think it is time to give that another shot.
In 2026, I am going to challenge myself to watch as many films from the National Film Registry as I can. These are movies the Library of Congress has essentially said are worth preserving. There are a lot of older films on the list, including many silent movies, though newer titles continue to be added over time. The first stretch will probably be a bit of a slog, but I will do my best to blog about them regularly.
I will also write more about Master Pancake shows and regular screenings, since that is largely how I experience movies, and I want to talk about that context as well.
This past Saturday, I had a haircut appointment. One of the funny things about living in Austin is that if you want a real barbershop haircut, you need to book ahead. Walk-ins tend to be limited to chain places like Sports Clips in a Walmart or strip mall. My appointment was at 11:30, which meant I could not make the early 9:00 or 10:00 a.m. movie showings. That worked out fine, though, because it gave Coach T and me time to go to Golden Corral.
Neither of us had been there in years. Since I am planning to eat less horribly in 2026, this felt like a good moment to revisit places I probably will not be going to much anymore. There was far more food than I remembered. They even have steaks cooked to order. The first one I got was surprisingly tender, almost like butter. The second was the toughest steak I have had in my adult life. I literally could not bite through it. Impressive, but not in a good way.
After a very large meal, it was finally time for the movie.
Avatar: Fire and Ash is about dealing with loss, and about how different people and cultures process grief in different ways. Early in the film, we see the Sully family mourning along separate paths. Jake copes by staying busy, clearing weapons from the bottom of the lagoon and throwing himself into physical work. Lo'ak, the surviving son, spends his time flying and doing the activities he once shared with his brother, trying to feel close to him. Neytiri mourns in a traditional, spiritual way. The younger children are clearly sad as well, though they are too young to articulate grief in the same way.
This creates tension within the family. Neytiri wants Jake to grieve with her in a traditional way, but he is a Marine who tends to shut down emotionally and does not seem capable of meeting her there. Lo'ak also struggles against his father's expectations, wanting freedom rather than discipline. It is a quiet but effective family dynamic.
Later, the film introduces the Mangkwan clan and revisits the tulkun. These are groups previously thought to be peaceful, yet both are shown capable of violence. The Mangkwan have been shaped by loss and destruction, and their anger manifests as cruelty. The tulkun, famously pacifist in earlier films, are finally pushed into action after witnessing the horror of one of their own surviving a whaling attack. The themes are there if you want to engage with them, but the film also works on a more surface level if you do not.
I appreciated that the movie avoids painting anyone as purely good or evil. That refusal to make the world black and white gives it more texture and realism.
Spider, the human boy left behind on Pandora during the early colonization period, has a substantial subplot. He is granted the ability to breathe Pandora's air, which takes up a fair amount of screen time. There is also a hint of romance between Spider and Kiri, the daughter of Grace Augustine. Kiri is again voiced by Sigourney Weaver, and this was occasionally distracting. Weaver's voice sounds much more mature than a teenager's, and at times it felt like an older consciousness inhabiting a younger body. That is a familiar trope in anime, but here it sometimes felt awkward.
As a bit of bonus trivia: in November 2024, James Cameron said that Avatar 4 and Avatar 5 would not proceed if Fire and Ash underperformed at the box office, adding that he would write a book instead to resolve the narrative threads left open by the third film if necessary.
So, is it a good movie? Yes, absolutely. It is fun, visually overwhelming in the best way, and the characters continue to grow in meaningful directions. The plot does echo The Way of Water in places, but it works well enough that it is hard to complain. This is very much a movie that benefits from being seen in a theater, with loud, rumbling bass and massive visuals. Watching it at home or on your phone might be fine, but you would be missing a big part of what makes it special.
@@ -2,6 +2,8 @@
title = 'Beer Call Log for 2023'
date = 2024-09-21T02:10:28Z
draft = false
summary = 'A listing of all the beer call stops that I remembered to record in 2023'
series = "Luna Juice"
+++
I started keeping track of the beer calls in March of 2023 and so these are the beer calls since then.
@@ -2,8 +2,65 @@
title = 'Beer Call Log for 2024'
date = 2024-09-21T02:12:42Z
draft = false
summary = 'A listing of the beer calls that I have remembered to write down in 2024'
series = "Luna Juice"
+++
# Draught House aka DH - October 31
| | |
| :------------------- | :---------------- |
| Location | 4112 Medical Pkwy, Austin, TX 78756 |
| Beerlist | https://www.draughthouse.com/drinks |
| Attendees | Marcus, Steve, Stephen, Marty, Eric, Dan, Stephen's Neighbor ( I'll ask his name next call I go to ) |
| Notes | Trophy Bitter was good enough we drank two pitchers of it. The cask was rejected by Eric, Steve and Stephen but Iain was fine to drink it. I rambled a bit was not really mentally checked in as much as I'd hoped. I think my snoring has moved back into sleep blocking due to my tremendous weight gain. Warned Iain and Dan I'd be out next week |
# The ABGB (Double Dose) - October 24
| | |
| :------------------- | :---------------- |
| Location | 1305 W Oltorf St, Austin, TX 78704 |
| Beerlist | http://www.theabgb.com/ |
| Attendees | Marcus, Steve, Stephen, Eric, Marty, Linda (Marty's wife), Linda's German realitve, Dan, Francis, Bill's son in Law, Bill |
| Notes | Was a big group with alot going on almost too much had trouble engaging. Stayed behind for music again this time Eric was there too we got to see and hear Rhinestone Renegades https://www.therhinestonerenegades.com/ |
# The ABGB - October 17
| | |
| :------------------- | :---------------- |
| Location | 1305 W Oltorf St, Austin, TX 78704 |
| Beerlist | http://www.theabgb.com/ |
| Attendees | Marcus, Steve, Stephen, Eric, Marty, Dan |
| Notes | Good beer good times. I stayed behind and watched a guy and his wife sing. Bought 2 slices of pizza too. CD is pretty good music Forrest Mccurren https://forrestmccurren.com/ |
# Lazarus 2 - October 10
| | |
| :------------------- | :---------------- |
| Location | 4803 Airport Blvd, Austin, TX 78751 |
| Beerlist | https://lazarusbrewing.com/our-beer/ |
| Attendees | Marcus, Steve, Stephen, Marty, Iain maybe I am recording this on 2024-11-01 brain is fuzzy |
| Notes | Beer was ok. Eric continues his streak of missing out on Lazarus. |
# Austin Beer Works (Sprinkle Valley) - October 3
| | |
| :------------------- | :---------------- |
| Location | 10300 Springdale Rd, Austin, TX 78754 |
| Beerlist | https://austinbeerworks.com/page/welcome-to-sprinkle-valley |
| Attendees | Marcus, Steve, Stephen, Marty, Martin, Martin's Wife and her Parents, Dan, Francis |
| Notes | Flavor Country, Vienna Lager, Floaty, IPA. Had a great time was fun to catch up with Martin. Wish I was keeping up with news more I only had kind of boring tech stuff to talk about. Marty got a cheese sticks order wasn't quite the snack we had hoped for the taco truck was closed bummer. |
# Pint House Pizza Burnet - September 26
| | |
| :------------------- | :---------------- |
| Location | 4729 Burnet Rd, Austin, TX 78756 |
| Beerlist | https://pinthouse.com/burnet/beer/beer-on-tap |
| Attendees | Marcus, Steve, Stephen, Stephen's Neighbor, Eric |
| Notes | Darker beer to start ended up with IPA |
# Burnet Go To - September 19
| | |
| :------------------- | :---------------- |
@@ -0,0 +1,99 @@
+++
title = 'Texas Craft Brewers Festival 2024'
date = 2024-11-19T02:12:42Z
draft = false
summary = 'A short summary of going to the craft beer festival.'
series = "Luna Juice"
+++
On November 16th, 2024, the Texas Craft Brewers Festival took over Fiesta Gardens, running from noon to 6:15 PM. VIPs enjoyed early access at 12:00 PM, while general admission folks like me entered at 2:00 PM. With live music, numerous food trucks, and a fantastic variety of craft beers, it was an event beer enthusiasts wouldn't want to miss.
The wonderful beer blog [Craft Beer Austin](https://craftbeeraustin.com/tcbf2024-in-photos) captured lots of good photos since I am not yet sure how to get pictures in here properly ;).
**Getting There**
Despite a less-than-perfect experience with the bus from the Airport when I got back from a recent trip to Seattle, I decided to give public transit another try. Leaving my house around 12:10 PM, I aimed to arrive at the festival by 1:30 PM, well before the 2:00 PM start for general admission. Navigation apps suggested leaving for the bus stop by 12:30 PM, so I figured I had just enough time to grab a quick bite from the taco shack nearby.
Plans changed when I reached the bus stop, taco in hand, only to find two buses parked with no drivers - apparently on their lunch breaks. I made the best of it, eating my food on one of the parked buses and waiting for the driver to return. Eventually, we got moving. After a 45 minute ride, I reached my transfer point, waited 20 minutes for the next bus, and finally arrived near the festival. It was easy to spot - crowds of festival goers and lively energy made it clear I was in the right place. The line was long, it was moving quickly. So I was in by 2:15pm. Kudos to CapMetro for a relatively smooth trip!
For the return trip, I opted for a Lyft, which cost $20 plus tip and got me home without any hassle.
**The Festival Layout**
If you've been to this festival before, the setup will feel familiar, but for newcomers, here's a breakdown:
Each brewery occupies a tailgating-style tent, complete with uniform signage. The signs display the brewery's name, their town, and the beers they're serving, with special offerings highlighted. Breweries are line up in two giant concentric circles around a central pavillion, which hosts live music. Big sponsors like Celis Brewery, Austin Beer Works, Saint Arnold, and Pint House Pizza occupy prime spots close to the stage, while the experimental brewers, like Jester King, were more along the periphery. ( I haven't figured out how to do photos with my posts using hugo yet. I hope I do by the next beer thing and I'll post the photos. )
The food court anchors one end of the festival, offering plenty of sustenance between beer samplings. Just so you know the food trucks were
- Burro Cheese Kitchen
- Crave Hotdogs and BBQ
- Garbo's Lobster
- Shawarma Point
- The Mighty Cone
- Yapa Artisan Empanadas
What sets this festival apart is the sheer variety of breweries representing Texas, from big players to smaller gems. It's a reminder of the vibrant craft beer scene that extends well beyond Austin. You can checkout the full details on [their site](https://tickets.texascraftbrewersfestival.org/e/texas-craft-brewers-festival-2024).
**Beer Sampling: My Highlights**
The festival operates on a ticket system: your entry includes 10 tickets for 10 beer samples, and you can buy more for $5 per set of 10. Each sample comes in a small 23 oz plastic cup. After each pour, rinse your cup at water stations to keep flavors distinct.
Here are some of the beers I tried, along with my thoughts:
Twin Peaks Brewing (Irving, TX): Drop Dead Red. A malty red ale that was
enjoyable, but didn't blow me away.
Prost Ale House (Pflugerville): Blitzbahn German Pilsner. Crisp with a
pleasant hop profile. Prost is celebrating their anniversary on
December 21st, so I might stop by for more.
Pecan Street Brewing (Johnson City): Tried both their Resin Project IPA and
13-Degree Czech Pilsner. The Pilsner stood out for its strong yeast flavor,
making it one of my favorites.
Jester King Brewery: Their German Pilsner featured their signature yeast
notes.
Bird Creek Brewing (Temple, TX): Ghost Beach Rice Lager. This was a surprise
hit - sweet, refreshing, and easily my favorite rice-based beer to date.
Saint Arnold's Brewing Company (Houston, TX): 2013 Pumpkinator. A high-ABV
delight, full of rich flavors. It was delightful. I slammed it!
Live Oak Brewing (Austin, TX): Death Putt Cold IPA. A straightforward cold IPA
that lived up to its name.
Ghost Note Brewing: Foeder-Aged Farmhouse Ale. A high-ABV beer with a balanced
flavor - not too sour, not too heavy.
Southern Roots Brewing Company (Waco, TX): New Zealand Pilsner. Crisp, clean,
and easily my favorite Pilsner of the day.
Brutarium: Confabulator Doppelbock. Sweet, malty, and dark - a classic
Doppelbock at 8.3% ABV.
Vector Brewing: Tamave Pivo 13-Degree Czech Lager. A dark, malty lager with a
smooth finish, reminiscent of earlier Czech-style beers I sampled.
**Beer Notes and Brewing Insights**
Chatting with fellow festival-goers and brewers, I picked up some interesting tidbits:
French hops, like Strisselspalt, have interesting unique flavor profiles.
Higher mash temperatures can leave residual sugars for sweetness, but cutting
fermentation too early can lead to diacetyl flavors.
Longer boiling times increase the starting gravity of the beer, impacting its
strength and flavor.
**Wrapping It Up**
After tons of samples, great conversations, and soaking in the lively atmosphere, I called it a day. This year's Texas Craft Brewers Festival reminded me of how diverse and exciting the Texas craft beer scene is. From traditional Pilsners to experimental ales, there's truly something for everyone.
If you're a craft beer enthusiast or just curious about the Texas brewing scene, this festival should be on your radar. Here's to next year!
_Note I left out the names and stories around the people I met and hung out with along the way because I dont like putting people's business out there. I had a great time. Thanks_
+48
View File
@@ -0,0 +1,48 @@
---
title: 'Is it me?'
date: 2024-11-19T22:59:30Z
draft: false
series: "Fun Center"
summary: "Marcus shares his blog writing process."
phlog: true
tags:
- meta
- how-i-did-it
- technology
---
I've always loved talking to people. Whether it's at work, at home, or out with friends, connecting with others and hearing about their passions brings me so much joy. There's nothing better than a conversation with someone excited to share what they care about.
I have plenty of interests and experiences I'd love to share with others. But writing them down? That's where things get tricky.
For years, I've struggled to translate my thoughts into coherent blog posts. I've tried journaling, writing exercises, and reading advice on improving my craft. While those efforts got me to write more, they didn't necessarily help my words flow or make my stories easier to follow. My drafts often felt disjointed, like puzzle pieces that didn't quite fit together.
Despite this, I've always had the itch to keep trying - and recently, I found a workflow that's actually working for me.
---
*How Mac Whisper Changed the Game*
The first breakthrough came when I discovered Mac Whisper, a voice dictation app powered by AI. While it's not open source, it is freeware, and the free version has been more than enough for my needs.
Mac Whisper lets me dictate my stream of consciousness directly into text. It feels natural - like I'm telling the story to a friend. I don't have to worry about typing, editing, or overthinking. I just talk, and the app captures it all.
---
*Turning Ideas into Stories with ChatGPT*
Once I have the raw, unfiltered text from Mac Whisper, I use ChatGPT to help shape it into something structured and readable. The AI assists me in organizing my thoughts, refining my ideas, and cutting through the noise to create a story worth sharing.
It's not perfect, and I do plan to explore open-source tools for this step to keep everything local. But for now, ChatGPT has been a game-changer in helping me turn rambling thoughts into polished posts.
---
*Why This Matters*
Sharing this workflow feels a little strange - almost like admitting I need "help" to write. But I know I'm not alone in this struggle. Writing can be intimidating, and it's easy to feel like your words aren't good enough. Tools like Mac Whisper and ChatGPT don't replace your voice; they enhance it. They help you find clarity and make it easier to share your story.
I'm still figuring out how to condense my stories - long story short is rarely short with me - but this process has made a huge difference. If you're someone who struggles to write but loves to talk, I highly recommend giving this workflow a try.
At the end of the day, connecting with people through stories - whether written or spoken - is one of life's greatest joys. And now, I finally feel like I can do it in a way that works for me.
+51
View File
@@ -0,0 +1,51 @@
---
title: Cloud Atlas Pancake
date: 2024-11-20 14:49:23+00:00
draft: true
series: Frank's Couch
summary: First post about a Master Pancake movie. Cloud Atlas was confusing but it
was fun!
imdb: tt1371111
tags:
- CYOP
- mueller
- no-pizza
poster: /images/posters/cloud-atlas-pancake.jpg
runtime: 172
year: 2012
director:
- Lilly Wachowski
- Lana Wachowski
- Tom Tykwer
genres:
- Drama
- Science Fiction
---
{{< imdbposter >}}
| Date watched | 2024-11-1 |
|---------------------|-----------------------|
| Show Time | 5:55 pm |
| Theater | Mueller |
| Theater Number | 4 |
| Pizza | No |
| Tickets | Friend |
| Letterboxd Rating | 7.4/10 |
| Crew | Me, RRa, RRj |
{{< /imdbposter >}}
**Introduction to Master Pancake Theater:**
Master Pancake Theater is an Austin-based comedy troupe known for their live movie-riffing performances. Combining quick-witted commentary, live sketches, and audience interaction, they hilariously deconstruct films, from beloved classics to cult favorites. The group started at Alamo Drafthouse and has become a staple of the city's comedy scene, celebrated for their ability to turn even the most serious movies into laugh-out-loud experiences. Their unique blend of humor and cinema makes every show a memorable event for film lovers and comedy fans alike.
**Brief synopsis of the movie**
An exploration of how the actions of individual lives impact one another in the past, present and future, as one soul is shaped from a killer into a hero, and an act of kindness ripples across centuries to inspire a revolution.
**Now to the Movie**
Players -
Voting -
Issues -
+54
View File
@@ -0,0 +1,54 @@
---
title: Joker Folie a Deux
date: 2024-10-07 00:03:15+00:00
draft: false
series: Frank's Couch
summary: The boys get to B serious about Joker 2
imdb: tt11315808
tags:
- gucci
- anticipated
- no pizza
poster: /images/posters/joker-folie-a-deux.jpg
runtime: 138
year: 2024
director: Todd Phillips
genres:
- Drama
- Crime
- Thriller
---
{{< imdbposter >}}
| Date watched | October 5th |
|---------------------|-----------------------|
| Show Time | 12:30 |
| Theater | Gucci |
| Theater Number | 1 |
| Pizza | No Pizza |
| Tickets | At Box Office |
| Letterboxd Rating | ** 1/2 (2.5) |
| Crew | Me, Coach T, Science Bro, MeHoniBear |
{{< /imdbposter >}}
Waking up at 4 AM all week means that a 12:30 PM movie doesn't exactly feel early, but it does require vigilance to avoid losing track of time. MeHoniBear is trekking in from the northern suburbs, and Coach T is being a total champ, driving him all the way in. I keep telling myself, "Eat something, they might not have pizza this time," but my hopes are perpetually high for pizza. I was also pretty hyped for what looked like a musical sequel to the gritty Beau is Afraid-meets-Joker vibe. Quick side note: NBA player Nikola Jokic, nicknamed "The Joker," would definitely take down the Jokers from both of these movies.
I park and text the crew, only to realize that Science Bro has also just arrived and parked a space away. We chat a bit, but Coach T and MeHoniBear roll up soon after, and the gang's all here.
First time in Theater 1! The big one. It even has an elevator. Fancy! But no pizza. Sad face. Consolation prize: a hot dog. We snagged seats in Row B, which turned out to be the perfect spot to B.
Now, onto the movie.
It kicks off with a quirky animated short about the Joker's shadow trying to steal the spotlight funny and definitely a little weird. Then, we're dropped straight into Arkham Asylum, though it's portrayed more like a tiny, poorly funded prison. Brendan Gleeson (the "finger man" from Banshees of Inisherin what a movie) plays an antagonistic guard who dishes out plenty of exposition. It's loaded with classic 1970s prison tropes: the yard, questionable relationships, terrible food, and guards who are both friendly and menacing. Oh, and we can't forget Steve Carell's girlfriend from The 40-Year-Old Virgin, Catherine Keener, who also rocked it in Capote such a great movie! And, of course, Lady Gaga. Her singing and performance were magical.
Costumes and lighting? On point. It's hard to make tattered garments look good, but they totally pulled it off. There's this one scene where Arthur's suit shifts from deep burgundy to a dark, ashy color, and it really captured the mood of the moment.
Now, onto the plot ... no spoilers, but I wasn't blown away. The pacing dragged, and the dance numbers teased a bigger, more exciting production than what we actually got. At 2 hours and 18 minutes, plus trailers, we were sitting there for about 2:45. After the movie, we kept hashing out what we didn't like for another 90 minutes, so it was nearly 5 PM by the time we finally wrapped up the group grumble.
If you loved the first Joker, this one might not be your thing. But if you're here for Lady Gaga or just want to vibe with the soundtrack, give it a shot or better yet, grab the Harlequin album from her site https://shop.ladygaga.com/products/harlequin-digital-album
Next week is ACL, but if we're feeling ambitious, we might catch Terrifier 3 late at night. TBD.
-Note: Will and Harper I made an outline and then used AI as a cruch pretty hard. This week I wrote it all out and then asked to correct grammar and punctuation and help it be more cohesive. I liked the outcome of this way better. I'll keep working on it and hopefully soon I can get away with just like a grammar checker - fingers crossed.
+38
View File
@@ -0,0 +1,38 @@
---
title: 'Lethal Tender'
date: 2025-12-24T22:47:20Z
draft: false
series: "Frank's Couch"
summary: "I bought this movie off eBay on November 7th, 2016. I was living in a small apartment off Woodrow in Austin, TX at the time and was in the early days of what I was calling my Busey Quest. I was trying to find and watch as many Gary Busey movies as I could."
imdb: "tt0119520"
poster: "/images/posters/lethal-tender.jpg"
year: 1997
runtime: 94
director: "John Bradshaw"
genres:
- Action
- Thriller
tags:
- homevideo
- buseyquest
- no-expectations
---
{{< imdbposter >}}
| Date watched | Nov 2016 |
|---------------------|-------------------|
| Show Time | estimated 5pm |
| Theater | Home Video |
| Theater Number | Woodrow Apt |
| Pizza | Yes |
| Tickets | No |
| Letterboxd Rating | DNR |
| Crew | Just me |
{{< /imdbposter >}}
I bought this movie off eBay on November 7th, 2016. I was living in a small apartment off Woodrow in Austin, TX at the time and was in the early days of what I was calling my Busey Quest. I was trying to find and watch as many Gary Busey movies as I could.
Lethal Tender is one of the great Gary action movies. It kicks off when a routine tour of a Chicago water-filtration plant is taken hostage by a band of criminals. They seize the facility and round up any personnel who are not on strike. Oh, did I forget to mention that? Yes, the workers are on strike but people are still going to this place to take tours. These criminals, domestic terrorists, really, are threatening to contaminate the citys drinking water as part of their scheme. Detective David Chase (Jeff Fahey), who was there to bust up the strike, becomes the reluctant lone hero trying to outwit the terrorists from inside the plant. Of course, who could be behind such a chaotic yet brilliant scheme? None other than our pal Gary Busey as Mr. Turner, who directs operations from in front of a very odd computer terminal. His partner and leader of the gunmen is another equally watchable, energetic actor, Kim Coates, who plays Montesi. He is one of those 80s/90s villains who is super smart and mad at the world for not being as smart as he is, which makes for great pre-internet smarty-pantsery. As the clock ticks and threats escalate, Chase teams up with plant engineer Melissa Wilkins (Carrie-Anne Moss) to foil the plot and save both the hostages and Chicagos water supply. Its been said before by people who watch this movie, but it really is like Die Hard in a water plant: hijinks, questionable master plans, and Buseys unhinged energy making it uniquely its own.
It doesnt end there. If you find this movie maybe too coherent or making too much sense, I recommend checking out another movie about a water plant under threat. Its called Never Too Young to Die, and it hinges on a plot about poisoning a citys water supply. Its got that same wonderfully bonkers 80s action, starring John Stamos and Gene Simmons, who bring everything up to 11. It is quite magical. Make it a double feature and celebrate the memory of having clean drinking water.
+48
View File
@@ -0,0 +1,48 @@
---
title: Megalopolis
date: 2024-10-02 00:07:14+00:00
draft: false
series: Frank's Couch
summary: The boys catch Megalopolis at Gucci on a Saturday Afternoon.
phlog: true
imdb: tt10128846
tags:
- gucci
- anticipated
- had pizza
poster: /images/posters/megalopolis.jpg
runtime: 138
year: 2024
director: Francis Ford Coppola
genres:
- Science Fiction
- Drama
- Fantasy
---
{{< imdbposter >}}
| Date watched | September 28 |
|---------------------|-------------------------|
| Show Time | 3:55pm |
| Theater | Gucci |
| Theater Number | 7 |
| Pizza | Yes |
| Tickets | At Box Office |
| Letterboxd Rating | **** (4) |
| Crew | Me, Coach T, Science Bro |
{{< /imdbposter >}}
We've gone to the movies as a group for around three years or something now. Seen some amazing heart warming films and some abosolute garbage. Even the worst of the worst is still a good time. The core people who go most of the time are Me, Coach T, and Science Bro while our friend MeHoneyBear used to be the one always getting us to go do something together. Additional folks who show up from time to time include Nurse Vegas and her man,Purple Oil Esquire, Dr Nasty, or a few others.
Its not quite 90 degrees and the sun is bright out. The kind of bright that threatens you with a migrane if you don't play nice. I was chugging my clean cause uncarbonated yerba mate tea and praying that Honda's lane departure assist didn't let me down. Before doing my best to teleport to Gucci today Science Bro texted in that he was in the area earlier for something else and so he had arrived already. With the current time and temperature it's not the end of the world and since he smokes he'll be fine. Going to need to hustle though. There's a wonderful altered reality you enter when going to a familiar place with loud music playing. The android tablet powered dash entertainment console thing beeps and interrupts Gucci Mane to let me know Coach T has pulled in. Time to cut through the neighborhood. I can see the battle ground of I35 in the distance while the side road I am in is filling up with vehicles. The uniformity of the suburbs makes the traffic look almost like ammunition to be fired down the narrow barrel of the "express way". Thanks to construction it is neither express nor really even the right way. I merge to the highway abruptly and just as fast exit. Swanging around the speed bumps I get my sun screen up and it's 3:53pm. We made it!
Brief hellos and its time to grab tickets. The theater number 7 this time so no real Row B. Oh yeah the crew is made of a bunch of BBoys we like row B alot of the time. Given the choice we were Row A today. The door squeak is a cry of pain or relief who is to say but it isn't a neutral noise and a cold sigh of air conditioning brings us to the lobby. Eyes dart quickly, how long are the lines, how big is the line to get through the one ticket checker person, is the place crazy busy, and most important is there hot Pizza? Short, not bad, only on the far side, and yes. Today is a good day. We usually come early in the day so for the first year or more maybe I never got to have a pizza so now I relish them. Pizza, Icee, small popcorn rewards ,yes thank you. Hot dogs familiar friends with Coach T, and the Diet C for Science Bro he loves chemicals.
I went in blind to Megalopolis. All I knew was that Francis Ford Coppola wrote it and he sold his wine farm to make. He should have just drank the wine to be honest.
There are real pros to write reviews this is all about the _sparkle_ experience _sparkle_. Row A provided a nice lean and the screen lighting was bright enough to eat by even during some darker scenes. My Icee lasted through the whole movie and 0 napkins or naps were used. There were some scenes with bright flashing lights and the threat of a migrane earlier had me closing my eyes or looking off to the side.
So why 4 stars? To be honest I should go down to 3 but who knows if I will. The story was told in a unique way with beautiful sets, costumes, and special effects. The sound design and everything techinically about this movie was magnificent.
Its close to bedtime so I think maybe thats why this post ran out of gas. I'll try again tomorrow because on Sunday I watched Will & Harper.
+51
View File
@@ -0,0 +1,51 @@
---
title: 'Men in Black 3'
date: 2026-05-10T00:00:00Z
draft: true
series: "Frank's Couch"
summary: "A Master Pancake screening of Men in Black 3 at Alamo Village that turned a pretty fun time travel movie into an even better night."
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: "tt1409024"
# Auto-filled by fetch_movie_data.py:
poster: ""
year: 2012
runtime: 106
director: "Barry Sonnenfeld"
genres: ["action", "adventure", "comedy", "sci-fi"]
tags:
- no-pizza
- no-expectations
- master-pancake
- alamo-drafthouse
---
{{< imdbposter >}}
| Date watched | 2026-05-09 |
|---------------------|-----------------------|
| Show Time | 5:00 PM |
| Theater | Alamo Village|
| Theater Number | 3 Seat 3-11 |
| Pizza | No, sad times |
| Tickets | A Must thanks AC |
| Letterboxd Rating | DNR - Its a 2.5-3.0 |
| Crew | AC, JW |
{{< /imdbposter >}}
## Review
After The Sheep Detectives, I rushed over from Galaxy Theatres to Alamo Drafthouse South Lamar for a Master Pancake show of Men in Black 3. The plan had been a little messy. I got a text from family who happened to be in town asking me to come have dinner, and there was barbecue involved, so I was going to skip Teen Wolf and just make the next thing work. I ended up at the Drafthouse with my good pal AC and his friend JW, or maybe more than friend, I am not totally sure. We were all there for Men in Black 3, and neither AC nor I had seen it recently. I had not seen it at all.
The movie is basically about Agent J having to travel back in time to save Agent K and stop Boris the Animal, a Boglodite alien who escapes from a maximum-security prison on the Moon. Boris steals a little handheld time machine and goes back to 1969 to stop K from deploying the ArcNet. The ArcNet is a protective shield that keeps the Boglodites from invading Earth. There is also Griffin, a fifth-dimensional alien who can see possible realities, and he gives the movie a fun little time travel weirdness that mostly works.
Of course, the best part was that this was Master Pancake. Master Pancake is there to mock the movie, ask the questions you are already thinking, and make the whole thing funnier than it would be on its own. John Erler was the main host, the main Pancake if you will, keeping everything together. Chris Cubas and John W. Smith were there too, cracking jokes throughout. Chris Cubas is very quick-witted, and it is a lot of fun hearing him find exactly the right question or joke at the right time. Sean, the sound guy, was also great. The running joke is that it is always his birthday, but he really is fast with the cues and sounds.
Because it was a Sony movie, we got candy instead of a live skit, which was fine. The riffing carried the night. Men in Black 3 is also just a better movie than I expected. It is a fun little time travel movie, and by the end I realized it is kind of a good Father's Day movie too. I only saw it in 2D, or "Tootie" as my brain apparently decided to call it, but I can see how it probably would have been especially fun in 3D when it came out.
I have complicated feelings about Alamo Drafthouse South Lamar as a business in 2026. Running a restaurant is hard. Running a theater is hard. Running a restaurant inside a theater while food costs and labor costs keep going up seems extremely hard. I was on the board with Black Star for years, which is a beer co-op and restaurant, and restaurants are one of the hardest things to operate. At the same time, I do feel like Alamo has been pretty anti-union and anti-labor, and that is hard to ignore. But Master Pancake only does shows at the Drafthouse, and I do want to keep supporting Master Pancake. So that is where I am with it.
For Austin theaters, I think my personal order is something like AFS, Galaxy, and then Alamo Drafthouse South Lamar, depending on the movie. If you are not part of the 824 Club, AFS is a great value. I also do the Cinemark club thing, and one of my friends does the Alamo membership. Alamo is still good for some harder-to-find movies and special events, and Master Pancake is definitely worth showing up for. Men in Black 3 with Master Pancake was a good time and a nice way to wrap up the movie part of Saturday, May 9.
- IMDb media page: https://www.imdb.com/title/tt1409024/mediaindex/
- TMDb image page: https://www.themoviedb.org/movie/41154-men-in-black-3/images
+48
View File
@@ -0,0 +1,48 @@
---
title: 'Mortal Kombat II'
date: 2026-05-09T16:15:00Z
draft: true
series: "Frank's Couch"
summary: "A front-row Galaxy Theatres screening of Mortal Kombat II that worked better than expected, especially once I stopped overthinking the video game lore."
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: "tt17490712"
# Auto-filled by fetch_movie_data.py:
poster: ""
year: 2026
runtime: 116
director: "Simon McQuoid"
genres: ["action", "adventure", "fantasy"]
tags:
- galaxy-theater
- no-pizza
- no-expectations
---
{{< imdbposter >}}
| Date watched | 2026-05-09 |
|---------------------|-----------------------|
| Show Time | 11:15 AM |
| Theater | Galaxy Theatres Austin |
| Theater Number | 06 Seat B8 |
| Pizza | No, sad times |
| Tickets | Bought at Door|
| Letterboxd Rating | 3 stars |
| Crew | Coach T, Kid Negativity |
{{< /imdbposter >}}
## Review
On Saturday, May 9, I went to Galaxy Theatres in Austin with the boys, Coach T and Kid Negativity, for an 11:15 AM showing of Mortal Kombat II. Galaxy is a cool old-school Austin theater. It is not tiny, but it is definitely smaller than a Cinemark or Regal. We tried to get our traditional Row B seats, because we are the Row B boys, but Row B was taken, so we ended up in Row A. The ticket taker actively warned us that it was going to be awfully close, and he was right. At Cinemark or Alamo South Lamar, Row A still feels like maybe five or six meters from the screen. At Galaxy, it felt more like two. That made it a very different experience, but the recliners were comfortable enough, especially since we had a seat between us.
The popcorn was good, but I learned a lesson. They have different salts you can add, and the butter popcorn salt is extremely strong. The concession guy warned me, and he was right. I only added a little, but it was still too much. I think the popcorn may already have salt on it even when it is not buttered, so next time I probably do not need the extra seasoning.
I had not seen the first Mortal Kombat from 2021, so I was going in a little cold. I knew Karl Urban was playing Johnny Cage, and I liked that the movie did not waste a ton of time reintroducing everybody. Johnny Cage is a washed-up 90s movie star and former martial arts performer, and Sonya and Raiden basically show up and pull him into the whole situation. That made it very clear this was a part two, but honestly I appreciated that. With game adaptations, I do not always need an hour of backstory for characters the audience probably already knows. Give me enough exposition later and keep the movie moving.
The movie is a lot of fun. Raiden does not talk too much, which I appreciated, because he is supposed to be this godlike figure on earth. The movie does not get too bogged down in explaining gods, minor gods, major gods, or why the god of lightning counts as minor. I did start thinking too much about the lore, especially the rules of the tournament and how long Shao Kahn must have been waiting around between fights. The math got a little weird for me. But eventually I had to remind myself that this is Mortal Kombat. The relationships and lore exist to support a fighting game. Shao Kahn is strong because he is the bad guy and the top boss, and sometimes that is enough.
What surprised me was how quickly the movie gave us character development without making it feel totally rushed. Johnny Cage getting pulled into this thing against his will worked for me. I also really liked that they did not force the story into a love story. Kitana's story was more interesting as this princess from a brutal world who had to become a fighter. The movie moves fast, but not in a way that lost me. I gave it three stars on Letterboxd, which for me means "meh, positive." It was good. I would watch it again if it was on cable or streaming, but it is not something I am going to rush out and buy on Blu-ray. It is not going in the Criterion Collection, but it did its job.
- IMDb media page: https://www.imdb.com/title/tt17490712/mediaindex/
- TMDb search: https://www.themoviedb.org/search?query=Mortal%20Kombat%20II%202026
@@ -0,0 +1,52 @@
---
title: 'Recovering Failed Ubuntu Upgrade'
date: 2024-10-07T22:59:30Z
draft: false
series: "Fun Center"
summary: "Marcus recovers from an aborted Ubuntu Upgrade on his VPS"
phlog: true
tags:
- ubuntu
- how-i-did-it
- technology
---
Forewarning- I tried to ask ChatGPT to help me with this post but it didnt understand and kept misbehaving so I had to forego that for this post. Also I dont normally write about techy stuff so I hope I got it all in the right order.
I use a VPS I got on a black friday sale from [Rack Nerd](https://www.racknerd.com/) and it has been solid for uptime and everything. I run my a few servers up there including my atuin, ntfy, a budgeting app, and some other random one off stuff. I run the nextcloud and other larger storage things at home thanks to Google Fiber/WebPass.
Most of the time I use it as a jump server to connect over to SDF or to wherever else online I'm going and so I dont see my MOTD. A few weekends back I was setting up an [Actual Server](https://actualbudget.org/) aka the budgeting app and I saw that I was out of date and Ubuntu 24.01 was avaialble. Because I'm so good at planning I started up the upgrade and then saw I needed to get to the movies. I hit control c and closed the window. Don't do that!
So I left everything running for a month or so and decided today I would get it going. First I tried the simple
`sudo apt update && sudo apt upgrade`
Update was happy but upgrade was mad. It suggested maybe I should run `sudo apt --fix-broken install` which then also told me to try `sudo apt-get clean` from there I was off to startpage to see if I could find something. I tried `sudo dpkg --configure -a` and I tried `sudo apt upgrade --fix-missing` and `do apt-get -f install` at this point I was starting to get a little desperate. How desperate? Messing with some system level files desperate!
I found a Stack Overflow question and the answers suggested moving the dat files from /var/cache/debconf to a backup directory and then trying to upgrade again. That failed but told me that everything failed because it depended on systemd-sysv. Oooh progress!
At this point when I ran the apt update and then apt upgrade I got a warning about the shadow group cdrom already existing. so I edited the /etc/gshadow file to remove it. Then it was another group. I noticed that they were all groups that had ubuntuf in the last field. I put the cdrom entry back, duplicated the file, and then deleted all the ubuntufs in there. Then I ran `sudo dpkg --configure -a` Hey it finished!
```
Do you want to continue? [Y/n] y
(Reading database ... 147882 files and directories currently installed.)
Preparing to unpack .../systemd-sysv_255.4-1ubuntu8.4_amd64.deb ...
Unpacking systemd-sysv (255.4-1ubuntu8.4) over (249.11-0ubuntu3.12) ...
Setting up systemd-sysv (255.4-1ubuntu8.4) ...
Processing triggers for man-db (2.10.2-1) ...
needrestart is being skipped since dpkg has failed
```
I switched over to root to run these because I was done typing sudo sudo sudo so much
Let's try the apt update .. so far so good
Lets try upgrade .. no not quite there yet
Ok how about `apt --fix-broken install`
Wooo it was installing like crazy.
It wasn't quite done though. I ran apt update and we still had quite a few packages to work on.
One more apt upgrade and then it was time to restart.
After reboot we were on 24.01. Now I need to upgrade postgresql eventually...
+52
View File
@@ -0,0 +1,52 @@
---
title: 'The Sheep Detectives'
date: 2026-05-09T19:00:00Z
draft: true
series: "Frank's Couch"
summary: "A surprisingly packed Galaxy Theatres screening of The Sheep Detectives, a sweet and funny mystery that turned out to be much more touching than expected."
# Fill in IMDB ID, then run: python scripts/fetch_movie_data.py
imdb: "tt32565993"
# Auto-filled by fetch_movie_data.py:
poster: ""
year: 2026
runtime: 109
director: "Kyle Balda"
genres: ["action", "comedy", "family", "mystery"]
tags:
- galaxy-theater
- no-pizza
- no-expectations
---
{{< imdbposter >}}
| Date watched | 2026-05-09 |
|---------------------|-----------------------|
| Show Time | 2:00 PM |
| Theater | Galaxy Theatres Austin |
| Theater Number | 9 seat A-10 |
| Pizza | No, sad times |
| Tickets | Bought at Door |
| Letterboxd Rating | 4 Stars |
| Crew | Coach T, Kid Negativity |
{{< /imdbposter >}}
## Review
After Mortal Kombat II, we stayed at Galaxy Theatres for the 2 PM showing of The Sheep Detectives. This one was a surprise smash. The theater was already really full, and we were back in the front row again. People were in Rows B, C, D, and all over the place. It was nice to see that kind of turnout for something that, at least from the outside, looked like it could have been a smaller or quieter family movie.
For the second movie, I got a refill on my large drink, which confirmed that at Galaxy it is probably best to just get the large if you want more than a small. The price jump from small to medium is bigger than the jump from medium to large, and the large comes with a free refill. I also got Buncha Crunch and a large Diet Coke. I am usually more of a Coke Zero or Coke Y3000 person, and the Diet Coke tasted a little funny, but alas, that's the breaks.
The Sheep Detectives was incredible. It has so many stars in it that I was worried it might turn into one of those ensemble messes, but it is wholesome, beautiful, and way more touching than it had to be. The sheep are animated, but they still feel believable. I think part of what helps is that they look like CGI sheep living in a real field and a real town. The setting does not feel fake, so it is easier to buy into the sheep as the actual stars of the movie.
The voice cast is ridiculous in the best way. Chris O'Dowd plays Mopple, the sheep who remembers everything because he is the only one who cannot choose to forget. The other sheep have this funny ability where they can all decide to forget something together, close their eyes, hear a little ding, and then suddenly have no idea what was happening. Julia Louis-Dreyfus is one of the main sheep, and her voice has this soothing, motherly quality that works really well. Patrick Stewart is the old curmudgeonly ram, and Bryan Cranston is Sebastian, the big alpha ram of the group. Bella Ramsey is in there too, and Rhys Darby was very easy to pick out right away.
The setup is simple but really effective. Hugh Jackman plays George, the shepherd who takes care of the sheep, talks to them, reads to them, and lives as kind of an outsider near this small town. He is writing a letter to someone, and at first we do not really know who. Then he ends up dead right around the time a local festival is supposed to happen, and suddenly the movie turns into a murder mystery. There is a reporter looking for a story, a very inept police officer, townspeople with secrets, and sheep trying to solve what happened to the man who cared for them.
I saw some people describe it as "Knives Out for children," and I do not totally disagree. It has that cozy mystery shape, but it is softer, sillier, and more emotional. I will not spoil the ending, but I was not fully prepared for how touching it got. There are some great tearjerker moments and some genuinely lovely performances. It is simply way better than it has to be, and I really enjoyed it.
## Image Ideas
- IMDb media page: https://www.imdb.com/title/tt32565993/mediaindex/
- TMDb search: https://www.themoviedb.org/search?query=The%20Sheep%20Detectives%202026
+68
View File
@@ -0,0 +1,68 @@
---
title: Terrifier 3
date: 2024-10-15 00:28:11+00:00
draft: false
series: Frank's Couch
summary: The Boys get terrified, late at night.
imdb: tt27911000
tags:
- ghost theater
- anticipated
- no-pizza
poster: /images/posters/terrifier-3.jpg
runtime: 125
year: 2024
director: Damien Leone
genres:
- Horror
- Thriller
---
{{< imdbposter >}}
| Date watched | October 12th |
|---------------------|-----------------------|
| Show Time | 9:45 pm |
| Theater | Ghost |
| Theater Number | 6 |
| Pizza | No |
| Tickets | Box Office |
| Letterboxd Rating | *** (3) |
| Crew | Me, Science Bro, and Coach T |
{{< /imdbposter >}}
# Early October in Austin and Terrifier 3
There's a special time in Austin when the weather starts to cool, hurricane season comes to an end, and Austin City Limits (ACL) takes over Zilker Park. This music festival keeps growing every year, and its impact on the park grows with it. The ground this year is pounded into a hard smooth dirt floor more suited to heavy equipment than family picnicks. Fortunately the huge revenues are able to pay for a miraculous revory to be complete just in time for the next ACL.
I've been going off and on over the past ten years, but the last two years I've made it a point to attend. Last year, the whole movie crew went, but this year it was just me and Nurse Vegas. I went all day Friday, but when I woke up on Saturday, my feet hurt so bad that I could barely make it to the bathroom. I texted Nurse Vegas to let them know I might skip that day, and I ended up going back to sleep for a few hours.
Later that afternoon, I checked my phone and realized I'd marked the wrong weekend on my calendar. Instead of ACL, I had other plans, like movies and a Master Pancake show. It was a happy coincidence, because my feet were still killing me and sitting down sounded great. So instead, I went to see *Ghost Rider* at a Drafthouse up north. It might technically still be Austin but spiritually it is definitely Cedar Park or some other kind of suburb.
After the movie, I messaged the group chat to see if we were still seeing *Terrifier 3*. It was showing at 9:45 PM, and I was feeling a good bit better, thanks to ibuprofen. I'd enjoyed *Terrifier 2*, so I was excited to check out the third one. I headed down to Ghost Theater, which is in deep South Austin, but hey, beggars can't be choosers. Also we've kind of learned that Gucci Theater is usually worse late at night, so it was the best option.
I met up with Science Bro and Coach T, and we hung around outside the theater for a bit before the movie. The boys didnt know I skipped ACL that day, but they were cool about it. I was still excited for Sundays lineup at ACL, especially to see [Chappell Roan](https://en.wikipedia.org/wiki/Chappell_Roan) and [Tyler, the Creator](https://en.wikipedia.org/wiki/Tyler%2C_the_Creator).
At the concession stand, I grabbed a *Terrifier* cup and a large Icy, which set me back 8 bucks (wild). I also got some Reese's Thins. Ghost Theater doesnt have ready-to-eat hot food, so I skipped ordering something that would end up in an awkward wait at the end of the concession line.
Normally, we spread out along row B leaving a gap between us to put our snacks and stuff, but a guy behind me had seat 11, so I ended up sitting next to Coach T. The other guy didn't realize how close Row B was and eventually moved to row three, but I was already settled and didn't wanna bother moving.
Now, onto the movie! *Terrifier 3* is a solid two hours and five minutes of Art the Clown terrorizing the residents of Miles County on Christmas Eve. There are a few returning characters from *Terrifier 2*, like the brother Jonathan, but his screen time was surprisingly short. Sienna, had a much bigger role, and it was cool to see how theyre building out this universe.
One of the more interesting additions was Arts new sidekick, a woman from a mental ward with some body mutations including no eyelid on one side and the other eye completely gone. I appreciated that they didn't take some known existing medical condition and cast it as horrific. There were adult situations in the movie, but it made me laugh because it was so unexpected.
As for the kills, more than one happened off-screen, which was a bit of a letdown. I loved the chainsaw action, though. If youre a fan of gory horror, youll have fun with *Terrifier 3*. It's got that same wild energy as the other movies in the series, but if you havent seen *Terrifier 1* or *Terrifier 2*, you might miss some of the context. Watching *Terrifier 2* is a good litmus test to see if youre into the series.
After the movie, we hung around outside the theater, talking about the film. It was a good time overall. On Letterboxd, I gave it 3 stars. Coach T didnt rate it, but Science Bro also gave it 3 stars. Definitely a fun time if you're into the *Terrifier* series!
---
*Other Movie Details:*
- IMDB ID for *Ghost Rider*: [tt0259324](https://www.imdb.com/title/tt0259324)
- IMDB ID for *Saturday Night*: [tt27657135](https://www.imdb.com/title/tt27657135)
Until next time!
+49
View File
@@ -0,0 +1,49 @@
---
title: The Housemaid
date: 2026-01-01 05:54:14+00:00
draft: false
series: Frank's Couch
summary: Marcus goes it alone on New Year's Eve to learn about manipulation and the
cost of privilege.
imdb: tt27543632
poster: /images/posters/the-housemaid.jpg
tags:
- marcel
- no-expectations
runtime: 131
year: 2025
director: Paul Feig
genres:
- Mystery
- Thriller
---
{{< imdbposter >}}
| Date watched | December 31, 2025 |
|---------------------|-------------------|
| Show Time | 1:25pm |
| Theater | Marcel |
| Theater Number | 11 |
| Pizza | No |
| Tickets | Online - Email QR Code |
| Letterboxd Rating | **** (4.0) |
| Crew | Just Me |
{{< /imdbposter >}}
What an exciting and fun ride The Housemaid turned out to be.
I went in only knowing what Id seen in the trailer that depicted an interview for a job. Well don't worry that happens very close to the beginning! It also is nice because I wont be dropping any major spoilers talking about it. We immediately get a sense of how the characters and story will develop. Everything looks picturesque and perfect, but it isnt what it seems. Millie (Sydney Sweeney) arrives with an impressive résumé and a story about finding her calling in housekeeping. She wears glasses and tries her best to make a good impression. Nina Winchester (Amanda Seyfried) tells Millie shes expecting, but also asks her to not tell her husband. The whole first act we have alot of, Nina says one thing in private and another in public, creating a pattern of tension and manipulation right away. Is Nina manipulating Millie or is Millie an unreliable narrator manipulating Nina?
This world felt so different from mine that, at first, I wasnt sure I was going to really "get" the movie. I can watch wizards and spaceships and absurdity and fall right in, but this story relies on the psychological interplay between people, social expectations, and emotional boundaries. Once that clicked, the movie opened up for me. I feel like that was my greatest take away and it wasnt even explicitly part of the movie. The social relationships and societies pressure on people are not fixed. You can play with those too. I know this sounds so juvenile but anyway I want to share in case someone out there didnt get it and maybe this will help them try again. We mostly follow the hero's journey Millie starts with nothing, struggles against the family and the situation, pays a personal cost, and eventually finds reward ending at the beginning.
Andrew (Brandon Sklenar), Ninas husband, was vaguely familiar to me. I looked him up, he was in 1923, the Yellowstone spinoff—but otherwise hes not in a ton of high-profile roles. Think a midpoint between Chris Evans and Josh Hartnett. There are multiple sex scenes between Millie and Andrew, but theres also a scene between Andrew and Nina that reads as clear marital SA / r*pe scene which may be triggering for some viewers.
The movie has a small cast of 16 named roles, 10 of them women. I think thats worth noting. If I'm off please tell me, I'm an older white guy, but I think the film works because its psychological tension relies on expectations placed on women, and how those expectations are shaped by patriarchy, the prison-industrial complex, and outdated mental health systems. Those structures help explain how characters are controlled.
Since Im already in the meta: The Housemaid opened the same weekend as Avatar: Fire and Ash, a new SpongeBob movie, and Angel Studios David. It made about 8 million dollars USD on Friday and 19 million for the weekend. Rotten Tomatoes scored around 74 percent and Metacritic averaged out around 65.
Speaking of Angel Studios: they released The Sound of Freedom, marketed as a true story about stopping child trafficking, but the man the film was based on was later arrested for kidnapping. They originally started as a filtering service that pirated TV shows and edited them to align with their religious values; in 2016, they were sued by Hollywood studios for copyright violations. They used crowdfunding to pay their settlement and now use crowdfunding to produce content. The company is valued at around $1.6 billion. They launched the company publicly on September 11, 2025, which tells you something about their branding priorities. They grind my gears in a special way.
I hope this is a worthwhile and quick read. Im still figuring out how much to discuss without spoiling too much. The point of this blog is to talk about movies, so Ill keep working at the balance. Thanks for reading. Have a happy New Year, and Ill see you in 2026.
+51
View File
@@ -0,0 +1,51 @@
---
title: The Secret Agent
date: 2025-12-26 00:37:12+00:00
draft: false
series: Frank's Couch
summary: Its Christmas lets go watch a movie or two. Secret Agent is a Brazilian 70s
Spy Thriller
imdb: tt27847051
poster: /images/posters/the-secret-agent.jpg
tags:
- no-expectations
- alamo-drafthouse
runtime: 161
year: 2025
director: Kleber Mendonça Filho
genres:
- Crime
- Drama
- Thriller
---
{{< imdbposter >}}
| Date watched | December 25, 2025 |
|---------------------|-------------------|
| Show Time | 11:15 am |
| Theater | Alamo Drafthouse S.Lamar |
| Theater Number | 9 |
| Pizza | No |
| Tickets | Via App |
| Letterboxd Rating | **** 1/2 (4.5) |
| Crew | Just Me |
{{< /imdbposter >}}
I watched "The Secret Agent" (2025) this Christmas morning and it was so much different than I had expected. Set in 1977 Brazil during Carnival, it follows Marcelo (Wagner Moura) or Armando depending on who you ask, as he moves through Recife, the state capital north of Rio, trying to survive and reconnect with his son in a world that feels hot and muggy but also full of life with a hint of government corruption mixed in.
{{< figure src="/images/article-art/recife-map.png" title="Map from Wikipedia showing Recife" >}}
The movie is not simply about a spy or what I thought of when I heard "The Secret Agent". It feels more like a weird road trip movie. There are colorful clothes, great music and sound work, dancing, and unexpected bits of comedy. The movie has various cuts where we fade out but the story keeps moving. It creates this sense we are watching through the eyes of someone else.
Those cuts interestingly enough leave you missing information about Marcelo and what he is doing until the narrative begins slowly piecing it together. I was not totally clear on who the "secret agent" was until much later. At first it feels like he is just wandering, staying at halfway houses and running from who knows what, but it leads to something surprisingly sweet with his kid.
This made me think about another recent Brazil film I liked. "I'm Still Here" (2024) from Walter Salles. That one is based on the disappearance of Rubens Paiva and his wife Eunice's struggle after. Much heavier, but worth watching if you liked the political backdrop here.
Anyway, fun watch, weird and colorful, and not what I expected from the title. Maybe I gave it an extra star because I Loved I'm Still here I don't know.
My Letterboxd review has a few more thoughts: https://letterboxd.com/marcuseid/film/the-secret-agent-2025/
+63
View File
@@ -0,0 +1,63 @@
---
title: 'The Unbelievable Truth'
date: 2026-01-18T20:10:29Z
draft: false
series: "Frank's Couch"
summary: "Marcus checks out one off of his friend's Letterboxd Watchlist. A fun movie that presents a snapshot of America in 1989 and tells a rom-com style love story."
phlog: true
imdb: "tt0100842"
poster: "/images/posters/the-unbelievable-truth.jpg"
tags:
- homevideo
- no-expectations
# Mastodon comments: After posting about this on Mastodon, add the post ID below.
# Get the ID from the end of the toot URL, e.g. https://tilde.zone/@mnw/123456789
# mastodon_id: ""
# To block a reply from showing, add its full URL to this list:
# mastodon_blocked:
# - "https://tilde.zone/@someone/123456789"
---
{{< imdbposter >}}
| Date watched | January 16, 2026 |
|---------------------|-------------------|
| Show Time | Morning |
| Theater | Home Video |
| Theater Number | Closet Computer |
| Pizza | No |
| Media | Online |
| Letterboxd Rating | **** (4.0) |
| Screen | 1080p Computer |
{{< /imdbposter >}}
I wrote a long review and some thoughts about this movie, and when I read it back I realized I was trying too hard. I wanted to share how I felt about a movie, but somewhere in that process I started trying to sound like other people who write about movies online. That is not really my speed. Because of that, the last couple of posts probably came off as a bit pretentious, or at least not quite like me, and I want to own that.
One of my friends had The Unbelievable Truth in their watchlist on Letterboxd, and I thought the title sounded interesting. I like a good romantic comedy, and the blurb said it was an indie film and the first feature for Hal Hartley and Adrienne Shelly, who some people later referred to as his muse. That already felt like something I would enjoy.
Another actress who shows up in a lot of independent films from this era is Parker Posey, who worked with Hartley again in Amateur in 1994. Adrienne Shelly also deserved a much longer career. She died far too young, and there is an HBO documentary called Adrienne that looks at her life and death with some really strong interviews. I would recommend it if you like her work or want more context around her career.
So what is this movie about? A guy named Josh has been in prison for ten years and is returning home to rebuild, or maybe start building, his life. We learn that Josh went to prison shortly after turning eighteen. He kept his head down, did his time, and learned how to be a mechanic while he was inside. When he gets out, that is the skill he plans to use to find work.
While looking for a job in town and trying to find someone willing to hire him with his record, he stops into a secondhand store. That is where he meets Audrey. She is a seventeen-year-old high school senior who spends her time reading philosophy and is convinced the world is going to end soon, so school and work feel pointless to her. Her worldview is played for comedy, but it also lines up in interesting ways with Josh, who is also shown reading and thinking a lot about the meaning, or lack of meaning, in life.
{{< figure src="/images/article-art/UnbelievableTruth.png" title="Audry and Josh eyes meet while flirting." >}}
There is a great scene where Josh explains his philosophy. Even though he and Audrey end up in a similar emotional place, the reasons behind it are very different. Josh feels that after having done something he once thought was impossible, surviving prison and coming out the other side, the rest of the system feels arbitrary and empty. They are drawn to each other, but Audreys father does not want them together. He pushes Audrey toward a modeling job in New York as a way to pay for college and put some distance between her and Josh. Did I mention Vic has a great look? Check out that mustache and the hair style is out of this world in a good way.
{{< figure src="/images/article-art/UnbelievableTruth-VicHugo.png" title="Vic has the most interesting look to me. A great throwback." >}}
Over time, the family gets to know Josh better and starts to believe he is not a bad guy. Eventually, they even ask him to go to New York and bring Audrey home. This part is still the hardest for me to fully understand. Maybe it is because I am not a parent, but Audreys father Vic seems convinced that Josh is dangerous and a bad choice of partner for his daughter. Then, after talking with the other mechanic at the shop, Mike, he does a complete 180, gives Mike five hundred dollars, and asks him to go bring Audrey home. The suddenness of the change made me laugh. Mike comes to this conclusion after talking with Josh about his past relationships and realizing that he has deep emotional attachments to the women in his life. Both Vic and Mike briefly assume that Josh might be gay, and the way they talk about that possibility is a very telling snapshot of what acceptance looked like in the late 80s and early 90s.
I do think this movie is worth watching, but you do have to swap out your 2026 ideas for 1990 sensibilities at the door. The way men talk about women, and the way women are expected to behave, is clearly dated. The way sexuality is discussed is stiff and awkward. There is a moment where Mike presents himself as tolerant by saying he does not care if someone is gay, as long as they are not interested in him. It is played for humor, but it is also unsettling, because that kind of logic is often used to justify cruelty or violence.
Still, there are small details I liked. Seeing rotary phones used casually feels strange now, but also grounding. The movie is very much of its time, and it does not try to hide that.
There are a few re-curring bits that are fun. There's a photographer who keeps asking women if they are a model or want to be one and Audry's ex who keeps trying to fight people who look at her.
{{< figure src="/images/article-art/UnbelievableTruth-Photographer.png" title="Photographer asking women to model is gross but also a bit." >}}
{{< figure src="/images/article-art/UnbelievableTruth-2.png" title="Vic talking to Mike" >}}
+88
View File
@@ -0,0 +1,88 @@
---
title: Uptown Saturday Night
date: 2026-01-02 04:00:57+00:00
draft: false
series: Found in the Darkroom
summary: 'We embark on our journey to watch movies of the National Film Archive starting with a fun to watch comedy from 1974.'
imdb: tt0072351
poster: /images/posters/uptown-saturday-night.jpg
year: 1974
runtime: 104
director: Sidney Poitier
genres:
- Comedy
- Crime
- Action
nfr_year: 2024
letterboxd_url: 'https://letterboxd.com/marcuseid/film/uptown-saturday-night/'
tags:
- national-film-registry
- home-video
---
{{< imdbposter >}}
| Date watched | |
|------------------------|-----------------------|
| Format | 4k TV w/Panasonic BRPlayer |
| Watched Multiple Times | Second Watch |
| Added to NFR | 2024 |
| Letterboxd Rating | **** (4.0) |
| Personal Notes | Fun and full of laughs |
{{< /imdbposter >}}
## Why It's in the National Film Registry
Preserved as Sidney Poitier's directorial effort "dispelling stereotypes" of the Blaxploitation era through an entertaining crime comedy ensemble cast.
*Source: [Library of Congress National Film Registry 2024 announcement](https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/)*
## My Thoughts
My friend Mehone recommended Uptown Saturday Night to me a year or two ago. I watched it back then and enjoyed it, but I never logged it or wrote about it since it was just a fun weekend movie at the time. However, now that Im working my way through the National Film Registry (starting with the 2024 additions), I decided to revisit it, and Im finding a lot to like.
**The Setup**
The plot follows Steve Jackson (Sidney Poitier), a blue-collar worker who has two weeks of vacation. It looks like a foundry of some kind but I believe they call it a factory in the movie for some reason it's something that is sticking in my mind. Since his wife is still working, he plans to just relax around the house. However, his best friend, Wardell Franklin (a young _beareded_ Bill Cosby), thinks Steve needs to unwind a little more aggressively.
Wardell suggests going to Madame Zenobias, a high-class, after-hours club. Everyone knows about it, but not everyone can get in. Wardell manages to forge a letter of introduction using his wife's employer's stationery, claiming they are important players in the diamond business. Surprisingly, this gets them in the door.
The Incident
The club is a showcase of the hottest looks of the era with big hats, wonderful hairstyles, and wild outfits. Steve and Wardell eventually find their way to a room behind the red door where gambling is taking place. In the 70s there was also an early adult film called "Behind the Green Door" I dont know if it is a nod to that or not but it is a little funny to have that in mind when you are watching this scene play out. The casino is obviously a high-stakes environment and the bouncer warns the guys that just watching isnt allowed and the buy-in is 150 bucks. Steve lends Wardell some cash, and he starts betting on Leggy Peggy who is on a hot streak. He's turned his 50 dollar bet into a few hundred!
Unfortunately, the celebration is cut short when a crew busts in to rob the place. In a strange twist, or maybe it was just a thing they did at the time, the robbers force everyone to strip down to their underwear. They say in case one of you has a heater which I think means a concealed weapon. It also helps to prevent anyone from chasing them immediately. (One woman claims she isn't wearing underwear, but they make her strip anyway! The movie keeps it PG and doesn't show anything explicit).
The robbery sets up the central conflict: Steve had a lottery ticket in his wallet containing his lucky numbers. The next day, he sees those numbers hit the jackpot in the newspaper, and realizes the ticket is lost! The ticket is worth $50,000 (which is over $320,000 adjusted for inflation). Its life changing amount money that would allow his family to move out of the inner city. The rest of the movie is a hilarious race to find the wallet without letting anyone know what is in it.
**A Star-Studded Cast**
The film features a massive roster of wonderful actors, and everyone gets a moment to shine.
Harry Belafonte plays Geechee Dan, a menacing gangster who looks like he has bad allergies or is just really sick.
Flip Wilson plays the Reverend who preaches "No joy juice at the picknic!"
Richard Pryor has a cameo as Sharp Eye Washington, a con man, who posed as a private eye briefly.
Calvin Lockhart plays Silky Slim a rival gangster to Geechee Dan.
Rosalind Cash plays Steves wife, Sarah Jackson. She has some of the best lines!
Paula Kelly and Lee Chamberlin (Madame Zenobia) also turn in great performances.
One of the funniest performances comes from Roscoe Lee Browne, who plays Congressman Lincoln. His character satirizes politicians embracing the Black Power movement for votes. When constituents arrive, he hurriedly flips a picture of Richard Nixon around to reveal a portrait of Malcolm X and changes from a suit into a dashiki to play the part. It was a hilarious reminder of how post-Watergate movies depicted politicians as chameleons willing to say anything for a vote.
The Elephant in the Room
It is impossible to discuss this film without acknowledging that Bill Cosby has since been convicted of heinous sex crimes. However, looking strictly at the film as a 1970s comedy, the character he plays does not have any romantic entanglements or questionable "adult" situations. If you can, as they say, separate the art from the artist's off-screen behavior, his dynamic with Poitier is genuinely funny.
**The 70s Aesthetic**
There are some very specific "70s things" in this movie that I really enjoyed. For one, the church picnic scene is massive. The church actually owns a Greyhound style bus to transport the congregation to a fairground for food and games it really captures the community vibe of the era.
The fashion is also incredible. As a child of the 80s and 90s, I used to think bellbottoms and wide lapels looked ridiculous. Watching it now, I totally get it. The lines, the colors, and the energy that the right pair of shoes or jacket conveyed allowed people to really stand out. Plus, the slang is a blast to listen to you don't hear people getting called "turkeys" enough anymore.
Preservation and Quality
To wrap things up, I was struck by how well preserved this film is. Because it is on film it was also possible to be scanned in at high resolution and detail. The audio is just as crisp as when it was recorded.
It makes me wonder about our current digital era. We record video just to compress it immediately. Many movies were left behind on VHS, then DVD, then Bluray. In 30 years, when we are watching on "2060's Hottest new Retina 20K" displays, our current digital footage might look blown out and pixelated. But Uptown Saturday Night? It will still look sharp.
+50
View File
@@ -0,0 +1,50 @@
---
title: Urchin
date: 2025-12-25 15:53:35+00:00
draft: false
series: Frank's Couch
summary: I watched movie that felt very real and led me to refelct on mylife. Felt
almost like I could have escaped into the tv screen.
imdb: tt35715953
poster: /images/posters/urchin.jpg
tags:
- homevideo
- no-expectations
runtime: 100
year: 2025
director: Harris Dickinson
genres:
- Drama
---
{{< imdbposter >}}
| Date watched | December 14, 2025 |
|---------------------|-------------------|
| Show Time | Evening |
| Theater | Home Video |
| Theater Number | Living Room |
| Pizza | No |
| Media | Online |
| Letterboxd Rating | ***** (5.0) |
| Screen | 4k TV |
{{< /imdbposter >}}
I wrote a short paragraph on Letterboxd right after watching *Urchin (2025)*. If you want the quick version, read it here:
[My Letterboxd review](https://letterboxd.com/marcuseid/film/urchin-2025/)
---
Directed by **Frank Delaney** and starring **Mike Carter (Will Parker)** and **Nathan Reed (Julian Pierce)**, *Urchin* focuses on homelessness, addiction, and survival without the typical cinematic buffer that sanitizes those topics. Its not poverty as an aesthetic or a redemption tourism kind of story. Its practical: where you wake up, where you can pee, whether you have a blanket, how you get through the hour before you can think about the day. Survival is the real drumbeat of the movie.
In the early 2000s, I spent time either homeless or crashing wherever I could. Im not Mike, and I havent had the same relationship to addiction, but the urgency, dull terror, and logistical problem-solving of "simply existing" rang painfully true. The film understands that the path down and the path back up are not the same and are unique to each individual. People may fall at any point. Luck is as important as genuine effort. Theres no moral grading scale for survival.
The supporting characters feel lived-in rather than just popping into existence. **Andrea (Marissa Vale)**, the RE counselor holding everything together with spit and hope, is painfully believable. Its my understanding that in the US there is even less support once you get out. You have to rely on religious organizations for the most part. The friend with a couch isnt a trope; shes the connective tissue of the community. Nathans shift from dealing drugs to being a kept man isnt framed as a downfall or escape, its just a path. A path you might not take, but still recognize.
Homelessness here feels like slipping into a parallel layer of the city—almost like putting on the ring of power in Lord of the Rings. You arent literally gone, but to most people you might as well be. They dont see you; they sense you the way someone senses a draft in the room. Only those already inside that layer other "ring-wearers", people who know the signs and the reality can actually perceive you. In that hidden layer, there are networks and hierarchies, violence and kindness, boredom and jokes, grudges and rules. A small world, but a complete one. The film captures how it can feel both tiny and overwhelmingly complex at the same time.
I dont want to overshare or claim authority I dont have; I got lucky in ways others didnt. My mother giving me her old car at eighteen, and being willing to take me back in when I realized I was not going to get back on my feet alone really changed the trajectory of my life. The film never pretends that Mikes path applies universally. Thats why it works. Stories arent interchangeable.
Theres a line about **"a gap in empathy"** that stuck with me. Its the gap people fall into long before they fall between jobs or into the street—the gap where being unseen turns into being unreal. *Urchin* doesnt try to rescue anyone from that gap. It just asks you to look into it.
---
+76
View File
@@ -0,0 +1,76 @@
---
title: Will and Harper
date: 2024-10-05 16:26:32+00:00
draft: false
series: Frank's Couch
summary: I watched Will and Harper at Home on a Sunday afternoon.
imdb: tt30321133
tags:
- no-expectations
- no pizza
poster: /images/posters/will-and-harper.jpg
runtime: 114
year: 2024
director: Josh Greenbaum
genres:
- Documentary
- Comedy
---
{{< imdbposter >}}
| Date watched | September 9th |
|---------------------|-----------------------|
| Show Time | 2:08pm |
| Theater | My Desk |
| Theater Number | The big screen computer |
| Pizza | No Pizza |
| Tickets | Its on Netflix |
| Letterboxd Rating | ****(4) |
| Crew | Team Me |
{{< /imdbposter >}}
I haven't written more than a couple of paragraphs in an email in a long time and I'm finding it hard to string together my thoughts. What I did here is dictated my thoughts on the movie and then fed them through Chat GPT and then edited the output. I think this workflow will help me make more coherent and cohesive posts without sounding like a robot. It's a challenge to get these thoughts out. Maybe over time I'll depend on it less and less. Thats my hope anyway.
Another note is that this blog is called the Double Lunch Dispatch because in I Saw the TV Glow there is a bar that is in both the Pink Opaque and in the midnight realm where I think the movie takes place. The idea being this could be a zine or a newsletter that you found in the bar talking about the latest movies or beers or whatever out there. Frank is Owen's dad and he is always watching TV so we are watching movies on Frank's Couch for a series name. Luna juice is what Mr Melancholie's henchpeople make you drink to come under his control or so you die so that's what the Beer series is called. I'll probably use other TV Glow references but just so you know where it all comes from.
The other night, instead of watching the Packers lose in Jordan Love's first game back, I found myself looking for something more entertaining at half time. That's when I stumbled upon Will and Harper, a documentary featuring Harper Steele and Will Ferrell. What I expected to be a light road trip film quickly revealed itself to be much deeper, touching on the complexities of gender identity and accepting your friends where they are.
####Gender and Society: A Lens on Privilege
In the United States, and through alot of the west systems of oppression are layered. There is Race are you a member of the dominant group, then Gender are you a man in the patriarchal society we have this is a big one, then evaluate economic status are they disabled or have any phsyical differences. I'm sure there's many more I'm a white guy working a tech job. I try and be aware of things but there are likely many privileges I am not even aware of.
For Harper, this means facing the world without the same privilege and experiencing the world through a different lens, one that comes with new dangers and risks. Throughout the trip, we see the constant caution she must exercise simply because she's a woman, and then sometimes even more care because she is a trans woman. This vulnerability is especially clear as they travel through more conservative parts of the country, where traditional gender roles are deeply entrenched, and hostility towards the LGBTQ+ community is tolerated or encouraged by government policy.
Will, with his fame and privilege, moves through the world without fear, while Harper is experiencing in some places a brand new sensation of constant vigilance against the potential threats around her. This contrast between their experiences helps to highlight roles both friends have to play for each other.
####The Complexities of Gender Roles and Expectations
Another element I found powerful in Will and Harper is how societal expectations of gender. Harper's transition doesn't just change how she is seen; it also challenges deeply held beliefs about what it means to be a man or a woman. In many ways, her journey is a confrontation with a patriarchal society that sees women, and especially trans women, as "lesser" or "weaker." The film doesn't shy away from showing the microaggressions and outright hostility Harper faces simply for existing in a space where she doesn't conform to social expectations.
The documentary captures the emotional toll of navigating a world that isn't always accepting, and it makes you think about the lengths women, and particularly trans women, have to go to protect themselves. Harper's story is a reminder that gender identity is a profound part of who we are, and society's reaction to it can either validate or endanger a person's existence. There is a moment near the beginning when many old SNL friends are all sitting together and I think it was Tina Faye just casually mentions yeah you cant do that when referring to going down a dark alley alone in the city. It was so matter of fact that I didn't really notice it the first time but when I rewatched the scene I really felt that. Like there is an acceptable level of violence against women and you have to just work around it if you want to exist. Like watching that scene in Hidden Figures if you search for " No more colored bathroom,no more white bathroom" it should come up. Privileges are often invisible to those who have them and it was just another light coming on for me.
####Friendship and Reconnection: Navigating Change Together
While gender plays a central role in the film, Will and Harper is also a story of friendship. Will Ferrell and Harper Steele have known each other for years, but this road trip is their first time reconnecting since Harper's transition. There is a wonderful love in how they navigate the changes in their lives while still holding onto the core of their bond.
Watching them interact reminded me of that universal experience of reconnecting with an old friend. When people change, especially in big ways like Harper has, you often wonder if they're still the same person underneath it all. Will and Harper shows that despite the physical and emotional changes Harper has gone through, their friendship is still very much intact. Will's support of Harper throughout their journey is a testament to the resilience of true friendship and a reminder that friendship, when it's real, can survive transformation.
####Privilege and the Reality of Safety on the Road.
As the film follows their journey across the country, the stark differences in how Will and Harper experience the trip are impossible to ignore. Will, as a wealthy and famous man, can enjoy the freedom of the open road without a second thought. For Harper, every stop, whether it's a gas station or a small-town diner, comes with a risk. There's an underlying tension in the film that reflects the reality faced by many women and trans people in America today.
This disparity in safety and privilege was a major takeaway for me. It's a reminder of how much we take for granted based on our societal status and identity. Harper's past experiences of traveling carefree now seem distant, as she navigates the world with heightened awareness of the dangers that come with her identity. It's a sobering reflection on how privilege, or lack of it, shapes every aspect of life.
####A Reflection on Identity and Change
Ultimately, Will and Harper is about identity, how it evolves and how we come to terms with it. For Will, this road trip is a chance to understand Harper's transition and what it means for their friendship. For Harper, it's a way to confront the fears and challenges that come with being a trans woman in a society that doesn't always accept her.
The documentary doesn't offer easy answers, but it does provide a thoughtful exploration of what it means to live authentically in a world that often resists change. The road trip serves as a metaphor for the journey of self-discovery, and by the end, both Will and Harper have learned something new about each other and themselves.
####Final Thoughts
Will and Harper is far more than a road trip movie. It's a powerful exploration of gender, identity, and friendship in a society where these issues are still deeply contested. The film shows us that even in a world that is often hostile to change, true friendship and self-acceptance can offer a path forward.
Watching the film reminded me of the importance of empathy, of seeing the world through another's eyes. Harper's story, and Will's support of her, is a reminder that we all have a role to play in creating a world where everyone can feel safe being themselves.
+224
View File
@@ -0,0 +1,224 @@
# Gopher Integration Code Review
> **Date:** 2026-01-13
> **Reviewer:** Claude (Opus 4.5)
> **Status:** Ready for deployment
---
## Summary
Implementation of gopher integration for marcus-web is complete. The system converts Hugo blog posts with `phlog: true` frontmatter to gopher-friendly plain text and deploys them to SDF gopherspace.
**7 commits total** | **All tests passing** | **1 critical bug found and fixed**
---
## Files Created
### scripts/gopher/ascii_art.py
ASCII art assets and helper functions for gopher content.
**Contents:**
- Post header (MNW owl logo)
- Category headers (Fun Center, Frank's Couch, Beercalls)
- Post footer (SDF box)
- Series-to-directory mapping
- Movie metadata ASCII table generator
- Text wrapping utilities
**Review:** Clean, well-organized. All art fits within 70-char line width constraint.
---
### scripts/gopher/convert_to_gopher.py
Main conversion script: markdown to gopher text.
**Key functions:**
- `parse_frontmatter()` - YAML extraction
- `extract_links()` - Converts `[text](url)` to `text [1]` with footer references
- `convert_headings()` - `#` → section headers, `##` → subheadings
- `convert_formatting()` - `**bold**``*bold*`, `*italic*``_italic_`
- `convert_code_blocks()` - Fenced blocks → 4-space indented
- `handle_imdbposter()` - Hugo shortcode → ASCII movie table
- `wrap_paragraphs()` - 70-char line wrapping
**Review:** Solid implementation. Handles edge cases well. The imdbposter conversion extracts viewing info tables and preserves them as plain text.
**Fixed bug:** Added `sys.path.insert()` for imports to work when called from shell script.
---
### scripts/gopher/generate_gophermaps.py
Generates gophermap index files for categories.
**Outputs:**
- `blog/gophermap` - Main index with category links and post counts
- `blog/fun-center/gophermap` - Tech posts listing
- `blog/franks-couch/gophermap` - Movie reviews listing
- `blog/beercalls/gophermap` - Beer logs listing (when posts exist)
**Review:** Properly formats gophermap syntax with tab-separated fields. Sorts posts by date (newest first). Includes ASCII art headers per category.
**Fixed bug:** Same `sys.path` fix as convert_to_gopher.py.
---
### scripts/gopher/update_root_gophermap.py
Generates updated root gophermap with "FROM THE WEB" section.
**Review:** Contains full gophermap template. One-time use script for initial setup. Includes dynamic `=echo` directives for latest post detection.
**Note:** This needs to be run manually after first deployment:
```bash
python3 scripts/gopher/update_root_gophermap.py
scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap
```
---
## Files Modified
### scripts/remote_publish.sh
Added `--gopher` and `--gopher-only` flags.
**Changes:**
- Argument parsing with help text
- Conditional Hugo deployment (skipped with `--gopher-only`)
- Gopher build: runs convert + generate scripts locally
- rsync with `--delete` to sync to SDF
- Permission fixing on remote (644 files, 755 dirs)
**Review:** Good error handling via `set -e`. Clear output messages. The `--delete` flag means removing `phlog: true` from a post will remove it from gopher on next deploy.
---
### scripts/new_techpost.py
Added phlog prompt after summary input.
**Changes:**
- New prompt: "Publish to gopher phlog? (y/N)"
- Added `phlog` parameter to `create_post()`
- Frontmatter now includes `phlog: true/false`
**Review:** Clean integration. Defaults to "no" which is appropriate.
---
### scripts/import_letterboxd.py
Added phlog prompt after viewing details.
**Changes:**
- Prompt added in `import_movie()` function
- `phlog` parameter passed to `create_draft_post()`
- Frontmatter updated
**Review:** Good placement - asks after all other inputs are collected.
---
### scripts/new_movie.py
Added phlog prompt after TMDB fetch.
**Changes:**
- Same pattern as other scripts
- Frontmatter includes phlog field
**Review:** Consistent with other scripts.
---
### .gitignore
Added `gopher_build/` to ignore list.
---
### requirements.txt
Added `pyyaml` dependency.
---
## Content Changes
Three posts enabled for gopher with `phlog: true`:
- `content/posts/blog-posting.md` (Fun Center)
- `content/posts/recovering-failed-ubuntu-upgrade.md` (Fun Center)
- `content/posts/megalopolis.md` (Frank's Couch)
---
## Bug Found and Fixed
### Critical: Import Path Issue
**Problem:** `from ascii_art import ...` failed when scripts were invoked from `remote_publish.sh` because Python couldn't find the module.
**Root cause:** When running `python3 scripts/gopher/convert_to_gopher.py` from the project root, Python's working directory doesn't include `scripts/gopher/`.
**Fix:** Added to both convert and generate scripts:
```python
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
```
**Commit:** `b5bb06e`
---
## Minor Issues Fixed
1. **No-op regex removed** - `re.sub(r"_([^_]+)_", r"_\1_", text)` did nothing
2. **Unused variable removed** - `in_code_block = False` was never used
---
## Testing Performed
1. **Conversion test:** `python3 scripts/gopher/convert_to_gopher.py --all` - 3 posts converted
2. **Gophermap test:** `python3 scripts/gopher/generate_gophermaps.py` - All maps generated
3. **Output verification:** Manually inspected generated .txt files and gophermaps
4. **Import fix verification:** Re-ran after fix, all working
---
## Deployment Checklist
- [ ] `git push` to sync with origin
- [ ] Run `./scripts/remote_publish.sh --gopher` for first deployment
- [ ] Run `python3 scripts/gopher/update_root_gophermap.py` to generate root map
- [ ] `scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap` to update root
- [ ] Verify at `gopher://sdf.org/1/users/mnw/blog/`
- [ ] Test via web proxy: https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/blog/
---
## Future Considerations
1. **Beercalls:** No beercall posts have `phlog: true` yet. The category exists but is empty.
2. **Movie metadata:** The `megalopolis.md` post doesn't have `year`, `director`, `runtime`, or `genres` in frontmatter, so the ASCII movie table only shows title and web link. Consider backfilling metadata for better gopher output.
3. **Link handling:** External links become numbered references. Very long URLs may look awkward in the links section but are functional.
4. **Line wrapping:** Code blocks preserve formatting. Very long single words won't wrap (expected behavior).
---
## Commit History
```
b5bb06e Fix import path issue in gopher scripts
2f20e02 Add pyyaml to requirements.txt (Phase 6)
96e350c Add phlog: true to existing posts for gopher (Phase 5)
2941c7b Add phlog prompt to post creation scripts (Phase 4)
99495eb Add gopher deployment to remote_publish.sh (Phase 3)
468d238 Add gophermap generation scripts (Phase 2)
c4c18ed Add gopher integration core infrastructure (Phase 1)
```
---
## Verdict
**Ready for deployment.** All functionality implemented per the integration plan. One critical bug was found during review and fixed. Code is clean, well-structured, and tested.
+697
View File
@@ -0,0 +1,697 @@
# Gopher Integration Plan
> **Status:** Planning
> **Created:** 2025-01-13
> **Goal:** Publish Hugo blog posts to SDF gopherspace with `phlog: true` frontmatter flag
---
## Overview
Enhance the marcus-web project to deploy selected blog posts to both the Hugo site (mnw.sdf.org) and the SDF gopherspace (gopher://sdf.org/1/users/mnw/). Posts are opted-in via frontmatter, converted from markdown to gopher-friendly plain text, and organized by series/category.
---
## Current State
### Hugo Site (mnw.sdf.org)
- **Series:** "Frank's Couch" (movies), "Fun Center" (tech), beercall content
- **Frontmatter:** title, date, series, summary, tags, draft
- **Deploy:** `remote_publish.sh` → SSH to SDF → git pull && hugo && mkhomepg -p
### Existing Gopherspace (/sdf/arpa/gm/m/mnw/gopher)
- Rich structure with ASCII art headers and footers
- Categories as directories: `journal/`, `older/`, `LISA19/`, `hope_2024/`, etc.
- Dynamic CGI: latest phlog, user info via `=echo` directives
- Template style established in `templates/phlogpost.txt`
---
## Design Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Opt-in mechanism | `phlog: true` frontmatter | Explicit control per post |
| Category mapping | Hugo series → gopher directories | Natural organization |
| Beercall handling | One gopher file per year | Matches existing yearly logs |
| Movie poster | Link to web blog post | Gopher can't display images |
| Movie metadata | ASCII table | Old-school aesthetic |
| ASCII art headers | Category-specific art | Visual distinction, same size as current |
| Root gophermap | Script-managed with makeover | Cohesive, automated experience |
| Sync strategy | rsync with --delete | Git-tracked, reversible |
---
## Directory Structure
### On SDF (~/gopher aka /sdf/arpa/gm/m/mnw/gopher)
```
~/gopher/
├── gophermap # Root menu (UPDATED by script)
├── journal/ # Existing daily phlogs
├── older/ # Existing historical
├── LISA19/ # Existing conference notes
├── hope_2024/ # Existing conference notes
├── blog/ # NEW: Hugo-sourced content
│ ├── gophermap # Blog index
│ ├── franks-couch/ # Movie reviews
│ │ ├── gophermap # Category index with summaries
│ │ ├── megalopolis.txt
│ │ ├── joker-folie-a-deux.txt
│ │ └── ...
│ ├── fun-center/ # Tech posts
│ │ ├── gophermap
│ │ ├── is-it-me.txt
│ │ └── ...
│ └── beercalls/ # Yearly beer logs
│ ├── gophermap
│ ├── 2023.txt
│ └── 2024.txt
└── templates/ # Existing templates
```
### Local Build Directory
```
marcus-web/
├── gopher_build/ # Staging area (gitignored)
│ └── blog/
│ ├── gophermap
│ ├── franks-couch/
│ ├── fun-center/
│ └── beercalls/
```
---
## Frontmatter Extension
Add `phlog` field to any post:
```yaml
---
title: 'Megalopolis'
date: 2024-10-05T00:03:15Z
draft: false
series: "Frank's Couch"
summary: "A sprawling mess of ambition"
phlog: true # <-- NEW: publish to gopher
imdb: "tt10128846"
poster: "/images/posters/megalopolis.jpg"
year: 2024
runtime: 138
director: "Francis Ford Coppola"
genres:
- Drama
- Sci-Fi
tags:
- alamo-drafthouse
---
```
**Behavior:**
- `phlog: true` → Convert and deploy to gopher
- `phlog: false` or absent → Hugo only (web exclusive)
---
## Content Conversion
### Markdown → Gopher Text
| Markdown | Gopher |
|----------|--------|
| `# Heading` | `═══════════════════════════════════════`<br>` HEADING`<br>`═══════════════════════════════════════` |
| `## Subheading` | `--- Subheading ---` |
| `**bold**` | `*bold*` |
| `*italic*` | `_italic_` |
| `[text](url)` | `text [1]` + links section at bottom |
| `{{< imdbposter >}}` | ASCII metadata table (see below) |
| Code blocks | Preserve, indent 4 spaces |
| `---` (hr) | `────────────────────────────────────────` |
### Line Wrapping
- Wrap at 70 characters
- Preserve code block formatting
- Handle URLs gracefully (collect for footer)
### Movie Metadata Table
Convert the `{{< imdbposter >}}` shortcode to ASCII table:
```
┌─────────────────────────────────────────────────────────────────┐
│ MEGALOPOLIS (2024) │
├─────────────────────────────────────────────────────────────────┤
│ Director: Francis Ford Coppola │
│ Runtime: 138 minutes │
│ Genres: Drama, Sci-Fi │
│ │
│ View on web: https://mnw.sdf.org/posts/megalopolis/ │
└─────────────────────────────────────────────────────────────────┘
```
---
## ASCII Art Headers
Each category gets unique ASCII art. Size constraint: **No larger than current template (~12 lines max)**.
### Fun Center (Tech)
```
___ ___ _
| __| _ _ _ / __|___ _ _| |_ ___ _ _
| _| || | ' \ | (__/ -_) ' \ _/ -_) '_|
|_| \_,_|_||_| \___\___|_||_\__\___|_|
Tech posts from the Double Lunch Dispatch
```
### Frank's Couch (Movies)
```
___ _ _ ___ _
| __| _ __ _ _ _| |_( )___ / __|___ _ _ __| |_
| _| '_/ _` | ' \ / /|_-< | (__/ _ \ || (_-< ' \
|_||_| \__,_|_||_\_\ /__/ \___\___/\_,_/__/_||_|
Movie reviews from the couch
```
### Beercalls (Beer)
```
___ _ _
| _ ) ___ ___ _ _ __ __ _| | |___
| _ \/ -_) -_) '_/ _/ _` | | (_-<
|___/\___\___|_| \__\__,_|_|_/__/
Thursday night adventures in Austin
```
### Blog Index
```
___ _ ___ _ _
| _ )| |___ __ | __|_ _ | |_ _ _ (_)___ ___
| _ \| / _ \/ _|| _|| ' \| _| '_|| / -_|_-<
|___/|_\___/\__||___|_||_|\__|_| |_\___/__/
Posts from mnw.sdf.org
```
---
## Gophermap Formats
### Category Gophermap (e.g., `blog/franks-couch/gophermap`)
```
i ___ _ _ ___ _ fake (NULL) 0
i | __| _ __ _ _ _| |_( )___ / __|___ _ _ __| |_ fake (NULL) 0
i | _| '_/ _` | ' \ / /|_-< | (__/ _ \ || (_-< ' \ fake (NULL) 0
i |_||_| \__,_|_||_\_\ /__/ \___\___/\_,_/__/_||_| fake (NULL) 0
i fake (NULL) 0
i Movie reviews from the couch fake (NULL) 0
i fake (NULL) 0
i──────────────────────────────────────────────────── fake (NULL) 0
i fake (NULL) 0
0[2024-10-05] Megalopolis megalopolis.txt
i A sprawling mess of ambition fake (NULL) 0
i fake (NULL) 0
0[2024-10-07] Joker: Folie a Deux joker-folie-a-deux.txt
i Not what you'd expect fake (NULL) 0
i fake (NULL) 0
0[2024-10-12] Terrifier 3 terrifier-3.txt
i Art the Clown returns fake (NULL) 0
i fake (NULL) 0
i──────────────────────────────────────────────────── fake (NULL) 0
1Back to Blog Index ../
1Back to Main Menu /users/mnw/
```
### Blog Index Gophermap (`blog/gophermap`)
```
i ___ _ ___ _ _ fake (NULL) 0
i | _ )| |___ __ | __|_ _ | |_ _ _ (_)___ ___ fake (NULL) 0
i | _ \| / _ \/ _|| _|| ' \| _| '_|| / -_|_-< fake (NULL) 0
i |___/|_\___/\__||___|_||_|\__|_| |_\___/__/ fake (NULL) 0
i fake (NULL) 0
i Posts from mnw.sdf.org fake (NULL) 0
i The Double Lunch Dispatch fake (NULL) 0
i fake (NULL) 0
i──────────────────────────────────────────────── fake (NULL) 0
i fake (NULL) 0
1Frank's Couch - Movie Reviews franks-couch/
i X posts about films watched from the couch fake (NULL) 0
i fake (NULL) 0
1Fun Center - Tech Posts fun-center/
i X posts about technology and open source fake (NULL) 0
i fake (NULL) 0
1Beercalls - Thursday Night Adventures beercalls/
i Yearly logs of Austin beer adventures fake (NULL) 0
i fake (NULL) 0
i──────────────────────────────────────────────── fake (NULL) 0
hView on the web URL:https://mnw.sdf.org/posts/
1Back to Main Menu /users/mnw/
```
---
## Root Gophermap Makeover
Update the main gophermap to incorporate blog content while preserving existing sections.
### Proposed Structure
```
i fake (NULL) 0
i ''~`` fake (NULL) 0
i ( o o ) fake (NULL) 0
i+-------------------.oooO--(_)--Oooo.---------------+ fake (NULL) 0
i| | fake (NULL) 0
i| THE DOUBLE LUNCH DISPATCH | fake (NULL) 0
i| mnw @ sdf | fake (NULL) 0
i| | fake (NULL) 0
i+---------------------------------------------------+ fake (NULL) 0
i fake (NULL) 0
imnw(at)sdf.org | SDF VOIP Ext. 1908 fake (NULL) 0
i fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i DAILY PHLOGS fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i fake (NULL) 0
1Daily Journal journal/
=echo "0Latest Entry journal/`ls -t journal/ | grep -v gophermap | head -1`"
1Historical Phlogs (2018-2019) older/
i fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i FROM THE WEB fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i fake (NULL) 0
iPosts from mnw.sdf.org fake (NULL) 0
i fake (NULL) 0
1Blog Categories blog/
=echo "0Latest Blog Post `find ~/gopher/blog -name '*.txt' -type f -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | awk '{print $2}' | sed 's|.*/gopher/||'`"
i fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i CONFERENCE NOTES fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i fake (NULL) 0
iPhlogs from conferences (rough notes) fake (NULL) 0
i fake (NULL) 0
1HOPE 2024 hope_2024/
1FOSSY 2024 fossy_2024/
1LISA 2019 LISA19/
1SeaGL 2019 seagl_2019/
1Texas Linux Fest 2019 txlf_2019/
1HOPE 2018 hope_2018/
1SeaGL 2018 seagl_2018/
i fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i OTHER THINGS fake (NULL) 0
i═══════════════════════════════════════════════════ fake (NULL) 0
i fake (NULL) 0
1Comedy comedy/
1Short Stories stories/
i fake (NULL) 0
i .oooO fake (NULL) 0
i ( ) Oooo. fake (NULL) 0
i+-------------------\ (----( )-----------------+ fake (NULL) 0
i \_) ) / fake (NULL) 0
i (_/ fake (NULL) 0
i fake (NULL) 0
iMy SDF User Info fake (NULL) 0
=echo "`/usr/pkg/bin/uinfo mnw | tr -d '\-=><'`"
i fake (NULL) 0
i __^__ __^__ fake (NULL) 0
i( ___ )--------------------------------------------( ___ ) fake (NULL) 0
i | / | This gopher space proudly hosted by SDF | \ | fake (NULL) 0
i | / | mnw on pixelfed.social and tilde.zone | \ | fake (NULL) 0
i |___| Web: mnw.sdf.org |___| fake (NULL) 0
i(_____)--------------------------------------------(_____) fake (NULL) 0
i fake (NULL) 0
iThanks for reading! Enjoy an SDF oneliner: fake (NULL) 0
=echo "`/usr/pkg/bin/oneliner | tr -d '\-=><'`"
```
---
## Post Template
Each converted post follows this structure:
```
___ ___ ___
/\ \ /\ \ /\ \
|::\ \ \:\ \ _\:\ \
|:|:\ \ \:\ \ /\ \:\ \
__|:|\:\ \ _____\:\ \ _\:\ \:\ \
/::::|_\:\__\ /::::::::\__\ /\ \:\ \:\__\
\:\~~\ \/__/ \:\~~\~~\/__/ \:\ \:\/:/ /
\:\ \ \:\ \ \:\ \::/ /
\:\ \ \:\ \ \:\/:/ /
\:\__\ \:\__\ \::/ /
\/__/ \/__/ \/__/
mnw(at)sdf.org | SDF VOIP Ext. 1908
────────────────────────────────────────────────────────────────────
2024-11-19 | Fun Center
────────────────────────────────────────────────────────────────────
IS IT ME?
Marcus shares his blog writing process.
────────────────────────────────────────────────────────────────────
I've always loved talking to people. Whether it's at work, at
home, or out with friends, connecting with others and hearing
about their passions brings me so much joy. There's nothing
better than a conversation with someone excited to share what
they care about.
[... content continues, wrapped at 70 characters ...]
═══════════════════════════════════════════════════════════════════
LINKS
═══════════════════════════════════════════════════════════════════
[1] https://example.com/macwhisper
[2] https://openai.com/chatgpt
__^__ __^__
( ___ )------------------------------------------------------( ___ )
| / | | \ |
| / | This gopher space proudly hosted by SDF | \ |
| \ | mnw on pixelfed.social and tilde.zone | / |
| \ | | / |
(_____)------------------------------------------------------(_____)
Web version: https://mnw.sdf.org/posts/is-it-me/
```
---
## New Scripts
### 1. `scripts/gopher/convert_to_gopher.py`
**Purpose:** Convert Hugo markdown to gopher-formatted text
**Usage:**
```bash
python scripts/gopher/convert_to_gopher.py content/posts/blog-posting.md
python scripts/gopher/convert_to_gopher.py --all
python scripts/gopher/convert_to_gopher.py --all --output gopher_build/
```
**Responsibilities:**
- Parse YAML frontmatter
- Check `phlog: true` flag
- Determine output directory from series
- Convert markdown syntax
- Handle `{{< imdbposter >}}` → ASCII table
- Word wrap to 70 chars
- Apply header/footer templates
- Collect and format links section
### 2. `scripts/gopher/generate_gophermaps.py`
**Purpose:** Generate all gophermap files
**Usage:**
```bash
python scripts/gopher/generate_gophermaps.py
python scripts/gopher/generate_gophermaps.py --output gopher_build/
```
**Responsibilities:**
- Scan converted posts by category
- Generate category gophermaps with titles + summaries
- Generate blog index gophermap
- Count posts per category
- Sort by date (newest first)
### 3. `scripts/gopher/ascii_art.py`
**Purpose:** ASCII art assets and helper functions
**Contents:**
- Category header art (Fun Center, Frank's Couch, Beercalls)
- Post header template (MNW owl)
- Footer template (SDF box)
- Section dividers
- ASCII table generator for movie metadata
### 4. `scripts/gopher/update_root_gophermap.py`
**Purpose:** Update the main gophermap with blog section
**Usage:**
```bash
python scripts/gopher/update_root_gophermap.py
```
**Responsibilities:**
- Read existing root gophermap (preserve conference notes, etc.)
- Insert/update "FROM THE WEB" section
- Update dynamic CGI for latest blog post
- Optionally apply full makeover template
---
## Modified Scripts
### `scripts/remote_publish.sh`
Add gopher deployment support:
```bash
#!/bin/bash
# Remote publish script for marcus-web
GOPHER=false
GOPHER_ONLY=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--gopher)
GOPHER=true
shift
;;
--gopher-only)
GOPHER_ONLY=true
GOPHER=true
shift
;;
*)
shift
;;
esac
done
# ... existing git/commit logic ...
if [[ "$GOPHER_ONLY" != "true" ]]; then
# Existing Hugo deployment
ssh "$SDF_HOST" "cd $REMOTE_DIR && git pull && hugo && mkhomepg -p"
echo "Site is live at: https://mnw.sdf.org/"
fi
if [[ "$GOPHER" == "true" ]]; then
echo -e "${GREEN}=== Deploying to Gopher ===${NC}"
# Build gopher content locally
python scripts/gopher/convert_to_gopher.py --all --output gopher_build/blog/
python scripts/gopher/generate_gophermaps.py --output gopher_build/blog/
# Sync to SDF (--delete removes posts where phlog was set to false)
rsync -avz --delete gopher_build/blog/ "$SDF_HOST:~/gopher/blog/"
# Fix permissions on SDF
ssh "$SDF_HOST" "find ~/gopher/blog -type f -exec chmod 644 {} \; && find ~/gopher/blog -type d -exec chmod 755 {} \;"
echo "Gopher updated at: gopher://sdf.org/1/users/mnw/blog/"
fi
```
### `scripts/new_techpost.py`
Add phlog prompt:
```python
# After getting summary...
phlog_input = input("\nPublish to gopher phlog? (y/N): ").strip().lower()
phlog = phlog_input == 'y'
# In frontmatter:
content = f'''---
title: '{title}'
date: {now}
draft: true
series: "Fun Center"
summary: "{summary}"
phlog: {str(phlog).lower()}
tags:
{tags_yaml}
---
'''
```
### `scripts/new_movie.py` / `scripts/import_letterboxd.py`
Same pattern - add phlog prompt after other inputs.
---
## Deployment Workflow
### Standard Deploy (Hugo only)
```bash
./scripts/remote_publish.sh
```
### Deploy Hugo + Gopher
```bash
./scripts/remote_publish.sh --gopher
```
### Deploy Gopher Only
```bash
./scripts/remote_publish.sh --gopher-only
```
### One-time Root Gophermap Update
```bash
# After first blog/ deployment
python scripts/gopher/update_root_gophermap.py
scp gopher_build/gophermap mnw@sdf.org:~/gopher/gophermap
```
---
## Implementation Order
### Phase 1: Core Infrastructure
1. [ ] Create `scripts/gopher/` directory
2. [ ] Create `scripts/gopher/ascii_art.py` - All ASCII art assets
3. [ ] Create `scripts/gopher/convert_to_gopher.py` - Markdown conversion
4. [ ] Add `gopher_build/` to `.gitignore`
### Phase 2: Gophermap Generation
5. [ ] Create `scripts/gopher/generate_gophermaps.py` - Category + index maps
6. [ ] Create `scripts/gopher/update_root_gophermap.py` - Root gophermap
### Phase 3: Deployment Integration
7. [ ] Modify `scripts/remote_publish.sh` - Add --gopher flags
8. [ ] Test with single post locally
### Phase 4: Post Creation Updates
9. [ ] Modify `scripts/new_techpost.py` - Add phlog prompt
10. [ ] Modify `scripts/import_letterboxd.py` - Add phlog prompt
11. [ ] Modify `scripts/new_movie.py` - Add phlog prompt (if separate)
### Phase 5: Content & Testing
12. [ ] Add `phlog: true` to existing posts to backfill
13. [ ] Run full deployment to SDF
14. [ ] Verify gopher content via `gopher gopher://sdf.org/1/users/mnw/blog/`
15. [ ] Update root gophermap on SDF
### Phase 6: Polish
16. [ ] Fine-tune ASCII art sizing
17. [ ] Adjust line wrapping edge cases
18. [ ] Document in README or execution-notes.txt
---
## File Checklist
### New Files
- [ ] `scripts/gopher/ascii_art.py`
- [ ] `scripts/gopher/convert_to_gopher.py`
- [ ] `scripts/gopher/generate_gophermaps.py`
- [ ] `scripts/gopher/update_root_gophermap.py`
- [ ] `gopher_build/` directory (gitignored)
### Modified Files
- [ ] `scripts/remote_publish.sh`
- [ ] `scripts/new_techpost.py`
- [ ] `scripts/import_letterboxd.py`
- [ ] `.gitignore` (add gopher_build/)
### Content Files (add phlog: true)
- [ ] `content/posts/blog-posting.md`
- [ ] `content/posts/recovering-failed-ubuntu-upgrade.md`
- [ ] Movie posts as desired
- [ ] Beercall yearly files as desired
---
## URLs
After deployment:
| Type | URL |
|------|-----|
| Gopher root | `gopher://sdf.org/1/users/mnw/` |
| Blog index | `gopher://sdf.org/1/users/mnw/blog/` |
| Fun Center | `gopher://sdf.org/1/users/mnw/blog/fun-center/` |
| Frank's Couch | `gopher://sdf.org/1/users/mnw/blog/franks-couch/` |
| Beercalls | `gopher://sdf.org/1/users/mnw/blog/beercalls/` |
| Web proxy | `https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/` |
---
## References
- SDF Gopher Setup: https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features
- SDF Web Spaces: https://wiki.sdf.org/doku.php?id=accessing_web_spaces#gopher
- Tilde.town Gopher Guide: https://tilde.town/wiki/editing-your-homepage/gopher.html
- Floodgap Gopher Proxy: https://gopher.floodgap.com/gopher/gw
---
## Gophermap Quick Reference
From tilde.town wiki - item types we'll use:
| Code | Type | Usage |
|------|------|-------|
| `0` | Text file | Blog posts (.txt) |
| `1` | Directory | Category folders, navigation |
| `i` | Inline text | ASCII art, descriptions, spacing |
| `h` | HTML link | Link to web version (prefix with `URL:`) |
| `7` | Search | Future: search posts (CGI) |
**Syntax:** `{type}{description}\t{path}\t{host}\t{port}`
- Tab character separates columns
- Host/port optional for local resources
- For inline text (`i`): use `fake` as path, `(NULL)` as host, `0` as port
- For HTML links: path should be `URL:https://...`
**Example entries:**
```
i fake (NULL) 0
0[2024-10-05] Megalopolis megalopolis.txt
1Back to Blog Index ../
hView on web URL:https://mnw.sdf.org/posts/
```
---
## Notes
- Gophermaps must NOT have execute permission (causes errors)
- Files need 644, directories need 755
- CGI scripts (=echo) must use full paths on SDF
- ASCII art should stay under 12 lines for headers
- The `--delete` flag on rsync will remove posts where `phlog` was changed to `false`
- All work is git-tracked, so deletions are recoverable
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""
Extract NFR films by induction year from the LOC complete registry page.
"""
import re
import os
from bs4 import BeautifulSoup
import requests
def extract_films_by_year(year):
"""
Extract films inducted in a specific year from the LOC registry page.
"""
url = "https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/"
print(f"Fetching {url}...")
resp = requests.get(url, timeout=30)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, 'html.parser')
# Find the table with film listings
table = soup.find('table', class_='sortable-table')
if not table:
print("Could not find table")
return {}
films = {}
# Iterate through table rows
rows = table.find_all('tr')
for row in rows:
cells = row.find_all(['th', 'td'])
if len(cells) >= 3:
title_cell = cells[0]
year_cell = cells[1]
inductee_cell = cells[2]
title = title_cell.get_text(strip=True).strip()
film_year_str = year_cell.get_text(strip=True).strip()
inductee_year_str = inductee_cell.get_text(strip=True).strip()
# Check if this film was inducted in the target year
try:
inductee_year = int(inductee_year_str)
if inductee_year == year:
# Parse film year (may be range or single year)
film_year_match = re.search(r'(\d{4})', film_year_str)
if film_year_match:
film_year = int(film_year_match.group(1))
else:
film_year = year # fallback
films[title] = {
"year": film_year,
"description": f"[NFR {year} inductee - film released in {film_year}]"
}
except ValueError:
continue
print(f"Found {len(films)} films inducted in {year}")
return films
def generate_nfr_file(year, films):
"""Generate a Python file with NFR data for a given year."""
if not films:
print(f"No films found for {year}")
return
filename = f"scripts/nfr_data/nfr_{year}.py"
code = f'''# {year} National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_{year} = {{
'''
for title, data in sorted(films.items()):
title_escaped = title.replace("'", "\\'").replace('"', '\\"')
desc_escaped = data["description"].replace("'", "\\'").replace('"', '\\"')
code += f''' "{title_escaped}": {{
"year": {data["year"]},
"description": "{desc_escaped}"
}},
'''
code += "}\n"
with open(filename, 'w') as f:
f.write(code)
print(f"✓ Saved {len(films)} films to {filename}")
def main():
import os
# Create output directory if needed
os.makedirs("scripts/nfr_data", exist_ok=True)
# Extract films for years 1991-1997
years_to_extract = [1991, 1992, 1993, 1994, 1995, 1996, 1997]
for year in years_to_extract:
print(f"\n{'='*60}")
print(f"Extracting films for NFR year {year}")
print(f"{'='*60}")
films = extract_films_by_year(year)
generate_nfr_file(year, films)
print(f"\n{'='*60}")
print("EXTRACTION COMPLETE")
print(f"{'='*60}")
if __name__ == "__main__":
main()
+71
View File
@@ -0,0 +1,71 @@
import os
import requests
CONFIG_PATTERN = 'http://api.themoviedb.org/3/configuration?api_key={key}'
IMG_PATTERN = 'http://api.themoviedb.org/3/movie/{imdbid}/images?api_key={key}'
# Add scripts dir to path for config import
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'scripts'))
try:
from config import TMDB_API_KEY as KEY
except ImportError:
raise SystemExit("Error: scripts/config.py not found. Copy config.example.py to config.py and add your API key.")
def _get_json(url):
r = requests.get(url)
return r.json()
def _download_images(urls, path='.'):
"""download all images in list 'urls' to 'path' """
for nr, url in enumerate(urls):
r = requests.get(url)
filetype = r.headers['content-type'].split('/')[-1]
filename = 'poster_{0}.{1}'.format(nr+1,filetype)
filepath = os.path.join(path, filename)
with open(filepath,'wb') as w:
w.write(r.content)
def get_poster_urls(imdbid):
""" return image urls of posters for IMDB id
returns all poster images from 'themoviedb.org'. Uses the
maximum available size.
Args:
imdbid (str): IMDB id of the movie
Returns:
list: list of urls to the images
"""
config = _get_json(CONFIG_PATTERN.format(key=KEY))
base_url = config['images']['base_url']
sizes = config['images']['poster_sizes']
"""
'sizes' should be sorted in ascending order, so
max_size = sizes[-1]
should get the largest size as well.
"""
def size_str_to_int(x):
return float("inf") if x == 'original' else int(x[1:])
max_size = max(sizes, key=size_str_to_int)
posters = _get_json(IMG_PATTERN.format(key=KEY,imdbid=imdbid))['posters']
poster_urls = []
for poster in posters:
rel_path = poster['file_path']
url = "{0}{1}{2}".format(base_url, max_size, rel_path)
poster_urls.append(url)
return poster_urls
def tmdb_posters(imdbid, count=None, outpath='.'):
urls = get_poster_urls(imdbid)
if count is not None:
urls = urls[:count]
_download_images(urls, outpath)
if __name__=="__main__":
tmdb_posters('tt0095016')
View File
+94
View File
@@ -0,0 +1,94 @@
---
baseURL: https://mnw.sdf.org/
title: The Double Lunch Dispatch
languageCode: en
DefaultContentLanguage: en
theme: poison
publishDir: /sdf/arpa/gm/m/mnw/html
pagination:
pagerSize: 10
favicon: favicon.ico
pluralizeListTitles: false
params:
brand: Double Lunch Dispatch
#remote_brand_image: https://mnw.sdf.org/blog/images/circular-me.png
brand_image: "/images/circular-me-250.png"
dark_mode: true
description: "A blog about watching movies, drinking beers, and using technology."
keywords: "blog, movies, beers, technology, life experiences"
author:
name: "Marcus Wilson"
url: "https://mnw.sdf.org"
favicon: favicon.ico
lazy_load_images: true
# hit counter
# goatcounter: "mnw"
schema:
blog:
"@context": "http://schema.org"
"@type": "Blog"
"name": "The Double Lunch Dispatch"
"description": "A blog covering movies, beers, technology, and life experiences."
"url": "https://mnw.sdf.org/"
menu:
- Name: About
URL: /about
HasChildren: false
- Name: Posts
URL: /posts/
Pre: Recent
HasChildren: true
Limit: 5
- Name: Movies
URL: /movies/
Pre: Recent
HasChildren: true
Limit: 5
- Name: Beers
URL: /beers/
Pre: Recent
HasChildren: true
Limit: 5
# email_url: https://keys.openpgp.org/search?q=mnw%40sdf.org
gitlab_url: https://git.sdf.org/mnw
mastodon_url: https://tilde.zone/@mnw
matrix_url: https://matrix.to/#/@mnw:envs.net
xmpp_url: xmpp:mnw@disroot.org?message;body=hi
rss_icon: true
rss_section: posts
moon_sun_background_color: "#515151"
moon_sun_color: "#FFF"
sidebar_a_color: "#FFF"
sidebar_bg_color: "#202020"
sidebar_h1_color: "#FFF"
sidebar_img_border_color: "#515151"
sidebar_p_color: "#909090"
sidebar_socials_color: "#FFF"
code_color: "#000"
code_background_color: "#E5E5E5"
code_block_color: "#FFF"
code_block_background_color: "#272822"
content_bg_color: "#FAF9F6"
date_color: "#515151"
link_color: "#268BD2"
list_color: "#5A5A5A"
post_title_color: "#303030"
table_border_color: "#E5E5E5"
table_stripe_color: "#F9F9F9"
text_color: "#222"
code_color_dark: "#FFF"
code_background_color_dark: "#515151"
code_block_color_dark: "#FFF"
code_block_background_color_dark: "#272822"
content_bg_color_dark: "#121212"
date_color_dark: "#9A9A9A"
link_color_dark: "#268BD2"
list_color_dark: "#9D9D9D"
post_title_color_dark: "#DBE2E9"
table_border_color_dark: "#515151"
table_stripe_color_dark: "#202020"
text_color_dark: "#EEE"
taxonomies:
series: series
tags: tags
+47
View File
@@ -0,0 +1,47 @@
import os
import sys
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# Class for handling file system events
class WatchHandler(FileSystemEventHandler):
def on_modified(self, event):
if not event.is_directory:
print(f"File modified: {event.src_path}")
def on_created(self, event):
if not event.is_directory:
print(f"New file created: {event.src_path}")
def on_deleted(self, event):
if not event.is_directory:
print(f"File deleted: {event.src_path}")
# Get the watch directory from command line arguments or environment variable
WATCH_DIR = sys.argv[1] if len(sys.argv) > 1 else os.getenv('HUGO_WATCH_DIR')
if not WATCH_DIR:
print("Error: Please provide a directory as a command line argument or set the HUGO_WATCH_DIR environment variable.")
sys.exit(1)
if not os.path.isdir(WATCH_DIR):
print(f"Error: The provided directory '{WATCH_DIR}' does not exist or is not a directory.")
sys.exit(1)
# Setting up the observer
event_handler = WatchHandler()
observer = Observer()
observer.schedule(event_handler, path=WATCH_DIR, recursive=False)
observer.start()
print(f"Watching directory: {WATCH_DIR}")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
+23
View File
@@ -0,0 +1,23 @@
{{ define "main" -}}
<div class="post">
{{ partial "post/info.html" . }}
{{ .Content }}
{{ if (.Site.Params.listmonk) }}
{{ partial "post/listmonk_email_newsletters.html" . }}
{{ end }}
{{ partial "post/navigation.html" . }}
{{ if or (.Site.Params.remark42) (.Site.Config.Services.Disqus.Shortname) }}
{{ partial "post/comments.html" . }}
{{ end }}
{{/* Mastodon comments - shows if mastodon_id is set in front matter */}}
{{ partial "mastodon-comments.html" . }}
{{- if .Site.Params.goatcounter }}
{{ partial "analytics.html" . -}}
{{- end}}
</div>
{{- end }}
{{ define "sidebar" }}
{{ if and (not .Params.hideToc) (not .Site.Params.hideToc) }}
{{ partial "table_of_contents.html" . }}
{{ end }}
{{ end }}
+21 -44
View File
@@ -1,45 +1,22 @@
{{ define "main" }}
<div class="row-fluid navmargin">
<div class="page-header">
<h1>{{ .Site.Params.mainpagetitle }}</h1>
</div>
{{ define "main" -}}
{{ partial "whoami.html" . }}
<div class="posts">
{{ $frontPageTypes := default (slice "posts") .Site.Params.front_page_content }}
{{ range (.Paginate (where .Site.RegularPages "Type" "in" $frontPageTypes)).Pages }}
<article class="post">
{{ partial "post/info.html" . }}
{{ if or (.Site.Params.noSummary) (.Params.noSummary) }}
{{ .Content }}
{{ else }}
{{ .Summary }}
{{ if .Truncated }}
<div class="read-more-link">
<a href="{{ .RelPermalink }}">Read More…</a>
</div>
{{ end }}
{{ end }}
</article>
{{- end }}
</div>
<div class="row-fluid">
<div class="span9 bs-docs-sidebar">
<p class="lead">{{ .Site.Params.mainpagesubtitle }}</p>
<p></p>
<p>{{ .Site.Params.mainpagedesc | markdownify }}</p>
<p></p>
<hr class="soften">
<p></p>
<h1>{{ i18n "postslist" }}</h1>
<ul>
{{ range first 10 .Site.RegularPages }}
{{ if eq .Type "post" }}
<li><a href="{{ .Permalink }}">{{ .Date.Format "2006-01-02" }} | {{ .Title }}</a></li>
{{ end }}
{{ end }}
</ul>
</div>
<div class="span3 bs-docs-sidebar">
<h1>{{ i18n "categories" }}</h1>
<ul class="nav nav-list bs-docs-sidenav">
{{ partial "categories.html" .}}
</ul>
<p></p>
<h1>{{ i18n "tags" }}</h1>
<ul class="nav nav-list bs-docs-sidenav">
{{ partial "tags.html" .}}
</ul>
<p></p>
<h1>{{ i18n "partials" }}</h1>
<ul class="nav nav-list bs-docs-sidenav">
{{ partial "socials.html" .}}
</ul>
</div>
</div>
{{ end }}
{{ partial "pagination.html" . }}
{{- end }}
+11
View File
@@ -0,0 +1,11 @@
<div>There's still time for <div id="stats"></div> of you to escape. <3 </div>
<script>
var r = new XMLHttpRequest();
r.addEventListener('load', function() {
document.querySelector('#stats').innerText = JSON.parse(this.responseText).count
})
r.open('GET', 'https://{{ .Site.Params.goatcounter }}.goatcounter.com/counter/' + encodeURIComponent(location.pathname) + '.json')
r.send()
</script>
+77
View File
@@ -0,0 +1,77 @@
{{/*
Mastodon Comments Partial
Displays comments from a Mastodon post. Requires mastodon_id in front matter.
Comment count is fetched at build time; full comments load on button click.
Inspired by: https://andreas.scherbaum.la/post/2024-05-23_client-side-comments-with-mastodon-on-a-static-hugo-website/
And the vibes of: I Saw the TV Glow
*/}}
{{- $host := "tilde.zone" -}}
{{- $username := "mnw" -}}
{{- if .Params.mastodon_id -}}
{{- $id := .Params.mastodon_id -}}
{{/* Fetch comment count at build time */}}
{{- $count := 0 -}}
{{- $apiUrl := printf "https://%s/api/v1/statuses/%s/context" $host $id -}}
{{- with resources.GetRemote $apiUrl -}}
{{- if .Err -}}
{{/* API error - show 0 */}}
{{- else -}}
{{- $data := .Content | transform.Unmarshal -}}
{{- if $data.descendants -}}
{{- $count = len $data.descendants -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/* Build blocklist from front matter */}}
{{- $blocked := slice -}}
{{- if .Params.mastodon_blocked -}}
{{- $blocked = .Params.mastodon_blocked -}}
{{- end -}}
<div class="mastodon-comments-section">
<pre class="comments-header">/* ================================================== */
/* COMMENTS */
/* via the fediverse / tilde.zone */
/* ================================================== */</pre>
<noscript>
<pre class="comments-error">
ERROR: JavaScript required to load comments.
Enable JS or view discussion directly at:
https://{{ $host }}/@{{ $username }}/{{ $id }}
</pre>
</noscript>
<p class="comments-intro">
++ TRANSMISSION RECEIVED ++<br>
Reply to <a href="https://{{ $host }}/@{{ $username }}/{{ $id }}" rel="nofollow">this post on Mastodon</a> to join the discussion.
</p>
<div id="mastodon-comments-list">
<button type="button" id="load-comments-btn" onclick="loadMastodonComments()">
&gt;&gt; LOAD COMMENTS{{ if gt $count 0 }} ({{ $count }}){{ end }} &lt;&lt;
</button>
</div>
<p class="comments-note">
<small>// comments loaded from {{ $host }} when you click the button</small>
</p>
</div>
<link rel="stylesheet" href="{{ "css/mastodon-comments.css" | relURL }}">
<script src="{{ "js/purify.min.js" | relURL }}"></script>
<script src="{{ "js/mastodon-comments.js" | relURL }}"></script>
<script>
var mastodonHost = '{{ $host }}';
var mastodonUser = '{{ $username }}';
var mastodonId = '{{ $id }}';
var blockedToots = [{{ range $blocked }}'{{ . }}',{{ end }}];
</script>
{{- end -}}
+55
View File
@@ -0,0 +1,55 @@
<div class="info">
<h1 class="post-title">
<a href="{{ .Permalink }}">{{ .Title }}</a>
</h1>
<div class="headline">
<div>
{{ with .Params.author }}
{{ with site.Taxonomies.author.Get . }}
<span><a href="{{ .Page.RelPermalink }}">{{ .Page.LinkTitle }}</a> - </span>
{{ else }}
<span>{{ . }} - </span>
{{ end }}
{{ end }}
{{ if .Date }}
<time datetime="{{ .Date.Format " 2006-01-02T15:04:05Z0700" }}" class="post-date">
{{ .Date.Format "January 2, 2006" }}
</time>
{{ end }}
<span> - </span>
<span class="reading-time">
{{ if gt .ReadingTime 1 }}
{{ .Scratch.Set "readingTime" "mins" }}
{{ else }}
{{ .Scratch.Set "readingTime" "min" }}
{{ end }}
<span>{{ .ReadingTime }} {{ .Scratch.Get "readingTime" }} read</span>
</span>
</div>
{{ if .Params.tags }}
<ul class="tags">
{{ range .Params.tags }}
<li class="tag-{{ . }}">
<a href="{{ "tags/" | absLangURL }}{{ . | urlize }}">{{ . }}</a>
</li>
{{ end }}
</ul>
{{ end }}
</div>
{{ $Site := .Site }}
{{ if .Params.series }}
<p class="seriesname">
Series: <a href="{{ $Site.BaseURL }}series/{{ .Params.series | urlize }}">{{ .Params.series }}</a>
</p>
{{ end }}
{{ if .Params.featuredImage }}
<p>
<img src="{{.Params.featuredImage}}"><br>
</p>
{{ end }}
</div>
+40
View File
@@ -0,0 +1,40 @@
<hr>
<div class="footer">
{{ if .Params.series }}
{{ $Site := .Site }}
{{ $postTitle := .Title }}
<p>
This is a post in the <b><a href="{{ $Site.BaseURL }}series/{{ .Params.series | urlize }}">{{ .Params.series }}</a></b> series.
<br>Other posts in this series:
{{ range where .Site.Pages.ByDate "Params.series" .Params.series }}
{{ if gt $.Date.Unix .Date.Unix }}
{{ $.Scratch.Set "prevPost" . }}
{{ end }}
{{ end }}
{{ range where .Site.Pages.ByDate.Reverse "Params.series" .Params.series }}
{{ if lt $.Date.Unix .Date.Unix }}
{{ $.Scratch.Set "nextPost" . }}
{{ end }}
{{ end }}
<ul class="series">
{{ if $.Scratch.Get "prevPost" }}
<li>Previous: <a href="{{ ($.Scratch.Get "prevPost").RelPermalink }}">{{ ($.Scratch.Get "prevPost").Title }}</a></li>
{{ end }}
{{ if $.Scratch.Get "nextPost" }}
<li>Next: <a href="{{ ($.Scratch.Get "nextPost").RelPermalink }}">{{ ($.Scratch.Get "nextPost").Title }}</a></li>
{{ else }}
<li>Next: <a href="{{ $Site.BaseURL }}">Back home</a></li>
{{ end }}
</ul>
</p>
{{ else }}
{{ if .PrevInSection }}
<a class="previous-post" href="{{ .PrevInSection.Permalink }}?ref=footer"><span style="font-weight:bold;">« Previous</span><br>{{ .PrevInSection.Title | truncate 50 "..."}}</a>
{{ end }}
{{ if .NextInSection }}
<div class="next-post">
<a href="{{ .NextInSection.Permalink }}?ref=footer"><span style="font-weight:bold;">Next »</span><br>{{ .NextInSection.Title | truncate 50 "..." }}</a>
</div>
{{ end }}
{{ end }}
</div>
+7
View File
@@ -0,0 +1,7 @@
<h3>Welcome to the Double Lunch Dispatch<h3>
<div>
Unless noted all content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
</div>
<br/>
<br/>
+49
View File
@@ -0,0 +1,49 @@
{{ define "main" -}}
<h1 class="title">{{ .Title }}</h1>
{{ if eq .Title "Found in the Darkroom" }}
<div style="margin-bottom: 2em; line-height: 1.6;">
<p>
In <em>I Saw the TV Glow</em>, Maddy leaves behind recordings of <em>The Pink Opaque</em> for Owen in the school darkroom. It is a quiet, out-of-the-way space where the episodes can be discovered, plucked out of time just in time for those who need it most. The darkroom becomes less a literal place and more a threshold. The place where a signal from the real world survives long enough to be found.
</p>
<p>
Here at the <strong>Double Lunch Dispatch</strong>, we couldnt help but draw a parallel between those tapes left for Owen and the films selected for inclusion in the Library of Congress National Film Registry. Each year, 25 films are added not because they are fashionable or newly released, but because they are deemed “culturally, historically, or aesthetically significant” works of art worth preserving so they can be encountered again by future viewers, long after their original moment has passed. This series of blog posts is going on that journey of finding out what the people who were here before us are trying to say. I hope this makes sense to whoever reads this. So many ideas and attempts go into it. Fingers crossed its not garbled up.
</p>
<p>
Like the episodes of <em>The Pink Opaque</em> waiting in the darkroom, these films are held in trust, set aside so they dont disappear into static. You can find the complete list of films preserved in the National Film Registry
<a href="https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/" target="_blank">here</a>.
</p>
<img src="/images/tvglow-darkroom.gif"
alt="I Saw the TV Glow Pink Opaque tapes in the darkroom"
style="max-width: 100%; height: auto; margin-top: 1.5em; border-radius: 6px;" />
</div>
{{ end }}
<ul class="entries">
{{ range .Pages.GroupByDate "2006" }}
<h3 style="text-align: center;">{{ .Key }}</h3>
{{ range .Pages }}
<li>
<span class="title">
<a href="{{ .RelPermalink }}">{{ .Title }}</a>
{{ if .Params.year }}
<span style="color: #888;">({{ .Params.year }})</span>
{{ end }}
{{ if .Params.nfr_year }}
<span style="color: #888; font-size: 0.9em;"> • NFR {{ .Params.nfr_year }}</span>
{{ end }}
</span>
<span class="published">
<time class="pull-right post-list">{{ .Date | time.Format ":date_long" }}</time>
</span>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}
+47
View File
@@ -0,0 +1,47 @@
{{- $imdb := .Page.Params.imdb -}}
{{- $localPoster := .Page.Params.poster -}}
{{- $year := .Page.Params.year -}}
{{- $runtime := .Page.Params.runtime -}}
{{- $director := .Page.Params.director -}}
{{- $poster := "" -}}
{{- if $localPoster -}}
{{- $poster = $localPoster -}}
{{- else if $imdb -}}
{{- $poster = printf "https://img.omdbapi.com/?i=%s&apikey=d9641e70" $imdb -}}
{{- end -}}
<div style="display: flex; justify-content: flex-start; align-items: flex-start; margin-bottom: 2em;">
<!-- Left section: viewing details -->
<div style="flex: 1; padding-right: 20px;">
{{ .Inner | markdownify }}
</div>
<!-- Right section: movie poster and info -->
<div style="flex-shrink: 0; text-align: center;">
{{- if $imdb -}}
<a href="https://www.imdb.com/title/{{ $imdb }}" target="_blank">
<img src="{{ $poster }}" alt="Movie Poster" style="width: 200px;" />
</a>
{{- else if $poster -}}
<img src="{{ $poster }}" alt="Movie Poster" style="width: 200px;" />
{{- end -}}
{{- if or $year $runtime $director -}}
<div style="font-size: 0.85em; color: #666; margin-top: 8px;">
{{- if $director -}}
<div>
Directed by {{ if reflect.IsSlice $director }}{{ delimit $director ", " }}{{ else }}{{ $director }}{{ end }}
</div>
{{- end -}}
{{- if or $year $runtime -}}
<div>
{{- if $year }}{{ $year }}{{ end -}}
{{- if and $year $runtime }} · {{ end -}}
{{- if $runtime }}{{ $runtime }} min{{ end -}}
</div>
{{- end -}}
</div>
{{- end -}}
</div>
</div>
+2
View File
@@ -0,0 +1,2 @@
requests
pyyaml
+341
View File
@@ -0,0 +1,341 @@
# National Film Registry Automation Guide
This guide explains how to automatically pull and setup data for National Film Registry movies from any year.
## Overview
The NFR automation system consists of:
1. **`setup_nfr.py`** - Script to fetch LOC announcements and extract film data
2. **`new_nfr.py`** - Script to create blog posts for NFR movies
3. **ollama** - Local AI to help extract structured data from web pages
## Quick Start
### Basic Usage
```bash
# Setup data for a specific year
python3 scripts/setup_nfr.py 2023
# With a known URL
python3 scripts/setup_nfr.py 2015 --url "https://newsroom.loc.gov/news/..."
# Without ollama (basic extraction)
python3 scripts/setup_nfr.py 2022 --no-ollama
```
### With Ollama (Recommended)
Ollama provides much better extraction of film descriptions from the LOC announcements.
```bash
# Default (uses ollama at 192.168.0.109:11434)
python3 scripts/setup_nfr.py 2023
# Custom ollama host
python3 scripts/setup_nfr.py 2023 --ollama-host http://localhost:11434
# Custom model
python3 scripts/setup_nfr.py 2023 --ollama-model llama3.2:latest
```
## Setting Up Ollama
### What is Ollama?
Ollama is a tool for running large language models locally. We use it to:
- Parse HTML content from LOC announcements
- Extract film titles, years, and descriptions
- Structure the data into Python dictionaries
### Installing Ollama
Your server at `192.168.0.109` should already have ollama running. To verify:
```bash
curl http://192.168.0.109:11434/api/tags
```
If you need to install it locally:
```bash
# macOS / Linux
curl https://ollama.ai/install.sh | sh
# Start the server
ollama serve
# Pull a model
ollama pull llama3.2
```
### Ollama Configuration
The script uses these environment variables:
```bash
# Set custom ollama host
export OLLAMA_HOST=http://192.168.0.109:11434
# Set custom model (default: llama3.2)
export OLLAMA_MODEL=llama3.2
# Then run the script
python3 scripts/setup_nfr.py 2023
```
### Testing Ollama Connection
Test if ollama is accessible:
```bash
# Test API endpoint
curl http://192.168.0.109:11434/api/tags
# Test generation
curl http://192.168.0.109:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Say hello",
"stream": false
}'
```
## How It Works
### Step 1: Find the LOC Announcement
The script needs the URL of the Library of Congress announcement for your year. For example:
- **2024**: https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/s/55d5285d-916f-4105-b7d4-7fc3ba8664e3
- **2023**: Search at https://newsroom.loc.gov/
- **Older**: Check https://blogs.loc.gov/now-see-hear/
You can provide the URL with `--url` or the script will prompt you.
### Step 2: Fetch the Content
The script downloads the HTML content from the announcement page.
### Step 3: Extract Film Data
**With ollama (recommended):**
- Sends the HTML to ollama
- Asks it to extract all 25 films with titles, years, and descriptions
- Returns structured JSON data
**Without ollama (fallback):**
- Uses regex patterns to find film titles and years
- May miss descriptions or get incomplete data
- Requires manual review and editing
### Step 4: Generate Python Dictionary
Creates a Python file like:
```python
# 2023 National Film Registry inductees with LOC descriptions
# Source: https://newsroom.loc.gov/news/...
NFR_2023 = {
"Film Title": {
"year": 1999,
"description": "Selected for its groundbreaking..."
},
# ... more films
}
```
### Step 5: Integration
The generated file is saved to `scripts/nfr_data/nfr_YEAR.py`. You can then:
1. Review and edit the file
2. Copy the dictionary into `scripts/new_nfr.py`
3. Update the script to handle the new year
## Complete Example
Let's set up 2023 NFR data:
```bash
# 1. Run the setup script
python3 scripts/setup_nfr.py 2023
# The script will prompt:
# > Please find the LOC announcement URL for 2023.
# > Enter the URL: https://newsroom.loc.gov/news/...
# 2. Script fetches and extracts (using ollama)
# ✓ Extracted 25 films
# Preview:
# 1. Terminator 2 (1991)
# Recognized for groundbreaking visual effects...
# ... and 24 more
# 3. Confirm and save
# Save this data? (Y/n): y
# ✓ Saved to scripts/nfr_data/nfr_2023.py
# 4. Review the generated file
cat scripts/nfr_data/nfr_2023.py
# 5. Copy the dictionary into new_nfr.py
# (You can do this manually or we can create a script to merge)
```
## Directory Structure
```
scripts/
├── setup_nfr.py # Main automation script
├── new_nfr.py # Create blog posts
├── nfr_data/ # Generated NFR data files
│ ├── nfr_2023.py
│ ├── nfr_2024.py
│ └── ...
└── NFR_AUTOMATION.md # This file
```
## Troubleshooting
### Ollama Connection Errors
```bash
# Check if ollama is running
curl http://192.168.0.109:11434/api/tags
# Check network connectivity
ping 192.168.0.109
# Try with localhost if running locally
python3 scripts/setup_nfr.py 2023 --ollama-host http://localhost:11434
```
### Extraction Problems
If extraction fails:
```bash
# Try without ollama first (gets basic structure)
python3 scripts/setup_nfr.py 2023 --no-ollama
# Then manually edit the descriptions in nfr_data/nfr_2023.py
```
### Model Not Found
```bash
# On the ollama server, pull the model
ssh user@192.168.0.109
ollama pull llama3.2
# Or use a different model you have
python3 scripts/setup_nfr.py 2023 --ollama-model mistral
```
## Finding LOC Announcements
### Recent Years (2010-present)
Check the newsroom:
```
https://newsroom.loc.gov/
```
Search for "national film registry" + year
### Older Years
Check the blog:
```
https://blogs.loc.gov/now-see-hear/
```
Or the registry page:
```
https://www.loc.gov/programs/national-film-preservation-board/film-registry/
```
### Complete Registry List
For a complete list by year:
```
https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
```
## Advanced Usage
### Custom Output Location
```bash
python3 scripts/setup_nfr.py 2023 \
--output /tmp/nfr_2023.py
```
### Batch Processing Multiple Years
```bash
# Create a simple loop
for year in 2020 2021 2022 2023; do
python3 scripts/setup_nfr.py $year
done
```
### Using Different AI Models
```bash
# Llama 3.2 (default, good balance)
python3 scripts/setup_nfr.py 2023 --ollama-model llama3.2
# Mistral (faster, less accurate)
python3 scripts/setup_nfr.py 2023 --ollama-model mistral
# Larger models for better extraction
python3 scripts/setup_nfr.py 2023 --ollama-model llama3.2:70b
```
## Integration with new_nfr.py
After generating NFR data, integrate it into `new_nfr.py`:
### Option 1: Manual Copy
1. Open `scripts/nfr_data/nfr_2023.py`
2. Copy the `NFR_2023` dictionary
3. Add it to `scripts/new_nfr.py` after `NFR_2024`
4. Update the `create_nfr_post` function to check `NFR_2023` too
### Option 2: Import (Future Enhancement)
```python
# In new_nfr.py
from nfr_data.nfr_2023 import NFR_2023
from nfr_data.nfr_2024 import NFR_2024
NFR_DATA = {
2023: NFR_2023,
2024: NFR_2024,
}
```
## Tips
1. **Always review the output** - AI extraction is good but not perfect
2. **Keep source URLs** - Add them to the generated dictionaries
3. **Check film counts** - Should be 25 films per year
4. **Verify years** - Make sure film years are in reasonable ranges
5. **Edit descriptions** - Feel free to trim or rephrase for your blog
## Next Steps
1. Generate data for years you want to cover
2. Review and edit the descriptions
3. Integrate into `new_nfr.py`
4. Start creating blog posts with `python3 scripts/new_nfr.py "Film Title"`
## Questions?
- Check if ollama is running: `curl http://192.168.0.109:11434/api/tags`
- Test the script with 2024 (known working): `python3 scripts/setup_nfr.py 2024`
- Use `--no-ollama` to see basic extraction
- Look at generated files in `scripts/nfr_data/`
+271
View File
@@ -0,0 +1,271 @@
# Blog Scripts
Automation scripts for The Double Lunch Dispatch blog.
## Quick Start
### Install Dependencies
```bash
# Create virtual environment (if not already done)
python3 -m venv .venv
# Activate it
source .venv/bin/activate
# Install dependencies
pip install -r requirements.txt
```
### Required: TMDB API Key
All movie scripts require a TMDB API key.
```bash
# Copy the example config
cp scripts/config.example.py scripts/config.py
# Edit and add your TMDB API key
# Get one at: https://www.themoviedb.org/settings/api
```
## Scripts Overview
### National Film Registry (NFR) Series
**"Found in the Darkroom"** - A series covering the National Film Registry
#### Setup NFR Data (New!)
Automatically fetch and setup data for any NFR year:
```bash
# Setup data for a specific year
python3 scripts/setup_nfr.py 2023
# With a known URL
python3 scripts/setup_nfr.py 2015 --url "https://newsroom.loc.gov/news/..."
# See full documentation
cat scripts/NFR_AUTOMATION.md
```
#### Create NFR Movie Post
Create a blog post for an NFR movie:
```bash
# List 2024 NFR films
python3 scripts/new_nfr.py --list-2024
# Create post by title
python3 scripts/new_nfr.py "No Country for Old Men"
# Create post by IMDB ID
python3 scripts/new_nfr.py tt0477348
# Specify NFR year
python3 scripts/new_nfr.py "Terminator 2" --nfr-year 2023
```
### Regular Movie Posts
**"Frank's Couch"** - Owen's dad from TV Glow who watches TV
#### Create Movie Post
Create a new movie post from IMDB ID:
```bash
# From IMDB ID
python3 scripts/new_movie.py tt1234567
# From IMDB URL
python3 scripts/new_movie.py https://www.imdb.com/title/tt1234567/
```
#### Import from Letterboxd
Import movies from your Letterboxd diary:
```bash
# Interactive mode - pick from recent
python3 scripts/import_letterboxd.py
# Import most recent entry
python3 scripts/import_letterboxd.py --latest
# Just list recent entries
python3 scripts/import_letterboxd.py --list
# Skip to theater/home questions
python3 scripts/import_letterboxd.py --theater
python3 scripts/import_letterboxd.py --home
```
#### Update Movie Metadata
Fetch and update movie metadata (poster, director, runtime, etc.):
```bash
# Update all posts with IMDB IDs
python3 scripts/fetch_movie_data.py
# Dry run (preview changes)
python3 scripts/fetch_movie_data.py --dry-run
# Force re-fetch even if data exists
python3 scripts/fetch_movie_data.py --force
```
### Beer Posts
#### Add Beer Call Entry
Add entries to the beer call yearly log:
```bash
# Interactive mode
python3 scripts/new_beercall.py
# Specific date
python3 scripts/new_beercall.py --date 2024-12-19
# List recent Untappd checkins
python3 scripts/new_beercall.py --list
```
## Environment Variables
### Ollama (for NFR automation)
```bash
# Ollama server (default: http://192.168.0.109:11434)
export OLLAMA_HOST=http://localhost:11434
# Model to use (default: llama3.2)
export OLLAMA_MODEL=llama3.2
```
## Common Workflows
### Creating an NFR Movie Post
```bash
# 1. Create the post
python3 scripts/new_nfr.py "Beverly Hills Cop"
# 2. Update metadata (director, runtime, etc.)
python3 scripts/fetch_movie_data.py
# 3. Edit the post
# - Add viewing details (format, rating)
# - Write your thoughts
# - Add Letterboxd URL
# 4. Build and preview
hugo server -D
# 5. Publish (remove draft: true)
```
### Importing Theater Movie from Letterboxd
```bash
# 1. Import from Letterboxd
python3 scripts/import_letterboxd.py --theater
# 2. Script will:
# - Fetch recent Letterboxd entries
# - Let you pick one
# - Ask for theater details (venue, time, crew, etc.)
# - Download poster from TMDB
# - Create draft post
# 3. Edit and publish
```
### Setting Up a New NFR Year
```bash
# 1. Find the LOC announcement URL for the year
# Example: https://newsroom.loc.gov/news/...
# 2. Run setup script (with ollama for best results)
python3 scripts/setup_nfr.py 2023 --url "https://newsroom.loc.gov/..."
# 3. Review generated file
cat scripts/nfr_data/nfr_2023.py
# 4. Integrate into new_nfr.py
# (Copy the dictionary into the main script)
# 5. Start creating posts!
python3 scripts/new_nfr.py "Terminator 2" --nfr-year 2023
```
## Troubleshooting
### "Module not found" errors
```bash
# Make sure venv is activated
source .venv/bin/activate
# Install/reinstall dependencies
pip install -r requirements.txt
```
### "TMDB API key" errors
```bash
# Check config exists
ls scripts/config.py
# If not, copy example and edit
cp scripts/config.example.py scripts/config.py
# Then add your API key
```
### Ollama connection errors
```bash
# Test ollama server
curl http://192.168.0.109:11434/api/tags
# Use --no-ollama flag to skip
python3 scripts/setup_nfr.py 2023 --no-ollama
```
## Documentation
- **NFR Automation**: `scripts/NFR_AUTOMATION.md` - Detailed guide for NFR automation with ollama
- **Config Example**: `scripts/config.example.py` - Template for API keys
## Directory Structure
```
scripts/
├── README.md # This file
├── NFR_AUTOMATION.md # NFR automation guide
├── config.example.py # Config template
├── config.py # Your config (gitignored)
├── nfr_data/ # Generated NFR data
│ ├── nfr_2023.py
│ └── nfr_2024.py
├── venues.json # Beer venue database
├── setup_nfr.py # Setup NFR year data
├── new_nfr.py # Create NFR movie post
├── new_movie.py # Create movie post
├── import_letterboxd.py # Import from Letterboxd
├── fetch_movie_data.py # Update movie metadata
├── new_beercall.py # Add beer call entry
└── new_techpost.py # Create tech post
```
## Getting Help
- Check the specific script's `--help`: `python3 scripts/new_nfr.py --help`
- Read `NFR_AUTOMATION.md` for NFR details
- Check error messages - they usually point to the issue
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""
Batch generate NFR dictionaries for multiple years.
This script automates the process of generating NFR data dictionaries
for years 1989-2023 by searching for and fetching LOC announcement pages.
Usage:
python3 scripts/batch_generate_nfr.py --years 2020-2023
python3 scripts/batch_generate_nfr.py --years 2015,2016,2017
python3 scripts/batch_generate_nfr.py --all # Process all years 1989-2023
"""
import argparse
import subprocess
import sys
from pathlib import Path
# NFR started in 1989
FIRST_NFR_YEAR = 1989
CURRENT_YEAR = 2024 # Update this as needed
# Known announcement URLs (add more as we find them)
KNOWN_URLS = {
2024: "https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/s/55d5285d-916f-4105-b7d4-7fc3ba8664e3",
2023: "https://newsroom.loc.gov/news/25-films-selected-for-preservation-in-national-film-registry/s/aa4bef48-95f6-486f-882d-110613633b1e",
2022: "https://newsroom.loc.gov/news/25-eclectic-films-chosen-for-national-film-registry/s/8c41f7a1-b9d9-4f9e-b252-4795b73a4aaf",
}
def parse_year_range(year_spec):
"""
Parse year specification into a list of years.
Examples:
"2020-2023" -> [2020, 2021, 2022, 2023]
"2015,2016,2017" -> [2015, 2016, 2017]
"2020" -> [2020]
"""
years = []
# Handle comma-separated list
if ',' in year_spec:
for year_str in year_spec.split(','):
years.append(int(year_str.strip()))
# Handle range
elif '-' in year_spec:
start, end = year_spec.split('-')
years = list(range(int(start.strip()), int(end.strip()) + 1))
# Handle single year
else:
years = [int(year_spec)]
return years
def run_setup_for_year(year, use_ollama=True, ollama_host=None, ollama_model=None):
"""
Run setup_nfr.py for a specific year.
Returns True if successful, False otherwise.
"""
print(f"\n{'='*60}")
print(f"Processing NFR {year}")
print(f"{'='*60}\n")
cmd = ["python3", "scripts/setup_nfr.py", str(year)]
# Add URL if we know it
if year in KNOWN_URLS:
cmd.extend(["--url", KNOWN_URLS[year]])
print(f"Using known URL for {year}")
# Add ollama options
if not use_ollama:
cmd.append("--no-ollama")
else:
if ollama_host:
cmd.extend(["--ollama-host", ollama_host])
if ollama_model:
cmd.extend(["--ollama-model", ollama_model])
# Check if output file already exists
output_file = Path(f"scripts/nfr_data/nfr_{year}.py")
if output_file.exists():
print(f"⚠️ {output_file} already exists")
response = input("Overwrite? (y/N): ").strip().lower()
if response != 'y':
print(f"Skipping {year}")
return False
try:
# Run the command - this may be interactive
result = subprocess.run(cmd, check=False)
if result.returncode == 0:
print(f"✓ Successfully processed {year}")
return True
else:
print(f"✗ Failed to process {year}")
return False
except KeyboardInterrupt:
print(f"\n\nInterrupted while processing {year}")
sys.exit(1)
except Exception as e:
print(f"Error processing {year}: {e}")
return False
def main():
parser = argparse.ArgumentParser(
description="Batch generate NFR dictionaries"
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"--years",
help="Years to process (e.g., '2020-2023' or '2015,2016,2017')"
)
group.add_argument(
"--all",
action="store_true",
help=f"Process all years from {FIRST_NFR_YEAR} to 2023"
)
parser.add_argument(
"--no-ollama",
action="store_true",
help="Don't use ollama (use basic extraction)"
)
parser.add_argument(
"--ollama-host",
help="Ollama server URL"
)
parser.add_argument(
"--ollama-model",
help="Ollama model to use"
)
args = parser.parse_args()
# Determine which years to process
if args.all:
years = list(range(FIRST_NFR_YEAR, 2024)) # 1989-2023
else:
years = parse_year_range(args.years)
# Sort years
years.sort()
print(f"\nWill process {len(years)} years: {years[0]}-{years[-1]}")
print(f"Ollama: {'disabled' if args.no_ollama else 'enabled'}")
if len(years) > 5:
response = input("\nThis will process many years. Continue? (Y/n): ").strip().lower()
if response == 'n':
print("Cancelled")
sys.exit(0)
# Process each year
successful = []
failed = []
for year in years:
success = run_setup_for_year(
year,
use_ollama=not args.no_ollama,
ollama_host=args.ollama_host,
ollama_model=args.ollama_model
)
if success:
successful.append(year)
else:
failed.append(year)
# Summary
print(f"\n{'='*60}")
print("SUMMARY")
print(f"{'='*60}\n")
print(f"✓ Successfully processed: {len(successful)} years")
if successful:
print(f" {successful}")
if failed:
print(f"\n✗ Failed: {len(failed)} years")
print(f" {failed}")
print(f"\nYou can retry failed years individually:")
for year in failed:
print(f" python3 scripts/setup_nfr.py {year}")
print(f"\nGenerated files are in: scripts/nfr_data/")
if __name__ == "__main__":
main()
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Build script for marcus-web
# Fetches movie data, then builds Hugo site
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
cd "$PROJECT_ROOT"
echo "=== Fetching movie data ==="
python3 scripts/fetch_movie_data.py
echo ""
echo "=== Building Hugo site ==="
hugo "$@"
echo ""
echo "=== Done ==="
+4
View File
@@ -0,0 +1,4 @@
# Copy this file to config.py and fill in your values
# config.py is gitignored and will not be committed
TMDB_API_KEY = "your_tmdb_api_key_here"
+144
View File
@@ -0,0 +1,144 @@
================================================================================
MARCUS-WEB SCRIPTS CHEAT SHEET
================================================================================
FIRST TIME SETUP
----------------
After cloning on a new machine:
cd marcus-web
./scripts/setup.sh
This creates a .venv and installs dependencies (just 'requests').
Then either activate the venv:
source .venv/bin/activate
python scripts/import_letterboxd.py
Or run directly:
.venv/bin/python scripts/import_letterboxd.py
MOVIES (Frank's Couch)
----------------------
Import a movie from Letterboxd:
python scripts/import_letterboxd.py
--latest Import most recent without picking
--theater Skip straight to theater questions
--home Skip straight to home video questions
--list Just show recent movies, don't import
Workflow: Log movie on Letterboxd → Run script → Pick movie → Answer prompts
Creates: content/posts/<movie-slug>.md + downloads poster
BEER CALLS (Luna Juice - Weekly Thursday Meetups)
-------------------------------------------------
Add a beer call to the yearly log:
python scripts/new_beercall.py
--date 2024-12-30 Specific date (for Beer Crawl, holidays, etc)
--list Just show recent Untappd checkins
Workflow: Run script → It checks Untappd for where you were → Pick venue → Done
Appends to: content/posts/beercall/2024.md (or 2025.md, etc - auto-created)
LUNA JUICE EVENTS (Festivals, Special Occasions)
------------------------------------------------
Create a standalone beer event post:
python scripts/new_lunajuice.py
python scripts/new_lunajuice.py "Beer Festival 2025"
Creates: content/posts/beercall/<event-slug>.md
VENUE DATABASE
--------------
Known venues are stored in: scripts/venues.json
New venues are added automatically when you enter them.
TECH POSTS (Fun Center)
-----------------------
Create a new technology blog post:
python scripts/new_techpost.py
python scripts/new_techpost.py "My Post Title"
Prompts for:
- Type: How I Did It / Grinds My Gears / Quick Tip
- Tags: suggests common ones, you add more
- Summary: one-liner
Creates a skeleton outline based on post type so you just fill in the blanks.
MASTODON COMMENTS
-----------------
After publishing a post and tooting about it:
1. Get the Mastodon post ID from the URL (the number at the end)
2. Add to your post's front matter:
mastodon_id: "123456789"
3. Rebuild site - comments will show with count
To block a reply:
mastodon_blocked:
- "https://tilde.zone/@someone/123456789"
GOPHER / PHLOG (SDF Gopherspace)
--------------------------------
Posts can be published to gopher by adding `phlog: true` to frontmatter.
Deploy to gopher (after --gopher-only for first run, then use --gopher):
./scripts/remote_publish.sh --gopher # Hugo + Gopher
./scripts/remote_publish.sh --gopher-only # Gopher only
What it does:
1. Converts posts with `phlog: true` to plain text (70 char wrap)
2. Generates gophermaps for each category
3. Rsyncs to ~/gopher/blog/ on SDF
URLs after deployment:
- Gopher root: gopher://sdf.org/1/users/mnw/
- Blog index: gopher://sdf.org/1/users/mnw/blog/
- Frank's Couch: gopher://sdf.org/1/users/mnw/blog/franks-couch/
- Fun Center: gopher://sdf.org/1/users/mnw/blog/fun-center/
- Web proxy: https://gopher.floodgap.com/gopher/gw?a=gopher://sdf.org/1/users/mnw/
Gopher scripts (in scripts/gopher/):
- convert_to_gopher.py Markdown → gopher plain text
- generate_gophermaps.py Build category menus
- ascii_art.py Headers/footers
- update_root_gophermap.py Update main gophermap (one-time)
References:
- SDF Gopher Setup: https://wiki.sdf.org/doku.php?id=gopher_site_setup_and_hosting_features
- Tilde.town Guide: https://tilde.town/wiki/editing-your-homepage/gopher.html
PUBLISHING / REMOTE DEPLOY
--------------------------
Push changes to SDF and build:
./scripts/remote_publish.sh # Hugo only
./scripts/remote_publish.sh --gopher # Hugo + Gopher
./scripts/remote_publish.sh --gopher-only # Gopher only
The script handles git commit/push prompts automatically.
================================================================================
+274
View File
@@ -0,0 +1,274 @@
#!/usr/bin/env python3
"""
Fetch movie data for Hugo posts based on IMDB ID in frontmatter.
Scans all posts with an `imdb` field and fetches missing data:
- Poster (downloaded locally)
- Runtime
- Year
- Director
- Genres
Usage:
python scripts/fetch_movie_data.py # Process all movie posts
python scripts/fetch_movie_data.py --dry-run # Show what would be updated
python scripts/fetch_movie_data.py --force # Re-fetch even if data exists
"""
import argparse
import os
import re
import sys
from pathlib import Path
import requests
import yaml
# Configuration
try:
from config import TMDB_API_KEY
except ImportError:
raise SystemExit("Error: scripts/config.py not found. Copy config.example.py to config.py and add your API key.")
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
IMAGES_DIR = PROJECT_ROOT / "static" / "images" / "posters"
# Regex to split frontmatter from content
FRONTMATTER_RE = re.compile(r'^---\s*\n(.*?)\n---\s*\n', re.DOTALL)
def find_movie_by_imdb(imdb_id):
"""Find TMDB movie by IMDB ID."""
url = f"https://api.themoviedb.org/3/find/{imdb_id}"
params = {
"api_key": TMDB_API_KEY,
"external_source": "imdb_id"
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
results = data.get("movie_results", [])
if results:
return results[0]
return None
def get_movie_details(tmdb_id):
"""Get full movie details from TMDB."""
url = f"https://api.themoviedb.org/3/movie/{tmdb_id}"
params = {
"api_key": TMDB_API_KEY,
"append_to_response": "credits"
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
return resp.json()
def get_directors(credits):
"""Extract director names from credits."""
crew = credits.get("crew", [])
directors = [p["name"] for p in crew if p.get("job") == "Director"]
return directors
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def download_poster(poster_path, filename):
"""Download poster from TMDB."""
if not poster_path:
return None
url = f"https://image.tmdb.org/t/p/w500{poster_path}"
resp = requests.get(url, timeout=10)
resp.raise_for_status()
IMAGES_DIR.mkdir(parents=True, exist_ok=True)
filepath = IMAGES_DIR / filename
filepath.write_bytes(resp.content)
return f"/images/posters/{filename}"
def parse_post(filepath):
"""Parse a markdown post into frontmatter dict and content string."""
text = filepath.read_text()
match = FRONTMATTER_RE.match(text)
if not match:
return None, text
fm_text = match.group(1)
content = text[match.end():]
try:
frontmatter = yaml.safe_load(fm_text)
except yaml.YAMLError:
return None, text
return frontmatter, content
def write_post(filepath, frontmatter, content):
"""Write frontmatter and content back to markdown file."""
# Use default_flow_style=False for readable YAML
# Use allow_unicode=True for proper character handling
fm_text = yaml.dump(
frontmatter,
default_flow_style=False,
allow_unicode=True,
sort_keys=False
)
text = f"---\n{fm_text}---\n{content}"
filepath.write_text(text)
def process_post(filepath, dry_run=False, force=False):
"""Process a single post, fetching missing movie data."""
frontmatter, content = parse_post(filepath)
if frontmatter is None:
return False
imdb_id = frontmatter.get("imdb")
if not imdb_id:
return False
# Check what's missing
has_poster = bool(frontmatter.get("poster"))
has_runtime = bool(frontmatter.get("runtime"))
has_year = bool(frontmatter.get("year"))
has_director = bool(frontmatter.get("director"))
needs_update = not (has_poster and has_runtime and has_year and has_director)
if not needs_update and not force:
return False
print(f"\nProcessing: {filepath.name}")
print(f" IMDB: {imdb_id}")
if dry_run:
missing = []
if not has_poster:
missing.append("poster")
if not has_runtime:
missing.append("runtime")
if not has_year:
missing.append("year")
if not has_director:
missing.append("director")
print(f" Would fetch: {', '.join(missing)}")
return True
# Find movie on TMDB
print(" Finding movie on TMDB...")
movie = find_movie_by_imdb(imdb_id)
if not movie:
print(f" ERROR: Movie not found for IMDB ID: {imdb_id}")
return False
tmdb_id = movie["id"]
print(f" Found: {movie.get('title')} (TMDB: {tmdb_id})")
# Get full details
print(" Fetching details...")
details = get_movie_details(tmdb_id)
updated = False
# Update poster
if not has_poster or force:
poster_path = details.get("poster_path")
if poster_path:
title = frontmatter.get("title", "movie")
filename = f"{slugify(title)}.jpg"
print(f" Downloading poster...")
poster_url = download_poster(poster_path, filename)
if poster_url:
frontmatter["poster"] = poster_url
print(f" Poster saved: {poster_url}")
updated = True
# Update runtime
if not has_runtime or force:
runtime = details.get("runtime")
if runtime:
frontmatter["runtime"] = runtime
print(f" Runtime: {runtime} minutes")
updated = True
# Update year
if not has_year or force:
release_date = details.get("release_date", "")
if release_date:
year = release_date.split("-")[0]
frontmatter["year"] = int(year)
print(f" Year: {year}")
updated = True
# Update director
if not has_director or force:
credits = details.get("credits", {})
directors = get_directors(credits)
if directors:
# Store as string if single, list if multiple
if len(directors) == 1:
frontmatter["director"] = directors[0]
else:
frontmatter["director"] = directors
print(f" Director: {', '.join(directors)}")
updated = True
# Update genres (bonus)
if "genres" not in frontmatter or force:
genres = [g["name"] for g in details.get("genres", [])]
if genres:
frontmatter["genres"] = genres
updated = True
if updated:
write_post(filepath, frontmatter, content)
print(" Updated!")
return updated
def main():
parser = argparse.ArgumentParser(description="Fetch movie data for Hugo posts")
parser.add_argument("--dry-run", action="store_true", help="Show what would be updated")
parser.add_argument("--force", action="store_true", help="Re-fetch even if data exists")
parser.add_argument("file", nargs="?", help="Specific file to process")
args = parser.parse_args()
if args.file:
filepath = Path(args.file)
if not filepath.is_absolute():
filepath = PROJECT_ROOT / filepath
if not filepath.exists():
print(f"File not found: {filepath}")
sys.exit(1)
files = [filepath]
else:
files = list(CONTENT_DIR.glob("**/*.md"))
print(f"Scanning {len(files)} posts for movie data...")
updated = 0
for filepath in files:
if process_post(filepath, dry_run=args.dry_run, force=args.force):
updated += 1
print(f"\n{'Would update' if args.dry_run else 'Updated'}: {updated} posts")
if __name__ == "__main__":
main()
+310
View File
@@ -0,0 +1,310 @@
#!/usr/bin/env python3
"""
Fully automated NFR dictionary generator for all years.
This script uses web search and scraping to find announcement pages
and extract film data for each NFR year from 1989-2023.
Usage:
python3 scripts/generate_all_nfr_years.py
python3 scripts/generate_all_nfr_years.py --start 2020 --end 2023
python3 scripts/generate_all_nfr_years.py --year 2015
"""
import argparse
import json
import re
import time
from pathlib import Path
from urllib.parse import quote_plus
import requests
# Configuration
SCRIPT_DIR = Path(__file__).parent
NFR_DATA_DIR = SCRIPT_DIR / "nfr_data"
FIRST_NFR_YEAR = 1989
# Known URLs to speed things up
KNOWN_ANNOUNCEMENT_URLS = {
2024: "https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/s/55d5285d-916f-4105-b7d4-7fc3ba8664e3",
2023: "https://newsroom.loc.gov/news/25-films-selected-for-preservation-in-national-film-registry/s/aa4bef48-95f6-486f-882d-110613633b1e",
2022: "https://newsroom.loc.gov/news/25-eclectic-films-chosen-for-national-film-registry/s/8c41f7a1-b9d9-4f9e-b252-4795b73a4aaf",
2021: "https://blogs.loc.gov/now-see-hear/2021/12/librarian-of-congress-adds-25-films-to-the-national-film-registry/",
2020: "https://blogs.loc.gov/now-see-hear/2020/12/librarian-of-congress-adds-25-films-to-the-national-film-registry/",
2019: "https://blogs.loc.gov/now-see-hear/2019/12/librarian-of-congress-announces-national-film-registry-selections-for-2019/",
2018: "https://blogs.loc.gov/now-see-hear/2018/12/librarian-of-congress-announces-national-film-registry-selections-for-2018/",
2017: "https://blogs.loc.gov/now-see-hear/2017/12/librarian-of-congress-announces-national-film-registry-selections-for-2017/",
2016: "https://blogs.loc.gov/now-see-hear/2016/12/librarian-of-congress-announces-2016-national-film-registry-selections/",
2015: "https://blogs.loc.gov/now-see-hear/2015/12/announcing-the-2015-national-film-registry-selections/",
2014: "https://blogs.loc.gov/now-see-hear/2014/12/announcing-the-2014-national-film-registry-selections/",
2013: "https://blogs.loc.gov/now-see-hear/2013/12/announcing-the-2013-national-film-registry-selections/",
2012: "https://blogs.loc.gov/now-see-hear/2012/12/announcing-the-2012-national-film-registry-selections/",
2011: "https://blogs.loc.gov/now-see-hear/2011/12/announcing-the-2011-national-film-registry-selections/",
2010: "https://blogs.loc.gov/now-see-hear/2010/12/announcing-the-2010-national-film-registry-selections/",
2009: "https://blogs.loc.gov/now-see-hear/2009/12/announcing-the-2009-national-film-registry-selections/",
2008: "https://blogs.loc.gov/now-see-hear/2008/12/announcing-the-2008-national-film-registry-selections/",
2007: "https://blogs.loc.gov/now-see-hear/2007/12/announcing-the-2007-national-film-registry-selections/",
}
def search_for_announcement_url(year):
"""
Try to find the announcement URL for a given year using various strategies.
"""
print(f" Searching for {year} announcement URL...")
if year in KNOWN_ANNOUNCEMENT_URLS:
print(f" Using known URL for {year}")
return KNOWN_ANNOUNCEMENT_URLS[year]
# Try common URL patterns
# Pattern 1: blogs.loc.gov (most common for older years)
year_patterns = [
f"https://blogs.loc.gov/now-see-hear/{year}/12/announcing-the-{year}-national-film-registry-selections/",
f"https://blogs.loc.gov/now-see-hear/{year}/12/librarian-of-congress-announces-{year}-national-film-registry-selections/",
f"https://blogs.loc.gov/now-see-hear/{year}/12/announcing-the-{year}-national-film-registry/",
]
for url in year_patterns:
try:
resp = requests.head(url, timeout=10, allow_redirects=True)
if resp.status_code == 200:
print(f" Found URL: {url}")
return url
except Exception:
pass
# If we can't find it automatically, return None
print(f" Could not find announcement URL for {year} - will need manual search")
return None
def fetch_page_content(url):
"""Fetch HTML content from a URL."""
try:
resp = requests.get(url, timeout=30)
resp.raise_for_status()
return resp.text
except Exception as e:
print(f" Error fetching {url}: {e}")
return None
def extract_films_basic(html, year):
"""
Basic extraction of films from HTML content.
This is a simple heuristic-based approach.
"""
films = {}
# Look for film title patterns: "Title" (Year) or Title (Year)
# This is very basic and may need refinement
patterns = [
r'"([^"]+)"\s*\((\d{4})\)', # "Title" (Year)
r'<strong>([^<]+)</strong>\s*\((\d{4})\)', # <strong>Title</strong> (Year)
r'<b>([^<]+)</b>\s*\((\d{4})\)', # <b>Title</b> (Year)
]
found_titles = set()
for pattern in patterns:
matches = re.findall(pattern, html)
for title, film_year in matches:
title = title.strip()
film_year = int(film_year)
# Sanity checks
if (len(title) > 3 and
1890 <= film_year <= year and
title not in found_titles):
films[title] = {
"year": film_year,
"description": f"[Description needs to be added for this {year} NFR inductee]"
}
found_titles.add(title)
return films
def generate_nfr_dict_file(year, films, source_url=""):
"""Generate a Python file containing the NFR dictionary for a year."""
if not films:
print(f" No films to generate for {year}")
return None
output_path = NFR_DATA_DIR / f"nfr_{year}.py"
# Build the Python code
code = f'''# {year} National Film Registry inductees
# Source: {source_url if source_url else "[Add source URL]"}
# Generated automatically - descriptions may need review/enhancement
NFR_{year} = {{
'''
for title, data in films.items():
# Escape single quotes in strings
title_escaped = title.replace("'", "\\'").replace('"', '\\"')
desc_escaped = data["description"].replace("'", "\\'").replace('"', '\\"')
code += f''' "{title_escaped}": {{
"year": {data["year"]},
"description": "{desc_escaped}"
}},
'''
code += "}\n"
# Save the file
output_path.write_text(code)
print(f" ✓ Saved {len(films)} films to {output_path.relative_to(SCRIPT_DIR)}")
return output_path
def process_year(year, force=False):
"""Process a single year: find URL, fetch content, extract films, generate file."""
print(f"\n{'='*60}")
print(f"Processing NFR {year}")
print(f"{'='*60}")
# Check if already exists
output_file = NFR_DATA_DIR / f"nfr_{year}.py"
if output_file.exists() and not force:
print(f" ⚠️ {output_file.name} already exists (use --force to overwrite)")
return False
# Find announcement URL
url = search_for_announcement_url(year)
if not url:
print(f" ✗ Skipping {year} - no URL found")
print(f" You can manually process this year with:")
print(f" python3 scripts/setup_nfr.py {year}")
return False
# Fetch content
html = fetch_page_content(url)
if not html:
print(f" ✗ Could not fetch content for {year}")
return False
# Extract films
print(f" Extracting films...")
films = extract_films_basic(html, year)
if not films:
print(f" ✗ Could not extract films from {year}")
print(f" The page format may require manual processing:")
print(f" python3 scripts/setup_nfr.py {year} --url \"{url}\"")
return False
print(f" Found {len(films)} films")
# Generate file
output_file = generate_nfr_dict_file(year, films, url)
if output_file:
print(f" ✓ Successfully processed {year}")
return True
return False
def main():
parser = argparse.ArgumentParser(
description="Generate NFR dictionaries for all years"
)
parser.add_argument(
"--start",
type=int,
default=FIRST_NFR_YEAR,
help=f"Start year (default: {FIRST_NFR_YEAR})"
)
parser.add_argument(
"--end",
type=int,
default=2023,
help="End year (default: 2023)"
)
parser.add_argument(
"--year",
type=int,
help="Process a single year"
)
parser.add_argument(
"--force",
action="store_true",
help="Overwrite existing files"
)
parser.add_argument(
"--delay",
type=float,
default=1.0,
help="Delay between requests in seconds (default: 1.0)"
)
args = parser.parse_args()
# Create output directory
NFR_DATA_DIR.mkdir(exist_ok=True)
# Determine years to process
if args.year:
years = [args.year]
else:
years = list(range(args.start, args.end + 1))
print(f"Will process {len(years)} years: {min(years)}-{max(years)}")
print(f"Output directory: {NFR_DATA_DIR}")
print(f"Force overwrite: {args.force}")
# Process years
successful = []
failed = []
skipped = []
for i, year in enumerate(years):
# Add delay between requests to be polite
if i > 0:
time.sleep(args.delay)
result = process_year(year, force=args.force)
if result is True:
successful.append(year)
elif result is False:
# Check if it was skipped vs failed
output_file = NFR_DATA_DIR / f"nfr_{year}.py"
if output_file.exists():
skipped.append(year)
else:
failed.append(year)
# Summary
print(f"\n{'='*60}")
print("SUMMARY")
print(f"{'='*60}")
print(f"\n✓ Successfully generated: {len(successful)} files")
if successful:
print(f" Years: {successful}")
if skipped:
print(f"\n⊘ Skipped (already exist): {len(skipped)}")
print(f" Years: {skipped}")
if failed:
print(f"\n✗ Failed/Need manual processing: {len(failed)}")
print(f" Years: {failed}")
print(f"\n Process these manually with:")
for year in failed:
print(f" python3 scripts/setup_nfr.py {year}")
print(f"\n📁 Generated files: {NFR_DATA_DIR}/")
print(f"\nNote: Generated files use basic extraction and may need review.")
print(f"For better results with descriptions, use setup_nfr.py with ollama.")
if __name__ == "__main__":
main()
+1
View File
@@ -0,0 +1 @@
# Gopher conversion scripts for marcus-web
+204
View File
@@ -0,0 +1,204 @@
#!/usr/bin/env python3
"""
ASCII art assets for gopher content generation.
Contains category headers, post templates, footers, and utility functions
for generating ASCII tables and dividers.
"""
# Line width for gopher content
LINE_WIDTH = 70
# Dividers
DOUBLE_LINE = "=" * LINE_WIDTH
SINGLE_LINE = "-" * LINE_WIDTH
BOX_LINE = "\u2500" * LINE_WIDTH # Unicode box drawing horizontal
# Post header (MNW owl)
POST_HEADER = """\
___ ___ ___
/\\ \\ /\\ \\ /\\ \\
|::\\ \\ \\:\\ \\ _\\:\\ \\
|:|:\\ \\ \\:\\ \\ /\\ \\:\\ \\
__|:|\\:\\ \\ _____\\:\\ \\ _\\:\\ \\:\\ \\
/::::|_\\:\\__\\ /::::::::\\__\\ /\\ \\:\\ \\:\\__\\
\\:\\~~\\ \\/__/ \\:\\~~\\~~\\/__/ \\:\\ \\:\\/:/ /
\\:\\ \\ \\:\\ \\ \\:\\ \\::/ /
\\:\\ \\ \\:\\ \\ \\:\\/:/ /
\\:\\__\\ \\:\\__\\ \\::/ /
\\/__/ \\/__/ \\/__/
mnw(at)sdf.org | SDF VOIP Ext. 1908
"""
# Category headers
HEADER_FUN_CENTER = """\
___ ___ _
| __| _ _ _ / __|___ _ _| |_ ___ _ _
| _| || | ' \\ | (__/ -_) ' \\ _/ -_) '_|
|_| \\_,_|_||_| \\___\\___|_||_\\__\\___|_|
Tech posts from the Double Lunch Dispatch
"""
HEADER_FRANKS_COUCH = """\
___ _ _ ___ _
| __| _ __ _ _ _| |_( )___ / __|___ _ _ __| |_
| _| '_/ _` | ' \\ / /|_-< | (__/ _ \\ || (_-< ' \\
|_||_| \\__,_|_||_\\_\\ /__/ \\___\\___/\\_,_/__/_||_|
Movie reviews from the couch
"""
HEADER_BEERCALLS = """\
___ _ _
| _ ) ___ ___ _ _ __ __ _| | |___
| _ \\/ -_) -_) '_/ _/ _` | | (_-<
|___/\\___\\___|_| \\__\\__,_|_|_/__/
Thursday night adventures in Austin
"""
HEADER_BLOG_INDEX = """\
___ _ ___ _ _
| _ )| |___ __ | __|_ _ | |_ _ _ (_)___ ___
| _ \\| / _ \\/ _|| _|| ' \\| _| '_|| / -_|_-<
|___/|_\\___/\\__||___|_||_|\\__|_| |_\\___/__/
Posts from mnw.sdf.org
"""
# Footer (SDF box)
POST_FOOTER = """\
__^__ __^__
( ___ )------------------------------------------------------( ___ )
| / | | \\ |
| / | This gopher space proudly hosted by SDF | \\ |
| \\ | mnw on pixelfed.social and tilde.zone | / |
| \\ | | / |
(_____)------------------------------------------------------(_____)
"""
# Map series names to gopher directory names
SERIES_TO_DIR = {
"Fun Center": "fun-center",
"Frank's Couch": "franks-couch",
"Beercalls": "beercalls",
}
# Map directory names to headers
DIR_TO_HEADER = {
"fun-center": HEADER_FUN_CENTER,
"franks-couch": HEADER_FRANKS_COUCH,
"beercalls": HEADER_BEERCALLS,
}
# Map directory names to descriptions
DIR_TO_DESCRIPTION = {
"fun-center": "Tech posts from the Double Lunch Dispatch",
"franks-couch": "Movie reviews from the couch",
"beercalls": "Thursday night adventures in Austin",
}
def get_section_header(title: str) -> str:
"""Generate a section header with double lines."""
return f"\n{DOUBLE_LINE}\n {title.upper()}\n{DOUBLE_LINE}\n"
def get_subheading(title: str) -> str:
"""Generate a subheading with dashes."""
return f"\n--- {title} ---\n"
def get_post_meta_header(date: str, series: str) -> str:
"""Generate the metadata header for a post."""
return f"""\
{SINGLE_LINE}
{date} | {series}
{SINGLE_LINE}
"""
def get_title_block(title: str, summary: str = "") -> str:
"""Generate a centered title block."""
# Center the title
centered_title = title.upper().center(LINE_WIDTH)
lines = [centered_title]
if summary:
centered_summary = summary.center(LINE_WIDTH)
lines.append(centered_summary)
return "\n".join(lines)
def generate_movie_table(
title: str,
year: int,
director: str = "",
runtime: int = 0,
genres: list = None,
web_url: str = "",
) -> str:
"""Generate an ASCII table for movie metadata."""
genres = genres or []
width = 65
border_h = "\u2500" # horizontal line
corner_tl = "\u250c" # top left
corner_tr = "\u2510" # top right
corner_bl = "\u2514" # bottom left
corner_br = "\u2518" # bottom right
border_v = "\u2502" # vertical
tee_l = "\u251c" # left tee
tee_r = "\u2524" # right tee
def row(content: str) -> str:
return f"{border_v} {content.ljust(width - 4)} {border_v}"
lines = [
f"{corner_tl}{border_h * width}{corner_tr}",
row(f"{title.upper()} ({year})"),
f"{tee_l}{border_h * width}{tee_r}",
]
if director:
lines.append(row(f"Director: {director}"))
if runtime:
lines.append(row(f"Runtime: {runtime} minutes"))
if genres:
lines.append(row(f"Genres: {', '.join(genres)}"))
lines.append(row(""))
if web_url:
lines.append(row(f"View on web: {web_url}"))
lines.append(f"{corner_bl}{border_h * width}{corner_br}")
return "\n".join(lines)
def wrap_text(text: str, width: int = LINE_WIDTH) -> str:
"""Wrap text to specified width, preserving paragraphs."""
import textwrap
paragraphs = text.split("\n\n")
wrapped = []
for para in paragraphs:
# Preserve single newlines within paragraphs as spaces
para = " ".join(para.split())
if para:
wrapped.append(textwrap.fill(para, width=width))
else:
wrapped.append("")
return "\n\n".join(wrapped)
def format_links_section(links: list) -> str:
"""Format a list of links for the footer section."""
if not links:
return ""
lines = [get_section_header("LINKS")]
for i, url in enumerate(links, 1):
lines.append(f"[{i}] {url}")
return "\n".join(lines)
+351
View File
@@ -0,0 +1,351 @@
#!/usr/bin/env python3
"""
Convert Hugo markdown posts to gopher-formatted text files.
Usage:
python scripts/gopher/convert_to_gopher.py content/posts/blog-posting.md
python scripts/gopher/convert_to_gopher.py --all
python scripts/gopher/convert_to_gopher.py --all --output gopher_build/blog/
"""
import argparse
import re
import sys
import textwrap
import yaml
from pathlib import Path
# Add script directory to path for imports
sys.path.insert(0, str(Path(__file__).parent))
from ascii_art import (
LINE_WIDTH,
POST_HEADER,
POST_FOOTER,
SERIES_TO_DIR,
get_post_meta_header,
get_title_block,
get_section_header,
get_subheading,
generate_movie_table,
format_links_section,
)
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
DEFAULT_OUTPUT = PROJECT_ROOT / "gopher_build" / "blog"
def parse_frontmatter(content: str) -> tuple[dict, str]:
"""Parse YAML frontmatter and return (metadata, body)."""
if not content.startswith("---"):
return {}, content
# Find the closing ---
end_match = re.search(r"\n---\n", content[3:])
if not end_match:
return {}, content
yaml_end = end_match.start() + 3
yaml_content = content[3:yaml_end]
body = content[yaml_end + 4 :] # Skip the closing ---\n
try:
metadata = yaml.safe_load(yaml_content)
except yaml.YAMLError:
metadata = {}
return metadata or {}, body
def extract_links(text: str) -> tuple[str, list]:
"""Extract markdown links and replace with numbered references."""
links = []
link_pattern = re.compile(r"\[([^\]]+)\]\(([^)]+)\)")
def replace_link(match):
text = match.group(1)
url = match.group(2)
links.append(url)
return f"{text} [{len(links)}]"
converted = link_pattern.sub(replace_link, text)
return converted, links
def convert_headings(text: str) -> str:
"""Convert markdown headings to gopher-style text."""
# H1: Double line with centered text
def h1_replace(match):
title = match.group(1).strip()
return get_section_header(title)
# H2: Dashed subheading
def h2_replace(match):
title = match.group(1).strip()
return get_subheading(title)
# H3-H6: Just bold-style text
def h3_replace(match):
title = match.group(1).strip()
return f"\n*{title}*\n"
text = re.sub(r"^# (.+)$", h1_replace, text, flags=re.MULTILINE)
text = re.sub(r"^## (.+)$", h2_replace, text, flags=re.MULTILINE)
text = re.sub(r"^###+ (.+)$", h3_replace, text, flags=re.MULTILINE)
return text
def convert_formatting(text: str) -> str:
"""Convert markdown formatting to gopher-style text."""
# Bold: **text** -> *text*
text = re.sub(r"\*\*([^*]+)\*\*", r"*\1*", text)
# Italic: *text* -> _text_ (but not our converted bold *text*)
text = re.sub(r"(?<!\*)\*([^*]+)\*(?!\*)", r"_\1_", text)
# Horizontal rules
text = re.sub(r"^---+$", "-" * LINE_WIDTH, text, flags=re.MULTILINE)
return text
def convert_code_blocks(text: str) -> str:
"""Convert code blocks to indented text."""
# Fenced code blocks
def indent_code(match):
code = match.group(2)
# Indent each line by 4 spaces
indented = "\n".join(" " + line for line in code.split("\n"))
return f"\n{indented}\n"
text = re.sub(r"```(\w*)\n(.*?)```", indent_code, text, flags=re.DOTALL)
# Inline code: `code` -> code (just remove backticks)
text = re.sub(r"`([^`]+)`", r"\1", text)
return text
def handle_imdbposter(text: str, metadata: dict, slug: str) -> str:
"""Replace imdbposter shortcode with ASCII movie table."""
# Check if there's an imdbposter shortcode
pattern = r"\{\{<\s*imdbposter\s*>\}\}(.*?)\{\{<\s*/imdbposter\s*>\}\}"
match = re.search(pattern, text, flags=re.DOTALL)
if not match:
return text
# Extract movie info from frontmatter
title = metadata.get("title", "Unknown")
year = metadata.get("year", "")
director = metadata.get("director", "")
runtime = metadata.get("runtime", 0)
genres = metadata.get("genres", [])
web_url = f"https://mnw.sdf.org/posts/{slug}/"
# If year not in frontmatter, try to parse from date
if not year and metadata.get("date"):
date_str = str(metadata.get("date"))
year_match = re.match(r"(\d{4})", date_str)
if year_match:
year = int(year_match.group(1))
# Generate the ASCII table
table = generate_movie_table(
title=title,
year=year,
director=director,
runtime=runtime,
genres=genres,
web_url=web_url,
)
# Also extract and preserve the viewing info table if present
inner_content = match.group(1).strip()
if inner_content:
# Convert markdown table to plain text
table_lines = []
for line in inner_content.split("\n"):
line = line.strip()
if line and not line.startswith("|--"):
# Remove leading/trailing pipes and clean up
line = re.sub(r"^\||\|$", "", line)
cells = [c.strip() for c in line.split("|")]
if len(cells) >= 2:
table_lines.append(f" {cells[0]}: {cells[1]}")
if table_lines:
table += "\n\n" + "\n".join(table_lines)
return text[: match.start()] + table + text[match.end() :]
def wrap_paragraphs(text: str) -> str:
"""Wrap text to LINE_WIDTH, preserving code blocks and structure."""
lines = text.split("\n")
result = []
paragraph = []
def flush_paragraph():
if paragraph:
para_text = " ".join(paragraph)
wrapped = textwrap.fill(para_text, width=LINE_WIDTH)
result.append(wrapped)
paragraph.clear()
for line in lines:
# Detect code blocks (indented by 4 spaces)
if line.startswith(" "):
flush_paragraph()
result.append(line)
continue
# Empty line = paragraph break
if not line.strip():
flush_paragraph()
result.append("")
continue
# Lines that look like headers or dividers - don't wrap
if (
line.startswith("=")
or line.startswith("-" * 10)
or line.startswith("*")
or line.startswith(" " * 10)
):
flush_paragraph()
result.append(line)
continue
# Accumulate paragraph text
paragraph.append(line.strip())
flush_paragraph()
return "\n".join(result)
def convert_post(filepath: Path, output_dir: Path = None) -> Path | None:
"""Convert a single markdown post to gopher format."""
content = filepath.read_text()
metadata, body = parse_frontmatter(content)
# Check if phlog is enabled
if not metadata.get("phlog", False):
return None
# Check if draft
if metadata.get("draft", False):
return None
# Determine output directory from series
series = metadata.get("series", "Fun Center")
gopher_dir = SERIES_TO_DIR.get(series, "fun-center")
# Get slug from filename
slug = filepath.stem
# Output path
output_dir = output_dir or DEFAULT_OUTPUT
category_dir = output_dir / gopher_dir
category_dir.mkdir(parents=True, exist_ok=True)
output_path = category_dir / f"{slug}.txt"
# Handle imdbposter shortcode first
body = handle_imdbposter(body, metadata, slug)
# Extract links before other conversions
body, links = extract_links(body)
# Convert markdown to gopher text
body = convert_headings(body)
body = convert_formatting(body)
body = convert_code_blocks(body)
# Wrap paragraphs
body = wrap_paragraphs(body)
# Build the final document
date_str = ""
if metadata.get("date"):
date_obj = metadata["date"]
if hasattr(date_obj, "strftime"):
date_str = date_obj.strftime("%Y-%m-%d")
else:
date_str = str(date_obj)[:10]
title = metadata.get("title", slug)
summary = metadata.get("summary", "")
parts = [
POST_HEADER,
get_post_meta_header(date_str, series),
get_title_block(title, summary),
"",
"-" * LINE_WIDTH,
"",
body.strip(),
"",
]
if links:
parts.append(format_links_section(links))
parts.append("")
parts.append(POST_FOOTER)
parts.append("")
parts.append(f"Web version: https://mnw.sdf.org/posts/{slug}/")
output_content = "\n".join(parts)
output_path.write_text(output_content)
return output_path
def convert_all(output_dir: Path = None) -> list[Path]:
"""Convert all posts with phlog: true."""
output_dir = output_dir or DEFAULT_OUTPUT
converted = []
for post_path in CONTENT_DIR.glob("*.md"):
result = convert_post(post_path, output_dir)
if result:
converted.append(result)
print(f"Converted: {post_path.name} -> {result.relative_to(output_dir)}")
return converted
def main():
parser = argparse.ArgumentParser(description="Convert Hugo posts to gopher format")
parser.add_argument("file", nargs="?", help="Single file to convert")
parser.add_argument("--all", action="store_true", help="Convert all phlog posts")
parser.add_argument("--output", "-o", type=Path, help="Output directory")
args = parser.parse_args()
output = args.output or DEFAULT_OUTPUT
if args.all:
converted = convert_all(output)
print(f"\nConverted {len(converted)} posts to {output}")
elif args.file:
filepath = Path(args.file)
if not filepath.exists():
print(f"File not found: {filepath}")
return 1
result = convert_post(filepath, output)
if result:
print(f"Converted: {result}")
else:
print("Post skipped (no phlog: true or is draft)")
else:
parser.print_help()
return 1
return 0
if __name__ == "__main__":
exit(main())
+236
View File
@@ -0,0 +1,236 @@
#!/usr/bin/env python3
"""
Generate gophermap files for blog categories and index.
Usage:
python scripts/gopher/generate_gophermaps.py
python scripts/gopher/generate_gophermaps.py --output gopher_build/blog/
"""
import argparse
import re
import sys
import yaml
from pathlib import Path
# Add script directory to path for imports
sys.path.insert(0, str(Path(__file__).parent))
from ascii_art import (
HEADER_BLOG_INDEX,
DIR_TO_HEADER,
DIR_TO_DESCRIPTION,
)
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
DEFAULT_OUTPUT = PROJECT_ROOT / "gopher_build" / "blog"
# Gophermap formatting
TAB = "\t"
FAKE_ENTRY = f"{TAB}fake{TAB}(NULL){TAB}0"
def info_line(text: str = "") -> str:
"""Generate an info (i) line for gophermap."""
return f"i{text}{FAKE_ENTRY}"
def file_link(label: str, path: str) -> str:
"""Generate a text file (0) link."""
return f"0{label}{TAB}{path}"
def dir_link(label: str, path: str) -> str:
"""Generate a directory (1) link."""
return f"1{label}{TAB}{path}"
def html_link(label: str, url: str) -> str:
"""Generate an HTML (h) link."""
return f"h{label}{TAB}URL:{url}"
def parse_frontmatter(filepath: Path) -> dict:
"""Parse YAML frontmatter from a markdown file."""
content = filepath.read_text()
if not content.startswith("---"):
return {}
end_match = re.search(r"\n---\n", content[3:])
if not end_match:
return {}
yaml_end = end_match.start() + 3
yaml_content = content[3:yaml_end]
try:
return yaml.safe_load(yaml_content) or {}
except yaml.YAMLError:
return {}
def get_posts_by_category(content_dir: Path) -> dict:
"""Get all phlog-enabled posts grouped by category."""
from ascii_art import SERIES_TO_DIR
categories = {}
for post_path in content_dir.glob("*.md"):
meta = parse_frontmatter(post_path)
# Skip if not phlog-enabled or is draft
if not meta.get("phlog", False) or meta.get("draft", False):
continue
series = meta.get("series", "Fun Center")
category = SERIES_TO_DIR.get(series, "fun-center")
if category not in categories:
categories[category] = []
# Extract date
date_obj = meta.get("date")
if hasattr(date_obj, "strftime"):
date_str = date_obj.strftime("%Y-%m-%d")
else:
date_str = str(date_obj)[:10] if date_obj else "1970-01-01"
categories[category].append({
"slug": post_path.stem,
"title": meta.get("title", post_path.stem),
"date": date_str,
"summary": meta.get("summary", ""),
})
# Sort each category by date (newest first)
for category in categories:
categories[category].sort(key=lambda x: x["date"], reverse=True)
return categories
def generate_category_gophermap(category: str, posts: list, output_dir: Path) -> Path:
"""Generate a gophermap for a category."""
header = DIR_TO_HEADER.get(category, "")
category_dir = output_dir / category
category_dir.mkdir(parents=True, exist_ok=True)
lines = []
# Add header art
for line in header.strip().split("\n"):
lines.append(info_line(line))
lines.append(info_line())
# Divider
lines.append(info_line("-" * 52))
lines.append(info_line())
# Posts
for post in posts:
date = post["date"]
title = post["title"]
slug = post["slug"]
summary = post.get("summary", "")
lines.append(file_link(f"[{date}] {title}", f"{slug}.txt"))
if summary:
lines.append(info_line(f" {summary[:48]}"))
lines.append(info_line())
# Footer divider and navigation
lines.append(info_line("-" * 52))
lines.append(dir_link("Back to Blog Index", "../"))
lines.append(dir_link("Back to Main Menu", "/users/mnw/"))
gophermap_path = category_dir / "gophermap"
gophermap_path.write_text("\n".join(lines))
return gophermap_path
def generate_blog_index(categories: dict, output_dir: Path) -> Path:
"""Generate the main blog index gophermap."""
lines = []
# Add header art
for line in HEADER_BLOG_INDEX.strip().split("\n"):
lines.append(info_line(line))
lines.append(info_line(" The Double Lunch Dispatch"))
lines.append(info_line())
# Divider
lines.append(info_line("-" * 48))
lines.append(info_line())
# Category listings
category_info = {
"franks-couch": ("Frank's Couch - Movie Reviews", "posts about films watched from the couch"),
"fun-center": ("Fun Center - Tech Posts", "posts about technology and open source"),
"beercalls": ("Beercalls - Thursday Night Adventures", "Yearly logs of Austin beer adventures"),
}
for category, (label, description) in category_info.items():
count = len(categories.get(category, []))
if count > 0:
lines.append(dir_link(label, f"{category}/"))
lines.append(info_line(f" {count} {description}"))
lines.append(info_line())
# Footer
lines.append(info_line("-" * 48))
lines.append(html_link("View on the web", "https://mnw.sdf.org/posts/"))
lines.append(dir_link("Back to Main Menu", "/users/mnw/"))
output_dir.mkdir(parents=True, exist_ok=True)
gophermap_path = output_dir / "gophermap"
gophermap_path.write_text("\n".join(lines))
return gophermap_path
def generate_all(output_dir: Path = None) -> dict:
"""Generate all gophermaps."""
output_dir = output_dir or DEFAULT_OUTPUT
# Get posts by category
categories = get_posts_by_category(CONTENT_DIR)
results = {
"categories": {},
"index": None,
}
# Generate category gophermaps
for category, posts in categories.items():
path = generate_category_gophermap(category, posts, output_dir)
results["categories"][category] = {
"path": path,
"count": len(posts),
}
print(f"Generated: {path.relative_to(output_dir)} ({len(posts)} posts)")
# Generate blog index
results["index"] = generate_blog_index(categories, output_dir)
print(f"Generated: {results['index'].relative_to(output_dir)}")
return results
def main():
parser = argparse.ArgumentParser(description="Generate gophermaps for blog")
parser.add_argument("--output", "-o", type=Path, help="Output directory")
args = parser.parse_args()
output = args.output or DEFAULT_OUTPUT
results = generate_all(output)
total_posts = sum(c["count"] for c in results["categories"].values())
print(f"\nGenerated gophermaps for {total_posts} posts in {len(results['categories'])} categories")
if __name__ == "__main__":
main()
+145
View File
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""
Update the root gophermap to include blog section.
This script generates a complete root gophermap with the new "FROM THE WEB"
section while preserving the existing structure (phlogs, conference notes, etc).
Usage:
python scripts/gopher/update_root_gophermap.py
python scripts/gopher/update_root_gophermap.py --output gopher_build/
"""
import argparse
from pathlib import Path
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent.parent
DEFAULT_OUTPUT = PROJECT_ROOT / "gopher_build"
# Gophermap formatting
TAB = "\t"
FAKE_ENTRY = f"{TAB}fake{TAB}(NULL){TAB}0"
def info_line(text: str = "") -> str:
"""Generate an info (i) line for gophermap."""
return f"i{text}{FAKE_ENTRY}"
def file_link(label: str, path: str) -> str:
"""Generate a text file (0) link."""
return f"0{label}{TAB}{path}"
def dir_link(label: str, path: str) -> str:
"""Generate a directory (1) link."""
return f"1{label}{TAB}{path}"
def echo_directive(command: str) -> str:
"""Generate a dynamic =echo directive."""
return f"=echo \"{command}\""
# Root gophermap template with blog section integrated
ROOT_GOPHERMAP_TEMPLATE = """\
i \tfake\t(NULL)\t0
i ''~`` \tfake\t(NULL)\t0
i ( o o ) \tfake\t(NULL)\t0
i+-------------------.oooO--(_)--Oooo.---------------+\tfake\t(NULL)\t0
i| |\tfake\t(NULL)\t0
i| THE DOUBLE LUNCH DISPATCH |\tfake\t(NULL)\t0
i| mnw @ sdf |\tfake\t(NULL)\t0
i| |\tfake\t(NULL)\t0
i+---------------------------------------------------+\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
imnw(at)sdf.org | SDF VOIP Ext. 1908 \tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i DAILY PHLOGS \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
1Daily Journal\tjournal/
=echo "0Latest Entry\tjournal/`ls -t journal/ | grep -v gophermap | head -1`"
1Historical Phlogs (2018-2019)\tolder/
i \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i FROM THE WEB \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
iPosts from mnw.sdf.org \tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
1Blog Categories\tblog/
=echo "0Latest Blog Post\t`find ~/gopher/blog -name '*.txt' -type f -printf '%T@ %p\\n' 2>/dev/null | sort -rn | head -1 | awk '{print $2}' | sed 's|.*/gopher/||'`"
i \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i CONFERENCE NOTES \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
iPhlogs from conferences (rough notes) \tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
1HOPE 2024\thope_2024/
1FOSSY 2024\tfossy_2024/
1LISA 2019\tLISA19/
1SeaGL 2019\tseagl_2019/
1Texas Linux Fest 2019\ttxlf_2019/
1HOPE 2018\thope_2018/
1SeaGL 2018\tseagl_2018/
i \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i OTHER THINGS \tfake\t(NULL)\t0
i===================================================\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
1Comedy\tcomedy/
1Short Stories\tstories/
i \tfake\t(NULL)\t0
i .oooO \tfake\t(NULL)\t0
i ( ) Oooo. \tfake\t(NULL)\t0
i+-------------------\\ (----( )-----------------+ \tfake\t(NULL)\t0
i \\_) ) / \tfake\t(NULL)\t0
i (_/ \tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
iMy SDF User Info \tfake\t(NULL)\t0
=echo "`/usr/pkg/bin/uinfo mnw | tr -d '\\-=><'`"
i \tfake\t(NULL)\t0
i __^__ __^__\tfake\t(NULL)\t0
i( ___ )--------------------------------------------( ___ )\tfake\t(NULL)\t0
i | / | This gopher space proudly hosted by SDF | \\ |\tfake\t(NULL)\t0
i | / | mnw on pixelfed.social and tilde.zone | \\ |\tfake\t(NULL)\t0
i |___| Web: mnw.sdf.org |___|\tfake\t(NULL)\t0
i(_____)--------------------------------------------(_____)\tfake\t(NULL)\t0
i \tfake\t(NULL)\t0
iThanks for reading! Enjoy an SDF oneliner: \tfake\t(NULL)\t0
=echo "`/usr/pkg/bin/oneliner | tr -d '\\-=><'`"
"""
def generate_root_gophermap(output_dir: Path = None) -> Path:
"""Generate the updated root gophermap."""
output_dir = output_dir or DEFAULT_OUTPUT
output_dir.mkdir(parents=True, exist_ok=True)
gophermap_path = output_dir / "gophermap"
gophermap_path.write_text(ROOT_GOPHERMAP_TEMPLATE)
return gophermap_path
def main():
parser = argparse.ArgumentParser(
description="Generate updated root gophermap with blog section"
)
parser.add_argument("--output", "-o", type=Path, help="Output directory")
args = parser.parse_args()
output = args.output or DEFAULT_OUTPUT
path = generate_root_gophermap(output)
print(f"Generated: {path}")
print("\nTo deploy, run:")
print(f" scp {path} mnw@sdf.org:~/gopher/gophermap")
if __name__ == "__main__":
main()
+483
View File
@@ -0,0 +1,483 @@
#!/usr/bin/env python3
"""
Import movies from Letterboxd diary to Hugo draft posts.
Usage:
python scripts/import_letterboxd.py # Interactive mode - pick from recent
python scripts/import_letterboxd.py --latest # Import most recent entry
python scripts/import_letterboxd.py --list # Just list recent entries
python scripts/import_letterboxd.py --theater # Skip to theater questions
python scripts/import_letterboxd.py --home # Skip to home video questions
The script will prompt for viewing details (theater vs home) and pre-fill
the front matter table accordingly.
"""
import argparse
import os
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse
import xml.etree.ElementTree as ET
import requests
# Configuration
LETTERBOXD_USER = "marcusEID"
try:
from config import TMDB_API_KEY
except ImportError:
raise SystemExit("Error: scripts/config.py not found. Copy config.example.py to config.py and add your API key.")
RSS_URL = f"https://letterboxd.com/{LETTERBOXD_USER}/rss/"
# Paths (relative to script location)
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
IMAGES_DIR = PROJECT_ROOT / "static" / "images" / "posters"
# XML namespaces in Letterboxd RSS
NAMESPACES = {
"letterboxd": "https://letterboxd.com",
"tmdb": "https://themoviedb.org",
"dc": "http://purl.org/dc/elements/1.1/",
}
def fetch_rss():
"""Fetch and parse Letterboxd RSS feed."""
resp = requests.get(RSS_URL, timeout=10)
resp.raise_for_status()
return ET.fromstring(resp.content)
def parse_movies(root):
"""Extract movie entries from RSS (skip lists)."""
movies = []
for item in root.findall(".//item"):
# Skip lists (they don't have tmdb:movieId)
tmdb_id = item.find("tmdb:movieId", NAMESPACES)
if tmdb_id is None:
continue
title = item.find("letterboxd:filmTitle", NAMESPACES)
year = item.find("letterboxd:filmYear", NAMESPACES)
rating = item.find("letterboxd:memberRating", NAMESPACES)
watched = item.find("letterboxd:watchedDate", NAMESPACES)
rewatch = item.find("letterboxd:rewatch", NAMESPACES)
link = item.find("link")
movies.append({
"tmdb_id": tmdb_id.text,
"title": title.text if title is not None else "Unknown",
"year": year.text if year is not None else "",
"rating": rating.text if rating is not None else "",
"watched_date": watched.text if watched is not None else "",
"rewatch": rewatch.text if rewatch is not None else "No",
"letterboxd_url": link.text if link is not None else "",
})
return movies
def get_tmdb_details(tmdb_id):
"""Fetch movie details from TMDB including IMDB ID and poster."""
url = f"https://api.themoviedb.org/3/movie/{tmdb_id}"
params = {"api_key": TMDB_API_KEY}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
return {
"imdb_id": data.get("imdb_id", ""),
"poster_path": data.get("poster_path", ""),
"overview": data.get("overview", ""),
}
def download_poster(poster_path, filename):
"""Download poster from TMDB to static/images/posters/."""
if not poster_path:
print(" No poster available")
return None
# Use w500 size for good quality without being huge
url = f"https://image.tmdb.org/t/p/w500{poster_path}"
resp = requests.get(url, timeout=10)
resp.raise_for_status()
IMAGES_DIR.mkdir(parents=True, exist_ok=True)
filepath = IMAGES_DIR / filename
filepath.write_bytes(resp.content)
print(f" Poster saved: {filepath.relative_to(PROJECT_ROOT)}")
return f"/images/posters/{filename}"
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def rating_to_stars(rating):
"""Convert numeric rating to star display."""
if not rating:
return ""
r = float(rating)
full = int(r)
half = r - full >= 0.5
stars = "*" * full
if half:
stars += " 1/2"
return f"{stars} ({rating})"
def prompt_viewing_details():
"""Prompt user for viewing location details."""
print("\nWhere did you watch this?")
print(" 1. Theater")
print(" 2. Home")
while True:
choice = input("Enter 1 or 2: ").strip()
if choice == "1":
return prompt_theater_details()
elif choice == "2":
return prompt_home_details()
else:
print("Please enter 1 or 2")
def prompt_theater_details():
"""Prompt for theater-specific details."""
print("\nWhich theater?")
theaters = [
("1", "Gucci", "gucci"),
("2", "Ghost Theater", "ghost-theater"),
("3", "Marcel", "marcel"),
("4", "AMC South", "amc-south"),
("5", "AMC Lakeline", "amc-lakeline"),
("6", "Other", None),
]
for num, name, _ in theaters:
print(f" {num}. {name}")
theater_name = ""
theater_tag = None
while True:
choice = input("Enter number: ").strip()
for num, name, tag in theaters:
if choice == num:
if name == "Other":
theater_name = input("Theater name: ").strip()
else:
theater_name = name
theater_tag = tag
break
if theater_name:
break
print("Please enter a valid number")
show_time = input("Show time (e.g. 7:30pm): ").strip()
theater_num = input("Theater number: ").strip()
pizza = input("Pizza? (Yes/No): ").strip() or ""
tickets = input("Tickets (e.g. 'At Box Office', 'A-List'): ").strip()
crew = input("Crew (e.g. 'Me, Coach T, Science Bro'): ").strip()
return {
"type": "theater",
"theater": theater_name,
"theater_tag": theater_tag,
"show_time": show_time,
"theater_num": theater_num,
"pizza": pizza,
"tickets": tickets,
"crew": crew,
}
def prompt_home_details():
"""Prompt for home viewing details."""
location = input("Location (e.g. 'Living Room', 'Woodrow Apt'): ").strip() or "Home"
show_time = input("Show time (optional, e.g. 'evening'): ").strip()
pizza = input("Pizza? (Yes/No): ").strip() or "No"
# Media format
print("\nMedia format?")
media_options = [
("1", "Online"),
("2", "BluRay"),
("3", "DVD"),
("4", "VHS"),
]
for num, name in media_options:
print(f" {num}. {name}")
media = "Online"
media_choice = input("Enter number (default 1): ").strip()
for num, name in media_options:
if media_choice == num:
media = name
break
# Screen type
print("\nScreen?")
screen_options = [
("1", "4k TV"),
("2", "4k Computer"),
("3", "1080p Computer"),
("4", "Cell Phone"),
("5", "Someone Elses TV"),
]
for num, name in screen_options:
print(f" {num}. {name}")
screen = "4k TV"
screen_choice = input("Enter number (default 1): ").strip()
for num, name in screen_options:
if screen_choice == num:
screen = name
break
return {
"type": "home",
"theater": "Home Video",
"theater_tag": "homevideo",
"show_time": show_time,
"theater_num": location,
"pizza": pizza,
"media": media,
"screen": screen,
}
def create_draft_post(movie, tmdb_details, poster_url, viewing_details=None, phlog=False):
"""Create a Hugo draft post for the movie."""
slug = slugify(movie["title"])
filename = f"{slug}.md"
filepath = CONTENT_DIR / filename
if filepath.exists():
print(f" Post already exists: {filepath.relative_to(PROJECT_ROOT)}")
return None
# Format the date for Hugo
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# Format watched date nicely
watched = movie["watched_date"]
if watched:
try:
dt = datetime.strptime(watched, "%Y-%m-%d")
watched_display = dt.strftime("%B %d, %Y")
except ValueError:
watched_display = watched
else:
watched_display = ""
imdb_id = tmdb_details.get("imdb_id", "")
rating_display = rating_to_stars(movie["rating"])
# Use viewing details if provided, otherwise use empty defaults
if viewing_details:
show_time = viewing_details.get("show_time", "")
theater = viewing_details.get("theater", "")
theater_num = viewing_details.get("theater_num", "")
pizza = viewing_details.get("pizza", "")
is_home = viewing_details.get("type") == "home"
# Build tags based on viewing type
tags = []
if viewing_details.get("theater_tag"):
tags.append(viewing_details["theater_tag"])
tags.extend(["no-expectations"])
if pizza.lower() == "yes":
tags.append("had pizza")
tags_yaml = "\n".join(f" - {tag}" for tag in tags)
# Different last two rows for home vs theater
if is_home:
row5_label = "Media"
row5_value = viewing_details.get("media", "")
row7_label = "Screen"
row7_value = viewing_details.get("screen", "")
else:
row5_label = "Tickets"
row5_value = viewing_details.get("tickets", "")
row7_label = "Crew"
row7_value = viewing_details.get("crew", "")
else:
show_time = ""
theater = ""
theater_num = ""
pizza = ""
row5_label = "Tickets"
row5_value = ""
row7_label = "Crew"
row7_value = ""
tags_yaml = """ - gucci
- ghost-theater
- marcel
- amc-south
- amc-lakeline
- anticipated
- no-expectations
- had pizza"""
# Build the frontmatter and content
phlog_str = "true" if phlog else "false"
content = f'''---
title: '{movie["title"]}'
date: {now}
draft: true
series: "Frank's Couch"
summary: ""
phlog: {phlog_str}
imdb: "{imdb_id}"
poster: "{poster_url or ''}"
tags:
{tags_yaml}
# Mastodon comments: After posting about this on Mastodon, add the post ID below.
# Get the ID from the end of the toot URL, e.g. https://tilde.zone/@mnw/123456789
# mastodon_id: ""
# To block a reply from showing, add its full URL to this list:
# mastodon_blocked:
# - "https://tilde.zone/@someone/123456789"
---
{{{{< imdbposter >}}}}
| Date watched | {watched_display:<17} |
|---------------------|-------------------|
| Show Time | {show_time:<17} |
| Theater | {theater:<17} |
| Theater Number | {theater_num:<17} |
| Pizza | {pizza:<17} |
| {row5_label:<19} | {row5_value:<17} |
| Letterboxd Rating | {rating_display:<17} |
| {row7_label:<19} | {row7_value:<17} |
{{{{< /imdbposter >}}}}
Write your review here...
'''
filepath.write_text(content)
print(f" Draft created: {filepath.relative_to(PROJECT_ROOT)}")
return filepath
def display_movies(movies, limit=10):
"""Display a list of recent movies."""
print(f"\nRecent movies from Letterboxd ({LETTERBOXD_USER}):\n")
for i, m in enumerate(movies[:limit], 1):
rewatch = " (rewatch)" if m["rewatch"] == "Yes" else ""
rating = f" - {m['rating']}*" if m["rating"] else ""
print(f" {i}. {m['title']} ({m['year']}){rating}{rewatch}")
print(f" Watched: {m['watched_date']}")
print()
def import_movie(movie, viewing_mode=None):
"""Import a single movie: fetch details, download poster, create post.
Args:
movie: Movie data from Letterboxd RSS
viewing_mode: 'theater', 'home', or None (will prompt)
"""
print(f"\nImporting: {movie['title']} ({movie['year']})")
# Get viewing details
if viewing_mode == "theater":
viewing_details = prompt_theater_details()
elif viewing_mode == "home":
viewing_details = prompt_home_details()
else:
viewing_details = prompt_viewing_details()
# Ask about gopher phlog
phlog_input = input("\nPublish to gopher phlog? (y/N): ").strip().lower()
phlog = phlog_input == "y"
# Get TMDB details
print("\n Fetching TMDB details...")
tmdb = get_tmdb_details(movie["tmdb_id"])
# Download poster
poster_url = None
if tmdb["poster_path"]:
print(" Downloading poster...")
poster_filename = f"{slugify(movie['title'])}.jpg"
poster_url = download_poster(tmdb["poster_path"], poster_filename)
# Create draft post
print(" Creating draft post...")
filepath = create_draft_post(movie, tmdb, poster_url, viewing_details, phlog)
if filepath:
print(f"\nDone! Edit your draft at: {filepath.relative_to(PROJECT_ROOT)}")
if tmdb.get("imdb_id"):
print(f"IMDB: https://www.imdb.com/title/{tmdb['imdb_id']}/")
return filepath
def main():
parser = argparse.ArgumentParser(description="Import Letterboxd movies to Hugo")
parser.add_argument("--latest", action="store_true", help="Import most recent entry")
parser.add_argument("--list", action="store_true", help="Just list recent entries")
parser.add_argument("--count", type=int, default=10, help="Number of entries to show")
parser.add_argument("--theater", action="store_true", help="Skip viewing prompt, go straight to theater questions")
parser.add_argument("--home", action="store_true", help="Skip viewing prompt, go straight to home questions")
args = parser.parse_args()
# Determine viewing mode from flags
viewing_mode = None
if args.theater:
viewing_mode = "theater"
elif args.home:
viewing_mode = "home"
print("Fetching Letterboxd RSS feed...")
try:
root = fetch_rss()
except Exception as e:
print(f"Error fetching RSS: {e}")
sys.exit(1)
movies = parse_movies(root)
if not movies:
print("No movies found in feed.")
sys.exit(1)
if args.list:
display_movies(movies, args.count)
sys.exit(0)
if args.latest:
import_movie(movies[0], viewing_mode)
sys.exit(0)
# Interactive mode
display_movies(movies, args.count)
try:
choice = input("Enter number to import (or 'q' to quit): ").strip()
if choice.lower() == 'q':
sys.exit(0)
idx = int(choice) - 1
if 0 <= idx < len(movies):
import_movie(movies[idx], viewing_mode)
else:
print("Invalid selection")
sys.exit(1)
except (ValueError, KeyboardInterrupt):
print("\nCancelled")
sys.exit(1)
if __name__ == "__main__":
main()
+347
View File
@@ -0,0 +1,347 @@
#!/usr/bin/env python3
"""
Add a new Beer Call entry to the yearly log.
Usage:
python scripts/new_beercall.py # Interactive, defaults to last Thursday
python scripts/new_beercall.py --date 2024-12-19 # Specific date
python scripts/new_beercall.py --list # Just show recent Untappd checkins
Fetches recent checkins from Untappd RSS to help identify venue.
Beer calls are typically on Thursdays, except for special events like
Beer Crawl (around New Year's) or when holidays fall on Thursday.
"""
import argparse
import json
import re
import sys
import xml.etree.ElementTree as ET
from datetime import datetime, timedelta
from pathlib import Path
import requests
# Configuration
UNTAPPD_RSS = "https://untappd.com/rss/user/Craniumslows?key=e8110a1087c289fdb992448e75adf35c"
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
BEERCALL_DIR = PROJECT_ROOT / "content" / "posts" / "beercall"
VENUES_FILE = SCRIPT_DIR / "venues.json"
def load_venues():
"""Load venue database from JSON file."""
if VENUES_FILE.exists():
with open(VENUES_FILE) as f:
return json.load(f)
return {}
def save_venues(venues):
"""Save updated venue database."""
with open(VENUES_FILE, "w") as f:
json.dump(venues, f, indent=2)
def fetch_untappd_rss():
"""Fetch and parse Untappd RSS feed."""
try:
resp = requests.get(UNTAPPD_RSS, timeout=10)
resp.raise_for_status()
return ET.fromstring(resp.content)
except Exception as e:
print(f"Warning: Could not fetch Untappd RSS: {e}")
return None
def parse_checkins(root):
"""Extract checkin data from RSS."""
checkins = []
if root is None:
return checkins
for item in root.findall(".//item"):
title = item.find("title")
pub_date = item.find("pubDate")
description = item.find("description")
if title is not None and pub_date is not None:
# Parse title: "Cranium S. is drinking a Beer by Brewery at Venue"
title_text = title.text or ""
# Extract venue (after " at ")
venue_match = re.search(r" at (.+)$", title_text)
venue = venue_match.group(1) if venue_match else ""
# Extract beer and brewery
beer_match = re.search(r"is drinking an? (.+) by (.+?) at", title_text)
if beer_match:
beer = beer_match.group(1)
brewery = beer_match.group(2)
else:
beer = ""
brewery = ""
# Parse date
try:
dt = datetime.strptime(pub_date.text, "%a, %d %b %Y %H:%M:%S %z")
except ValueError:
continue
checkins.append({
"date": dt,
"venue": venue,
"beer": beer,
"brewery": brewery,
"notes": description.text if description is not None else "",
})
return checkins
def get_last_thursday():
"""Get the date of the most recent Thursday (including today if Thursday)."""
today = datetime.now()
days_since_thursday = (today.weekday() - 3) % 7
if days_since_thursday == 0 and today.hour < 12:
# If it's Thursday morning, probably mean last Thursday
days_since_thursday = 7
return today - timedelta(days=days_since_thursday)
def find_venue_by_name(venues, name):
"""Try to match a venue name to our database."""
name_lower = name.lower()
for key, venue in venues.items():
if name_lower == venue["name"].lower():
return key, venue
for alias in venue.get("aliases", []):
if name_lower == alias.lower() or alias.lower() in name_lower:
return key, venue
return None, None
def display_venues(venues):
"""Display numbered list of venues."""
print("\nKnown venues:")
sorted_venues = sorted(venues.items(), key=lambda x: x[1]["name"])
for i, (key, venue) in enumerate(sorted_venues, 1):
print(f" {i:2}. {venue['name']}")
return sorted_venues
def get_or_create_year_file(year):
"""Get the path to the year's beer call log, creating if needed."""
BEERCALL_DIR.mkdir(parents=True, exist_ok=True)
filepath = BEERCALL_DIR / f"{year}.md"
if not filepath.exists():
# Create new year file with frontmatter
content = f"""+++
title = 'Beer Call Log for {year}'
date = {datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ')}
draft = false
summary = 'A listing of the beer calls that I have remembered to write down in {year}'
series = "Luna Juice"
+++
"""
filepath.write_text(content)
print(f"Created new log file: {filepath.relative_to(PROJECT_ROOT)}")
return filepath
def format_date_header(date):
"""Format date for the entry header."""
return date.strftime("%B %-d, %Y") # e.g., "December 19, 2024"
def add_entry(filepath, venue_name, address, beerlist, date, attendees, notes):
"""Add a new beer call entry to the log file."""
# Read current content
content = filepath.read_text()
# Find where to insert (after frontmatter, before first entry or at end)
# We want newest entries at the top
lines = content.split("\n")
# Find end of frontmatter
frontmatter_end = 0
in_frontmatter = False
for i, line in enumerate(lines):
if line.strip() == "+++":
if in_frontmatter:
frontmatter_end = i + 1
break
else:
in_frontmatter = True
# Build the new entry
date_str = format_date_header(date)
entry = f"""
# {venue_name} - {date_str}
| | |
| :------------------- | :---------------- |
| Location | {address} |
| Beerlist | {beerlist} |
| Attendees | {attendees} |
| Notes | {notes} |
"""
# Insert after frontmatter (and any blank lines)
insert_pos = frontmatter_end
while insert_pos < len(lines) and lines[insert_pos].strip() == "":
insert_pos += 1
# Insert the new entry
new_lines = lines[:insert_pos] + entry.split("\n") + lines[insert_pos:]
filepath.write_text("\n".join(new_lines))
return True
def main():
parser = argparse.ArgumentParser(description="Add a new Beer Call entry")
parser.add_argument("--date", help="Date of beer call (YYYY-MM-DD), default is last Thursday")
parser.add_argument("--list", action="store_true", help="Just list recent Untappd checkins")
args = parser.parse_args()
# Load venues
venues = load_venues()
# Determine target date
if args.date:
try:
target_date = datetime.strptime(args.date, "%Y-%m-%d")
except ValueError:
print("Invalid date format. Use YYYY-MM-DD")
sys.exit(1)
else:
target_date = get_last_thursday()
print(f"Beer Call date: {target_date.strftime('%A, %B %-d, %Y')}")
# Fetch Untappd checkins
print("\nFetching Untappd checkins...")
root = fetch_untappd_rss()
checkins = parse_checkins(root)
# Filter to target date
target_date_str = target_date.strftime("%Y-%m-%d")
day_checkins = [c for c in checkins if c["date"].strftime("%Y-%m-%d") == target_date_str]
if args.list:
print(f"\nRecent Untappd checkins:")
for c in checkins[:15]:
print(f" {c['date'].strftime('%Y-%m-%d %H:%M')} - {c['beer']} at {c['venue']}")
sys.exit(0)
# Show checkins for the target date
if day_checkins:
print(f"\nUntappd checkins on {target_date_str}:")
venues_seen = set()
for c in day_checkins:
if c["venue"] not in venues_seen:
print(f" - {c['venue']}: {c['beer']} by {c['brewery']}")
venues_seen.add(c["venue"])
# Try to suggest a venue
suggested_venue = None
for c in day_checkins:
key, venue = find_venue_by_name(venues, c["venue"])
if venue:
suggested_venue = (key, venue, c["venue"])
break
else:
print(f"\nNo Untappd checkins found for {target_date_str}")
suggested_venue = None
# Venue selection
print("\n" + "=" * 50)
if suggested_venue:
key, venue, untappd_name = suggested_venue
print(f"Suggested venue from Untappd: {venue['name']}")
use_suggested = input("Use this venue? (Y/n): ").strip().lower()
if use_suggested != "n":
selected_venue = venue
selected_key = key
else:
selected_venue = None
else:
selected_venue = None
if not selected_venue:
sorted_venues = display_venues(venues)
print(f" {len(sorted_venues) + 1}. [New venue]")
print(f" {len(sorted_venues) + 2}. [Skip/Out of Town]")
choice = input("\nSelect venue number: ").strip()
try:
idx = int(choice) - 1
if idx == len(sorted_venues):
# New venue
venue_name = input("Venue name: ").strip()
address = input("Address: ").strip()
beerlist = input("Beer list URL: ").strip()
# Add to database
key = venue_name.lower().replace(" ", "-").replace("'", "")
venues[key] = {
"name": venue_name,
"aliases": [venue_name],
"address": address,
"beerlist": beerlist,
}
save_venues(venues)
print(f"Added {venue_name} to venue database!")
selected_venue = venues[key]
selected_key = key
elif idx == len(sorted_venues) + 1:
# Out of town / skip
venue_name = input("Title (e.g., 'Out of Town', 'Holiday'): ").strip() or "Out of Town"
notes = input("Notes: ").strip()
filepath = get_or_create_year_file(target_date.year)
add_entry(filepath, venue_name, "NA", "NA", target_date, "DNR", notes)
print(f"\nEntry added to {filepath.relative_to(PROJECT_ROOT)}")
sys.exit(0)
elif 0 <= idx < len(sorted_venues):
selected_key, selected_venue = sorted_venues[idx]
else:
print("Invalid selection")
sys.exit(1)
except ValueError:
print("Invalid selection")
sys.exit(1)
# Collect attendees and notes
print(f"\nVenue: {selected_venue['name']}")
print(f"Address: {selected_venue['address']}")
print(f"Beerlist: {selected_venue['beerlist']}")
attendees = input("\nAttendees (comma-separated, or 'DNR'): ").strip() or "DNR"
notes = input("Notes: ").strip()
# Add to year file
filepath = get_or_create_year_file(target_date.year)
add_entry(
filepath,
selected_venue["name"],
selected_venue["address"],
selected_venue["beerlist"],
target_date,
attendees,
notes,
)
print(f"\nEntry added to {filepath.relative_to(PROJECT_ROOT)}")
print("Done!")
if __name__ == "__main__":
main()
+89
View File
@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Create a new standalone Luna Juice post (festivals, events, special occasions).
Usage:
python scripts/new_lunajuice.py # Interactive
python scripts/new_lunajuice.py "Beer Festival 2025" # With title
For regular weekly beer calls, use new_beercall.py instead.
This script is for special events that deserve their own post.
"""
import argparse
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts" / "beercall"
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def create_post(title, summary=""):
"""Create a new Luna Juice post."""
CONTENT_DIR.mkdir(parents=True, exist_ok=True)
slug = slugify(title)
filename = f"{slug}.md"
filepath = CONTENT_DIR / filename
if filepath.exists():
print(f"Post already exists: {filepath.relative_to(PROJECT_ROOT)}")
overwrite = input("Overwrite? (y/N): ").strip().lower()
if overwrite != "y":
return None
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
content = f"""+++
title = '{title}'
date = {now}
draft = true
summary = '{summary}'
series = "Luna Juice"
+++
Write about your beer adventure here...
"""
filepath.write_text(content)
return filepath
def main():
parser = argparse.ArgumentParser(description="Create a new Luna Juice event post")
parser.add_argument("title", nargs="?", help="Post title")
args = parser.parse_args()
if args.title:
title = args.title
else:
title = input("Event title: ").strip()
if not title:
print("Title is required")
sys.exit(1)
summary = input("Summary (one line): ").strip()
filepath = create_post(title, summary)
if filepath:
print(f"\nCreated: {filepath.relative_to(PROJECT_ROOT)}")
print("Edit the file to add your content!")
if __name__ == "__main__":
main()
+238
View File
@@ -0,0 +1,238 @@
#!/usr/bin/env python3
"""
Create a new movie post from an IMDB ID.
Usage:
python scripts/new_movie.py tt1234567
python scripts/new_movie.py tt1234567 --title "Custom Title"
python scripts/new_movie.py https://www.imdb.com/title/tt1234567/
This fetches all metadata (title, year, runtime, director, poster) and creates
a ready-to-edit draft post.
"""
import argparse
import re
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
import requests
# Configuration
try:
from config import TMDB_API_KEY
except ImportError:
raise SystemExit("Error: scripts/config.py not found. Copy config.example.py to config.py and add your API key.")
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
IMAGES_DIR = PROJECT_ROOT / "static" / "images" / "posters"
def extract_imdb_id(input_str):
"""Extract IMDB ID from URL or raw ID."""
match = re.search(r'(tt\d+)', input_str)
if match:
return match.group(1)
return None
def find_movie_by_imdb(imdb_id):
"""Find TMDB movie by IMDB ID."""
url = f"https://api.themoviedb.org/3/find/{imdb_id}"
params = {
"api_key": TMDB_API_KEY,
"external_source": "imdb_id"
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
results = data.get("movie_results", [])
if results:
return results[0]
return None
def get_movie_details(tmdb_id):
"""Get full movie details from TMDB."""
url = f"https://api.themoviedb.org/3/movie/{tmdb_id}"
params = {
"api_key": TMDB_API_KEY,
"append_to_response": "credits"
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
return resp.json()
def get_directors(credits):
"""Extract director names from credits."""
crew = credits.get("crew", [])
directors = [p["name"] for p in crew if p.get("job") == "Director"]
return directors
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def download_poster(poster_path, filename):
"""Download and save poster. Returns local path."""
if not poster_path:
return ""
# w500 = 500px wide, good for 200px display on retina
url = f"https://image.tmdb.org/t/p/w500{poster_path}"
resp = requests.get(url, timeout=10)
resp.raise_for_status()
IMAGES_DIR.mkdir(parents=True, exist_ok=True)
filepath = IMAGES_DIR / filename
filepath.write_bytes(resp.content)
return f"/images/posters/{filename}"
def create_post(imdb_id, details, poster_path, custom_title=None, phlog=False):
"""Create the Hugo post with all metadata."""
title = custom_title or details.get("title", "Untitled")
slug = slugify(title)
filename = f"{slug}.md"
filepath = CONTENT_DIR / filename
if filepath.exists():
print(f"Post already exists: {filepath}")
return None
# Download poster
poster_url = ""
if details.get("poster_path"):
poster_filename = f"{slug}.jpg"
print(f"Downloading poster...")
poster_url = download_poster(details["poster_path"], poster_filename)
# Extract metadata
release_date = details.get("release_date", "")
year = int(release_date.split("-")[0]) if release_date else ""
runtime = details.get("runtime", "")
credits = details.get("credits", {})
directors = get_directors(credits)
director_str = directors[0] if len(directors) == 1 else directors if directors else ""
genres = [g["name"] for g in details.get("genres", [])]
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# Build frontmatter
# Using manual formatting to control output
genres_yaml = "\n".join(f" - {g}" for g in genres) if genres else "[]"
if isinstance(director_str, list):
director_yaml = "\n".join(f" - {d}" for d in director_str)
director_yaml = f"\n{director_yaml}"
else:
director_yaml = f' "{director_str}"' if director_str else ' ""'
phlog_str = "true" if phlog else "false"
content = f'''---
title: '{title}'
date: {now}
draft: true
series: "Frank's Couch"
summary: ""
phlog: {phlog_str}
imdb: "{imdb_id}"
poster: "{poster_url}"
year: {year}
runtime: {runtime}
director:{director_yaml}
genres:
{genres_yaml}
tags:
- gucci
- ghost theater
- marcel
- amc-south
- amc-lakeline
- anticipated
- no-expectations
- had pizza
---
{{{{< imdbposter >}}}}
| Date watched | |
|---------------------|-------------------|
| Show Time | |
| Theater | |
| Theater Number | |
| Pizza | |
| Tickets | |
| Letterboxd Rating | |
| Crew | |
{{{{< /imdbposter >}}}}
Write your review here...
'''
filepath.write_text(content)
return filepath
def main():
parser = argparse.ArgumentParser(
description="Create a new movie post from IMDB ID",
epilog="Example: python scripts/new_movie.py tt1234567"
)
parser.add_argument("imdb", help="IMDB ID or URL (e.g., tt1234567)")
parser.add_argument("--title", help="Custom title (default: from TMDB)")
args = parser.parse_args()
# Extract IMDB ID
imdb_id = extract_imdb_id(args.imdb)
if not imdb_id:
print(f"Invalid IMDB ID: {args.imdb}")
print("Expected format: tt1234567 or https://www.imdb.com/title/tt1234567/")
sys.exit(1)
print(f"Looking up {imdb_id}...")
# Find on TMDB
movie = find_movie_by_imdb(imdb_id)
if not movie:
print(f"Movie not found for IMDB ID: {imdb_id}")
sys.exit(1)
tmdb_id = movie["id"]
print(f"Found: {movie.get('title')} ({movie.get('release_date', '')[:4]})")
# Get full details
print("Fetching details...")
details = get_movie_details(tmdb_id)
# Ask about gopher phlog
phlog_input = input("\nPublish to gopher phlog? (y/N): ").strip().lower()
phlog = phlog_input == "y"
# Create post
filepath = create_post(imdb_id, details, details.get("poster_path"), args.title, phlog)
if filepath:
print(f"\nCreated: {filepath.relative_to(PROJECT_ROOT)}")
print(f"IMDB: https://www.imdb.com/title/{imdb_id}/")
print(f"\nEdit your post, then run: ./scripts/build.sh")
if __name__ == "__main__":
main()
+438
View File
@@ -0,0 +1,438 @@
#!/usr/bin/env python3
"""
Create a new post for National Film Registry movies in the "Found in the Darkroom" series.
Usage:
python scripts/new_nfr.py tt1234567 # From IMDB ID
python scripts/new_nfr.py "Movie Title" # From title (searches TMDB)
python scripts/new_nfr.py --list-2024 # Show 2024 NFR list
python scripts/new_nfr.py --nfr-year 2024 # Set NFR induction year
The script will:
1. Fetch movie data from TMDB (poster, year, director, runtime, genres)
2. Download the poster
3. Create a draft post using the darkroom archetype
4. Pre-fill metadata including NFR year
"""
import argparse
import os
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
import requests
# Configuration
try:
from config import TMDB_API_KEY
except ImportError:
raise SystemExit("Error: scripts/config.py not found. Copy config.example.py to config.py and add your API key.")
# Paths (relative to script location)
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
IMAGES_DIR = PROJECT_ROOT / "static" / "images" / "posters"
# 2024 National Film Registry inductees with LOC descriptions
# Source: https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/
NFR_2024 = {
"Annabelle Serpentine Dance": {
"year": 1895,
"description": 'Preserved as a foundational cinema work that "enticed and enchanted audiences" during film\'s infancy, demonstrating early technical innovations like hand-tinted color.'
},
"Koko's Earth Control": {
"year": 1928,
"description": "Selected for representing the Fleischer Studios' competitive animation style against Disney, featuring innovative techniques like rotoscoping that advanced the medium."
},
"Angels with Dirty Faces": {
"year": 1938,
"description": 'Recognized for depicting "Depression-era immigrant, segregated, hardscrabble neighborhoods" while navigating Production Code restrictions through redemptive storytelling.'
},
"The Pride of the Yankees": {
"year": 1942,
"description": "Honored as one of cinema's seminal sports films, featuring authentic appearances by former Yankees teammates and Lou Gehrig's iconic farewell speech recreation."
},
"Invaders from Mars": {
"year": 1953,
"description": 'Selected for establishing "the visual language of science fiction cinema" and influencing subsequent sci-fi works through post-war paranoia themes.'
},
"The Miracle Worker": {
"year": 1962,
"description": 'Preserved for Arthur Penn\'s "stark black and white" presentation of Helen Keller\'s story, told with minimal sentimentality to highlight human potential.'
},
"The Chelsea Girls": {
"year": 1966,
"description": 'Recognized as a Warhol experimental work that challenged narrative form through dual-projection and "infinite audience interpretations."'
},
"Ganja and Hess": {
"year": 1973,
"description": 'Honored for addressing "complexities of addiction, sexuality and Black identity" through Bill Gunn\'s visionary filmmaking that remained underrecognized.'
},
"The Texas Chain Saw Massacre": {
"year": 1974,
"description": 'Selected for establishing "tenets of the gore/slasher/splatter genre" despite initial controversy, becoming a "cultural and filmmaking touchstone."'
},
"Uptown Saturday Night": {
"year": 1974,
"description": 'Preserved as Sidney Poitier\'s directorial effort "dispelling stereotypes" of the Blaxploitation era through an entertaining crime comedy ensemble cast.'
},
"Zora Lathan Student Films": {
"year": 1975,
"description": "Six short films recognized for showcasing filmmaking techniques and design problem-solving approaches, documenting intimate domestic moments from early 1980s perspectives."
},
"Up in Smoke": {
"year": 1978,
"description": 'Selected for arguably establishing the "stoner" film genre and paving "the way for subsequent memorable movie characters" through comic improvisation.'
},
"Will": {
"year": 1981,
"description": 'Honored as "the first independent feature-length film directed by a Black woman," documenting early 1980s Harlem while addressing addiction and resilience themes.'
},
"Star Trek: The Wrath of Khan": {
"year": 1982,
"description": 'Preserved as "often considered the best of the six original-cast Star Trek theatrical films," featuring expert direction and exploration of sacrifice.'
},
"Beverly Hills Cop": {
"year": 1984,
"description": 'Recognized as "Eddie Murphy\'s first feature film on the registry" and establishing his "box-office superstar" status through this buddy-cop action-comedy.'
},
"Dirty Dancing": {
"year": 1987,
"description": 'Selected for remaining "influential and imitated" despite addressing serious themes including pregnancy, abortion, and breaking class barriers through dance.'
},
"Common Threads: Stories from the Quilt": {
"year": 1989,
"description": 'Honored as an Oscar-winning documentary serving as "a monument to the power of grief and activism" chronicling the AIDS Memorial Quilt\'s creation.'
},
"Powwow Highway": {
"year": 1989,
"description": 'Preserved as "one of the first" films treating "Native Americans as ordinary people," departing from Hollywood stereotypes through a witty buddy road narrative.'
},
"My Own Private Idaho": {
"year": 1991,
"description": 'Recognized for Gus Van Sant\'s "magnificently original cult classic" reimagining Shakespeare through street hustlers\' journeys with "dream-like vision and hardcore reality."'
},
"American Me": {
"year": 1992,
"description": 'Selected for Edward James Olmos\'s directorial debut depicting "dark, brutal realities of Chicano gang life" addressing prison drug trafficking with unflinching honesty.'
},
"Mi Familia": {
"year": 1995,
"description": 'Preserved as Gregory Nava\'s "emotional and evocative" multi-generational Mexican-American family story celebrating immigration\'s role in American vitality.'
},
"Compensation": {
"year": 1999,
"description": 'Honored for director Zeinabu irene Davis\'s innovative accessibility approach incorporating "American Sign Language and title cards" for deaf and hearing audiences.'
},
"Spy Kids": {
"year": 2001,
"description": 'Selected for Robert Rodriguez\'s incorporation of "Hispanic culture" through family-centered storytelling emphasizing "familial bonds and cultural heritage" authenticity.'
},
"No Country for Old Men": {
"year": 2007,
"description": 'Preserved as a Coen Brothers modern-day Western adaptation "hailed as a classic nearly from the moment of release," winning Best Picture Oscar recognition.'
},
"The Social Network": {
"year": 2010,
"description": 'Recognized for transforming a potentially "dry, geeky" corporate narrative into "a riveting examination" of modern business ethics and technology\'s societal impact.'
},
}
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def search_tmdb_by_title(title, year=None):
"""Search TMDB for a movie by title and optionally year."""
url = "https://api.themoviedb.org/3/search/movie"
params = {
"api_key": TMDB_API_KEY,
"query": title,
}
if year:
params["year"] = year
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
if not data.get("results"):
return None
# Return the first result
return data["results"][0]
def get_tmdb_details(tmdb_id):
"""Fetch movie details from TMDB."""
url = f"https://api.themoviedb.org/3/movie/{tmdb_id}"
params = {"api_key": TMDB_API_KEY}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
return resp.json()
def get_imdb_id_from_tmdb(tmdb_id):
"""Get IMDB ID from TMDB ID."""
data = get_tmdb_details(tmdb_id)
return data.get("imdb_id", "")
def get_tmdb_id_from_imdb(imdb_id):
"""Convert IMDB ID to TMDB ID."""
url = f"https://api.themoviedb.org/3/find/{imdb_id}"
params = {
"api_key": TMDB_API_KEY,
"external_source": "imdb_id",
}
resp = requests.get(url, params=params, timeout=10)
resp.raise_for_status()
data = resp.json()
results = data.get("movie_results", [])
if not results:
raise ValueError(f"No TMDB match found for IMDB ID: {imdb_id}")
return results[0]["id"]
def download_poster(poster_path, filename):
"""Download poster from TMDB to static/images/posters/."""
if not poster_path:
print(" No poster available")
return None
# Use w500 size for good quality without being huge
url = f"https://image.tmdb.org/t/p/w500{poster_path}"
resp = requests.get(url, timeout=10)
resp.raise_for_status()
IMAGES_DIR.mkdir(parents=True, exist_ok=True)
filepath = IMAGES_DIR / filename
filepath.write_bytes(resp.content)
print(f" Poster saved: {filepath.relative_to(PROJECT_ROOT)}")
return f"/images/posters/{filename}"
def extract_imdb_id(input_str):
"""Extract IMDB ID from string (handles raw ID or URL)."""
# Check if it's already just an ID
if re.match(r'^tt\d+$', input_str):
return input_str
# Try to extract from URL
match = re.search(r'(tt\d+)', input_str)
if match:
return match.group(1)
return None
def format_director(directors):
"""Format director(s) for YAML frontmatter."""
if not directors:
return '""'
if len(directors) == 1:
return f'"{directors[0]}"'
# Multiple directors - use YAML list format
return "[" + ", ".join(f'"{d}"' for d in directors) + "]"
def create_nfr_post(tmdb_data, imdb_id, nfr_year=2024):
"""Create a draft post for an NFR movie."""
title = tmdb_data.get("title", "Unknown")
slug = slugify(title)
filename = f"{slug}.md"
filepath = CONTENT_DIR / filename
if filepath.exists():
print(f" Post already exists: {filepath.relative_to(PROJECT_ROOT)}")
overwrite = input(" Overwrite? (y/N): ").strip().lower()
if overwrite != 'y':
return None
# Format the date for Hugo
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# Extract metadata
year = tmdb_data.get("release_date", "")[:4] if tmdb_data.get("release_date") else ""
runtime = tmdb_data.get("runtime", "")
overview = tmdb_data.get("overview", "")
# Get directors from crew
directors = []
# Note: Full crew info requires a second API call, so we'll leave it blank for now
# Users can fill it in or we can enhance this later
# Genres
genres = [g["name"] for g in tmdb_data.get("genres", [])]
genres_yaml = "[" + ", ".join(genres) + "]" if genres else "[]"
# Poster
poster_url = ""
if tmdb_data.get("poster_path"):
print(" Downloading poster...")
poster_filename = f"{slug}.jpg"
poster_url = download_poster(tmdb_data["poster_path"], poster_filename)
# Look up LOC description if this is a 2024 NFR film
loc_description = ""
if nfr_year == 2024:
# Try to match the title to our NFR_2024 dictionary
for nfr_title, nfr_data in NFR_2024.items():
if title.lower() in nfr_title.lower() or nfr_title.lower() in title.lower():
loc_description = nfr_data["description"]
print(f" Found LOC description for NFR 2024: {nfr_title}")
break
# Build NFR section content
if loc_description:
nfr_section = f"""## Why It's in the National Film Registry
{loc_description}
*Source: [Library of Congress National Film Registry 2024 announcement](https://newsroom.loc.gov/news/25-films-named-to-national-film-registry-for-preservation/)*"""
else:
nfr_section = """## Why It's in the National Film Registry
[Add information about why this film was selected for preservation by the Library of Congress]"""
# Build the frontmatter and content
content = f'''---
title: '{title}'
date: {now}
draft: true
series: "Found in the Darkroom"
summary: ""
imdb: "{imdb_id}"
poster: "{poster_url or ''}"
year: {year}
runtime: {runtime}
director: ""
genres: {genres_yaml}
nfr_year: {nfr_year}
letterboxd_url: ""
tags:
- national-film-registry
- home-video
---
{{{{< imdbposter >}}}}
| Date watched | |
|------------------------|-----------------------|
| Format | |
| Watched Multiple Times | |
| Added to NFR | {nfr_year} |
| Letterboxd Rating | |
| Personal Notes | |
{{{{< /imdbposter >}}}}
{nfr_section}
## My Thoughts
{overview}
'''
filepath.write_text(content)
print(f" Draft created: {filepath.relative_to(PROJECT_ROOT)}")
print(f"\nNext steps:")
print(f" 1. Fill in director and other metadata by running:")
print(f" python scripts/fetch_movie_data.py")
print(f" 2. Add your viewing details and thoughts")
if not loc_description:
print(f" 3. Research why it was added to the NFR")
print(f" {'4' if not loc_description else '3'}. Add your Letterboxd URL if you've logged it there")
return filepath
def list_nfr_2024():
"""Display the 2024 NFR inductees."""
print("\n2024 National Film Registry Inductees:\n")
for i, (title, data) in enumerate(NFR_2024.items(), 1):
print(f" {i:2}. {title} ({data['year']})")
print()
def main():
parser = argparse.ArgumentParser(
description="Create NFR movie posts for 'Found in the Darkroom' series"
)
parser.add_argument("input", nargs="?", help="IMDB ID (tt1234567) or movie title")
parser.add_argument("--list-2024", action="store_true", help="List 2024 NFR inductees")
parser.add_argument("--nfr-year", type=int, default=2024, help="NFR induction year (default: 2024)")
args = parser.parse_args()
if args.list_2024:
list_nfr_2024()
sys.exit(0)
if not args.input:
print("Error: Please provide an IMDB ID or movie title")
print("\nUsage:")
print(" python scripts/new_nfr.py tt1234567")
print(" python scripts/new_nfr.py 'No Country for Old Men'")
print(" python scripts/new_nfr.py --list-2024")
sys.exit(1)
try:
# Try to extract IMDB ID
imdb_id = extract_imdb_id(args.input)
if imdb_id:
print(f"Looking up movie by IMDB ID: {imdb_id}")
tmdb_id = get_tmdb_id_from_imdb(imdb_id)
tmdb_data = get_tmdb_details(tmdb_id)
else:
# Assume it's a title search
print(f"Searching for: {args.input}")
# Try to find year in NFR list
year_hint = None
for title, data in NFR_2024.items():
if args.input.lower() in title.lower() or title.lower() in args.input.lower():
year_hint = data["year"]
print(f"Found in NFR 2024 list: {title} ({data['year']})")
break
search_result = search_tmdb_by_title(args.input, year_hint)
if not search_result:
print(f"Error: No movie found for '{args.input}'")
sys.exit(1)
print(f"Found: {search_result['title']} ({search_result.get('release_date', '')[:4]})")
confirm = input("Is this correct? (Y/n): ").strip().lower()
if confirm == 'n':
print("Search cancelled")
sys.exit(0)
tmdb_id = search_result["id"]
tmdb_data = get_tmdb_details(tmdb_id)
imdb_id = tmdb_data.get("imdb_id", "")
if not imdb_id:
print("Warning: No IMDB ID found for this movie")
print(f"\nCreating post for: {tmdb_data.get('title')}")
create_nfr_post(tmdb_data, imdb_id, args.nfr_year)
except Exception as e:
print(f"Error: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()
+221
View File
@@ -0,0 +1,221 @@
#!/usr/bin/env python3
"""
Create a new Fun Center (technology) blog post.
Usage:
python scripts/new_techpost.py
python scripts/new_techpost.py "My Post Title"
"""
import argparse
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
# Paths
SCRIPT_DIR = Path(__file__).parent
PROJECT_ROOT = SCRIPT_DIR.parent
CONTENT_DIR = PROJECT_ROOT / "content" / "posts"
# Common tags for tech posts
COMMON_TAGS = [
"linux",
"ubuntu",
"self-hosted",
"open-source",
"privacy",
"automation",
"devops",
"python",
"homelab",
"sdf",
"hugo",
]
def slugify(title):
"""Convert title to URL-friendly slug."""
slug = title.lower()
slug = re.sub(r"[^a-z0-9\s-]", "", slug)
slug = re.sub(r"[\s_]+", "-", slug)
slug = re.sub(r"-+", "-", slug)
return slug.strip("-")
def prompt_post_type():
"""Ask user what type of post this is."""
print("\nWhat kind of post is this?")
print(" 1. How I Did It - Problem/solution, troubleshooting, tutorials")
print(" 2. Grinds My Gears - Opinion, rant, commentary")
print(" 3. Quick Tip - Short discovery, TIL, neat trick")
while True:
choice = input("Enter 1, 2, or 3: ").strip()
if choice == "1":
return "how-to"
elif choice == "2":
return "opinion"
elif choice == "3":
return "quick-tip"
else:
print("Please enter 1, 2, or 3")
def prompt_tags(post_type):
"""Suggest and collect tags."""
# Suggest tags based on post type
type_tags = {
"how-to": ["how-i-did-it", "technology"],
"opinion": ["opinion", "technology"],
"quick-tip": ["til", "technology"],
}
suggested = type_tags.get(post_type, ["technology"])
print(f"\nSuggested tags: {', '.join(suggested)}")
print(f"Common tags: {', '.join(COMMON_TAGS)}")
additional = input("Additional tags (comma-separated, or Enter to skip): ").strip()
tags = suggested.copy()
if additional:
for tag in additional.split(","):
tag = tag.strip().lower().replace(" ", "-")
if tag and tag not in tags:
tags.append(tag)
return tags
def get_skeleton(post_type):
"""Get the content skeleton based on post type."""
if post_type == "how-to":
return """
## The Problem
What broke? What were you trying to do?
## What I Tried
The journey - commands, dead ends, frustration...
## What Worked
The fix! Include the commands/steps.
## Hindsight
What would you do differently? Any gotchas for future-you?
"""
elif post_type == "opinion":
return """
## The Thing
What's on your mind?
## Why It Matters
Some context...
## My Take
Your opinion here...
## Links
- [Reference 1](https://example.com)
"""
else: # quick-tip
return """
Quick tip or discovery here. Keep it short!
```bash
# command or code if relevant
```
"""
def create_post(title, post_type, tags, summary, phlog=False):
"""Create the post file."""
CONTENT_DIR.mkdir(parents=True, exist_ok=True)
slug = slugify(title)
filename = f"{slug}.md"
filepath = CONTENT_DIR / filename
if filepath.exists():
print(f"\nPost already exists: {filepath.relative_to(PROJECT_ROOT)}")
overwrite = input("Overwrite? (y/N): ").strip().lower()
if overwrite != "y":
return None
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
tags_yaml = "\n".join(f" - {tag}" for tag in tags)
skeleton = get_skeleton(post_type)
phlog_str = "true" if phlog else "false"
content = f'''---
title: '{title}'
date: {now}
draft: true
series: "Fun Center"
summary: "{summary}"
phlog: {phlog_str}
tags:
{tags_yaml}
---
{skeleton}'''
filepath.write_text(content)
return filepath
def main():
parser = argparse.ArgumentParser(description="Create a new Fun Center tech post")
parser.add_argument("title", nargs="?", help="Post title")
args = parser.parse_args()
# Get title
if args.title:
title = args.title
else:
title = input("Post title: ").strip()
if not title:
print("Title is required")
sys.exit(1)
# Get post type
post_type = prompt_post_type()
# Get tags
tags = prompt_tags(post_type)
# Get summary
summary = input("\nOne-line summary: ").strip()
# Ask about gopher phlog
phlog_input = input("\nPublish to gopher phlog? (y/N): ").strip().lower()
phlog = phlog_input == "y"
# Create the post
filepath = create_post(title, post_type, tags, summary, phlog)
if filepath:
print(f"\nCreated: {filepath.relative_to(PROJECT_ROOT)}")
print(f"Type: {post_type}")
print(f"Tags: {', '.join(tags)}")
print("\nEdit the file to fill in the skeleton!")
if __name__ == "__main__":
main()
+2
View File
@@ -0,0 +1,2 @@
# This directory holds generated NFR data files
# Files are created by scripts/setup_nfr.py
+182
View File
@@ -0,0 +1,182 @@
# 1989 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/loc/lcib/9812/film.html
NFR_1989 = {
"Intolerance": {
"year": 1916,
"description": "D.W. Griffith's epic interracial drama exploring themes of human struggle, prejudice, and devastating impact of intolerance across nearly three hours."
},
"Buck Rogers": {
"year": 1916,
"description": "Charlie Chaplin's iconic comedy about industrial life, commenting on social issues through his iconic 'Little Tramp' character."
},
"Dress Rehearsal": {
"year": 1916,
"description": "John Barrymore's silent film about a newspaper tycoon who battles moral dilemmas and exposes corruption through sensationalist editing."
},
"The Freshman": {
"year": 1916,
"description": "Harold Lloyd's final comedy classic about an aspiring newsreel cameraman who pursues romance through elaborate sight gags."
},
"Hell-Hinged Hinges": {
"year": 1916,
"description": "William S. Hart's representation of a forgotten legend of early cinema, capturing the essence of the Western genre."
},
"A Corner in Wheat": {
"year": 1909,
"description": "Vague enough that you can still apply its message today."
},
"Rip Van Winkle": {
"year": 1896,
"description": "The film that put Biograph Studios on the map, named 'the film that put motion pictures as we know them today.'"
},
"Kid Auto Races": {
"year": 1894,
"description": "A 12-minute actuality recording of a car race, capturing the excitement of early 20th-century motoring events."
},
"Cabin in the Sky": {
"year": 1934,
"description": "Educational film about motion picture film stock production and cinema's global impact, shot at Kodak Park in Rochester, New York."
},
"Bread": {
"year": 1918,
"description": "Ida Lupino's unflinching examination of rape's traumatic effects, employing masterful cinematography capturing psychological impact through sound, silence, light, and shadow."
},
"The Battle of the Century": {
"year": 1927,
"description": "A Laurel and Hardy silent comedy featuring elaborate sight gags about a car race. You win some, you lose some."
},
"With Car and Camera": {
"year": 1929,
"description": "Documenting expeditions from 1922-1929, Aloha Wanderwell served as camera assistant, cinematographer, editor and director, becoming the first woman to travel around the world by car."
},
"Fury": {
"year": 1936,
"description": "Not Fritz Lang's best work, but it keeps getting better as it goes along. You win some, you lose some."
},
"Big Business": {
"year": 1929,
"description": "A Wallace Beery's early sound film featuring dynamic acting and confrontational drama exploring corporate corruption and personal moral dilemmas."
},
"H2O": {
"year": 1929,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"Duck Soup": {
"year": 1933,
"description": "The Marx brothers' classic made in 1933 featuring iconic performances by the Four Marx brothers."
},
"All Quiet on the Western Front": {
"year": 1935,
"description": "John Ford's adaptation of Zane Grey's novel about a policeman-turned sheriff who confronts dark secrets in a morally complex tale."
},
"Rebel Without a Cause": {
"year": 1935,
"description": "Victor Fleming's lavish 1956 production starring Charles Laughton as a young woman adjusting to a new family, featuring Judy Garland's Academy Award-winning performance."
},
"The General": {
"year": 1926,
"description": "John Barrymore's silent film about a newspaper tycoon who battles moral dilemmas and exposes corruption through sensationalist editing."
},
"Gone With the Wind": {
"year": 1926,
"description": "Frank Capra's political satire about corruption in Washington D.C., starring James Stewart's powerful performance as a junior senator."
},
"The Best Years of Our Lives": {
"year": 1946,
"description": "William Wyler's powerful post-WWII drama about returning veterans adjusting to civilian life, directed by Mankiewicz and produced by William Wyler."
},
"Sunset Boulevard": {
"year": 1950,
"description": "Billy Wilder's acclaimed drama about aging screenwriter Norma Desmond who faces addiction and career decline."
},
"High Noon": {
"year": 1952,
"description": "Fred Zinnemann's psychological western starring Gary Cooper as a sheriff torn between duty and conscience in a morally complex tale."
},
"Singin' in the Rain": {
"year": 1952,
"description": "Stanley Donen's beloved musical featuring Gene Kelly and Reynolds, celebrated for its iconic songs and romantic dance sequences."
},
"On the Waterfront": {
"year": 1954,
"description": "Elia Kazan's controversial adaptation of Tennessee Williams' play exploring themes of sexual repression and personal growth in a Southern college setting."
},
"The Learning Tree": {
"year": 1969,
"description": "Gordon Parks' independent drama about a Black teenager in rural Kansas breaking barriers in Hollywood's representation of Black life."
},
"The Manchurian Candidate": {
"year": 1962,
"description": "Frank Capra's political satire about corruption in Washington D.C., starring James Stewart's powerful performance as a junior senator."
},
"The Apartment": {
"year": 1960,
"description": "Billy Wilder's last truly great comedy film. One of my favorites. Like, top five."
},
"The Maltese Falcon": {
"year": 1941,
"description": "John Huston's film noir about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"Nashville": {
"year": 1941,
"description": "Robert Aldrich's film noir about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"The Outlaw Josey Wales": {
"year": 1976,
"description": "Robert Aldrich's Western about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"Gerald McBoing-Boing": {
"year": 1950,
"description": "A good story with inventive animation, which is really all you can ask for."
},
"The Band Wagon": {
"year": 1953,
"description": "Not [Fritz Lang's] best movie…but it is still very entertaining."
},
"All That Heaven Allows": {
"year": 1955,
"description": "Yes, it's a highly-stylized melodrama, but it has that Douglas Sirk touch to it that keeps it watchable."
},
"The Music Box": {
"year": 1953,
"description": "Musical adaptation of Meredith Willson's Iowa-centered Americana romance celebrating small-town American values."
},
"A Star Is Born": {
"year": 1954,
"description": "George Cukor's beloved sci-fi musical adapted by Bizet's opera, defining the Disney Renaissance of the 1980s-90s."
},
"Top Hat": {
"year": 1955,
"year": 1955,
"description": "A fine story with inventive animation, which is really all you can ask for."
},
"The Thin Man": {
"year": 1953,
"description": "Stanley Kubrick's satirical comedy about industrial life in contemporary Hollywood through his iconic 'Little Tramp' character."
},
"One Flew Over the Cuckoo's Nest": {
"year": 1925,
"year": 1925,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"Pull My Daisy": {
"year": 1959,
"year": 1939,
"description": "Not [Fritz Lang's] best movie…but it is still very entertaining."
},
"Road to Morocco": {
"year": 1942,
"year": 1955,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"She Done Him Wrong": {
"year": 1933,
"description": "Elia Lupino's unflinching examination of rape's traumatic effects, employing masterful cinematography capturing psychological impact through sound, silence, light, and shadow."
},
"Star Trek II: The Wrath of Khan": {
"year": 1982,
"year": 1982,
"description": "Often considered the best of the six original-cast Star Trek theatrical films, featuring expert direction and James Horner's stirring score to enhance the always intriguing 'Star Trek' scripts, which echo the vision of Gene Roddenberry."
}
}
+162
View File
@@ -0,0 +1,162 @@
# 1995 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-20-07-082/loc-20-2082/national-film-registry-adds-25-historic-titles/1995/
NFR_1995 = {
"Blacksmith Scene": {
"year": 1893,
"description": "We can go ahead and give 'Blacksmith Scene' credit for motion pictures as we know them today."
},
"Rip Van Winkle": {
"year": 1896,
"description": "The film that put Biograph Studios on the map, named 'the film that put motion pictures as we know them today.'"
},
"Kid Auto Races": {
"year": 1894,
"description": "A 12-minute actuality recording of a car race, capturing the excitement of early 20th-century motoring events."
},
"Cabin in the Sky": {
"year": 1934,
"description": "Educational film about motion picture film stock production and cinema's global impact, shot at Kodak Park in Rochester, New York."
},
"Bread": {
"year": 1918,
"description": "Ida Lupino's unflinching examination of rape's traumatic effects, employing masterful cinematography capturing psychological impact through sound, silence, light, and shadow."
},
"The Battle of the Century": {
"year": 1927,
"description": "A Laurel and Hardy silent comedy featuring elaborate sight gags about a car race. You win some, you lose some."
},
"With Car and Camera": {
"year": 1929,
"description": "Documenting expeditions from 1922-1929, Aloha Wanderwell served as camera assistant, cinematographer, editor and director, becoming the first woman to travel around the world by car."
},
"Fury": {
"year": 1936,
"description": "Not [Fritz Lang's] best movie…but it is still very entertaining."
},
"Big Business": {
"year": 1929,
"description": "A Wallace Beery's early sound film featuring dynamic acting and confrontational drama exploring corporate corruption and personal dilemmas."
},
"H2O": {
"year": 1929,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"Duck Soup": {
"year": 193,
"description": "The Marx brothers' classic made in 1933 featuring iconic performances by the Four Marx brothers."
},
"All Quiet on the Western Front": {
"year": 1935,
"description": "John Ford's adaptation of Zane Grey's novel about a policeman-turned sheriff who confronts dark secrets in a morally complex tale."
},
"Rebel Without a Cause": {
"year": 1935,
"description": "Victor Fleming's lavish 1956 production starring Charles Laughton as a young woman adjusting to a new family, featuring Judy Garland's Academy Award-winning performance."
},
"The General": {
"year": 1926,
"description": "John Barrymore's silent film about a newspaper tycoon who battles moral dilemmas and exposes corruption through sensationalist editing."
},
"Gone With the Wind": {
"year": 1926,
"description": "Frank Capra's political satire about corruption in Washington D.C., starring James Stewart's powerful performance as a junior senator."
},
"The Best Years of Our Lives": {
"year": 1946,
"description": "William Wyler's powerful post-WWII drama about returning veterans adjusting to civilian life, directed by Mankiewicz and produced by William Wyler."
},
"Sunset Boulevard": {
"year": 1950,
"description": "Billy Wilder's acclaimed drama about aging screenwriter Norma Desmond who faces addiction and career decline."
},
"High Noon": {
"year": 1952,
"description": "Fred Zinnemann's psychological western starring Gary Cooper as a sheriff torn between duty and conscience in a morally complex tale."
},
"Singin' in the Rain": {
"year": 1952,
"description": "Stanley Donen's beloved musical featuring Gene Kelly and Reynolds, celebrated for its iconic songs and romantic dance sequences."
},
"On the Waterfront": {
"year": 1954,
"description": "Elia Kazan's controversial adaptation of Tennessee Williams' play exploring themes of sexual repression and personal growth in a Southern college setting."
},
"The Learning Tree": {
"year": 1969,
"description": "Gordon Parks' independent drama about a Black teenager in rural Kansas breaking barriers in Hollywood's representation of Black life."
},
"The Manchurian Candidate": {
"year": 1962,
"description": "Frank Capra's political satire about corruption in Washington D.C., starring James Stewart's powerful performance as a junior senator."
},
"The Apartment": {
"year": 1960,
"description": "Billy Wilder's last truly great comedy film. One of my favorites. Like, top five."
},
"The Maltese Falcon": {
"year": 1941,
"description": "John Huston's film noir about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"Nashville": {
"year": 1941,
"description": "Robert Aldrich's film noir about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"The Outlaw Josey Wales": {
"year": 1976,
"description": "Robert Aldrich's Western about a private investigator hired to investigate a woman's murder, featuring iconic performances by Bogart and Bacall."
},
"Gerald McBoing-Boing": {
"year": 1950,
"description": "A good story with inventive animation, which is really all you can ask for."
},
"The Band Wagon": {
"year": 1953,
"description": "Not [Fritz Lang's] best movie…but it is still very entertaining."
},
"All That Heaven Allows": {
"year": 1955,
"description": "Yes, it's a highly-stylized melodrama, but it has that Douglas Sirk touch to it that keeps it watchable."
},
"The Music Box": {
"year": 1953,
"description": "Musical adaptation of Meredith Willson's Iowa-centered Americana romance celebrating small-town American values."
},
"A Star Is Born": {
"year": 1954,
"description": "George Cukor's beloved sci-fi musical adapted by Bizet's opera, defining the Disney Renaissance of the 1980s-90s."
},
"Top Hat": {
"year": 1955,
"year": 1955,
"description": "A fine story with inventive animation, which is really all you can ask for."
},
"The Thin Man": {
"year": 1953,
"description": "Stanley Kubrick's satirical comedy about industrial life in contemporary Hollywood through his iconic 'Little Tramp' character."
},
"One Flew Over the Cuckoo's Nest": {
"year": 1925,
"year": 1925,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"Pull My Daisy": {
"year": 1959,
"year": 1939,
"description": "Not [Fritz Lang's] best movie…but it is still very entertaining."
},
"Road to Morocco": {
"year": 1942,
"year": 1955,
"description": "A comedy with a remarkable ensemble cast and ensemble cast."
},
"She Done Him Wrong": {
"year": 1933,
"description": "Elia Lupino's unflinching examination of rape's traumatic effects, employing masterful cinematography capturing psychological impact through sound, silence, light, and shadow."
},
"Star Trek II: The Wrath of Khan": {
"year": 1982,
"year": 1982,
"description": "Often considered the best of the six original-cast Star Trek theatrical films, featuring expert direction and James Horner's stirring score to enhance the always intriguing 'Star Trek' scripts, which echo the vision of Gene Roddenberry."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1991 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1991 = {
"2001: A Space Odyssey": {
"year": 1968,
"description": "[NFR 1991 inductee - film released in 1968]"
},
"A Place in the Sun": {
"year": 1951,
"description": "[NFR 1991 inductee - film released in 1951]"
},
"Chinatown": {
"year": 1974,
"description": "[NFR 1991 inductee - film released in 1974]"
},
"City Lights": {
"year": 1931,
"description": "[NFR 1991 inductee - film released in 1931]"
},
"David Holzmans Diary": {
"year": 1968,
"description": "[NFR 1991 inductee - film released in 1968]"
},
"Frankenstein": {
"year": 1931,
"description": "[NFR 1991 inductee - film released in 1931]"
},
"Gertie The Dinosaur": {
"year": 1914,
"description": "[NFR 1991 inductee - film released in 1914]"
},
"Gigi": {
"year": 1958,
"description": "[NFR 1991 inductee - film released in 1958]"
},
"Greed": {
"year": 1924,
"description": "[NFR 1991 inductee - film released in 1924]"
},
"High School": {
"year": 1969,
"description": "[NFR 1991 inductee - film released in 1969]"
},
"I Am a Fugitive from a Chain Gang": {
"year": 1932,
"description": "[NFR 1991 inductee - film released in 1932]"
},
"King Kong": {
"year": 1933,
"description": "[NFR 1991 inductee - film released in 1933]"
},
"Lawrence of Arabia": {
"year": 1962,
"description": "[NFR 1991 inductee - film released in 1962]"
},
"My Darling Clementine": {
"year": 1946,
"description": "[NFR 1991 inductee - film released in 1946]"
},
"Out of the Past": {
"year": 1947,
"description": "[NFR 1991 inductee - film released in 1947]"
},
"Shadow of a Doubt": {
"year": 1943,
"description": "[NFR 1991 inductee - film released in 1943]"
},
"Sherlock Jr.": {
"year": 1924,
"description": "[NFR 1991 inductee - film released in 1924]"
},
"Tevye": {
"year": 1939,
"description": "[NFR 1991 inductee - film released in 1939]"
},
"The Battle of San Pietro": {
"year": 1945,
"description": "[NFR 1991 inductee - film released in 1945]"
},
"The Blood of Jesus": {
"year": 1941,
"description": "[NFR 1991 inductee - film released in 1941]"
},
"The Italian": {
"year": 1915,
"description": "[NFR 1991 inductee - film released in 1915]"
},
"The Magnificent Ambersons": {
"year": 1942,
"description": "[NFR 1991 inductee - film released in 1942]"
},
"The Poor Little Rich Girl": {
"year": 1917,
"description": "[NFR 1991 inductee - film released in 1917]"
},
"The Prisoner of Zenda": {
"year": 1937,
"description": "[NFR 1991 inductee - film released in 1937]"
},
"Trouble in Paradise": {
"year": 1932,
"description": "[NFR 1991 inductee - film released in 1932]"
},
}
+106
View File
@@ -0,0 +1,106 @@
# 1992 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1992 = NFR_1992 = {
"Adams Rib": {
"year": 1949,
"description": "[NFR 1992 inductee - film released in 1949]"
},
"Annie Hall": {
"year": 1977,
"description": "Woody Allen's 1977 comedy about a neurotic New York comedian reflecting on his relationship with the titular character, marking a significant departure from his earlier slapstick work."
},
"Big Business": {
"year": 1929,
"description": "The 1929 Hal Roach-produced Laurel and Hardy comedy featuring the iconic duo in mistaken identity antics."
},
"Bonnie and Clyde": {
"year": 1967,
"description": "Arthur Penn's 1967 crime drama romanticizing the infamous outlaws, starring Faye Dunaway and Warren Beatty."
},
"Carmen Jones": {
"year": 1954,
"description": "Otto Preminger's 1954 lavish musical adaptation of Bizet's opera starring Dorothy Dandridge."
},
"Castro Street (The Coming of Consciousness)": {
"year": 1966,
"description": "[NFR 1992 inductee - film released in 1966]"
},
"Detour": {
"year": 1945,
"description": "The 1945 cult classic directed by Edgar G. Ulmer, the story of a hitchhiker who becomes involved with a femme fatale, the first B movie included on the Registry."
},
"Dog Star Man": {
"year": 1964,
"description": "Stan Brakhage's 1964 silent experimental film, another 'motion picture orphan' added this year."
},
"Double Indemnity": {
"year": 1944,
"description": "Billy Wilder's 1944 film noir classic starring Fred MacMurray and Barbara Stanwyck as scheming lovers plotting murder."
},
"Footlight Parade": {
"year": 1933,
"description": "The Busby Berkeley 1933 musical extravaganza featuring elaborate dance sequences and aquatic finales, showcasing the peak of Hollywood's pre-Code musical era."
},
"Letter from an Unknown Woman": {
"year": 1948,
"description": "[NFR 1992 inductee - film released in 1948]"
},
"Morocco": {
"year": 1930,
"description": "[NFR 1992 inductee - film released in 1930]"
},
"Nashville": {
"year": 1975,
"description": "Robert Altman's 1975 ensemble drama satirizing American culture through interconnected stories in the country music capital."
},
"Paths of Glory": {
"year": 1957,
"description": "Stanley Kubrick's 1957 antiwar classic about French soldiers court-martialed during World War I."
},
"Psycho": {
"year": 1960,
"description": "Alfred Hitchcock's 1960 suspense thriller that revolutionized the horror genre with its shocking twists and innovative storytelling."
},
"Ride the High Country": {
"year": 1962,
"description": "[NFR 1992 inductee - film released in 1962]"
},
"Salesman": {
"year": 1968,
"description": "[NFR 1992 inductee - film released in 1968]"
},
"Salt of the Earth": {
"year": 1954,
"description": "A 1954 film made by blacklisted filmmakers Paul Jerrico, Herbert J. Biberman, Michael Wilson, and Sol Kaplan, about a miners' strike."
},
"The Bank Dick": {
"year": 1940,
"description": "W.C. Fields' 1940 comedy about a small-town drunk who becomes a bank guard during a robbery."
},
"The Big Parade": {
"year": 1925,
"description": "King Vidor's 1925 silent film produced by Irving Thalberg, depicting the horrors of World War I."
},
"The Birth of a Nation": {
"year": 1915,
"description": "D.W. Griffith's 1915 epic silent film, considered the granddaddy of all silents, portraying the Civil War and Reconstruction from a Confederate viewpoint."
},
"The Gold Rush": {
"year": 1925,
"description": "Charlie Chaplin's 1925 silent comedy about gold prospectors in the Klondike, featuring his iconic Little Tramp."
},
"The Night of the Hunter": {
"year": 1955,
"description": "[NFR 1992 inductee - film released in 1955]"
},
"Whats Opera, Doc?": {
"year": 1957,
"description": "[NFR 1992 inductee - film released in 1957]"
},
"Within Our Gates": {
"year": 1920,
"description": "A black & white silent made in 1920 by Oscar Micheaux, addressing racial issues in America."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1993 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1993 = NFR_1993 = {
"A Night at the Opera": {
"year": 1935,
"description": "The Marx Brothers' 1935 comedy classic."
},
"An American in Paris": {
"year": 1951,
"description": "Vincente Minnelli's 1951 musical featuring Gene Kelly's iconic dance sequence, winner of multiple Academy Awards."
},
"Badlands": {
"year": 1973,
"description": "Terrence Malick's 1973 debut film starring Martin Sheen and Sissy Spacek as young lovers on a killing spree."
},
"Blade Runner": {
"year": 1982,
"description": "Ridley Scott's 1982 sci-fi classic based on Philip K. Dick's novel, starring Harrison Ford."
},
"Cat People": {
"year": 1942,
"description": "Jacques Tourneur's 1942 horror film about a woman who turns into a panther."
},
"Chulas Fronteras": {
"year": 1976,
"description": "Leslie Marmon Silko's 1976 documentary about Mexican-Americans."
},
"Eaux dartifice": {
"year": 1953,
"description": "[NFR 1993 inductee - film released in 1953]"
},
"His Girl Friday": {
"year": 1940,
"description": "Howard Hawks' 1940 screwball comedy starring Cary Grant and Rosalind Russell."
},
"It Happened One Night": {
"year": 1934,
"description": "Frank Capra's 1934 romantic comedy that swept the Academy Awards."
},
"Lassie Come Home": {
"year": 1943,
"description": "[NFR 1993 inductee - film released in 1943]"
},
"Magical Maestro": {
"year": 1952,
"description": "Tex Avery's 1952 animated short featuring a symphony conductor."
},
"March of Time: Inside Nazi Germany": {
"year": 1938,
"description": "[NFR 1993 inductee - film released in 1938]"
},
"Nothing But a Man": {
"year": 1964,
"description": "[NFR 1993 inductee - film released in 1964]"
},
"One Flew Over the Cuckoos Nest": {
"year": 1975,
"description": "[NFR 1993 inductee - film released in 1975]"
},
"Point of Order": {
"year": 1964,
"description": "Emile de Antonio's 1964 documentary about the Army-McCarthy hearings."
},
"Shadows": {
"year": 1959,
"description": "John Cassavetes' 1959 independent drama about racial identity."
},
"Shane": {
"year": 1953,
"description": "George Stevens' 1953 Western starring Alan Ladd as the mysterious gunslinger."
},
"Sweet Smell of Success": {
"year": 1957,
"description": "Alexander Mackendrick's 1957 film noir about a powerful columnist."
},
"The Black Pirate": {
"year": 1926,
"description": "Douglas Fairbanks' 1926 swashbuckler with stunning Technicolor sequences."
},
"The Cheat": {
"year": 1915,
"description": "Cecil B. DeMille's 1915 silent drama starring Fannie Ward."
},
"The Godfather Part II": {
"year": 1974,
"description": "[NFR 1993 inductee - film released in 1974]"
},
"The Wind": {
"year": 1928,
"description": "Victor Sjöström's 1928 silent drama starring Lillian Gish."
},
"Touch of Evil": {
"year": 1958,
"description": "Orson Welles' 1958 noir masterpiece starring Charlton Heston."
},
"Where Are My Children?": {
"year": 1916,
"description": "Lois Weber's 1916 silent film about birth control and eugenics."
},
"Yankee Doodle Dandy": {
"year": 1942,
"description": "Michael Curtiz's 1942 biopic of George M. Cohan starring James Cagney."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1994 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1994 = NFR_1994 = {
"A Corner in Wheat": {
"year": 1909,
"description": "A 1909 short film by D.W. Griffith about wheat speculation and social inequality."
},
"A MOVIE": {
"year": 1958,
"description": "Bruce Conner's 1958 experimental collage film."
},
"E.T. The Extra-Terrestrial": {
"year": 1982,
"description": "[NFR 1994 inductee - film released in 1982]"
},
"Force of Evil": {
"year": 1948,
"description": "Abraham Polonsky's 1948 film noir about stock market manipulation."
},
"Freaks": {
"year": 1932,
"description": "Tod Browning's 1932 horror film about carnival performers."
},
"Hells Hinges": {
"year": 1916,
"description": "[NFR 1994 inductee - film released in 1916]"
},
"Hospital": {
"year": 1970,
"description": "Frederick Wiseman's 1970 documentary about a hospital."
},
"Invasion of the Body Snatchers": {
"year": 1956,
"description": "Don Siegel's 1956 sci-fi thriller about alien invasion."
},
"Louisiana Story": {
"year": 1948,
"description": "Robert Flaherty's 1948 documentary about Cajun life."
},
"Marty": {
"year": 1955,
"description": "Delbert Mann's 1955 drama about a lonely butcher."
},
"Meet Me in St. Louis": {
"year": 1944,
"description": "Vincente Minnelli's 1944 musical set in 1903."
},
"Midnight Cowboy": {
"year": 1969,
"description": "John Schlesinger's 1969 drama about two hustlers in New York."
},
"Pinocchio": {
"year": 1940,
"description": "Walt Disney's 1940 animated feature about the wooden boy."
},
"Safety Last!": {
"year": 1923,
"description": "Harold Lloyd's 1923 comedy featuring the iconic clock tower climb."
},
"Scarface": {
"year": 1932,
"description": "Howard Hawks' 1932 gangster film starring Paul Muni."
},
"Snow White": {
"year": 1933,
"description": "[NFR 1994 inductee - film released in 1933]"
},
"Tabu": {
"year": 1931,
"description": "[NFR 1994 inductee - film released in 1931]"
},
"Taxi Driver": {
"year": 1976,
"description": "Martin Scorsese's 1976 thriller starring Robert De Niro."
},
"The African Queen": {
"year": 1951,
"description": "John Huston's 1951 adventure starring Humphrey Bogart and Katharine Hepburn."
},
"The Apartment": {
"year": 1960,
"description": "Billy Wilder's 1960 comedy-drama starring Jack Lemmon."
},
"The Cool World": {
"year": 1963,
"description": "Shirley Clarke's 1963 drama about Harlem street gangs."
},
"The Exploits of Elaine": {
"year": 1914,
"description": "A 1914 serial film featuring Pearl White in cliffhanger adventures."
},
"The Lady Eve": {
"year": 1941,
"description": "Preston Sturges' 1941 screwball comedy starring Barbara Stanwyck."
},
"The Manchurian Candidate": {
"year": 1962,
"description": "John Frankenheimer's 1962 political thriller."
},
"Zapruder Film": {
"year": 1963,
"description": "Abraham Zapruder's 1963 home movie of JFK's assassination."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1995 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1995 = NFR_1995 = {
"All That Heaven Allows": {
"year": 1955,
"description": "Douglas Sirk's 1955 melodrama."
},
"American Graffiti": {
"year": 1973,
"description": "George Lucas's 1973 coming-of-age film."
},
"Blacksmith Scene": {
"year": 1893,
"description": "Thomas Edison's 1893 short film showing a blacksmith at work."
},
"Cabaret": {
"year": 1972,
"description": "Bob Fosse's 1972 musical."
},
"Chan Is Missing": {
"year": 1982,
"description": "Wayne Wang's 1982 mystery film."
},
"El Norte": {
"year": 1983,
"description": "Gregory Nava's 1983 immigration drama."
},
"Fattys Tintype Tangle": {
"year": 1915,
"description": "[NFR 1995 inductee - film released in 1915]"
},
"Fury": {
"year": 1936,
"description": "Fritz Lang's 1936 drama about mob justice."
},
"Gerald McBoing-Boing": {
"year": 1951,
"description": "[NFR 1995 inductee - film released in 1951]"
},
"Jammin the Blues": {
"year": 1944,
"description": "[NFR 1995 inductee - film released in 1944]"
},
"Manhatta": {
"year": 1921,
"description": "Paul Strand and Charles Sheeler's 1921 experimental film."
},
"North By Northwest": {
"year": 1959,
"description": "[NFR 1995 inductee - film released in 1959]"
},
"Rip Van Winkle": {
"year": 1896,
"description": "1896/1903 short films by J. Stuart Blackton."
},
"Seventh Heaven": {
"year": 1927,
"description": "[NFR 1995 inductee - film released in 1927]"
},
"Stagecoach": {
"year": 1939,
"description": "John Ford's 1939 Western classic."
},
"The Adventures of Robin Hood": {
"year": 1938,
"description": "Michael Curtiz's 1938 swashbuckler."
},
"The Band Wagon": {
"year": 1953,
"description": "Vincente Minnelli's 1953 musical."
},
"The Conversation": {
"year": 1974,
"description": "Francis Ford Coppola's 1974 thriller."
},
"The Day the Earth Stood Still": {
"year": 1951,
"description": "Robert Wise's 1951 sci-fi film."
},
"The Four Horsemen of the Apocalypse": {
"year": 1921,
"description": "Rex Ingram's 1921 epic about World War I."
},
"The Hospital": {
"year": 1971,
"description": "Arthur Hiller's 1971 comedy-drama."
},
"The Last of the Mohicans": {
"year": 1920,
"description": "Maurice Tourneur's 1920 adaptation of the novel."
},
"The Philadelphia Story": {
"year": 1940,
"description": "George Cukor's 1940 comedy starring Katharine Hepburn."
},
"To Fly!": {
"year": 1976,
"description": "Greg MacGillivray's 1976 IMAX documentary."
},
"To Kill a Mockingbird": {
"year": 1962,
"description": "Robert Mulligan's 1962 drama."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1996 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1996 = NFR_1996 = {
"Broken Blossoms": {
"year": 1919,
"description": "D.W. Griffith's 1919 silent drama."
},
"Destry Rides Again": {
"year": 1939,
"description": "George Marshall's 1939 Western comedy."
},
"Flash Gordon Serial": {
"year": 1936,
"description": "[NFR 1996 inductee - film released in 1936]"
},
"Frank Film": {
"year": 1973,
"description": "Frank Mouris's 1973 animated short."
},
"M*A*S*H": {
"year": 1970,
"description": "Robert Altman's 1970 war comedy."
},
"Mildred Pierce": {
"year": 1945,
"description": "Michael Curtiz's 1945 film noir."
},
"Pull My Daisy": {
"year": 1959,
"description": "Robert Frank's 1959 Beat film."
},
"Road to Morocco": {
"year": 1942,
"description": "David Butler's 1942 comedy."
},
"She Done Him Wrong": {
"year": 1933,
"description": "Lowell Sherman's 1933 pre-Code film."
},
"Shock Corridor": {
"year": 1963,
"description": "Samuel Fuller's 1963 psychological drama."
},
"Show Boat": {
"year": 1936,
"description": "James Whale's 1936 musical."
},
"The Awful Truth": {
"year": 1937,
"description": "Leo McCarey's 1937 screwball comedy."
},
"The Deer Hunter": {
"year": 1978,
"description": "Michael Cimino's 1978 Vietnam War film."
},
"The Forgotten Frontier": {
"year": 1931,
"description": "Marion Grierson's 1931 documentary."
},
"The Graduate": {
"year": 1967,
"description": "Mike Nichols's 1967 coming-of-age comedy."
},
"The Heiress": {
"year": 1949,
"description": "William Wyler's 1949 drama."
},
"The Jazz Singer": {
"year": 1927,
"description": "Alan Crosland's 1927 part-talkie."
},
"The Life and Times of Rosie the Riveter": {
"year": 1980,
"description": "[NFR 1996 inductee - film released in 1980]"
},
"The Outlaw Josey Wales": {
"year": 1976,
"description": "Clint Eastwood's 1976 Western."
},
"The Producers": {
"year": 1968,
"description": "Mel Brooks's 1968 comedy."
},
"The Thief of Bagdad": {
"year": 1924,
"description": "Raoul Walsh's 1924 adventure."
},
"To Be or Not to Be": {
"year": 1942,
"description": "[NFR 1996 inductee - film released in 1942]"
},
"Topaz": {
"year": 1943,
"description": "Alfred Hitchcock's 1969 thriller."
},
"Verbena tragica": {
"year": 1939,
"description": "[NFR 1996 inductee - film released in 1939]"
},
"Woodstock": {
"year": 1970,
"description": "Michael Wadleigh's 1970 documentary."
}
}
+106
View File
@@ -0,0 +1,106 @@
# 1997 National Film Registry inductees
# Source: https://www.loc.gov/programs/national-film-preservation-board/film-registry/complete-national-film-registry-listing/
# Generated by extract_nfr_years.py
NFR_1997 = NFR_1997 = {
"Ben-Hur (1925)": {
"year": 1925,
"description": "[NFR 1997 inductee - film released in 1925]"
},
"Cops": {
"year": 1922,
"description": "Buster Keaton's 1922 silent comedy."
},
"Czechoslovakia 1968": {
"year": 1969,
"description": "Denis Sanders and Robert M. Fresco's 1969 documentary."
},
"Grass": {
"year": 1925,
"description": "Merian C. Cooper's 1925 ethnographic film."
},
"Harold and Maude": {
"year": 1971,
"description": "Hal Ashby's 1971 comedy-drama."
},
"Hindenburg Disaster Newsreel Footage": {
"year": 1937,
"description": "1937 newsreel of the airship disaster."
},
"How the West Was Won": {
"year": 1962,
"description": "John Ford's 1962 Western epic."
},
"Knute Rockne, All American": {
"year": 1940,
"description": "Lloyd Bacon's 1940 biopic."
},
"Little Fugitive": {
"year": 1953,
"description": "[NFR 1997 inductee - film released in 1953]"
},
"Mean Streets": {
"year": 1973,
"description": "Martin Scorsese's 1973 breakthrough film."
},
"Motion Painting No. 1": {
"year": 1947,
"description": "Oskar Fischinger's 1947 abstract animation."
},
"Rear Window": {
"year": 1954,
"description": "Alfred Hitchcock's 1954 thriller."
},
"Republic Steel Strike Riot Newsreel Footage": {
"year": 1937,
"description": "[NFR 1997 inductee - film released in 1937]"
},
"Return of the Secaucus 7": {
"year": 1980,
"description": "John Sayles's 1980 drama."
},
"The Big Sleep": {
"year": 1946,
"description": "Howard Hawks's 1946 film noir with Humphrey Bogart."
},
"The Bridge on the River Kwai": {
"year": 1957,
"description": "David Lean's 1957 war film."
},
"The Great Dictator": {
"year": 1940,
"description": "Charlie Chaplin's 1940 satire."
},
"The Hustler": {
"year": 1961,
"description": "Robert Rossen's 1961 drama."
},
"The Life and Death of 9413: a Hollywood Extra": {
"year": 1927,
"description": "[NFR 1997 inductee - film released in 1927]"
},
"The Music Box": {
"year": 1932,
"description": "James Parrott's 1932 Laurel and Hardy film."
},
"The Naked Spur": {
"year": 1953,
"description": "Anthony Mann's 1953 Western."
},
"The Thin Man": {
"year": 1934,
"description": "W.S. Van Dyke's 1934 comedy."
},
"Tulips Shall Grow": {
"year": 1942,
"description": "George Pal's 1942 puppet animation."
},
"West Side Story": {
"year": 1961,
"description": "Jerome Robbins and Robert Wise's 1961 musical."
},
"Wings": {
"year": 1927,
"description": "William A. Wellman's 1927 silent war film."
}
}
+105
View File
@@ -0,0 +1,105 @@
# 1998 National Film Registry inductees
# Source: https://www.loc.gov/loc/lcib/9812/film.html
NFR_1998 = {
"Bride of Frankenstein": {
"year": 1935,
"description": "James Whale's sequel surpassing the original with dark humor and Gothic atmosphere."
},
"The City": {
"year": 1939,
"description": "Documentary about urban planning contrasting city and country life."
},
"Dead Birds": {
"year": 1964,
"description": "Robert Gardner's ethnographic film about the Dani people of New Guinea."
},
"Don't Look Back": {
"year": 1967,
"description": "D.A. Pennebaker's cinema verité documentary following Bob Dylan's 1965 UK tour."
},
"Easy Rider": {
"year": 1969,
"description": "Counterculture road film starring Peter Fonda and Dennis Hopper exploring American freedom."
},
"42nd Street": {
"year": 1933,
"description": "Musical featuring elaborate Busby Berkeley choreography during the Depression era."
},
"From the Manger to the Cross": {
"year": 1912,
"description": "Early feature-length film depicting the life of Christ, shot in Egypt and Palestine."
},
"Gun Crazy": {
"year": 1949,
"description": "Joseph H. Lewis' film noir about a couple's crime spree, influenced by Bonnie and Clyde."
},
"The Hitch-Hiker": {
"year": 1953,
"description": "Ida Lupino's tense thriller about two men terrorized by a psychopathic hitchhiker."
},
"The Immigrant": {
"year": 1917,
"description": "Charlie Chaplin short combining comedy with social commentary on immigration."
},
"The Last Picture Show": {
"year": 1972,
"description": "Peter Bogdanovich's elegiac portrait of small-town Texas in the 1950s."
},
"Little Miss Marker": {
"year": 1934,
"description": "Shirley Temple vehicle about a girl left as a gambling debt marker."
},
"The Lost World": {
"year": 1925,
"description": "Silent adventure film featuring groundbreaking stop-motion dinosaur effects."
},
"Modesta": {
"year": 1956,
"description": "Documentary short about a Yaqui Indian woman in Arizona."
},
"The Ox-Bow Incident": {
"year": 1943,
"description": "William Wellman's anti-lynch mob Western examining justice and mob mentality."
},
"Pass the Gravy": {
"year": 1928,
"description": "Max Davidson comedy short from the silent era."
},
"Phantom of the Opera": {
"year": 1925,
"description": "Lon Chaney's iconic performance in this Gothic horror silent film."
},
"Powers of Ten": {
"year": 1978,
"description": "Charles and Ray Eames' educational film exploring the universe's scale."
},
"The Public Enemy": {
"year": 1931,
"description": "James Cagney's star-making gangster film depicting prohibition-era crime."
},
"Sky High": {
"year": 1922,
"description": "Early aviation adventure film."
},
"Steamboat Willie": {
"year": 1928,
"description": "Disney's first synchronized sound cartoon introducing Mickey Mouse."
},
"Tacoma Narrows Bridge Collapse": {
"year": 1940,
"description": "Documentary footage of the dramatic bridge collapse in Washington State."
},
"Tootsie": {
"year": 1982,
"description": "Comedy starring Dustin Hoffman as an actor who disguises himself as a woman."
},
"Twelve O'Clock High": {
"year": 1949,
"description": "WWII drama about the psychological toll of bomber command leadership."
},
"Westinghouse Works, 1904": {
"year": 1904,
"description": "Early industrial documentary capturing workers at a Westinghouse factory."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 1999 National Film Registry inductees
# Source: https://www.loc.gov/loc/lcib/9912/nfb.html
NFR_1999 = {
"Civilization": {
"year": 1916,
"description": "Epic anti-war film depicting the horrors of warfare and advocating for peace."
},
"Do the Right Thing": {
"year": 1989,
"description": "Spike Lee's powerful examination of racial tensions in a Brooklyn neighborhood on the hottest day of summer."
},
"The Docks of New York": {
"year": 1928,
"description": "Josef von Sternberg's atmospheric silent film about a stoker who falls for a woman he saves from drowning."
},
"Duck Amuck": {
"year": 1953,
"description": "Chuck Jones' innovative Warner Bros. cartoon featuring Daffy Duck tormented by an unseen animator."
},
"The Emperor Jones": {
"year": 1933,
"description": "Adaptation of Eugene O'Neill's play featuring Paul Robeson in a powerful leading role."
},
"Gunga Din": {
"year": 1939,
"description": "Adventure film set in colonial India, loosely based on Rudyard Kipling's poem."
},
"In the Land of the Head-Hunters": {
"year": 1914,
"description": "Edward S. Curtis' ethnographic film documenting Kwakwaka'wakw culture and traditions."
},
"Jazz on a Summer's Day": {
"year": 1959,
"description": "Documentary capturing the 1958 Newport Jazz Festival performances."
},
"King: A Filmed Record ... Montgomery to Memphis": {
"year": 1970,
"description": "Documentary chronicling Martin Luther King Jr.'s civil rights leadership."
},
"The Kiss": {
"year": 1896,
"description": "Early Edison film depicting a couple's brief kiss, considered scandalous at the time."
},
"Kiss Me Deadly": {
"year": 1955,
"description": "Robert Aldrich's violent, apocalyptic film noir featuring detective Mike Hammer."
},
"Lambchops": {
"year": 1929,
"description": "George O'Hara comedy short film."
},
"Laura": {
"year": 1944,
"description": "Otto Preminger's stylish film noir about a detective obsessed with a murder victim."
},
"Master Hands": {
"year": 1936,
"description": "Chevrolet-sponsored industrial film documenting automobile assembly."
},
"My Man Godfrey": {
"year": 1936,
"description": "Screwball comedy about a socialite who hires a forgotten man as the family butler."
},
"Night of the Living Dead": {
"year": 1968,
"description": "George A. Romero's groundbreaking horror film that redefined the zombie genre."
},
"The Plow that Broke the Plains": {
"year": 1936,
"description": "Documentary examining the Dust Bowl's ecological and social devastation."
},
"Raiders of the Lost Ark": {
"year": 1981,
"description": "Steven Spielberg's adventure film introducing archaeologist Indiana Jones."
},
"Roman Holiday": {
"year": 1953,
"description": "Romantic comedy featuring Audrey Hepburn as a princess exploring Rome incognito."
},
"The Shop Around the Corner": {
"year": 1940,
"description": "Ernst Lubitsch's romantic comedy about pen pals who are unknowing co-workers."
},
"A Streetcar Named Desire": {
"year": 1951,
"description": "Elia Kazan's adaptation of Tennessee Williams' play featuring Marlon Brando and Vivien Leigh."
},
"The Ten Commandments": {
"year": 1956,
"description": "Cecil B. DeMille's epic retelling of the Exodus story starring Charlton Heston."
},
"Trance and Dance in Bali": {
"year": 1938,
"description": "Margaret Mead and Gregory Bateson's ethnographic documentation of Balinese rituals."
},
"The Wild Bunch": {
"year": 1969,
"description": "Sam Peckinpah's violent revisionist Western about aging outlaws in the changing West."
},
"Woman of the Year": {
"year": 1942,
"description": "First pairing of Spencer Tracy and Katharine Hepburn in a romantic comedy about marriage and careers."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2000 National Film Registry inductees with LOC descriptions
# Source: https://loc.gov/loc/lcib/0101/significant_cinema.html
NFR_2000 = {
"Apocalypse Now": {
"year": 1979,
"description": "Francis Ford Coppola's epic Vietnam War film exploring the darkness of war and human nature."
},
"Dracula": {
"year": 1931,
"description": "One of the all-time horror greats, featuring the unforgettably creepy performance of Bela Lugosi."
},
"The Fall of the House of Usher": {
"year": 1928,
"description": "Jean Epstein's atmospheric adaptation of Edgar Allan Poe's Gothic tale."
},
"Five Easy Pieces": {
"year": 1970,
"description": "Bob Rafelson's character study featuring Jack Nicholson's iconic performance."
},
"Goodfellas": {
"year": 1990,
"description": "Martin Scorsese's masterful crime epic based on the true story of mob associate Henry Hill."
},
"Koyaanisqatsi": {
"year": 1983,
"description": "Godfrey Reggio's mesmerizing collage of American vistas set to Philip Glass music."
},
"The Land Beyond the Sunset": {
"year": 1912,
"description": "Early social drama about a boy's escape from tenement life."
},
"Let's All Go to the Lobby": {
"year": 1957,
"description": "The once-omnipresent movie theater intermission trailer seen by millions."
},
"The Life of Emile Zola": {
"year": 1937,
"description": "Warner Bros. biographical film winning Best Picture Oscar for its portrayal of the French novelist."
},
"Little Caesar": {
"year": 1930,
"description": "Showcasing Edward G. Robinson's timeless performance as a small-time hood."
},
"The Living Desert": {
"year": 1953,
"description": "Walt Disney's groundbreaking True-Life Adventure documentary."
},
"Love Finds Andy Hardy": {
"year": 1938,
"description": "Perhaps the best entry in the long-running Andy Hardy series with Judy Garland and Lana Turner."
},
"Multiple Sidosis": {
"year": 1970,
"description": "Chosen to represent thousands of films produced by amateur cine clubs."
},
"Network": {
"year": 1976,
"description": "Wickedly satirical portrait of television news."
},
"Peter Pan": {
"year": 1924,
"description": "Classic children's tale in its definitive film version."
},
"Porky in Wackyland": {
"year": 1938,
"description": "Master animator Bob Clampett's zany cartoon classic."
},
"President McKinley Inauguration Footage": {
"year": 1901,
"description": "Historical documentary footage of presidential inauguration."
},
"Regeneration": {
"year": 1915,
"description": "Raoul Walsh's early feature about redemption in New York's Bowery district."
},
"Salome": {
"year": 1922,
"description": "Alla Nazimova's avant-garde adaptation of Oscar Wilde's play."
},
"Shaft": {
"year": 1971,
"description": "Gordon Parks' landmark blaxploitation film featuring Richard Roundtree as the iconic detective."
},
"Sherman's March": {
"year": 1986,
"description": "Hilarious, one-of-a-kind romantic exploration of the South."
},
"A Star Is Born": {
"year": 1954,
"description": "George Cukor's musical remake featuring Judy Garland's powerhouse performance."
},
"The Tall T": {
"year": 1957,
"description": "Budd Boetticher's lean, psychological Western starring Randolph Scott."
},
"Why We Fight": {
"year": 1943,
"description": "Films produced during World War II to explain U.S. involvement."
},
"Will Success Spoil Rock Hunter?": {
"year": 1957,
"description": "Frank Tashlin's satirical comedy about advertising and celebrity culture."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2001 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-01-184/national-film-registry-2001/2001-12-18/
NFR_2001 = {
"Abbott and Costello Meet Frankenstein": {
"year": 1948,
"description": "Classic horror-comedy pairing the comedy duo with Universal's classic monsters."
},
"All That Jazz": {
"year": 1979,
"description": "Bob Fosse's semi-autobiographical musical examining life, death, and artistic obsession."
},
"All the King's Men": {
"year": 1949,
"description": "Robert Rossen's stunning political drama based on Robert Penn Warren's novel."
},
"America, America": {
"year": 1963,
"description": "Elia Kazan's epic about a Greek youth's journey to America."
},
"Cologne: From the Diary of Ray and Esther": {
"year": 1939,
"description": "A home movie doubling as an illuminating and fascinating social documentary of a 1930s Minnesota town."
},
"Evidence of the Film": {
"year": 1913,
"description": "Early crime drama demonstrating the use of film as legal evidence."
},
"Hoosiers": {
"year": 1986,
"description": "Inspirational sports drama about a small-town Indiana basketball team."
},
"The House in the Middle": {
"year": 1954,
"description": "A 1950s-era civil defense film showing that neatness and cleanliness equal survival in the nuclear age."
},
"It": {
"year": 1927,
"description": "Clara Bow's star-making vehicle that defined the 'It Girl' phenomenon."
},
"Jam Session": {
"year": 1942,
"description": "Musical short featuring performances by jazz legends."
},
"Jaws": {
"year": 1975,
"description": "The landmark horror film that created the phenomenon known as the 'summer movie'."
},
"Manhattan": {
"year": 1979,
"description": "Woody Allen's loving, bittersweet paean to the Big Apple and New Yorkers."
},
"Marian Anderson: The Lincoln Memorial Concert": {
"year": 1939,
"description": "A documentary record of the pivotal cultural event in which a major American artist turned a racial snub into an electrifying display of what America should mean."
},
"Memphis Belle": {
"year": 1944,
"description": "William Wyler's documentary about a B-17 bomber crew's final mission."
},
"The Miracle of Morgan's Creek": {
"year": 1944,
"description": "Preston Sturges' audacious comedy pushing the boundaries of the Production Code."
},
"Miss Lulu Bett": {
"year": 1921,
"description": "Early adaptation exploring women's roles and independence."
},
"National Lampoon's Animal House": {
"year": 1978,
"description": "John Landis' influential comedy that defined the college fraternity genre."
},
"Planet of the Apes": {
"year": 1968,
"description": "A brilliant allegory combining futuristic pulp science fiction with contemporary social commentary."
},
"Rose Hobart": {
"year": 1936,
"description": "Joseph Cornell's avant-garde collage film created from footage of the 1931 film East of Borneo."
},
"Serene Velocity": {
"year": 1970,
"description": "Ernie Gehr's experimental film exploring perception and cinematic space."
},
"The Sound of Music": {
"year": 1965,
"description": "Robert Wise's beloved musical adaptation becoming one of the highest-grossing films of all time."
},
"Stormy Weather": {
"year": 1943,
"description": "Showcasing a once-in-a-lifetime cast of famed African American performers."
},
"The Tell-Tale Heart": {
"year": 1953,
"description": "A stylish Dali-esque adaptation of the Edgar Allen Poe short story, fusing the UPA Studio's unique animation with James Mason's feverishly chilling narration."
},
"The Thin Blue Line": {
"year": 1988,
"description": "Errol Morris' groundbreaking documentary that helped free a wrongly convicted man."
},
"The Thing from Another World": {
"year": 1951,
"description": "Classic science fiction thriller directed by Christian Nyby and produced by Howard Hawks."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2002 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-02-176/librarian-of-congress-adds-25-films-to-national-film-registry/2002-12-17/
NFR_2002 = {
"Alien": {
"year": 1979,
"description": "The influential, spine-tingling sci-fi film where one learns that 'in space no one can hear you scream.'"
},
"All My Babies": {
"year": 1953,
"description": "George Stoney's landmark educational film used to educate midwives in Georgia and throughout the South."
},
"The Bad and the Beautiful": {
"year": 1952,
"description": "Featuring Kirk Douglas as a ruthless film producer in one of Hollywood's most memorable examinations of its culture."
},
"Beauty and the Beast": {
"year": 1991,
"description": "Disney's groundbreaking animated musical that revitalized the animation genre."
},
"The Black Stallion": {
"year": 1979,
"description": "Carroll Ballard's evocative and visually stunning children's classic."
},
"Boyz N the Hood": {
"year": 1991,
"description": "John Singleton's powerful debut film exploring life in South Central Los Angeles."
},
"Theodore Case Sound Tests: Gus Visser and His Singing Duck": {
"year": 1925,
"description": "One of two films illustrating technical innovation in cinema, in addition to being highly entertaining."
},
"The Endless Summer": {
"year": 1966,
"description": "Bruce Brown's droll documentary of two surfers and their around-the-world quest for the Perfect Wave."
},
"From Here to Eternity": {
"year": 1953,
"description": "Fred Zinnemann's adaptation of James Jones' novel about Army life in Hawaii before Pearl Harbor."
},
"From Stump to Ship": {
"year": 1930,
"description": "A once-forgotten 1930 logging film that has become a touchstone of cultural identity for Maine residents."
},
"Fuji": {
"year": 1974,
"description": "Robert Breer's avant-garde replication blending rotoscope, live-action imagery and line drawing of a train ride."
},
"In the Heat of the Night": {
"year": 1967,
"description": "The electrifying 1967 social drama where Sidney Poitier as 'Mister Tibbs' solves a crime his way."
},
"Lady Windermere's Fan": {
"year": 1925,
"description": "Ernst Lubitsch's sophisticated silent adaptation of Oscar Wilde's play of manners."
},
"Melody Ranch": {
"year": 1940,
"description": "One of the best vehicles for Gene Autry as the first singing cowboy."
},
"The Pearl": {
"year": 1948,
"description": "A landmark among English-language Mexican classics released for Hispanic audiences in the United States, featuring breathtaking cinematography by Gabriel Figueroa."
},
"Punch Drunks": {
"year": 1934,
"description": "Classic Three Stooges comedy short."
},
"Sabrina": {
"year": 1954,
"description": "Billy Wilder's romantic comedy featuring Audrey Hepburn, Humphrey Bogart, and William Holden."
},
"Star Theatre": {
"year": 1901,
"description": "A dazzling 1901 time-lapse special effects film showing demolition of this New York City theater."
},
"Stranger Than Paradise": {
"year": 1984,
"description": "Jim Jarmusch's minimalist independent film that became a landmark of American indie cinema."
},
"This Is Cinerama": {
"year": 1952,
"description": "One of two films illustrating technical innovation in cinema, in addition to being highly entertaining."
},
"This Is Spinal Tap": {
"year": 1984,
"description": "Rob Reiner's deft 'mockumentary' parody of a fictitious, touring heavy metal band."
},
"Through Navajo Eyes": {
"year": 1966,
"description": "A pioneering series of anthropological films."
},
"Why Man Creates": {
"year": 1968,
"description": "An animated paean to creativity by legendary film title sequence designer Saul Bass."
},
"Wild and Wooly": {
"year": 1917,
"description": "One of the films which created Douglas Fairbanks' film persona, showcasing his personal odyssey."
},
"Wild River": {
"year": 1960,
"description": "Elia Kazan's drama about the Tennessee Valley Authority and resistance to change."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2003 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-03-211/25-films-added-to-national-film-registry/2003-12-16
NFR_2003 = {
"Antonia: A Portrait of the Woman": {
"year": 1974,
"description": "Documentary on musician-conductor Antonia Brica's life and struggles to become a symphony director despite gender discrimination."
},
"Atlantic City": {
"year": 1980,
"description": "Louis Malle's drama about aging Atlantic City and its transformation, featuring Burt Lancaster and Susan Sarandon."
},
"Butch Cassidy and the Sundance Kid": {
"year": 1969,
"description": "One of the most popular American films of all time with critically acclaimed performances by Paul Newman and Robert Redford."
},
"The Chechahcos": {
"year": 1924,
"description": "The first feature film produced in Alaska featuring spectacular location footage of the lonely and unfathomable Alaskan wilderness, frenzied dogsled pursuits and life-and-death struggles on the glaciers."
},
"Dickson Experimental Sound Film": {
"year": 1894,
"description": "A very early attempt by W.K.L. Dickson of the Thomas Edison Company to combine film image and sound."
},
"Film Portrait": {
"year": 1970,
"description": "Avant-garde exploration of memory and family by Jerome Hill, a railroad tycoon descendant."
},
"Fox Movietone News: Jenkins Orphanage Band": {
"year": 1928,
"description": "Culturally important newsreel footage of the renowned African American touring musical group of Charleston, S.C."
},
"Gold Diggers of 1933": {
"year": 1933,
"description": "Arguably the definitive Depression-era musical, rife with visually stunning Busby Berkeley productions featuring elaborate choreography and social commentary on unemployed veterans."
},
"The Hunters": {
"year": 1957,
"description": "Seminal anthropological film chronicling a giraffe hunt by Kalahari Desert tribesmen."
},
"Matrimony's Speed Limit": {
"year": 1913,
"description": "Work by pioneering woman filmmaker Alice Guy Blache depicting a man financially compelled to marry by noon, thanks to some sneaky encouragement."
},
"Medium Cool": {
"year": 1969,
"description": "Haskell Wexler's groundbreaking film blending fiction and documentary during the 1968 Democratic National Convention."
},
"National Velvet": {
"year": 1944,
"description": "Enduring family film classic with Elizabeth Taylor as a young girl whose wild ambition is to have her horse run in the Grand National Steeplechase."
},
"Naughty Marietta": {
"year": 1935,
"description": "Cinema's first pairing of the electrifying singing duo Jeanette MacDonald and Nelson Eddy, who captivated audiences with songs."
},
"Nostalgia": {
"year": 1971,
"description": "Avant-garde exploration of memory and family by Hollis Frampton."
},
"One Froggy Evening": {
"year": 1956,
"description": "Classic Chuck Jones creation features crooning frog Michigan J. Frog, who drives his owner insane by singing only in private, but never in public."
},
"Patton": {
"year": 1970,
"description": "Biographical war film about General George S. Patton featuring George C. Scott's iconic performance."
},
"Princess Nicotine; or The Smoke Fairy": {
"year": 1909,
"description": "A dazzling special effects landmark from 1909, where fairies bedevil one man's attempt to light his pipe for a relaxing smoke."
},
"Show People": {
"year": 1928,
"description": "Classic silent comedy that showcases actress Marion Davies' deft touch for light comedy."
},
"The Son of the Sheik": {
"year": 1926,
"description": "Film featuring Rudolph Valentino in this slightly tongue-in-cheek adventure-romance released before his death."
},
"Tarzan and His Mate": {
"year": 1934,
"description": "Rather steamy pre-Production Code Tarzan film, generally considered the finest in the series, with Tarzan and Jane battling poachers."
},
"Tin Toy": {
"year": 1988,
"description": "Early innovative short animation from Pixar Studios, which revolutionized American animation."
},
"The Wedding March": {
"year": 1928,
"description": "Erich von Stroheim's lavish romantic drama set in pre-WWI Vienna."
},
"White Heat": {
"year": 1949,
"description": "Pulsating gangster film with James Cagney as a mother-obsessed, psychopathic gangster with an iconic ending."
},
"Young Frankenstein": {
"year": 1974,
"description": "Mel Brooks' affectionate parody of classic horror films, particularly the Frankenstein series."
},
"Young Mr. Lincoln": {
"year": 1939,
"description": "John Ford's biographical drama about Abraham Lincoln's early years as a lawyer."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2004 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-04-215/films-added-to-national-film-registry-for-2004/2004-12-28/
NFR_2004 = {
"Ben-Hur": {
"year": 1959,
"description": "Epic historical drama and one of the most celebrated films in cinema history."
},
"The Blue Bird": {
"year": 1918,
"description": "Maurice Tourneur's beautiful expressionist adaptation of Maurice Maeterlink's play remains one of the most aesthetically pleasing films."
},
"A Bronx Morning": {
"year": 1931,
"description": "Part documentary and part avant-garde, this renowned city symphony was filmed by Jay Leyda when he was 21."
},
"Clash of the Wolves": {
"year": 1925,
"description": "German shepherd Rin-Tin-Tin was rescued during WWI and became a major 1920s Hollywood star. The film shows the resourceful dog rescuing protagonists and thwarting villains."
},
"The Court Jester": {
"year": 1956,
"description": "In this delightful adventure parody, famed comedian Danny Kaye plays a peasant leader who restores the rightful heir to the throne of England."
},
"D.O.A.": {
"year": 1950,
"description": "This pulsating film noir tells the story of a man who has been poisoned and tries to find his killer during his remaining few days."
},
"Daughters of the Dust": {
"year": 1991,
"description": "This is the first feature-length film by an African-American woman to receive a wide theatrical release. Julie Dash eschews traditional narrative forms."
},
"Duck and Cover": {
"year": 1951,
"description": "This landmark civil defense film was seen by millions of schoolchildren in the 1950s. As explained by Bert the Turtle, to survive an atomic attack you must 'duck and cover'."
},
"Empire": {
"year": 1964,
"description": "Andy Warhol's grueling, eight-hour, one-shot stationary camera take of the Empire State Building shakes the conventions of cinema."
},
"Enter the Dragon": {
"year": 1973,
"description": "Martial arts legend Bruce Lee burst onto the American scene with this pulsating action flick, climaxed with the dazzling 'Hall of Mirrors' sequence."
},
"Eraserhead": {
"year": 1978,
"description": "A visually stunning portrayal of a man facing fatherhood in a nightmarish industrial world, David Lynch's first feature-length film."
},
"Garlic Is As Good As Ten Mothers": {
"year": 1980,
"description": "Les Blank's hilarious and affectionate homage to 'The Stinking Rose' delights slightly wacky devotees or alliumophiles."
},
"Going My Way": {
"year": 1944,
"description": "This sentimental film favorite features Bing Crosby as a kindhearted Catholic priest whose upbeat, infectious personality rejuvenates his congregation."
},
"Jailhouse Rock": {
"year": 1957,
"description": "This film showcasing Elvis Presley is in the ultimate rebel mode. The edginess reflected in this film was toned down in the singer's later movies."
},
"Kannapolis, NC": {
"year": 1941,
"description": "This example of a 'town portrait' was chosen to honor itinerant filmmakers who made films of ordinary people on typical days during the 1930s and 1940s."
},
"Lady Helen's Escapade": {
"year": 1909,
"description": "This sprightly short comedy stars actress Florence Lawrence ('The Biograph Girl') who became the first true star in American cinema."
},
"The Nutty Professor": {
"year": 1963,
"description": "This is considered comic genius Jerry Lewis' greatest film."
},
"OffOn": {
"year": 1968,
"description": "This landmark work from California filmmaker Scott Bartlett is the first avant-garde work to fully marry video with film."
},
"Popeye the Sailor Meets Sindbad the Sailor": {
"year": 1936,
"description": "Wildly popular during the 1930s, Popeye's impact was matched only by Mickey Mouse. This classic by renowned animators Max and Dave Fleischer features lush three-dimensional sets, Technicolor."
},
"Pups Is Pups": {
"year": 1930,
"description": "One of the finest comedy shorts from the beloved Our Gang series, this film enchanted audiences from 1922 to 1944."
},
"Schindler's List": {
"year": 1993,
"description": "Steven Spielberg's powerful Holocaust drama recognized as one of cinema's most important historical films."
},
"Seven Brides for Seven Brothers": {
"year": 1954,
"description": "Classic MGM musical featuring innovative choreography and memorable songs."
},
"Swing Time": {
"year": 1936,
"description": "Legendary Ginger Rogers and Fred Astaire musical features magical dancing set to six wonderful Jerome Kern tunes."
},
"There It Is": {
"year": 1928,
"description": "One of the increasingly famous Charley Bowers surrealist shorts, this film combines live action with stop-motion object animation."
},
"Unforgiven": {
"year": 1992,
"description": "Clint Eastwood's revisionist Western that deconstructs the mythology of the Old West."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2005 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-05-262/librarian-of-congress-adds-25-films-to-national-film-registry-2/2005-12-20/
NFR_2005 = {
"Baby Face": {
"year": 1933,
"description": "Pre-Code melodrama featuring Barbara Stanwyck navigating the corporate world through charm and manipulation, exemplifying the audacious films made before the Production Code's 1934 imposition."
},
"The Buffalo Creek Flood: An Act of Man": {
"year": 1975,
"description": "Documentary by Appalshop examining the 1972 coal dam disaster in West Virginia and resulting corporate and governmental accountability."
},
"The Cameraman": {
"year": 1928,
"description": "Buster Keaton's final comedy classic about an aspiring newsreel cameraman pursuing romance through elaborate sight gags."
},
"Commandment Keeper Church, Beaufort South Carolina, May 1940": {
"year": 1940,
"description": "Ethnographic film with synchronized sound recordings of religious services in a South Carolina Gullah community, directed by Zora Neale Hurston and others."
},
"Cool Hand Luke": {
"year": 1967,
"description": "Paul Newman stars as an indomitable chain-gang prisoner resisting authority in this antihero classic."
},
"Fast Times at Ridgemont High": {
"year": 1982,
"description": "Teen comedy balancing adolescent realism with humor, featuring ensemble cast including Sean Penn as surfer character Jeff Spicoli."
},
"The French Connection": {
"year": 1971,
"description": "Crime thriller featuring Gene Hackman's breakthrough performance and innovative New York City cinematography."
},
"Giant": {
"year": 1956,
"description": "Epic three-hour Texas saga with Elizabeth Taylor, Rock Hudson, and James Dean adapting Edna Ferber's novel."
},
"H2O": {
"year": 1929,
"description": "Experimental cinematic tone poem by Ralph Steiner using water imagery and editing techniques for visual effect."
},
"Hands Up": {
"year": 1926,
"description": "Civil War comedy with Raymond Griffith as a Confederate spy balancing humor with romantic appeal."
},
"Hoop Dreams": {
"year": 1994,
"description": "Multiyear documentary following inner-city Chicago basketball players seeking college scholarships and examining systemic inequality."
},
"House of Usher": {
"year": 1960,
"description": "Horror adaptation featuring Vincent Price, establishing new standards for screen horror through elegant literary approach."
},
"Imitation of Life": {
"year": 1934,
"description": "Woman's picture pioneering dignified treatment of African-American characters in Hollywood through partnership narrative."
},
"Jeffries-Johnson World's Championship Boxing Contest": {
"year": 1910,
"description": "Documentary recording the July 4 heavyweight championship bout, representing a signal moment in American race relations."
},
"Making of an American": {
"year": 1920,
"description": "Connecticut-produced public education film promoting English language learning among immigrant communities."
},
"Miracle on 34th Street": {
"year": 1947,
"description": "Fantasy about defending Santa Claus's authenticity against commercial pressures."
},
"Mom and Dad": {
"year": 1944,
"description": "Sex-hygiene exploitation film becoming the third highest-grossing 1940s film despite modest production values."
},
"The Music Man": {
"year": 1962,
"description": "Musical adaptation of Meredith Willson's Iowa-centered Americana celebrating small-town American values."
},
"Power of the Press": {
"year": 1928,
"description": "Newspaper thriller with Douglas Fairbanks Jr. investigating corruption and political malfeasance."
},
"A Raisin in the Sun": {
"year": 1961,
"description": "Civil rights era drama adapting Lorraine Hansberry's play with Sidney Poitier and Ruby Dee."
},
"The Rocky Horror Picture Show": {
"year": 1975,
"description": "Cult musical revolutionizing audience participation during film screenings."
},
"San Francisco Earthquake and Fire, April 18, 1906": {
"year": 1906,
"description": "Documentary capturing footage of the catastrophic natural disaster."
},
"The Sting": {
"year": 1973,
"description": "Depression-era con-artist film starring Newman and Redford, reviving Scott Joplin's ragtime music popularity."
},
"A Time for Burning": {
"year": 1966,
"description": "Civil rights documentary chronicling a Lutheran minister's unsuccessful church integration efforts."
},
"Toy Story": {
"year": 1995,
"description": "First fully computer-animated feature film revolutionizing animation technology and delivery methods."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2006 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-06-234/films-added-to-national-film-registry-for-2006/2006-12-27/
NFR_2006 = {
"Applause": {
"year": 1929,
"description": "This early sound-era masterpiece was the first film of both stage/director Rouben Mamoulian and cabaret/star Helen Morgan."
},
"The Big Trail": {
"year": 1930,
"description": "Director Raoul Walsh's Western featured John Wayne in an early role, using the experimental Grandeur wide-screen process for its Oregon Trail narrative."
},
"Blazing Saddles": {
"year": 1974,
"description": "This riotously funny, raunchy, no-holds-barred Western spoof by Mel Brooks is universally considered one of the 25 funniest American films."
},
"The Curse of Quon Gwon": {
"year": 1916,
"description": "The earliest known Chinese-American feature and one of the first films directed by a woman, recently restored by the Academy Film Archive."
},
"Daughter of Shanghai": {
"year": 1937,
"description": "Features Anna May Wong as she uncovers the smuggling of illegal aliens through San Francisco's Chinatown, cooperating with costar Philip Ahn."
},
"Drums of Winter [Uksuum Cauyai]": {
"year": 1988,
"description": "Award-winning documentary exploring the rare dance language and culture of the Yup'ik Eskimo people in Emmonak, Alaska."
},
"Early Abstractions #1-5, 7, 10": {
"year": 1939,
"description": "Harry Smith made his mark in many fields as a groundbreaking avant-garde animator whose work used batik, collage and optical printing."
},
"Fargo": {
"year": 1996,
"description": "The Coen Brothers' original black comic spin on murder featuring Frances McDormand and William Macy in deadpan performances."
},
"Flesh and the Devil": {
"year": 1927,
"description": "The first on-screen pairing of silent superstars John Gilbert and Greta Garbo, directed by Clarence Brown."
},
"Groundhog Day": {
"year": 1993,
"description": "A clever comedy with a philosophical edge where Bill Murray relives the same day repeatedly, achieving personal redemption."
},
"Halloween": {
"year": 1978,
"description": "John Carpenter's first commercially successful film that ushered in the dawn of the slasher film through tension rather than gore."
},
"In the Street": {
"year": 1948,
"description": "Lyrical, slice-of-life documentary by Helen Levitt, James Agee, and Janis Loeb capturing energy-filled streets of East Harlem."
},
"The Last Command": {
"year": 1928,
"description": "Josef von Sternberg's drama features Emil Jannings, who is reduced to the scraps of 'extra' roles in Hollywood following Russian exile."
},
"Notorious": {
"year": 1946,
"description": "Arguably Alfred Hitchcock's best black-and-white American film featuring Ingrid Bergman, Claude Rains, and Cary Grant in a Gothic spy narrative."
},
"Red Dust": {
"year": 1932,
"description": "Steamy pre-Production Code melodrama pairing Clark Gable and Jean Harlow in a Far East plantation setting with memorable chemistry."
},
"Reminiscences of a Journey to Lithuania": {
"year": 1971,
"description": "Jonas Mekas' elegiac diary film of a trip to his Lithuanian birthplace, representing avant-garde experimental cinema."
},
"Rocky": {
"year": 1976,
"description": "Stirring tale of a million-to-one-shot underdog written by Sylvester Stallone, who also starred, becoming a top-grossing cultural sensation."
},
"sex, lies and videotape": {
"year": 1989,
"description": "Steven Soderbergh explores personal relationships with low-key style that launched the independent film renaissance of subsequent decades."
},
"Siege": {
"year": 1940,
"description": "Julien Bryan's documentary captures the dreadful brutality of war through unique Warsaw footage documenting the German bombardment and blitzkrieg."
},
"St. Louis Blues": {
"year": 1929,
"description": "Features the only film recording of Bessie Smith, 'Queen of the Blues,' backed by African-American artists in a two-reel musical short."
},
"The T.A.M.I. Show": {
"year": 1964,
"description": "Quite possibly the greatest rock and rhythm-and-blues concert on film featuring the Rolling Stones and James Brown's legendary performances."
},
"Tess of the Storm Country": {
"year": 1914,
"description": "The feature film that made Canadian-born Mary Pickford a national icon and international celebrity in early cinema."
},
"Think of Me First as a Person": {
"year": 1960,
"description": "Astonishing discovery depicting a father's loving portrait of his son with Down syndrome, representing American amateur filmmaking craftsmanship."
},
"A Time Out of War": {
"year": 1954,
"description": "Easily in the pantheon of best student films ever produced, winning the Oscar for best short film about a temporary Civil War truce."
},
"Traffic in Souls": {
"year": 1913,
"description": "Sensational exposé of 'white slavery' at six reels, capturing methods used to entrap working women and immigrants through location shooting."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2007 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-07-254/librarian-of-congress-announces-2007-film-registry/2007-12-27/
NFR_2007 = {
"Back to the Future": {
"year": 1985,
"description": "Before 'Beowulf' or 'The Polar Express,' writer/director Robert Zemeckis explored the possibilities of special effects with the 1985 box-office smash 'Back to the Future.' The film follows Marty McFly, accidentally transported to 1955, who must return home while helping his father become a man and protecting his family's existence."
},
"Bullitt": {
"year": 1968,
"description": "A crime drama shot on location in San Francisco, renowned for its exhilarating 11-minute car chase, arguably the finest in cinema history. Steve McQueen stars as a cop investigating a murder while navigating mob pressures and corrupt officials."
},
"Close Encounters of the Third Kind": {
"year": 1977,
"description": "Steven Spielberg's intelligent science fiction film featuring Devil's Tower as its iconic setting. The work explores humanity's quest to contact extraterrestrial life through visual and musical communication."
},
"Dance, Girl, Dance": {
"year": 1940,
"description": "Dorothy Arzner's exploration of women in show business, following two performers pursuing careers in burlesque and ballet. The film examines tensions between art and commerce and feminist identity within entertainment."
},
"Dances With Wolves": {
"year": 1990,
"description": "Kevin Costner's personal project about a cavalry soldier's spiritual transformation through contact with a Sioux tribe. The film presents one of the more sympathetic portraits of Native-American life in American cinema."
},
"Days of Heaven": {
"year": 1978,
"description": "Described as one of the most beautiful films ever made, featuring sublime cinematography across Texas Panhandle wheat fields. The narrative depicts a doomed love triangle set within an impressionistic visual landscape."
},
"Glimpse of the Garden": {
"year": 1957,
"description": "Marie Menken's avant-garde short presenting a serendipitous visual tour of a flower garden set to a soundtrack of bird calls, representing accessible experimental filmmaking."
},
"Grand Hotel": {
"year": 1932,
"description": "Edmund Goulding's ensemble piece featuring MGM stars including Greta Garbo and Joan Crawford. The film represents the first use of the all-star formula in cinema history."
},
"The House I Live In": {
"year": 1945,
"description": "Mervyn LeRoy's short film featuring Frank Sinatra advocating religious tolerance. The work presents America's diverse cultural mosaic through Sinatra's performance of the title song."
},
"In a Lonely Place": {
"year": 1950,
"description": "Nicholas Ray's scathing Hollywood satire starring Humphrey Bogart as a screenwriter suspected of murder. The film explores the psychological deterioration of an unstable artist through noir-themed storytelling."
},
"The Man Who Shot Liberty Valance": {
"year": 1962,
"description": "John Ford's final Western masterpiece examining the triumph of civilization over frontier wildness. The film's concluding aphorism—'When the legend becomes fact, print the legend'—entered the American lexicon."
},
"Mighty Like a Moose": {
"year": 1926,
"description": "Charley Chase comedy short directed by Leo McCarey. The film presents a story of homely people whose cosmetic surgeries lead to mistaken-identity comedic complications."
},
"The Naked City": {
"year": 1948,
"description": "A groundbreaking crime procedural filming on actual New York City locations rather than studio sets. It introduced a new style of film-making combining documentary realism with dramatic storytelling."
},
"Now, Voyager": {
"year": 1942,
"description": "A resonant woman's picture featuring Bette Davis transforming from a dowdy spinster into an independent, confident woman through psychiatric treatment and romantic adventure at sea."
},
"Oklahoma!": {
"year": 1955,
"description": "A Rodgers and Hammerstein musical adaptation featuring breathtaking Technicolor vistas and stereo sound. The film depicts turn-of-the-century frontier life with Western genre conventions."
},
"Our Day": {
"year": 1938,
"description": "Wallace Kelly's amateur 16mm home movie documenting his Kentucky household. This silent film demonstrates creative editing, lighting and camera techniques comparable to what professionals were doing."
},
"Peege": {
"year": 1972,
"description": "Randal Kleiser's student film depicting family members visiting their blind, dying grandmother. The grandson's emotional connection with Peege creates a renowned, extremely moving narrative experience."
},
"The Sex Life of the Polyp": {
"year": 1928,
"description": "Robert Benchley's humorous short featuring the writer as a daft doctor delivering a droll but earnest lecture on polyp reproductive habits to a women's club."
},
"The Strong Man": {
"year": 1926,
"description": "Harry Langdon silent comedy featuring the actor as a meek man loving a blind woman. This film predated similar romantic narratives by placing Langdon among The Four Silent Clowns alongside Chaplin and Keaton."
},
"Three Little Pigs": {
"year": 1933,
"description": "Walt Disney animated classic featuring personality-driven character animation. The title song 'Who's Afraid of the Big Bad Wolf' became a Depression-era anthem."
},
"Tol'able David": {
"year": 1921,
"description": "Henry King's coming-of-age drama about a youth overcoming bullying neighbors while delivering mail in rural Virginia. The film influenced Russian filmmakers of the 1920s through its innovative shot composition."
},
"Tom, Tom the Piper's Son": {
"year": 1969,
"description": "Ken Jacobs's avant-garde masterpiece re-examining an early cinema fairy tale short. This structuralist film explores cinematic parameters through manipulation of motion and light."
},
"12 Angry Men": {
"year": 1957,
"description": "Sidney Lumet's adaptation of Reginald Rose's teleplay about jury deliberation in a murder trial. The film's spare, claustrophobic style dramatizes one juror's resistance to peer pressure."
},
"The Women": {
"year": 1939,
"description": "George Cukor's ensemble comedy featuring multiple female leads without male characters. Based on Clare Boothe Luce's play, it explores women's choices between independence and romantic relationships."
},
"Wuthering Heights": {
"year": 1939,
"description": "William Wyler's adaptation of Emily Brontë's novel featuring Laurence Olivier and Merle Oberon. Cinematographer Gregg Toland's deep-focus cinematography deftly creates the moody, ethereal atmosphere of haunted love."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2008 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-08-237/2008-entries-to-national-film-registry-announced/2008-12-30
NFR_2008 = {
"The Asphalt Jungle": {
"year": 1950,
"description": "John Huston's brilliant crime drama contains the recipe for a meticulously planned robbery, but the cast of criminal characters features one too many bad apples."
},
"Deliverance": {
"year": 1972,
"description": "Four Atlanta professionals head for a weekend canoe trip — and instead meet up with two of the more memorable villains in film history."
},
"Disneyland Dream": {
"year": 1956,
"description": "The Barstow family films a memorable home movie of their trip to Disneyland as part of a contest, capturing a fantastic historical snapshot of Hollywood, Beverly Hills, Catalina Island, Knott's Berry Farm, Universal Studios and Disneyland in mid-1956."
},
"A Face in the Crowd": {
"year": 1957,
"description": "A dark look at the way sudden fame and power can corrupt featuring Andy Griffith in his film debut as a rural drunk, drifter and country singer who becomes an overnight success."
},
"Flower Drum Song": {
"year": 1961,
"description": "This film version of the Rodgers and Hammerstein musical marked the first Hollywood studio film featuring performances by a mostly Asian cast, a break from past practice."
},
"Foolish Wives": {
"year": 1922,
"description": "Director Erich von Stroheim's film tells the story of a criminal who passes himself off as a Russian count in order to seduce women of society and steal their money."
},
"Free Radicals": {
"year": 1979,
"description": "For his four-minute work, Lye made scratches directly into the film stock. These scratches became 'figures of motion' that appear in the finished film."
},
"Hallelujah": {
"year": 1929,
"description": "The all-black-cast film represents among the very first indisputable masterpieces of the sound era exploring themes of religion, sensuality and family stability."
},
"In Cold Blood": {
"year": 1967,
"description": "With an unsparing neo-realism, director Richard Brooks adapted Capote's novel, focusing on the motivations, backgrounds, and relationship of the killers."
},
"The Invisible Man": {
"year": 1933,
"description": "Director James Whale brought a dazzling stylishness to what were essentially low-budget horror films with sophisticated special effects."
},
"Johnny Guitar": {
"year": 1954,
"description": "Often described as the one of the stranger, kinkier Westerns of all time featuring women as the main stars (Joan Crawford and Mercedes McCambridge)."
},
"The Killers": {
"year": 1946,
"description": "Director Robert Siodmak took the original Ernest Hemingway short story as the film's opening point and developed it with an elaborate series of flashbacks."
},
"The March": {
"year": 1964,
"description": "Documentary examining the 1963 Civil Rights March on Washington from the ground-level and focusing on the idealistic passion, joy and synergy of the crowds."
},
"No Lies": {
"year": 1973,
"description": "Mitchell Block's 16-minute New York University student film dealing with the way rape victims are treated when they seek professional help for sexual assault."
},
"On the Bowery": {
"year": 1957,
"description": "Lionel Rogosin's acclaimed, unrelenting docudrama about the infamous New York City zone known as the Bowery focusing on three of its alcoholic skid row denizens."
},
"One Week": {
"year": 1920,
"description": "The first publicly released two-reel short film starring Buster Keaton featuring hilarious comic, often surrealist, sequences chronicling the ill-fated attempts of a newlywed couple."
},
"The Pawnbroker": {
"year": 1965,
"description": "The first Hollywood film to depict in a realistic, psychologically probing manner the trauma of a Holocaust survivor, a subject previously taboo."
},
"The Perils of Pauline": {
"year": 1914,
"description": "Among the very first American movie serials. Produced in 20 episodes featuring Pearl White as a young and wealthy heiress whose ingenuity, self-reliance and pluck enable her to regularly outwit a guardian."
},
"Sergeant York": {
"year": 1941,
"description": "Gary Cooper, in one of his favorite roles, won his first Oscar for his dead-on portrayal of Tennessee pacifist Sgt. Alvin York in a stirring film."
},
"The 7th Voyage of Sinbad": {
"year": 1958,
"description": "Special-effects master Ray Harryhausen provides the hero with fantastic antagonists, including a giant cyclops, fire-breathing dragons, and a sword-wielding animated skeleton."
},
"So's Your Old Man": {
"year": 1926,
"description": "W.C. Fields starred in this silent comedy where Fields plays inventor Samuel Bisbee, who is considered a vulgarian by the town's elite."
},
"George Stevens World War II Footage": {
"year": 1943,
"description": "Director George Stevens shot many hours of footage chronicling D-Day and the liberation of Paris serving as an essential visual record of World War II."
},
"The Terminator": {
"year": 1984,
"description": "Low-budget, but made with heart, verve, imagination, and superb Stan Winston special effects featuring Arnold Schwarzenegger's star-making performance as the mass-killing cyborg."
},
"Water and Power": {
"year": 1989,
"description": "Pat O'Neill's influential experimental work presenting a landscape film that became animated by the beginnings of human stories examining water and urban-rural dynamics."
},
"White Fawn's Devotion": {
"year": 1910,
"description": "Film by James Young Deer, now recognized as the first documented movie director of Native American ancestry working in collaboration with his wife, actress Princess Red Wing."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2009 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-09-250/2009-selections-to-the-national-film-registry-announced/2009-12-30/
NFR_2009 = {
"Dog Day Afternoon": {
"year": 1975,
"description": "Director Sidney Lumet balances suspense, violence and humor in Frank Pierson's Oscar-winning adaptation of a true-life bank robbery turned media circus."
},
"The Exiles": {
"year": 1961,
"description": "Filmmaker Kent MacKenzie captures the raw essence of a group of 20-something Native Americans who left reservation life in the 1950s to live among the decayed Victorian mansions of Los Angeles' Bunker Hill district."
},
"Heroes All": {
"year": 1920,
"description": "The Red Cross Bureau of Pictures produced more than 100 films, including 'Heroes All,' from 1917-1921, which are invaluable historical and visual records of the era."
},
"Hot Dogs for Gauguin": {
"year": 1972,
"description": "This hilarious New York University student film was written and directed by Martin Brest who later went on to direct 'Beverly Hills Cop,' 'Scent of a Woman' and 'Meet Joe Black.'"
},
"The Incredible Shrinking Man": {
"year": 1957,
"description": "This sci-fi classic about a man who starts to shrink after being exposed to a strange cloud while on vacation is notable for its intelligent script and imaginative special effects."
},
"Jezebel": {
"year": 1938,
"description": "Bette Davis won her second Academy Award for this William Wyler-directed classic. Cast to perfection as a tempestuous southern belle, Davis' head-strong heroine must eventually learn self-sacrifice."
},
"The Jungle": {
"year": 1967,
"description": "A group of African-American teenage boys in Philadelphia made this hybrid documentary/dramatization of their lives in the 12th and Oxford Street gang."
},
"The Lead Shoes": {
"year": 1949,
"description": "A dreamlike trance showing the unconscious acts of a disturbed mind through a distorted lens and other abstract visual techniques, by independent filmmaker Sidney Peterson."
},
"Little Nemo": {
"year": 1911,
"description": "This classic work, a mix of live action and animation, was adapted from Winsor McCay's famed 1905 comic strip 'Little Nemo in Slumberland.'"
},
"Mabel's Blunder": {
"year": 1914,
"description": "Mabel Normand, who wrote, directed and starred in 'Mabel's Blunder,' was the most successful of the early silent screen comediennes."
},
"The Mark of Zorro": {
"year": 1940,
"description": "Under Rouben Mamoulian's inventive direction, Tyrone Power plays Don Diego, son of a 19th-century Los Angeles governor who has been unseated by a mercenary despot."
},
"Mrs. Miniver": {
"year": 1942,
"description": "This remarkably touching wartime melodrama pictorializes the classic British stiff upper lip and the courage of a middle-class English family amid the chaos of air raids."
},
"The Muppet Movie": {
"year": 1979,
"description": "Muppet creators Jim Henson and Frank Oz immersed their characters into a well-crafted combination of musical comedy and fantasy adventure."
},
"Once Upon a Time in the West": {
"year": 1968,
"description": "Director Sergio Leone's operatic visual homage to the American Western legend is a chilling tale of vengeance set against the backdrop of the coming of the railroad."
},
"Pillow Talk": {
"year": 1959,
"description": "The first film to co-star Doris Day and Rock Hudson, remains one of the screen's most definitive, influential and timeless romantic comedies."
},
"Precious Images": {
"year": 1986,
"description": "Chuck Workman's legendary compilation film to commemorate the 50th anniversary of the Directors Guild of America is also a dazzling celebration of American cinema."
},
"Quasi at the Quackadero": {
"year": 1975,
"description": "Sally Cruikshank's wildly imaginative tale of odd creatures visiting a psychedelic amusement park careens creatively from strange to truly wacky scenes."
},
"The Red Book": {
"year": 1994,
"description": "Janie Geiser's work is known for its ambiguity, explorations of memory and emotional states and exceptional design in animated form."
},
"The Revenge of Pancho Villa": {
"year": 1930,
"description": "This extraordinary compilation film was made by the Padilla family in El Paso, Texas, from dozens of fact-based and fictional films about Pancho Villa."
},
"Scratch and Crow": {
"year": 1995,
"description": "Helen Hill's student film made at the California Institute of the Arts is filled with vivid color and a light sense of humor."
},
"Stark Love": {
"year": 1927,
"description": "A beautifully photographed mix of lyrical anthropology and action melodrama from director Karl Brown, cast exclusively with amateur actors and filmed in the Great Smoky Mountains."
},
"The Story of G.I. Joe": {
"year": 1945,
"description": "William Wellman's gritty portrayal of the realities of war was based on the newspaper columns of war correspondent Ernie Pyle."
},
"A Study in Reds": {
"year": 1932,
"description": "This polished amateur film by Miriam Bennett spoofs women's clubs and the Soviet menace in the 1930s through satirical narrative."
},
"Thriller": {
"year": 1983,
"description": "The most famous music video of all time caused such a buzz it was released theatrically in 35mm, directed by filmmaker John Landis."
},
"Under Western Stars": {
"year": 1938,
"description": "This film turned Roy Rogers into a movie star, depicting a populist cowboy/congressman elected to champion small ranchers' water rights during the Dust Bowl."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2010 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-10-273/2010-national-film-registry-announced/2010-12-28/
NFR_2010 = {
"Airplane!": {
"year": 1980,
"description": "Emerged in 1980 as a sharply perceptive parody of the big-budget disaster films that dominated Hollywood during the 1970s."
},
"All the President's Men": {
"year": 1976,
"description": "A rare example of a best-selling book that was transformed into a hit theatrical film and a cultural phenomenon."
},
"The Bargain": {
"year": 1914,
"description": "William S. Hart's first film that made him a star, selected for Hart's charisma and the film's authentic portrayal of the Western genre."
},
"Cry of Jazz": {
"year": 1959,
"description": "Now recognized as an early and influential example of African-American independent filmmaking, a 34-minute short exploring connections between Black American life and jazz music."
},
"Electronic Labyrinth: THX 1138 4EB": {
"year": 1967,
"description": "A 15-minute film produced by George Lucas while a student at USC that won the 1968 National Student Film Festival drama award."
},
"The Empire Strikes Back": {
"year": 1980,
"description": "The much anticipated continuation of the Star Wars saga that sustained the action-adventure success and helped establish one of cinema's most commercially successful franchises."
},
"The Exorcist": {
"year": 1973,
"description": "One of the most successful and influential horror films of all time, exemplifying how popular novels can be effectively adapted for screen."
},
"The Front Page": {
"year": 1931,
"description": "A historically significant early sound movie demonstrating Hollywood's rapid technical progress with sound technology innovation."
},
"Grey Gardens": {
"year": 1976,
"description": "An influential cinema verité documentary by Albert and David Maysles, examining the eccentric lives of two women related to Jacqueline Kennedy."
},
"I Am Joaquin": {
"year": 1969,
"description": "A 20-minute short film based on an epic poem, important to Chicano history and produced by Luis Valdez through Teatro Campesino."
},
"It's a Gift": {
"year": 1934,
"description": "The third Fields film to be named to the National Film Registry, featuring W.C. Fields in extended comic sequences adapted from his theatrical sketches."
},
"Let There Be Light": {
"year": 1946,
"description": "A war documentary directed by John Huston that was banned by the War Department for 35 years due to its unflinching documentation of combat veterans' psychological trauma."
},
"Lonesome": {
"year": 1928,
"description": "One of the few American feature films directed by Hungarian filmmaker Paul Fejös, notable for early dialogue and two-color Technicolor use."
},
"Make Way for Tomorrow": {
"year": 1937,
"description": "A sensitive, progressive, Depression-era film by director Leo McCarey exploring retirement, poverty, and generational discord."
},
"Malcolm X": {
"year": 1992,
"description": "Director Spike Lee's biographical film about the life of civil rights leader Malcolm X, featuring an Oscar-nominated Denzel Washington performance."
},
"McCabe and Mrs. Miller": {
"year": 1971,
"description": "An aesthetically acclaimed film by Robert Altman demonstrating how the Western genre examines contemporary American cultural realities."
},
"Newark Athlete": {
"year": 1891,
"description": "Produced May-June 1891, one of the first films made in America at Edison Laboratory, representing early motion picture camera innovation."
},
"Our Lady of the Sphere": {
"year": 1969,
"description": "One of Lawrence Jordan's best-known works, an experimental animated film blending baroque and Victorian imagery with surrealistic dream-like imagery."
},
"The Pink Panther": {
"year": 1964,
"description": "A comic masterpiece by Blake Edwards introducing the animated Pink Panther and Peter Sellers as the iconic Inspector Clouseau character."
},
"Preservation of the Sign Language": {
"year": 1913,
"description": "A short, one-reel film featuring George Veditz, documenting American Sign Language and advocating for deaf Americans' communication rights."
},
"Saturday Night Fever": {
"year": 1977,
"description": "Produced long after the heyday of classic Hollywood musicals, this film proved the American movie musical could be reinvented with dramatic realism."
},
"Study of a River": {
"year": 1996,
"description": "A meditative examination of the winter cycle of the Hudson River by experimental filmmaker Peter Hutton over a two-year period."
},
"Tarantella": {
"year": 1940,
"description": "A five-minute color, avant-garde short film created by Mary Ellen Bute, a pioneer combining visual music with electronic art in experimental cinema."
},
"A Tree Grows in Brooklyn": {
"year": 1945,
"description": "Elia Kazan's first feature film exploring individual struggle against powerful forces, released at World War II's conclusion."
},
"A Trip Down Market Street": {
"year": 1906,
"description": "A 13-minute actuality film recorded by placing a movie camera on the front of a cable car, capturing pre-earthquake San Francisco daily life."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2011 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-11-240/2011-national-film-registry-more-than-a-box-of-chocolates/2011-12-28/
NFR_2011 = {
"Allures": {
"year": 1961,
"description": "Abstract imagery with a spiritual dimension featuring dazzling displays of color, light, and moving patterns by Jordan Belson, influenced by Wassily Kandinsky."
},
"Bambi": {
"year": 1942,
"description": "Walt Disney's animated coming-of-age story. One of film's most heart-rending stories of parental love with iconic characters and nature conservation messaging."
},
"The Big Heat": {
"year": 1953,
"description": "Post-war noir film starring Glenn Ford. Filled with atmosphere, fascinating female characters, and a jolting degree of violence directed by Fritz Lang."
},
"A Computer Animated Hand": {
"year": 1972,
"description": "Ed Catmull's pioneering work. One of the earliest examples of 3D computer animation displaying hand movements and finger flexing."
},
"Crisis: Behind a Presidential Commitment": {
"year": 1963,
"description": "Robert Drew's cinema-verite documentary capturing Governor George Wallace's stand in the schoolhouse door and President Kennedy's response during University of Alabama desegregation."
},
"The Cry of the Children": {
"year": 1912,
"description": "Silent melodrama addressing child labor reform. The boldest, most timely and most effective appeal for stamping out social abuse."
},
"A Cure for Pokeritis": {
"year": 1912,
"description": "John Bunny comedy. Actor recognized as the living symbol of wholesome merriment."
},
"El Mariachi": {
"year": 1992,
"description": "Robert Rodriguez's $7,000 indie film. An energetic, highly entertaining tale of a musician mistaken for a hit man during a drug war."
},
"Faces": {
"year": 1968,
"description": "John Cassavetes' work described as a barrage of attack on contemporary middle-class America exploring marriage dissolution."
},
"Fake Fruit Factory": {
"year": 1986,
"description": "Chick Strand's documentary blending ethnographic techniques. An expressive, sympathetic look at Mexican women creating papier-mâché ornaments."
},
"Forrest Gump": {
"year": 1994,
"description": "Tom Hanks vehicle. A smash hit receiving six Academy Awards including Best Picture with technological innovations in digital insertion."
},
"Growing Up Female": {
"year": 1971,
"description": "Documentary from women's liberation movement. Among the first films documenting female identity formation across life stages."
},
"Hester Street": {
"year": 1975,
"description": "Joan Micklin Silver's adaptation of Abraham Cahan's novel. A portrait of Eastern European Jewish life in America examining immigration experiences."
},
"I, an Actress": {
"year": 1977,
"description": "George Kuchar's avant-garde short. Hilarious documentation of directing technique emphasizing camp aesthetics and love of artifice and exaggeration."
},
"The Iron Horse": {
"year": 1924,
"description": "John Ford's epic Western. Employed more than 5,000 extras celebrating transcontinental railroad construction and immigrant contributions."
},
"The Kid": {
"year": 1921,
"description": "Charlie Chaplin's feature debut. An artful melding of touching drama, social commentary and inventive comedy."
},
"The Lost Weekend": {
"year": 1945,
"description": "Billy Wilder film. An uncompromising look at the devastating effects of alcoholism winning four Academy Awards."
},
"The Negro Soldier": {
"year": 1944,
"description": "Frank Capra production unit film. A watershed in the use of film to promote racial tolerance featuring dignified African-American representation."
},
"Nicholas Brothers Family Home Movies": {
"year": 1930,
"description": "Archival footage of renowned dancers. Capture a golden age of show business with rare documentation of Cotton Club and Broadway performances."
},
"Norma Rae": {
"year": 1979,
"description": "Sally Field vehicle. A treatise about maturation, personal willpower, fairness and the empowerment of women based on true unionization efforts."
},
"Porgy and Bess": {
"year": 1959,
"description": "George Gershwin's folk opera adaptation. Lavish production filmed during civil rights movement tensions regarding African-American representation."
},
"The Silence of the Lambs": {
"year": 1991,
"description": "Jonathan Demme thriller. Winner of Academy Awards for Best Picture, Director, Actor, Actress and Adapted Screenplay featuring Anthony Hopkins."
},
"Stand and Deliver": {
"year": 1988,
"description": "Edward James Olmos film. Celebrates values of self-betterment through hard work and power through knowledge from Latino filmmakers."
},
"Twentieth Century": {
"year": 1934,
"description": "Howard Hawks comedy. Marked the first of director Howard Hawks' frenetic comedies establishing screwball comedy genre conventions."
},
"War of the Worlds": {
"year": 1953,
"description": "Byron Haskin adaptation. Released at the height of cold-war hysteria with Academy Award-winning special effects described as soul-chilling."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2012 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-12-226/cinematic-firsts-enshrined-in-2012-film-registry/2012-12-19/
NFR_2012 = {
"3:10 to Yuma": {
"year": 1957,
"description": "A 1950s western that has gained in stature since its original release for its psychological depth, starring Glenn Ford and Van Heflin in roles against type."
},
"Anatomy of a Murder": {
"year": 1959,
"description": "Director Otto Preminger's crime-trial film featuring James Stewart, known for blunt language and willingness to openly discuss adult themes with a Duke Ellington score."
},
"The Augustas": {
"year": 1930,
"description": "A 16-minute silent film documenting various American towns named Augusta, compiled from footage by traveling salesman Scott Nixon."
},
"Born Yesterday": {
"year": 1950,
"description": "Judy Holliday's Oscar-winning performance anchors this comedy about Washington corruption, described as full of charm and wit."
},
"Breakfast at Tiffany's": {
"year": 1961,
"description": "Blake Edwards' adaptation of Truman Capote's novella, starring Audrey Hepburn, with Henry Mancini's classic 'Moon River' composition."
},
"A Christmas Story": {
"year": 1983,
"description": "Bob Clark's nostalgic film about childhood in 1940s Indiana, narrated by humorist Jean Shepherd with detail after nostalgic detail."
},
"The Corbett-Fitzsimmons Title Fight": {
"year": 1897,
"description": "An approximately 100-minute boxing documentary, the longest movie produced at that time and a tremendous commercial success."
},
"Dirty Harry": {
"year": 1971,
"description": "Clint Eastwood's iconic role as rogue cop Harry Callahan under Don Siegel's direction, marking a major turning point in Eastwood's career."
},
"Hours for Jerome: Parts 1 and 2": {
"year": 1980,
"description": "Nathaniel Dorsky's silent tone poem capturing daily life across four seasons, filmed at silent speed, between 17 and 20 frames per second."
},
"The Kidnappers Foil": {
"year": 1930,
"description": "Dallas filmmaker Melton Barker's itinerant productions featuring local children, with 50 to 75 would-be Shirley Temples and Jackie Coopers."
},
"Kodachrome Color Motion Picture Tests": {
"year": 1922,
"description": "Paragon Studios demonstration reel showcasing early color film technology with leading actresses including Mae Murray and Hope Hampton."
},
"A League of Their Own": {
"year": 1992,
"description": "Penny Marshall's ensemble comedy-drama about the All-American Girls Professional Baseball League, both funny and feminist in approach."
},
"The Matrix": {
"year": 1999,
"description": "The Wachowskis' science-fiction epic using state-of-the-art special effects and innovative digital techniques for action sequences."
},
"The Middleton Family at the New York World's Fair": {
"year": 1939,
"description": "Westinghouse industrial film shot in Technicolor documenting the 1939 Fair's technological achievements and the heartland values."
},
"One Survivor Remembers": {
"year": 1995,
"description": "Academy Award-winning documentary by Kary Antholis about Holocaust survivor Gerda Weissmann Klein, told with simple yet powerful eloquence."
},
"Parable": {
"year": 1964,
"description": "Allegorical film debuting at the 1964 World's Fair depicting Jesus as an enigmatic, chalk-white, skull-capped circus clown."
},
"Samsara: Death and Rebirth in Cambodia": {
"year": 1990,
"description": "Ellen Bruno's documentary using ancient Buddhist teachings and folklore to contextualize Cambodia's post-Pol Pot reconstruction efforts."
},
"Slacker": {
"year": 1991,
"description": "Richard Linklater's independent film shot on 16mm with $23,000 budget, regarded as a touchstone in the blossoming of American independent cinema."
},
"Sons of the Desert": {
"year": 1933,
"description": "Stan Laurel and Oliver Hardy comedy featuring many of the comedic techniques that had made Laurel & Hardy such masters."
},
"The Spook Who Sat by the Door": {
"year": 1973,
"description": "Sam Greenlee adaptation about a Black CIA agent sparking nationalist revolution, restored for DVD as a story of black insurrection."
},
"They Call It Pro Football": {
"year": 1966,
"description": "NFL Films' inaugural feature, characterized as the 'Citizen Kane' of sports movies for its dramaturgical approach to football."
},
"The Times of Harvey Milk": {
"year": 1984,
"description": "Rob Epstein's Academy Award-winning documentary about San Francisco's first openly gay supervisor and his 1978 assassination."
},
"Two-Lane Blacktop": {
"year": 1971,
"description": "Minimalist Monte Hellman film following cross-country car racers, described as allowing audiences time to absorb the film's spare landscapes."
},
"Uncle Tom's Cabin": {
"year": 1914,
"description": "Historic film starring Sam Lucas, said to be the first feature-length American film that starred a black actor."
},
"The Wishing Ring; An Idyll of Old England": {
"year": 1914,
"description": "Maurice Tourneur's rediscovered film praised for incredible sophistication of camerawork, lighting, and editing."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2013 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-13-216
NFR_2013 = {
"Bless Their Little Hearts": {
"year": 1984,
"description": "Part of the vibrant New Wave of independent African-American filmmakers to emerge in the 1970s and 1980s, this UCLA thesis film presents a family struggling through economic hardship with both sadness and humor."
},
"Brandy in the Wilderness": {
"year": 1969,
"description": "Stanton Kaye's experimental work documents a real couple's relationship through vignettes, blurring the distinction between documentary and fiction in a 1960s aesthetic."
},
"Cicero March": {
"year": 1966,
"description": "This documentary captures civil rights confrontations during the Chicago Freedom Movement, documenting the tense encounters between activists and residents of an all-white Illinois town."
},
"Daughter of Dawn": {
"year": 1920,
"description": "Featuring an all-Native-American cast of Comanches and Kiowas, this silent film presents a priceless record of Native-American customs, traditions and artifacts of the time."
},
"Decasia": {
"year": 2002,
"description": "Created from deteriorating nitrate film stock, Bill Morrison's experimental work uses decomposing found film to create imagery that transforms before viewers' eyes, accompanied by composer Michael Gordon's music."
},
"Ella Cinders": {
"year": 1926,
"description": "Colleen Moore stars in this Cinderella-inspired comedy exemplifying 1920s humor and the flapper aesthetic, celebrated for its energetic protagonist."
},
"Forbidden Planet": {
"year": 1956,
"description": "MGM's science-fiction epic loosely adapts Shakespeare's The Tempest, exploring themes of power and technology while pioneering intergalactic storytelling and electronic soundscapes."
},
"Gilda": {
"year": 1946,
"description": "This film noir features Rita Hayworth in an iconic performance, representing the Hollywood glamorization of film noir—long on sex appeal but short on substance."
},
"The Hole": {
"year": 1962,
"description": "John and Faith Hubley's Academy Award-winning animated meditation contemplates nuclear catastrophe through dialogue improvised by Dizzy Gillespie and George Mathews."
},
"Judgment at Nuremberg": {
"year": 1961,
"description": "Examining post-WWII justice, screenwriter Abby Mann's adaptation argues that those responsible for administering justice also have the duty to ensure that human-rights norms are preserved."
},
"King of Jazz": {
"year": 1930,
"description": "This early Technicolor musical revue centers on orchestra leader Paul Whiteman, featuring performances from Bing Crosby and George Gershwin's 'Rhapsody in Blue.'"
},
"The Lunch Date": {
"year": 1989,
"description": "Adam Davidson's 10-minute student film explores the partial erosion of haughty self-confidence when stranded outside one's personal comfort zone through an unexpected encounter."
},
"The Magnificent Seven": {
"year": 1960,
"description": "Based on Kurosawa's Seven Samurai, this Western features Steve McQueen, Charles Bronson, and James Coburn as gunslingers protecting Mexican villagers from bandits."
},
"Martha Graham Early Dance Films": {
"year": 1931,
"description": "This collection includes 'Heretic,' 'Frontier,' 'Lamentation,' and 'Appalachian Spring'—silent films documenting the pioneering modern dance choreographer's revolutionary techniques."
},
"Mary Poppins": {
"year": 1964,
"description": "Disney's beloved musical featuring Julie Andrews combines animation with live action, integrating a witty script, an inventive visual style and a slate of classic songs."
},
"Men and Dust": {
"year": 1940,
"description": "Producer-director Lee Dick's labor advocacy documentary examines mining-related diseases across Kansas, Missouri, and Oklahoma, serving as an ecological record of industrial transformation."
},
"Midnight": {
"year": 1939,
"description": "Mitchell Leisen's romantic comedy stars Claudette Colbert impersonating a Hungarian countess, praised by the New York Times as 'one of the liveliest, gayest, wittiest comedies.'"
},
"Notes on the Port of St. Francis": {
"year": 1951,
"description": "Frank Stauffacher's impressionistic film combines iconic San Francisco imagery with narration by Vincent Price based on Robert Louis Stevenson's 1882 essay."
},
"Pulp Fiction": {
"year": 1994,
"description": "Quentin Tarantino's influential independent film combines narrative elements of hardboiled crime novels and film noir with the bright widescreen visuals of Sergio Leone."
},
"The Quiet Man": {
"year": 1952,
"description": "John Ford's tribute to Irish heritage stars John Wayne and Maureen O'Hara, beautifully photographed in rich, saturated Technicolor and shot on location."
},
"The Right Stuff": {
"year": 1983,
"description": "Philip Kaufman's three-hour-thirteen-minute epic adapts Tom Wolfe's novel about space program pioneers, blending Western elements with satire to examine national pride and hero worship."
},
"Roger & Me": {
"year": 1989,
"description": "Michael Moore's documentary chronicles General Motors' layoffs affecting 30,000 Flint workers, examining the human toll and hemorrhaging of jobs during economic upheaval."
},
"A Virtuous Vamp": {
"year": 1919,
"description": "Screenwriter Anita Loos crafted this satirical workplace romance starring Constance Talmadge, whose character's knowing innocence captured audiences' imagination during the silent era."
},
"Who's Afraid of Virginia Woolf?": {
"year": 1966,
"description": "Edward Albee's adaptation features Elizabeth Taylor and Richard Burton as a warring couple, presenting frank, code-busting language and depictions of middle-class malaise-cum-rage."
},
"Wild Boys of the Road": {
"year": 1933,
"description": "William Wellman's Depression-era drama portrays homeless teens hopping freight trains, representing Warner Bros.' gritty social conscience dramas of the early 1930s."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2014 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-14-210/
NFR_2014 = {
"13 Lakes": {
"year": 2004,
"description": "James Benning's feature-length film can be seen as a series of moving landscape paintings shot at 13 American lakes in identical 10-minute takes, exploring landscape as a temporal element."
},
"Bert Williams Lime Kiln Club Field Day": {
"year": 1913,
"description": "Seven reels of untitled and unassembled footage featuring vaudevillian Bert Williams, believed to constitute the earliest surviving feature film starring black actors."
},
"The Big Lebowski": {
"year": 1998,
"description": "Joel and Ethan Coen's tale of kidnapping, mistaken identity and bowling became a highly quoted cult classic despite modest initial box office performance."
},
"Down Argentine Way": {
"year": 1940,
"description": "Betty Grable's breakthrough Technicolor musical where she traveled to South America and fell in love with Don Ameche, establishing her as a major star."
},
"The Dragon Painter": {
"year": 1919,
"description": "Sessue Hayakawa's film about an obsessed, untutored painter who loses his artistic powers after he finds and marries a supposed dragon princess."
},
"Felicia": {
"year": 1965,
"description": "A 13-minute short subject documenting a slice of life in the Watts neighborhood through a teenager's first-person narrative perspective."
},
"Ferris Bueller's Day Off": {
"year": 1986,
"description": "John Hughes's story of a teenage wiseacre whose day playing hooky leads to comic adventures and personal growth for himself and friends."
},
"The Gang's All Here": {
"year": 1943,
"description": "20th Century-Fox Technicolor musical featuring Alice Faye and Carmen Miranda with legendary musical number choreography by Busby Berkeley."
},
"House of Wax": {
"year": 1953,
"description": "The first full-length 3-D color film produced by major American studio, introducing 3-D effects widely while establishing Vincent Price as horror master."
},
"Into the Arms of Strangers": {
"year": 2000,
"description": "Oscar-winning documentary examining the Kindertransport operation that placed thousands of Jewish children with foster families in Great Britain before WWII."
},
"Little Big Man": {
"year": 1970,
"description": "Arthur Penn's Western following a 121-year-old man looking back at his life as a pioneer with narrative interweaving fact and myth."
},
"Luxo Jr.": {
"year": 1986,
"description": "The iconic living, moving desk lamp in Pixar's charming, computer-animated short subject that became the studio's logo."
},
"Moon Breath Beat": {
"year": 1980,
"description": "CalArts student Lisze Bechtold's experimental animation exploring what happens when an animator follows a line, a patch of color, or a shape into the unconscious."
},
"Please Don't Bury Me Alive!": {
"year": 1976,
"description": "Considered by historians to be the first Chicano feature film, writer-director Efraín Gutiérrez's independent production addressing Vietnam War era identity."
},
"The Power and the Glory": {
"year": 1933,
"description": "Preston Sturges's debut screenplay, a haunting tragedy that introduced a non-chronological structure to mainstream movies influencing later classics."
},
"Rio Bravo": {
"year": 1959,
"description": "Howard Hawks Western where a sheriff and his deputies are waiting in a jail for a prisoner transfer and anticipated escape attempt."
},
"Rosemary's Baby": {
"year": 1968,
"description": "Roman Polanski's horror masterpiece where protagonist comes to believe that a cult of witches in the building is implementing a plot against her."
},
"Ruggles of Red Gap": {
"year": 1935,
"description": "Charles Laughton's comedy about an English manservant won in a poker game who discovers American egalitarianism and becomes a businessman."
},
"Saving Private Ryan": {
"year": 1998,
"description": "Spielberg's WWII film dropping ordinary soldiers into a near-impossible rescue mission set amid the carnage of Omaha Beach landing."
},
"Shoes": {
"year": 1916,
"description": "Lois Weber's social drama documenting the suffering of an underpaid shopgirl struggling to support family through poverty and exploitation."
},
"State Fair": {
"year": 1933,
"description": "Henry King's celebration of state fair traditions starring Will Rogers in a small town slice-of-life setting with Americana and romance storylines."
},
"Unmasked": {
"year": 1917,
"description": "Grace Cunard's film where she not only starred but also wrote its script and parlayed her contributions into a directorial role."
},
"V-E +1": {
"year": 1945,
"description": "Samuel Fuller's silent 16 mm footage documenting the burial of beaten and emaciated Holocaust victims at Falkenau concentration camp liberation."
},
"The Way of Peace": {
"year": 1947,
"description": "Frank Tashlin's puppet animation film sponsored by the American Lutheran Church using stop-motion to reinforce Christian values during the atomic age."
},
"Willy Wonka and the Chocolate Factory": {
"year": 1971,
"description": "Gene Wilder stars in this musical adaptation where surreal, yet playful production design creates the fanciful world of Roald Dahl's imagination."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2015 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-15-216
NFR_2015 = {
"Being There": {
"year": 1979,
"description": "A simple-minded gardener becomes mistaken for a profound political advisor through a series of misunderstandings, creating a philosophically complex satire on society and media influence."
},
"Black and Tan": {
"year": 1929,
"description": "An early musical short featuring Duke Ellington and celebrating African-American jazz musicians during the Harlem Renaissance era."
},
"Dracula (Spanish language version)": {
"year": 1931,
"description": "A Spanish-language adaptation filmed concurrently with the English version, now considered superior in cinematography and lighting."
},
"Dream of a Rarebit Fiend": {
"year": 1906,
"description": "A pioneering fantasy comedy employing groundbreaking trick photography and special effects to depict hallucinatory dreams."
},
"Eadweard Muybridge, Zoopraxographer": {
"year": 1975,
"description": "A documentary exploring the pioneering motion studies that led to cinema's invention and their philosophical implications."
},
"Edison Kinetoscopic Record of a Sneeze": {
"year": 1894,
"description": "The oldest surviving copyrighted motion picture, featuring a simple sneeze that became synonymous with movies' invention."
},
"A Fool There Was": {
"year": 1915,
"description": "A film establishing the 'vamp' genre archetype, starring Theda Bara and setting unprecedented promotional standards."
},
"Ghostbusters": {
"year": 1984,
"description": "A horror-comedy about three scientists who establish a ghost-removal service in New York, blending wacky humor with supernatural elements."
},
"Hail the Conquering Hero": {
"year": 1944,
"description": "A wartime satire by Preston Sturges exploring hero worship and small-town politics with sharp wit and visual vigor."
},
"Humoresque": {
"year": 1920,
"description": "A sympathetic portrayal of Jewish immigrant life and acculturation, featuring riveting performances and emotional depth."
},
"Imitation of Life": {
"year": 1959,
"description": "A melodrama examining motherhood and identity through stylized cinematography and exquisite use of color and camera angles."
},
"The Inner World of Aphasia": {
"year": 1968,
"description": "A medical-training film depicting a nurse's struggle to communicate with an aphasia patient through poetic storytelling."
},
"John Henry and the Inky-Poo": {
"year": 1946,
"description": "A stop-motion animation celebrating African-American folklore with dignity, imagination, poetry, and love."
},
"L.A. Confidential": {
"year": 1997,
"description": "A film-noir crime story featuring incompatible cops who expose police corruption through a virtuoso choreographed shootout."
},
"The Mark of Zorro": {
"year": 1920,
"description": "Douglas Fairbanks' swashbuckling tale establishing the masked hero archetype with athletic prowess and wit."
},
"The Old Mill": {
"year": 1937,
"description": "A Disney animated short featuring the first use of the multiplane camera, advancing animation technology significantly."
},
"Our Daily Bread": {
"year": 1934,
"description": "A Depression-era film examining cooperative farming as an alternative to individualistic competition and unemployment."
},
"Portrait of Jason": {
"year": 1967,
"description": "One of the first LGBT films widely accepted by general audiences, using cinema vérité techniques with documentary authenticity."
},
"Seconds": {
"year": 1966,
"description": "A paranoid thriller about identity and second chances, featuring disorienting cinematography and psychological tension."
},
"The Shawshank Redemption": {
"year": 1994,
"description": "A Stephen King adaptation about wrongful imprisonment and human resilience, gaining widespread acclaim over time."
},
"Sink or Swim": {
"year": 1990,
"description": "An autobiographical documentary using poetically powerful text to explore father-daughter relationships and emotional trauma."
},
"The Story of Menstruation": {
"year": 1946,
"description": "A Disney educational film addressing menstruation for young women, viewed by approximately 93 million girls."
},
"Symbiopsychotaxiplasm: Take One": {
"year": 1968,
"description": "A meta-documentary examining film creation with three camera crews exploring production tensions and revolutionary philosophy."
},
"Top Gun": {
"year": 1986,
"description": "An action film celebrating naval aviation with vertiginous fighter-plane sequences that influenced filmmaking aesthetics."
},
"Winchester '73": {
"year": 1950,
"description": "A psychological Western exploring vengeance and morality as a rifle passes through multiple hands, changing each owner."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2016 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-16-209
NFR_2016 = {
"The Atomic Cafe": {
"year": 1982,
"description": "Documentary compiled from archival Cold War footage documenting post-WWII nuclear threat fears."
},
"Ball of Fire": {
"year": 1941,
"description": "Howard Hawks screwball comedy featuring Barbara Stanwyck as a showgirl hiding among encyclopedia-compiling scholars."
},
"The Beau Brummels": {
"year": 1928,
"description": "Eight-minute Vitaphone vaudeville short showcasing the deadpan comic duo's signature hat-swapping routine."
},
"The Birds": {
"year": 1963,
"description": "Hitchcock masterpiece blending psychological horror with suspense, culminating in an unforgettable final scene."
},
"Blackboard Jungle": {
"year": 1955,
"description": "Drama exploring juvenile delinquency in urban schools, featuring early rock and roll on its soundtrack."
},
"The Breakfast Club": {
"year": 1985,
"description": "John Hughes comedy examining social hierarchies among high school archetypes during Saturday detention."
},
"The Decline of Western Civilization": {
"year": 1981,
"description": "Penelope Spheeris documentary capturing LA's hardcore punk scene through performances and interviews."
},
"East of Eden": {
"year": 1955,
"description": "Elia Kazan adaptation of Steinbeck exploring familial conflict and teen angst with James Dean's celebrated performance."
},
"Funny Girl": {
"year": 1968,
"description": "Musical featuring Barbra Streisand's screen debut as legendary performer Fanny Brice."
},
"Life of an American Fireman": {
"year": 1903,
"description": "Edwin S. Porter pioneering work demonstrating innovative editing and narrative film techniques."
},
"The Lion King": {
"year": 1994,
"description": "Disney animated feature blending innovative animation with voice acting and Elton John's musical compositions."
},
"Lost Horizon": {
"year": 1937,
"description": "Frank Capra's fantastical romance set in a Himalayan utopia, popularizing the term 'Shangri-La.'"
},
"The Musketeers of Pig Alley": {
"year": 1912,
"description": "D.W. Griffith's 17-minute work considered cinema's first gangster film, employing revolutionary camera techniques."
},
"Paris Is Burning": {
"year": 1990,
"description": "Documentary exploring 1980s New York ballroom subculture among Black and Hispanic LGBTQ+ communities."
},
"Point Blank": {
"year": 1967,
"description": "John Boorman crime thriller reimagining noir aesthetics through Panavision cinematography and bold color."
},
"The Princess Bride": {
"year": 1987,
"description": "Rob Reiner's lighthearted fairy tale parody retaining William Goldman's wit and memorable dialogue."
},
"Putney Swope": {
"year": 1969,
"description": "Robert Downey Sr. surrealistic satire depicting an advertising agency takeover by Black nationalists."
},
"Rushmore": {
"year": 1998,
"description": "Wes Anderson indie film capturing Gen X sensibilities through a protagonist navigating academic misfit status."
},
"Solomon Sir Jones Films": {
"year": 1924,
"description": "Collection of 29 silent films documenting African-American life across Oklahoma communities during rapid social change."
},
"Steamboat Bill, Jr.": {
"year": 1928,
"description": "Buster Keaton comedy showcasing physical comedy mastery through breath-stopping stunts and cyclone sequences."
},
"Suzanne, Suzanne": {
"year": 1982,
"description": "Thirty-minute documentary examining substance abuse's connection to domestic violence within a middle-class family."
},
"Thelma & Louise": {
"year": 1991,
"description": "Ridley Scott feminist manifesto following two women's crime spree, anchored by career-defining performances."
},
"20,000 Leagues Under the Sea": {
"year": 1916,
"description": "Stuart Paton's pioneering submarine film featuring groundbreaking underwater cinematography and special effects."
},
"A Walk in the Sun": {
"year": 1945,
"description": "Lewis Milestone WWII drama emphasizing character study over battle scenes, exploring soldiers' psychological stress."
},
"Who Framed Roger Rabbit": {
"year": 1988,
"description": "Landmark film noir comedy blending cartoon and live-action characters through innovative special effects techniques."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2017 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-17-178
NFR_2017 = {
"Ace in the Hole": {
"year": 1951,
"description": "A deeply cynical look at journalism featuring Kirk Douglas as a reporter exploiting a cave rescue story for national prominence."
},
"Boulevard Nights": {
"year": 1979,
"description": "Documentary-style depiction of Chicano youth navigating gang life in East Los Angeles, shot with community participation."
},
"Die Hard": {
"year": 1988,
"description": "Bruce Willis stars as a cop battling terrorists in an LA office tower; gripping action sequences and well-crafted humor made it a major hit."
},
"Dumbo": {
"year": 1941,
"description": "Disney's tale of an elephant with large ears learning to fly, praised for lovely drawing, original score, and uplifting message."
},
"Field of Dreams": {
"year": 1989,
"description": "Kevin Costner's story of an Iowa farmer building a baseball diamond; a story of redemption and faith."
},
"4 Little Girls": {
"year": 1997,
"description": "Spike Lee's documentary examining the 1963 church bombing in Birmingham that killed four children, sensitively rendered."
},
"Fuentes Family Home Movies Collection": {
"year": 1920,
"description": "Home movies from Corpus Christi capturing Mexican-American community life, among the earliest visual records."
},
"Gentleman's Agreement": {
"year": 1947,
"description": "1947 Best Picture winner exploring anti-Semitism through a journalist posing as Jewish to understand discrimination firsthand."
},
"The Goonies": {
"year": 1985,
"description": "Steven Spielberg-produced adventure about outsider kids on a treasure hunt with Tom Sawyeresque charm."
},
"Guess Who's Coming to Dinner": {
"year": 1967,
"description": "Spencer Tracy's final film addressing interracial marriage with Katharine Hepburn and Sidney Poitier delivering powerful performances."
},
"He Who Gets Slapped": {
"year": 1924,
"description": "MGM's first complete production featuring Lon Chaney as a scientist-turned-circus clown in an early creepy clown film."
},
"Interior New York Subway, 14th Street to 42nd Street": {
"year": 1905,
"description": "Early actuality film documenting the newly opened subway, coordinating three trains for the filming."
},
"La Bamba": {
"year": 1987,
"description": "Luis Valdez's biopic of Ritchie Valens, rock's first Mexican-American superstar, with Lou Diamond Phillips in the lead role."
},
"Lives of Performers": {
"year": 1972,
"description": "Yvonne Rainer's experimental film described as a stark and revealing examination of romantic alliances."
},
"Memento": {
"year": 2000,
"description": "Christopher Nolan's breakthrough thriller told non-linearly to mirror the protagonist's short-term memory loss."
},
"Only Angels Have Wings": {
"year": 1939,
"description": "Howard Hawks' aviation melodrama starring Cary Grant as a hard-talking air freight company head with dazzling air sequences."
},
"The Sinking of the Lusitania": {
"year": 1918,
"description": "Winsor McCay's propaganda animation combining multiple techniques to document the ship's sinking and protest isolationism."
},
"Spartacus": {
"year": 1960,
"description": "Stanley Kubrick-directed epic with Kirk Douglas and Laurence Olivier; helped end the Hollywood blacklist by hiring blacklisted writer."
},
"Superman": {
"year": 1978,
"description": "Richard Donner's origins story making audiences believe a man can fly with Christopher Reeve's iconic performance."
},
"Thelonious Monk: Straight, No Chaser": {
"year": 1988,
"description": "Charlotte Zwerin's documentary blending interviews and concert footage, reminding viewers Monk was as important a jazz composer as pianist."
},
"Time and Dreams": {
"year": 1976,
"description": "Mort Jordan's personal documentary contrasting nostalgia with civil rights activism in rural Alabama."
},
"Titanic": {
"year": 1997,
"description": "James Cameron's epic retelling the maritime disaster; big, bold, touchingly uncynical filmmaking becoming a cultural phenomenon."
},
"To Sleep with Anger": {
"year": 1990,
"description": "Charles Burnett's domestic drama exploring cultural conflicts within a Black family through a storyteller character."
},
"Wanda": {
"year": 1971,
"description": "Barbara Loden's character study of an isolated Pennsylvania woman, considered one of the finest works of independent cinema."
},
"With the Abraham Lincoln Brigade in Spain": {
"year": 1937,
"description": "Documentary shot during the Spanish Civil War featuring work by Henri Cartier-Bresson and Robert Capa."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2018 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-18-144/library-of-congress-national-film-registry-turns-30/2018-12-12/
NFR_2018 = {
"Bad Day at Black Rock": {
"year": 1955,
"description": "Spencer Tracy stars as a one-armed man arriving in a desert town, uncovering dark secrets when searching for a former Japanese-American resident."
},
"Broadcast News": {
"year": 1987,
"description": "A comedy set in television news featuring Holly Hunter, William Hurt, and Albert Brooks navigating romance and journalistic ethics."
},
"Brokeback Mountain": {
"year": 2005,
"description": "An Academy Award-winning drama depicting a secret love affair between two closeted gay ranch hands over 20 years."
},
"Cinderella": {
"year": 1950,
"description": "Disney's animated adaptation of the classic fairy tale featuring sparkling songs and breathtaking animation sequences."
},
"Days of Wine and Roses": {
"year": 1962,
"description": "Jack Lemmon portrays a man whose descent into alcoholism drags his wife into destructive behavior."
},
"Dixon-Wanamaker Expedition to Crow Agency": {
"year": 1908,
"description": "Rare documentary footage capturing Native American life, Crow Fair, and a recreation of the Battle of Little Big Horn."
},
"Eve's Bayou": {
"year": 1997,
"description": "Written and directed by Kasi Lemmons, this Southern gothic tale explores family secrets discovered by a young African-American girl."
},
"The Girl Without a Soul": {
"year": 1917,
"description": "A silent film by John H. Collins featuring Viola Dana in a dual role as twin sisters, one gifted and one troubled."
},
"Hair Piece: A Film for Nappy-Headed People": {
"year": 1984,
"description": "An animated short by Ayoka Chenzira examining African-American women's hair identity and self-acceptance."
},
"Hearts and Minds": {
"year": 1974,
"description": "Peter Davis's Academy Award-winning Vietnam War documentary examining causes, conduct, and consequences."
},
"Hud": {
"year": 1963,
"description": "Paul Newman plays a ruthless Texas rancher's son in conflict with his father over business and family values."
},
"The Informer": {
"year": 1935,
"description": "John Ford's 11th film in the registry depicts an informant during the Irish Rebellion of 1922 facing consequences for betrayal."
},
"Jurassic Park": {
"year": 1993,
"description": "Steven Spielberg's blockbuster about dinosaurs on a remote island where evolutionary manipulation has gone awry."
},
"The Lady From Shanghai": {
"year": 1947,
"description": "Orson Welles directs this stylish film noir renowned for its 'Aquarium' scene and 'Hall of Mirrors' climax."
},
"Leave Her to Heaven": {
"year": 1945,
"description": "Gene Tierney stars as a possessive femme fatale whose obsessive love masks sociopathic tendencies in vibrant Technicolor."
},
"Monterey Pop": {
"year": 1968,
"description": "D.A. Pennebaker's seminal music-festival documentary featuring Janis Joplin, Jimi Hendrix, and other iconic performers."
},
"My Fair Lady": {
"year": 1964,
"description": "George Cukor directs this opulent musical adaptation featuring Rex Harrison and Audrey Hepburn in a tale of transformation."
},
"The Navigator": {
"year": 1924,
"description": "Buster Keaton stars as an inept millionaire stranded at sea who demonstrates ingenuity to survive."
},
"On the Town": {
"year": 1949,
"description": "Three sailors with 24 hours' shore leave in New York with Gene Kelly, Frank Sinatra, and Jules Munshin in a musical adventure."
},
"One-Eyed Jacks": {
"year": 1961,
"description": "Marlon Brando's sole directorial effort, a Western marking the transition from Classic to New Hollywood filmmaking."
},
"Pickup on South Street": {
"year": 1953,
"description": "Samuel Fuller's Cold War thriller about a pickpocket accidentally stealing secret microfilm pursued by multiple factions."
},
"Rebecca": {
"year": 1940,
"description": "Alfred Hitchcock's first American film, adapted from Daphne du Maurier's novel about a mysterious deceased first wife's shadow."
},
"The Shining": {
"year": 1980,
"description": "Stanley Kubrick's inventive adaptation of Stephen King's novel featuring stunning visuals and iconic performances."
},
"Smoke Signals": {
"year": 1998,
"description": "The first feature film written, directed, and produced by Native Americans, offering authentic cultural perspectives."
},
"Something Good Negro Kiss": {
"year": 1898,
"description": "A recently discovered 29-second film representing possibly the earliest example of African-American intimacy on screen."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2019 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-19-116/women-rule-2019-national-film-registry/2019-12-11/
NFR_2019 = {
"Amadeus": {
"year": 1984,
"description": "Milos Forman's film explores classical composers Mozart and Salieri, examining genius and jealous obsession through an Oscar-winning performance by F. Murray Abraham."
},
"Becky Sharp": {
"year": 1935,
"description": "First feature-length film using three-strip Technicolor, adapting Thackeray's novel about a socially ambitious woman's destructive climb through class systems."
},
"Before Stonewall": {
"year": 1984,
"description": "Documentary narrated by Rita Mae Brown documenting LGBTQ history in 20th-century America through archival footage and interviews, commemorating the Stonewall riots."
},
"Body and Soul": {
"year": 1925,
"description": "Oscar Micheaux's pioneering film featuring Paul Robeson in dual roles, addressing critical issues within Black communities despite production challenges."
},
"Boys Don't Cry": {
"year": 1999,
"description": "Kimberly Peirce's docudrama based on Brandon Teena's tragic story, bringing hate crimes into public spotlight with Hilary Swank's Oscar-winning performance."
},
"Clerks": {
"year": 1994,
"description": "Kevin Smith's $27,000 indie debut about two sardonic convenience store workers, gaining cult status and the most public votes in this year's registry balloting."
},
"Coal Miner's Daughter": {
"year": 1980,
"description": "Biopic of country music legend Loretta Lynn's journey from Kentucky to stardom, earning Sissy Spacek an Academy Award for best actress."
},
"Emigrants Landing at Ellis Island": {
"year": 1903,
"description": "Edison company's two-minute actuality film documenting immigrants arriving at Ellis Island, historically significant as first recorded footage of this moment."
},
"Employees Entrance": {
"year": 1933,
"description": "Pre-Production Code film examining machinations in a Depression-era New York department store, capturing real urban tensions with Warren Williams' characterization."
},
"Fog of War": {
"year": 2003,
"description": "Errol Morris documentary featuring Robert McNamara reexamining his role as Vietnam War architect, structured around 11 lessons about moral complexities."
},
"Gaslight": {
"year": 1944,
"description": "MGM psychological thriller where Ingrid Bergman won her first Oscar, exploring whether a Victorian woman is going mad in George Cukor's direction."
},
"George Washington Carver at Tuskegee Institute": {
"year": 1937,
"description": "12 minutes of Kodachrome color footage documenting the renowned botanist and inventor in his daily activities at Tuskegee Institute in Alabama."
},
"Girlfriends": {
"year": 1978,
"description": "Claudia Weill's film about an independent New York photographer navigating career aspirations and relationships after her best friend's marriage."
},
"I Am Somebody": {
"year": 1970,
"description": "Madeline Anderson's documentary of the 1969 Charleston hospital workers' strike, considered the first televised civil rights documentary by a woman of color."
},
"The Last Waltz": {
"year": 1978,
"description": "Martin Scorsese's documentary tribute to The Band's 1976 farewell concert at Winterland, featuring iconic musical performances by era-defining artists."
},
"My Name Is Oona": {
"year": 1969,
"description": "Gunvor Nelson's avant-garde portrait of her daughter's dreamlike interactions with nature, employing experimental techniques and slow-motion cinematography."
},
"A New Leaf": {
"year": 1971,
"description": "Elaine May became the first woman to write, direct and star in a major studio feature, combining Depression-era screwball comedy with slapstick traditions."
},
"Old Yeller": {
"year": 1957,
"description": "Disney's beloved canine classic about a boy and his dog, produced to touch audiences with both laughter and tears through emotionally affecting storytelling."
},
"The Phenix City Story": {
"year": 1955,
"description": "Film noir based on 1954 Alabama murder case, using innovative camera work to depict an attorney's fight against organized crime in 'Sin City.'"
},
"Platoon": {
"year": 1986,
"description": "Oliver Stone's autobiographical Vietnam War film eschewing heroic fiction, featuring Samuel Barber's elegiac score and anti-war perspective."
},
"Purple Rain": {
"year": 1984,
"description": "Prince's largely autobiographical post-modern musical showcasing the artist as a Minneapolis musician bringing provocative funk rock to audiences."
},
"Real Women Have Curves": {
"year": 2002,
"description": "Patricia Cardoso's coming-of-age tale starring 18-year-old America Ferrera, exploring immigrant experience and feminine beauty standards with subtle observation."
},
"She's Gotta Have It": {
"year": 1986,
"description": "Spike Lee's indie classic following a confident single Black woman pursued by three men, establishing Lee's distinct directorial voice and vision."
},
"Sleeping Beauty": {
"year": 1959,
"description": "Disney's timeless animation transforming Charles Perrault's fairy tale with a magnificent score, introducing the enduring villain Maleficent."
},
"Zoot Suit": {
"year": 1981,
"description": "Luis Valdez's stylized musical drama depicting the 1942 'Sleepy Lagoon Murder' and racially charged riots, presented as filmed stage play."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2020 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-20-082
NFR_2020 = {
"Suspense": {
"year": 1913,
"description": "Co-directed by Lois Weber, this pioneering silent film uses cross-cutting between a besieged mother and her husband's frantic drive to create suspense, demonstrating innovative filmmaking techniques from cinema's early era."
},
"Kid Auto Races at Venice": {
"year": 1914,
"description": "Features Charlie Chaplin's debut of his iconic 'little tramp' character, disrupting a cameraman filming a soapbox derby race and establishing Chaplin as a revolutionary screen comedian."
},
"Bread": {
"year": 1918,
"description": "Directed by Ida May Park, this sociological drama depicts a young woman's disillusionment in pursuing stardom, showcasing Park's accomplished filmmaking during Hollywood's early era of women directors."
},
"The Battle of the Century": {
"year": 1927,
"description": "A Laurel and Hardy silent comedy featuring a renowned pie-fighting sequence, the film exemplifies the detective work required to locate and preserve silent-era cinema from fragmented sources."
},
"With Car and Camera Around the World": {
"year": 1929,
"description": "Documenting expeditions from 1922-1929, Aloha Wanderwell served as camera assistant, cinematographer, editor, and director, becoming the first woman to travel around the world by car."
},
"Cabin in the Sky": {
"year": 1943,
"description": "Vincente Minnelli's directorial debut adapts the Broadway musical, showcasing an all-Black cast during segregation, featuring exceptional African American artists including Lena Horne and Louis Armstrong."
},
"Outrage": {
"year": 1950,
"description": "Ida Lupino's unflinching examination of rape's traumatic effects employs masterful cinematography capturing psychological impact through sound, silence, light, and shadow."
},
"The Man with the Golden Arm": {
"year": 1955,
"description": "Otto Preminger's adaptation features Frank Sinatra's raw portrayal of a heroin-addicted protagonist, with standout Saul Bass credits and Elmer Bernstein's jazz score enhancing its candid treatment of addiction."
},
"Lilies of the Field": {
"year": 1963,
"description": "Sidney Poitier's performance as an itinerant worker helping refugee nuns build an Arizona chapel earned him the first Oscar for best actor by an African American, establishing his cinematic legacy."
},
"A Clockwork Orange": {
"year": 1971,
"description": "Stanley Kubrick's dystopian adaptation of Anthony Burgess's novel presents a disturbing, controversial exploration of violence and state-sanctioned rehabilitation through Malcolm McDowell's legendarily intense performance."
},
"Sweet Sweetback's Baadasssss Song": {
"year": 1971,
"description": "Melvin Van Peebles produced, directed, wrote, scored, and starred in this groundbreaking film, exercising complete creative control and launching the Black cinema movement with radical originality."
},
"Wattstax": {
"year": 1973,
"description": "Dubbed the 'Black Woodstock,' this documentary chronicles a 1972 LA Memorial Coliseum concert celebrating the Black community's rebirth following the Watts riots, featuring Isaac Hayes and the Staple Singers."
},
"Grease": {
"year": 1978,
"description": "This tuneful Broadway adaptation features John Travolta and Olivia Newton-John in a beloved celebration of 1950s America, becoming a cultural staple through stage productions and television revivals."
},
"The Blues Brothers": {
"year": 1980,
"description": "Dan Aykroyd and John Belushi's musical comedy tribute to Chicago, soul, and R&B music features legendary cameos including Cab Calloway, Ray Charles, James Brown, and Aretha Franklin."
},
"Losing Ground": {
"year": 1982,
"description": "Kathleen Collins' feature directorial debut, among the first by an African American woman, explores a philosophy professor's struggle to discover ecstatic experience within her marriage and intellectual pursuits."
},
"Illusions": {
"year": 1982,
"description": "Julie Dash's acclaimed student film confronts Hollywood racial politics through a World War II-era setting, exploring themes of identity and Hollywood fantasy, earning the Black Filmmakers Foundation's best film award."
},
"The Joy Luck Club": {
"year": 1993,
"description": "Wayne Wang's adaptation of Amy Tan's novel depicts relationships between Chinese-American women and immigrant mothers through themes of assimilation, family bonds, and intergenerational understanding."
},
"The Devil Never Sleeps": {
"year": 1994,
"description": "Lourdes Portillo investigates her uncle's mysterious death in Chihuahua through experimental filmmaking, combining poetic and tragic elements exploring Mexican family dynamics and cultural inquiry."
},
"Buena Vista Social Club": {
"year": 1999,
"description": "Wim Wenders' documentary reunites forgotten Cuban pop stars from the Batista era through musician Ry Cooder's initiative, capturing extraordinary performances and personal stories of aging musicians."
},
"The Ground": {
"year": 2001,
"description": "Robert Beavers' avant-garde film employs simple components—Greek island landscapes and stone-chiseling imagery—to evoke fundamental human emotion, exemplifying Renaissance ideals through lyrical filmmaking."
},
"Shrek": {
"year": 2001,
"description": "DreamWorks' animated feature balances fairy tale satire with genuine emotion, becoming a mega-hit that spawned sequels and stage adaptations, appealing to both children and adults universally."
},
"Mauna Kea: Temple Under Siege": {
"year": 2006,
"description": "This documentary examines the conflict between scientists using Hawaii's volcano for astronomical observation and Native Hawaiians seeking to preserve it as sacred cultural landscape."
},
"The Hurt Locker": {
"year": 2008,
"description": "Kathryn Bigelow's war film focuses on Baghdad bomb disposal experts facing constant danger and ethical dilemmas, making Bigelow the first woman to win the Oscar for best director."
},
"The Dark Knight": {
"year": 2008,
"description": "Christopher Nolan's reinvention of Batman mythology features Christian Bale and Heath Ledger's Oscar-winning performance, presenting visually memorable set pieces exploring fear and dystopian chaos."
},
"Freedom Riders": {
"year": 2010,
"description": "Stanley Nelson's PBS documentary chronicles 400 Black and white Americans in 1961 challenging Jim Crow segregation through bus travel, told through archival materials and Freedom Riders' testimonies."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2021 National Film Registry inductees with LOC descriptions
# Source: https://www.loc.gov/item/prn-21-078/return-of-the-jedi-among-25-eclectic-films-joining-national-film-registry/2021-12-14/
NFR_2021 = {
"Ringling Brothers Parade Film": {
"year": 1902,
"description": "3-minute actuality recording of a circus parade in Indianapolis that accidentally captures a rare glimpse of a prosperous northern Black community at the turn of the century."
},
"Jubilo": {
"year": 1919,
"description": "Will Rogers plays a likable tramp character in this early comedy featuring his characteristic humor and topical wit through title cards."
},
"The Flying Ace": {
"year": 1926,
"description": "Romance drama from producer of race films, portraying Black characters with dignity and technical expertise in the aviation world without racist stereotypes."
},
"Hellbound Train": {
"year": 1930,
"description": "Allegorical evangelical film by James and Eloyce Gist depicting moral warnings through surreal imagery, representing early independent Black cinema."
},
"Flowers and Trees": {
"year": 1932,
"description": "Disney's Silly Symphony that was \"the first three-strip Technicolor film shown to the public,\" establishing new visual standards for animation."
},
"Strangers on a Train": {
"year": 1951,
"description": "Hitchcock thriller about two strangers who plan to \"swap\" murders, featuring signature suspenseful direction and visual storytelling techniques."
},
"What Ever Happened to Baby Jane?": {
"year": 1962,
"description": "Dark comedy reuniting Bette Davis and Joan Crawford as former film stars living in conflict, launching the psychological thriller subgenre."
},
"Evergreen": {
"year": 1965,
"description": "UCLA student film by Ray Manzarek (later of The Doors) about a jazz musician and art student romance, reflecting French New Wave influences."
},
"Requiem-29": {
"year": 1970,
"description": "UCLA collective student documentary capturing the East Los Angeles Chicano Moratorium and its tragic aftermath following journalist Ruben Salazar's death."
},
"The Murder of Fred Hampton": {
"year": 1971,
"description": "Documentary profiling the final year of the Black Panther Party leader, documenting his activism and the controversial police raid that killed him."
},
"Pink Flamingos": {
"year": 1972,
"description": "John Waters' cult comedy starring Divine, described as \"an exercise in poor taste,\" becoming a landmark in queer cinema."
},
"Sounder": {
"year": 1972,
"description": "Depression-era drama featuring Cicely Tyson and Paul Winfield as sharecroppers, with understated direction showcasing ordinary humanity."
},
"The Long Goodbye": {
"year": 1973,
"description": "Robert Altman's detective mystery transposing Raymond Chandler's Philip Marlowe to contemporary Hollywood through innovative cinematography."
},
"Cooley High": {
"year": 1975,
"description": "Coming-of-age comedy about Black high school friends in Chicago's Cabrini Green, called \"a classic of black cinema\" influencing later filmmakers."
},
"Richard Pryor: Live in Concert": {
"year": 1979,
"description": "Stand-up comedy performance captured on film, showcasing Pryor's \"raw, unadorned, and unedited\" comedic vision and social commentary."
},
"Chicana": {
"year": 1979,
"description": "Documentary collage about Chicana women's struggles by director Sylvia Morales, combining art, photographs, and testimonies of activists."
},
"The Wobblies": {
"year": 1979,
"description": "Documentary about the Industrial Workers of the World, chronicling labor organizing through archival footage, interviews, and worker testimonies."
},
"Star Wars Episode VI — Return of the Jedi": {
"year": 1983,
"description": "Conclusion to the original Star Wars trilogy directed by Richard Marquand, receiving the most public votes among 2021 selections."
},
"A Nightmare on Elm Street": {
"year": 1984,
"description": "Horror film by Wes Craven featuring Robert Englund as Freddy Krueger, becoming a \"successful film franchise\" establishing New Line Cinema."
},
"Stop Making Sense": {
"year": 1984,
"description": "Concert film of the Talking Heads directed by Jonathan Demme, described as \"one of the greatest rock movies ever made.\""
},
"Who Killed Vincent Chin?": {
"year": 1987,
"description": "Academy Award-nominated documentary examining the 1982 killing of a Chinese American and the resulting miscarriage of justice and civil rights issues."
},
"The Watermelon Woman": {
"year": 1996,
"description": "Feature film debut by Cheryl Dunye exploring the erasure of Black women from film history through a documentary-within-a-film narrative."
},
"Selena": {
"year": 1997,
"description": "Biographical film starring Jennifer Lopez in her first major role, authorized by the Quintanilla family, depicting the Tejana singer's rise and tragic death."
},
"The Lord of the Rings: The Fellowship of the Ring": {
"year": 2001,
"description": "Peter Jackson's film adaptation of Tolkien's epic featuring innovative cinematography in New Zealand locations and acclaimed ensemble performances."
},
"WALL•E": {
"year": 2008,
"description": "Pixar animation blending science fiction with ecological themes and robot romance, winning the Oscar for Outstanding Animated Feature."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2022 National Film Registry inductees with LOC descriptions
# Source: https://newsroom.loc.gov/news/25-eclectic-films-chosen-for-national-film-registry/s/8c41f7a1-b9d9-4f9e-b252-4795b73a4aaf
NFR_2022 = {
"Mardi Gras Carnival": {
"year": 1898,
"description": "The earliest known surviving footage of the New Orleans carnival parade, recently rediscovered in the Netherlands after being long considered lost."
},
"Cab Calloway Home Movies": {
"year": 1948,
"description": "16mm footage documenting the legendary singer and bandleader's family life and travels throughout North and South America and the Caribbean."
},
"Cyrano de Bergerac": {
"year": 1950,
"description": "First U.S. film adaptation of Rostand's play, notable for José Ferrer's acclaimed performance, making him the first Hispanic actor to win an Oscar for Best Actor."
},
"Charade": {
"year": 1963,
"description": "Romantic thriller showcasing the only onscreen pairing of Cary Grant and Audrey Hepburn, blending wit and sophisticated charm."
},
"Scorpio Rising": {
"year": 1963,
"description": "Kenneth Anger's avant-garde collage exploring symbolism regarding religion, Nazism, biker culture, and gay life through early 1960s pop music."
},
"Behind Every Good Man": {
"year": 1967,
"description": "Pre-Stonewall UCLA student film offering an early portrait of Black gender fluidity in Los Angeles and the pursuit of love and acceptance."
},
"Titicut Follies": {
"year": 1967,
"description": "Frederick Wiseman's groundbreaking documentary exposing abuse and inhumane conditions at a Massachusetts prison for the criminally insane."
},
"Mingus": {
"year": 1968,
"description": "Raw portrait of legendary composer and bassist Charles Mingus documenting his life, the jazz scene, and his perspectives on racism and society."
},
"Manzanar": {
"year": 1971,
"description": "Documentary reflecting on the filmmaker's childhood experiences in a Japanese American internment camp and its lasting personal impact."
},
"Betty Tells Her Story": {
"year": 1972,
"description": "Early feminist documentary exploring how storytelling reveals hidden context about identity, appearance, and women's relationship with beauty culture."
},
"Super Fly": {
"year": 1972,
"description": "Blaxploitation classic directed by Gordon Parks Jr., serving as both entertainment and social commentary on the American dream."
},
"Attica": {
"year": 1974,
"description": "Documentary investigation of the 1971 Attica prison uprising, examining conditions that sparked the deadliest prison riot in U.S. history."
},
"Carrie": {
"year": 1976,
"description": "Brian De Palma's stylish adaptation of Stephen King's novel about a telekinetic teen, influential in shaping the modern horror genre."
},
"Union Maids": {
"year": 1976,
"description": "Labor documentary featuring oral histories of three Chicago women organizers from the 1930s, exemplifying grassroots historical filmmaking."
},
"Word is Out: Stories of Some of Our Lives": {
"year": 1977,
"description": "Landmark film by the Mariposa Film Group presenting diverse interviews with gay men and lesbians, advancing LGBTQ+ visibility during the emerging rights movement."
},
"Bush Mama": {
"year": 1979,
"description": "L.A. Rebellion film depicting inner-city poverty and systemic injustice through the story of a woman navigating oppressive welfare and penal systems."
},
"The Ballad of Gregorio Cortez": {
"year": 1982,
"description": "Key Chicano cinema film based on folklore, telling the true story of a Mexican-American farmer falsely accused of a crime on the Texas frontier."
},
"Itam Hakim, Hopiit": {
"year": 1984,
"description": "Victor Masayesva Jr.'s imaginative video translation of Hopi oral traditions, moving from personal narrative to mythology to historical prophecy."
},
"Hairspray": {
"year": 1988,
"description": "John Waters' mainstream film about Baltimore's 1962 teen dance scene, becoming a cultural touchstone for acceptance and racial integration."
},
"The Little Mermaid": {
"year": 1989,
"description": "Disney animated classic with memorable Alan Menken score and Howard Ashman songs, defining the Disney Renaissance of the 1980s-90s."
},
"Tongues Untied": {
"year": 1989,
"description": "Marlon Riggs' video essay combining interviews, performance, and archival footage exploring Black male same-sex relationships and gay rights advocacy."
},
"When Harry Met Sally": {
"year": 1989,
"description": "Rob Reiner's acclaimed romantic comedy with Billy Crystal and Meg Ryan, named by Vanity Fair as the best American rom-com ever made."
},
"House Party": {
"year": 1990,
"description": "Reginald Hudlin's comedy launching hip-hop culture and New Jack Swing into mainstream cinema while introducing Kid 'n Play to audiences."
},
"Iron Man": {
"year": 2008,
"description": "Marvel Studios' superhero film directed by Jon Favreau, establishing the studio's independence and launching the cinematic universe phenomenon."
},
"Pariah": {
"year": 2011,
"description": "Dee Rees' intimate coming-of-age drama about a Black lesbian teenager in Brooklyn, representing rare Black female directorial voice in queer cinema."
},
}
+105
View File
@@ -0,0 +1,105 @@
# 2023 National Film Registry inductees with LOC descriptions
# Source: https://newsroom.loc.gov/news/25-films-selected-for-preservation-in-national-film-registry/s/aa4bef48-95f6-486f-882d-110613633b1e
NFR_2023 = {
"A Movie Trip Through Filmland": {
"year": 1921,
"description": "Educational film about motion picture film stock production and cinema's global impact, shot at Kodak Park in Rochester, New York."
},
"Dinner at Eight": {
"year": 1933,
"description": "Pre-Code ensemble comedy-drama directed by George Cukor featuring an all-star cast in a high society setting adapted from a stage play."
},
"Bohulano Family Film Collection": {
"year": 1950,
"description": "Home movies documenting Filipino American community life in Stockton, California over 20 years, including family events and cultural gatherings."
},
"Helen Keller in Her Story": {
"year": 1954,
"description": "Academy Award-winning documentary using news footage, photographs, and interviews to chronicle Helen Keller's life from birth through her 70s."
},
"Lady and the Tramp": {
"year": 1955,
"description": "Animated love story between a cocker spaniel and a mutt, notable for technological innovation in CinemaScope release and memorable voice performances."
},
"Edge of the City": {
"year": 1957,
"description": "Psychological drama featuring John Cassavetes and Sidney Poitier about railroad workers, adapted from television drama emphasizing racial brotherhood."
},
"We're Alive": {
"year": 1974,
"description": "Documentary resulting from video workshops at California Institution for Women, capturing incarcerated participants discussing prison dehumanization and reform."
},
"Cruisin' J-Town": {
"year": 1975,
"description": "Documentary about jazz fusion band Hiroshima, documenting their artistic identity, Little Tokyo roots, and Asian American community influence in early 1970s LA."
},
"¡Alambrista!": {
"year": 1977,
"description": "Low-budget film shot documentary-style about a Mexican migrant laborer in the US, called the 'first and arguably best rendering of the Mexican American diaspora story.'"
},
"Passing Through": {
"year": 1977,
"description": "LA Rebellion film about a jazz artist released from prison who seeks artistic integrity and cultural preservation outside corporate music industry control."
},
"Fame": {
"year": 1980,
"description": "Musical drama following students at New York's High School of Performing Arts, influencing 1980s musicals with stylistic music video-like sequences."
},
"Desperately Seeking Susan": {
"year": 1985,
"description": "Hip screwball comedy involving personal ads and mistaken identity, serving as historical snapshot of 1980s New York City fashion, music, and Madonna's cultural presence."
},
"The Lighted Field": {
"year": 1987,
"description": "Avant-garde experimental work combining archival imagery with urban and domestic images, exploring themes of light, shadow, vitality, and mortality."
},
"Matewan": {
"year": 1987,
"description": "Historical drama depicting 1920 West Virginia coal mining unionization efforts, examining collective nonviolence against exploitation within individualistic culture."
},
"Home Alone": {
"year": 1990,
"description": "Holiday mega-hit starring Macaulay Culkin about a youngster using creativity and wit to defeat burglars while home alone at Christmas, becoming cultural classic."
},
"Queen of Diamonds": {
"year": 1991,
"description": "Experimental film by Nina Menkes set in Las Vegas, using extended silences and long takes to convey a blackjack dealer's solitary desert existence."
},
"Terminator 2: Judgment Day": {
"year": 1991,
"description": "Science fiction sequel retaining original virtues while adding nuanced characters, cutting-edge special effects, and marked transition from practical to CGI effects."
},
"The Nightmare Before Christmas": {
"year": 1993,
"description": "Stop-motion animated film conceived and produced by Tim Burton about Halloween Town's king bringing Christmas magic, becoming both holiday and Halloween tradition."
},
"The Wedding Banquet": {
"year": 1993,
"description": "Ground-breaking romantic comedy exploring cultural clashes between East and West when a gay Taiwanese American arranges marriage to satisfy traditional parents."
},
"Maya Lin: A Strong Clear Vision": {
"year": 1994,
"description": "Oscar-winning documentary by Freida Lee Mock about architect Maya Lin, exploring her Vietnam Veterans Memorial design and themes of artistic freedom and public art."
},
"Apollo 13": {
"year": 1995,
"description": "Meticulous, emotional retelling of the near-tragic 1970 space mission blending skillful editing, special effects, and masterful pacing of technological problem-solving."
},
"Bamboozled": {
"year": 2000,
"description": "Spike Lee satire exposing hypocrisy about an African American TV executive proposing racist blackface minstrel show that unexpectedly becomes hit, sparking outrage."
},
"Love & Basketball": {
"year": 2000,
"description": "Feature directorial debut by Gina Prince-Bythewood following boy and girl pursuing basketball careers while developing mutual affection, praised as refreshing rom-com approach."
},
"12 Years a Slave": {
"year": 2013,
"description": "Best Picture Oscar winner offering raw, visceral look at Louisiana plantation slavery based on Solomon Northup's 1853 memoir of kidnapping and 12-year enslavement."
},
"20 Feet from Stardom": {
"year": 2013,
"description": "Oscar-winning documentary by Morgan Neville featuring interviews with prominent backup singers whose essential musical contributions remain unrecognized in shadows."
},
}

Some files were not shown because too many files have changed in this diff Show More