<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bhavy Khatod</title>
    <description>The latest articles on DEV Community by Bhavy Khatod (@joyboy_8509).</description>
    <link>https://dev.to/joyboy_8509</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160140%2F883a9365-ebd6-488f-855e-4f4c2af67081.jpeg</url>
      <title>DEV Community: Bhavy Khatod</title>
      <link>https://dev.to/joyboy_8509</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joyboy_8509"/>
    <language>en</language>
    <item>
      <title>Log It Already : The movie backlog was overwhelming, so I built my friend an AI that just picks one.</title>
      <dc:creator>Bhavy Khatod</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:32:38 +0000</pubDate>
      <link>https://dev.to/joyboy_8509/log-it-already-the-movie-backlog-was-overwhelming-so-i-built-my-friend-an-ai-that-just-picks-one-3oln</link>
      <guid>https://dev.to/joyboy_8509/log-it-already-the-movie-backlog-was-overwhelming-so-i-built-my-friend-an-ai-that-just-picks-one-3oln</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;My friend loves movies. But watching him actually sit down to watch a movie is an exercise in frustration. The actual bottleneck is never finding a good film—it's the paradox of choice. He has over 500 movies in his Letterboxd watchlist. He scrolls, reads three reviews, checks the runtime, gets overwhelmed, and then just closes the app. &lt;/p&gt;

&lt;p&gt;He spends 45 minutes deciding what to watch, and by the time he picks something, he's too tired to actually watch it.&lt;/p&gt;

&lt;p&gt;So I built him &lt;strong&gt;Log It Already&lt;/strong&gt;: a fast, minimalist movie selector. You paste in your Letterboxd watchlist URL, type in exactly how you are feeling today ("brain fried from work, want a sci-fi"), and it cross-references your exact mood with your existing backlog to spit out &lt;em&gt;one&lt;/em&gt; single recommendation. No carousels. No endless scrolling. Just the movie you should watch right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://log-it-already-newqbt7tcsehhhwobcecyh.streamlit.app/" rel="noopener noreferrer"&gt;Live Demo: Log It Already&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jd20fh5ozg8o41hwynr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2jd20fh5ozg8o41hwynr.png" alt="Search box with list URL and Mood" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fng9nbv2f2g2oki0l285s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fng9nbv2f2g2oki0l285s.png" alt="Result with Poster" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/joyboy-8509" rel="noopener noreferrer"&gt;
        joyboy-8509
      &lt;/a&gt; / &lt;a href="https://github.com/joyboy-8509/log-it-already" rel="noopener noreferrer"&gt;
        log-it-already
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Hacktoberfest Weekend Challenge: Build for a Friend
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/joyboy-8509/log-it-already/assets/top4.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjoyboy-8509%2Flog-it-already%2FHEAD%2Fassets%2Ftop4.png" alt="My Current Top 4"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;My Current Top 4&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🍿 Log It Already (Hacktoberfest Weekend Challenge: Build for a Friend)&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;For the cinephile with 500 movies in their watchlist and 45 minutes of decision paralysis
"Log It Already" is a minimalist, AI-powered movie recommender built with a clean, high-contrast aesthetic. It scans your Letterboxd watchlist and uses AI to pick the absolute best movie for your current mood.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Letterboxd Integration:&lt;/strong&gt; Automatically scrapes your public watchlist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vibe Check:&lt;/strong&gt; Tell the AI exactly what you're in the mood for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimalist UI:&lt;/strong&gt; Clean, high-contrast, distraction-free design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smart Fallback:&lt;/strong&gt; Don't have a watchlist? Leave it blank and the AI will recommend a global trending movie based on your mood.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to Run&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Python 3.9+&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ollama.com/" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; (If running local models) or an Ollama Cloud API Key.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;git clone https://github.com/joyboy-8509/log-it-already.git
&lt;span class="pl-c1"&gt;cd&lt;/span&gt; log-it-already&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Install the required dependencies:
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install -r requirements.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Set your Ollama API key…&lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/joyboy-8509/log-it-already" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Watchlist URL ──▶ BeautifulSoup Scraper ──┐
                                              │
                                              ▼
    Mood Input ─────▶ Streamlit UI ─────▶ Ollama API (Gemma4:31b) ──▶ 1 Perfect Movie
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The constraint that shaped everything&lt;/strong&gt;&lt;br&gt;
My first plan was obvious: just hook up to the Letterboxd API, pull his watchlist JSON, and feed it to an LLM. &lt;/p&gt;

&lt;p&gt;That plan died immediately. Letterboxd doesn't have an open, public API for standard developers. I had to scrape the data dynamically. But scraping a modern web app isn't as simple as &lt;code&gt;requests.get()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Gemma 4 at the core&lt;/strong&gt;&lt;br&gt;
The engine running the logic is &lt;code&gt;gemma4:31b&lt;/code&gt;, Google's open-weight model, served through the Ollama Cloud API.&lt;/p&gt;

&lt;p&gt;The design decision I'm happiest with: there is no complex RAG pipeline. The entire scraped watchlist easily fits into a single context window. So every query sends the user's mood and their &lt;em&gt;entire&lt;/em&gt; watchlist array directly to the model. The system prompt does the heavy lifting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answer &lt;em&gt;only&lt;/em&gt; from the provided watchlist array.&lt;/li&gt;
&lt;li&gt;Explain &lt;em&gt;why&lt;/em&gt; it fits their specific mood.&lt;/li&gt;
&lt;li&gt;Never hallucinate a movie that isn't on the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. What I got wrong on the way&lt;/strong&gt;&lt;br&gt;
I originally targeted the &lt;code&gt;og:image&lt;/code&gt; meta tag to pull movie posters, but that returned horizontal backdrop banners that destroyed my vertical UI layout. I had to rewrite the scraper to dig into the &lt;code&gt;application/ld+json&lt;/code&gt; script tag to regex-extract the true 2:3 vertical poster URL.&lt;/p&gt;

&lt;p&gt;Later, I tried to speed up the app by scraping the posters directly from the watchlist page. I deployed it, and suddenly &lt;em&gt;every&lt;/em&gt; poster broke. It turns out Letterboxd lazy-loads watchlist images, so my scraper was proudly serving a tiny 1x1 transparent &lt;code&gt;empty-poster.png&lt;/code&gt; to the UI instead of the actual movie poster. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model choice is a swap.&lt;/strong&gt; Gemma is just an API call away. If something better ships, or I want to run it completely offline on my own laptop, I change one string. Nothing else in the project knows or cares which model answers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's inspectable and honest.&lt;/strong&gt; The closed path here would be relying on a massive recommendation algorithm like Netflix's, which is a black box optimized for watch-time. What I built is small and honest. It only looks at the movies &lt;em&gt;you&lt;/em&gt; already curated and explicitly want to watch.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The hand-over
&lt;/h2&gt;

&lt;p&gt;I sent it to him to try out. The most important question was: does this actually stop you from scrolling?&lt;/p&gt;

&lt;p&gt;He went through his watchlist, typed in his mood, and it immediately grabbed a psychological thriller he'd added three years ago and forgotten about. He liked that it explained &lt;em&gt;why&lt;/em&gt; it picked it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What his feedback actually changed
&lt;/h2&gt;

&lt;p&gt;All of this is live on the repo now, shipped after his feedback:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;He said&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;What changed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"The &lt;em&gt;Look Back&lt;/em&gt; poster is some guy in goggles, not the anime."&lt;br&gt;
The AI had guessed the URL slug and hit a 1959 film with the same name. Rewrote the scraper to pull the exact slug directly from the watchlist data.&lt;/p&gt;

&lt;p&gt;"Press enter to search is not working"&lt;br&gt;
Wrapped the entire input section in an &lt;code&gt;st.form&lt;/code&gt; so keyboard submission works natively.&lt;/p&gt;

&lt;p&gt;"What if they don't have a watchlist?"&lt;br&gt;
Made the URL input optional. If left blank, it dynamically falls back to querying global trends.&lt;/p&gt;

&lt;p&gt;"I got a 401 Unauthorized error"&lt;br&gt;
Migrated the API key infrastructure to natively check Streamlit Secrets first, fixing the cloud deployment.&lt;/p&gt;

&lt;p&gt;The useful version of AI here isn't one that endlessly generates new content. It's the one that looks at a pile of data you already curated, points at one thing, and says "Watch this," and then gets out of the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma&lt;/strong&gt; — &lt;code&gt;gemma4:31b&lt;/code&gt; is the open-weight model doing the reasoning, constrained to cross-reference the user's specific mood against a scraped array of movie titles via the Ollama API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;The project was built with AI assistance. Especially, debugging of Streamlit forms, and BeautifulSoup JSON-LD parsing were solved via a weekend pair-programming session with an AI agent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;em&gt;P.S. Cover image is my top 4&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
