Files
marcus-web/scripts/new_movie.py
T

230 lines
6.2 KiB
Python
Executable File

#!/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
TMDB_API_KEY = "9e36fdcf70a4918e0dce327acc437dff"
# 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):
"""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 ' ""'
content = f'''---
title: '{title}'
date: {now}
draft: true
series: "Frank's Couch"
summary: ""
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)
# Create post
filepath = create_post(imdb_id, details, details.get("poster_path"), args.title)
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()