<?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>Forem: Smit Patil</title>
    <description>The latest articles on Forem by Smit Patil (@coder_smit).</description>
    <link>https://forem.com/coder_smit</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3672082%2Fd7bc2fbc-6331-4885-a16f-0fe380ca051f.jpg</url>
      <title>Forem: Smit Patil</title>
      <link>https://forem.com/coder_smit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/coder_smit"/>
    <language>en</language>
    <item>
      <title># I Built a Free In-Browser Music Player for AI Playlists — Here's What I Learned</title>
      <dc:creator>Smit Patil</dc:creator>
      <pubDate>Mon, 06 Apr 2026 10:18:24 +0000</pubDate>
      <link>https://forem.com/coder_smit/-i-built-a-free-in-browser-music-player-for-ai-playlists-heres-what-i-learned-270p</link>
      <guid>https://forem.com/coder_smit/-i-built-a-free-in-browser-music-player-for-ai-playlists-heres-what-i-learned-270p</guid>
      <description>&lt;p&gt;&lt;em&gt;17 years old. Vanilla JS. No framework. No backend server. Just shipped.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem Nobody Was Solving
&lt;/h2&gt;

&lt;p&gt;Every week, thousands of people ask ChatGPT, Claude, or Gemini for a playlist. The AI happily gives them a beautiful list of 10 songs. And then... nothing. They're stuck copy-pasting each song into Spotify or YouTube one by one.&lt;/p&gt;

&lt;p&gt;That's annoying. So I fixed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PlaylistBridge&lt;/strong&gt; (&lt;a href="https://playlistbridge.netlify.app" rel="noopener noreferrer"&gt;playlistbridge.netlify.app&lt;/a&gt;) converts any AI-generated song list into instant playable links. No login. No app install. Paste and play.&lt;/p&gt;

&lt;p&gt;I started with a simple idea. Over the past few months it became something I didn't expect — a full in-browser music player with video mode, community playlists, shareable cards, and a Firestore-backed song cache. All in vanilla JS.&lt;/p&gt;

&lt;p&gt;This is the story of how I built it and what I learned along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack (And Why I Chose It)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Vanilla HTML, CSS, JavaScript — no React, no Vue, nothing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Netlify Functions (serverless)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; Firebase Firestore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting:&lt;/strong&gt; Netlify free tier&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata:&lt;/strong&gt; iTunes Search API (free, no key needed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playback:&lt;/strong&gt; YouTube IFrame API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose vanilla JS deliberately. No build step, no dependency hell, no framework overhead. Every file is directly editable and deployable. When something breaks, I know exactly where to look.&lt;/p&gt;

&lt;p&gt;The tradeoff is more verbose DOM manipulation — but I handled this by creating a &lt;code&gt;ui.js&lt;/code&gt; rendering layer that separates all visual state from business logic. &lt;code&gt;script.js&lt;/code&gt; never touches the DOM directly. &lt;code&gt;window.UI.*&lt;/code&gt; handles everything visual.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Feature: Metadata Matching
&lt;/h2&gt;

&lt;p&gt;When a user pastes a song list, here's what happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parser strips numbering, dashes, and whitespace&lt;/li&gt;
&lt;li&gt;Each song query hits my Netlify function which proxies the &lt;strong&gt;iTunes Search API&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;iTunes returns the real track name, artist, and album art URL&lt;/li&gt;
&lt;li&gt;Cards render progressively as each song resolves — no waiting for all songs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The progressive rendering was important. If I waited for all 20 songs to resolve before showing anything, users would think the app was broken. Progressive rendering makes it feel instant.&lt;/p&gt;

&lt;p&gt;One tricky edge case: the iTunes API sometimes returns the wrong song if the query is ambiguous. I solved this by constructing the query as &lt;code&gt;"Artist Title"&lt;/code&gt; from the parsed input, which dramatically improves match accuracy.&lt;/p&gt;




&lt;h2&gt;
  
  
  InstantPlay: The Feature That Changed Everything
&lt;/h2&gt;

&lt;p&gt;The original app just gave links. Users had to click 20 times to open 20 songs. That's still better than nothing, but it's not &lt;em&gt;great&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;InstantPlay&lt;/strong&gt; — an in-browser music player using the YouTube IFrame API.&lt;/p&gt;

&lt;p&gt;The flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User clicks Play
→ Check in-memory cache
→ Check Firestore songs collection
→ Call /.netlify/functions/ytsearch
   → Try Invidious API (3 instances, 3s timeout each)
   → Fallback: YouTube HTML scrape
→ Load YouTube IFrame player
→ Auto-advance on song end
→ Prefetch next song ID in background
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Caching Strategy
&lt;/h3&gt;

&lt;p&gt;I built three layers of caching for video IDs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 — In-memory JS object:&lt;/strong&gt; Zero latency, lost on page refresh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2 — sessionStorage:&lt;/strong&gt; Survives page refresh within the same browser session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 — Firestore &lt;code&gt;songs&lt;/code&gt; collection:&lt;/strong&gt; Cross-user, permanent. Document ID is the normalized query (&lt;code&gt;query.toLowerCase().replace(/[^a-z0-9 ]/g, '').trim()&lt;/code&gt;). First user to play a song pays the API cost. Every user after gets it from Firestore instantly.&lt;/p&gt;

&lt;p&gt;This meant that as the app grew, the Netlify function calls for video IDs would actually &lt;em&gt;decrease&lt;/em&gt; over time as the cache filled up.&lt;/p&gt;

&lt;h3&gt;
  
  
  The YouTube ToS Problem
&lt;/h3&gt;

&lt;p&gt;Here's something I had to think carefully about: the YouTube IFrame API Terms of Service explicitly prohibit creating an "audio-only" experience. My player was hiding the iframe with &lt;code&gt;height: 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My solution: an expandable full-screen player with an &lt;strong&gt;Audio/Video toggle&lt;/strong&gt;. In Audio mode, users see the album art. In Video mode, they see the actual YouTube video. The hidden iframe is always present for audio — but users can switch to video mode to see the visual content, keeping the experience ToS-compliant.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Expanded Player
&lt;/h2&gt;

&lt;p&gt;This was the most complex UI piece.&lt;/p&gt;

&lt;p&gt;When users tap the mini bar at the bottom, it slides up into a full-screen player — exactly like YouTube Music's expanded view. Behind the scenes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The background becomes a blurred version of the current album art&lt;/li&gt;
&lt;li&gt;Album art is displayed large and centered with a subtle glow&lt;/li&gt;
&lt;li&gt;Progress bar, controls, and queue are all visible&lt;/li&gt;
&lt;li&gt;Switching to Video mode injects a standard YouTube embed iframe at the current timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trickiest bug: when Video mode injected its own iframe, the hidden YT API player was still running — two audio sources playing simultaneously. The fix was to &lt;code&gt;mute()&lt;/code&gt; and &lt;code&gt;pauseVideo()&lt;/code&gt; on the API player when switching to video mode, then &lt;code&gt;unMute()&lt;/code&gt; and &lt;code&gt;playVideo()&lt;/code&gt; when switching back to audio.&lt;/p&gt;




&lt;h2&gt;
  
  
  Community Playlists
&lt;/h2&gt;

&lt;p&gt;I wanted users to share what they'd built. The community page shows playlists published by other users — each card has a 2×2 album art collage, song preview, play count, and an "Open &amp;amp; Play" button.&lt;/p&gt;

&lt;p&gt;A key optimisation: instead of fetching album art from iTunes on every community page load (which would be 48 API calls for 12 cards), I save the &lt;code&gt;artUrls&lt;/code&gt; array to Firestore at publish time. The community page reads them directly — zero API calls.&lt;/p&gt;

&lt;p&gt;For playlist titles, I auto-generate them: &lt;code&gt;"The Weeknd, Taylor Swift + 3 more"&lt;/code&gt;. No user input required — frictionless publishing means more people actually publish.&lt;/p&gt;




&lt;h2&gt;
  
  
  Share Cards
&lt;/h2&gt;

&lt;p&gt;After generating a playlist, users can share a beautiful image card — like Spotify Wrapped for their playlist.&lt;/p&gt;

&lt;p&gt;Built entirely with &lt;strong&gt;HTML5 Canvas&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First album art becomes a blurred background&lt;/li&gt;
&lt;li&gt;2×2 collage of album arts at the top&lt;/li&gt;
&lt;li&gt;Song list with thumbnails below&lt;/li&gt;
&lt;li&gt;PlaylistBridge branding + CTA button at the bottom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The CORS challenge: Canvas taints when drawing cross-origin images. The fix was adding &lt;code&gt;crossorigin="anonymous"&lt;/code&gt; to the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements at card render time, then reading those DOM elements directly in the Canvas — zero re-fetch, zero additional API calls.&lt;/p&gt;

&lt;p&gt;On mobile, it triggers the native share sheet. On desktop, it downloads as PNG.&lt;/p&gt;




&lt;h2&gt;
  
  
  SEO That Actually Worked
&lt;/h2&gt;

&lt;p&gt;I'm getting 100% foreign traffic (US, UK, Australia) with zero paid promotion.&lt;/p&gt;

&lt;p&gt;What worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple dedicated landing pages targeting long-tail keywords (&lt;code&gt;/chatgpt-to-spotify&lt;/code&gt;, &lt;code&gt;/text-to-youtube-music&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;JSON-LD schema for &lt;code&gt;WebApplication&lt;/code&gt; and &lt;code&gt;FAQPage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;llms.txt&lt;/code&gt; — a plain text file explaining the tool to AI models. This is why ChatGPT and Gemini have been recommending PlaylistBridge to users organically.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;alternateName: "Playlist Bridge"&lt;/code&gt; in schema to capture the two-word search variant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What didn't work: Reddit. Every post got removed regardless of account age or content quality. Moved on.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Numbers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;319+ playlists generated&lt;/strong&gt; (tracked via Firestore)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;100% foreign traffic&lt;/strong&gt; — US, UK, Australia, Europe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10 days&lt;/strong&gt; to reach 100 visitors after the redesign (vs 2 months before)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;777 Netlify function calls in a single day&lt;/strong&gt; peak&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0 paid promotion&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use a design system from day one.&lt;/strong&gt; I spent hours fixing inconsistent spacing because I didn't establish CSS variables properly at the start. Now I have a full design system — but retrofitting it was painful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build the caching layer earlier.&lt;/strong&gt; I only added the Firestore song cache after noticing Netlify function calls spiking. It should have been there from day one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test on real devices sooner.&lt;/strong&gt; So many bugs only appeared on mobile — the expanded player layout, volume controls getting cropped, background play limitations. Emulators lie.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spotify OAuth&lt;/strong&gt; — create real playlists in user accounts. This is the feature users actually want.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mood/Vibes page&lt;/strong&gt; — browse community playlists by genre (Gym, Romance, Sad, Late Night)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AdSense&lt;/strong&gt; — the foreign traffic makes this viable now&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://playlistbridge.netlify.app" rel="noopener noreferrer"&gt;playlistbridge.netlify.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Paste any AI playlist. Hit play. It just works.&lt;/p&gt;

&lt;p&gt;If you've built something similar or have thoughts on the architecture decisions, I'd love to hear them in the comments. Especially interested in how others have handled the YouTube IFrame ToS compliance question.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with vanilla JS, Firebase, and Netlify. No VC funding. No team. Just me, 17, figuring it out.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>music</category>
      <category>javascript</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Smit Patil</dc:creator>
      <pubDate>Sat, 20 Dec 2025 17:19:46 +0000</pubDate>
      <link>https://forem.com/coder_smit/-obl</link>
      <guid>https://forem.com/coder_smit/-obl</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/coder_smit" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3672082%2Fd7bc2fbc-6331-4885-a16f-0fe380ca051f.jpg" alt="coder_smit"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/coder_smit/i-built-a-tool-that-converts-plain-text-song-lists-like-from-chatgpt-into-playable-music-links-222b" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;I built a tool that converts plain text song lists (like from ChatGPT) into playable music links instantly.&lt;/h2&gt;
      &lt;h3&gt;Smit Patil ・ Dec 20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#chatgpt&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#music&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ai&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>webdev</category>
      <category>chatgpt</category>
      <category>music</category>
      <category>ai</category>
    </item>
    <item>
      <title>I built a tool that converts plain text song lists (like from ChatGPT) into playable music links instantly.</title>
      <dc:creator>Smit Patil</dc:creator>
      <pubDate>Sat, 20 Dec 2025 17:18:43 +0000</pubDate>
      <link>https://forem.com/coder_smit/i-built-a-tool-that-converts-plain-text-song-lists-like-from-chatgpt-into-playable-music-links-222b</link>
      <guid>https://forem.com/coder_smit/i-built-a-tool-that-converts-plain-text-song-lists-like-from-chatgpt-into-playable-music-links-222b</guid>
      <description>&lt;p&gt;Hey everyone,&lt;br&gt;
I am 17&lt;br&gt;
​I often use ChatGPT to generate playlists for workouts or coding, but moving those songs into Spotify or YouTube Music was a pain. I had to search for them one by one.&lt;/p&gt;

&lt;p&gt;​Existing transfer tools usually require you to log in with your Spotify account (which feels sketchy for a quick task) or pay for a subscription.&lt;/p&gt;

&lt;p&gt;​So I built PlaylistBridge.&lt;/p&gt;

&lt;p&gt;​What it does:&lt;/p&gt;

&lt;p&gt;​You paste a text list of songs (numbered, bulleted, whatever). ​It instantly fetches the album art and metadata (using the iTunes API). ​It generates "Search Links" that open directly in your preferred app (Spotify, YT Music, or YouTube). ​Privacy: It is 100% client-side. There is no database, no login, and no tracking. &lt;/p&gt;

&lt;p&gt;​The Tech:&lt;/p&gt;

&lt;p&gt;It’s a static site hosted on Netlify. It uses a hybrid approach: iTunes for instant metadata (so it feels fast) and URL hashing to create shareable session links without a backend.&lt;/p&gt;

&lt;p&gt;​Link: &lt;a href="https://dev.tourl"&gt;https://playlistbridge.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;​Hope it saves you some clicks!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>chatgpt</category>
      <category>music</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
