Creating a Spotify Song Downloader: Dancing with `spotdl`, React, and Express 🎵💃🚀
Tags: react, express, api, cli
Published: 2023-09-11 15:27:49

### **Friendly Reminder:**

Before we embark on this musical coding journey, a reminder! Our intention is purely educational. As much as we'd love to jam to those tunes, downloading copyrighted content without proper rights is a big no-no. Always dance within the bounds of the law!

---

### **Introduction**

Ever wanted to blend the magic of React, the power of Express, and the prowess of `spotdl` into a groovy app? Well, put on your coding headphones because we're about to embark on a musical adventure!
[Github repo with full code](https://github.com/OthmanAdi/Dangerously_Fun_WebApp)

---

### **Tuning the Frontend with React 🎸**

#### **Prerequisites**

- Your coding groove on!
- Node.js and npm installed.

#### **Striking the React Notes**

Our frontend is like the face of our band - it's what the crowd sees! Let's dive into the React part and understand each chord:

```jsx
// ----- Imports -----
import React, { useState } from 'react';
import styled from 'styled-components';
import Swal from 'sweetalert2';
import 'bootstrap/dist/css/bootstrap.min.css';

// ----- Styled Components -----

// Container components
const ScrollContainer = styled.div`
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 100vh;
`;
const SectionsContainer = styled.div`
  max-height: 40vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
`;

// Layout and positioning components
const Section = styled.div`
  min-height: 100vh;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  justify-content: center;
  // align-items: center;
`;
const TableContainer = styled.div`
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 20px;
  margin: 20px;
`;
const InputGroupContainer = styled.div`
  display: flex;
  justify-content: center;
`;

// List and item components
const ListContainer = styled.div`
  height: 20vh; 
  overflow-y: scroll;
`;

// ----- App Component -----
export default function App() {
  // State hooks
  const [sections, setSections] = useState([{ songUrl: '', audioFormat: 'mp3', urlList: [] }]);

  // Handle adding song URL and downloading
  const handleAddUrl = async (index) => {
    const newSections = [...sections];
    const section = newSections[index];

    try {
      const response = await fetch('http://localhost:3001/api/download', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ url: section.songUrl, format: section.audioFormat }),
      });

      if (response.ok) {
        const data = await response.json();
        section.urlList = [section.songUrl, ...section.urlList];
        newSections[index] = section;
        setSections(newSections);
        Swal.fire({ icon: 'success', title: 'OK', showConfirmButton: false, timer: 1000 });
      } else {
        Swal.fire({ icon: 'error', title: 'Song not found', showConfirmButton: false, timer: 1000 });
      }
    } catch (error) {
      Swal.fire({ icon: 'error', title: 'Song not found', showConfirmButton: false, timer: 1000 });
    }

    // Clear the input
    section.songUrl = '';
    newSections[index] = section;
    setSections(newSections);
  };

  const addSection = () => {
    setSections([...sections, { songUrl: '', audioFormat: 'mp3', urlList: [] }]);
  };

  // Main render
  return (
    <ScrollContainer>
      {/* Intro Section */}
      <Section className="container-fluid text-center">
        <h1 className="display-3">Download Spotify Songs with <code>spotdl</code></h1>
        <h1 className="display-5 text-center my-4">How to Download Music with SpotDL</h1>
        <p className="text-center mb-4">
          SpotDL is a utility that allows you to download music from Spotify directly to your computer. Here's a simple guide on how to use it with terminal commands.
        </p>
      </Section>

      {/* Command Table Section */}
      <Section className="container-fluid text-center">
        <TableContainer>
          <table className="table table-bordered">
            <thead>
              <tr>
                <th className="text-center">Command</th>
                <th className="text-center">Description</th>
              </tr>
            </thead>
            <tbody>
              {/* Commands */}
              <tr>
                <td className="text-center"><code>spotdl [trackUrl]</code></td>
                <td className="text-center">Download a track by its Spotify URL</td>
              </tr>
              {/* ... other commands ... */}
            </tbody>
          </table>
        </TableContainer>
        {/* Command Examples */}
        {/* ... */}
      </Section>

      {/* Download Section */}
      <Section className="container-fluid text-center">
        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '1rem' }}>
          <button className="btn btn-success w-25" style={{ width: 'auto' }} onClick={addSection}>New Section</button>
        </div>
        <SectionsContainer>
          {/* Iterating through sections for download */}
          {/* ... */}
        </SectionsContainer>
      </Section>
    </ScrollContainer>
  );
}
```

**Decoding the Chords:**
- **Styled Components:** We're using `styled-components` to strike a fashion statement with our app. Just like a rockstar needs an outfit, our components need styles!
- **Swal Alerts:** These pop-up alerts are like the light effects on stage. They inform the user whether their download was a hit or a miss.
- **React Hooks:** Just like how a song has multiple verses, our app keeps track of song URLs and formats using the `useState` hook.
- **Fetch API:** When the user wants to download a song, we send a request to our backstage (backend) crew using the Fetch API.

---

### **Strumming the Backend with Express 🎤**

#### **Prerequisites**

- Your coding rhythm!
- Node.js and npm.

#### **Hitting the Express High Notes**

Our backend is the unseen hero, doing all the heavy lifting. It's like the bassist, setting the foundation:

```javascript
// ----- Imports -----
const express = require('express');
const cors = require('cors');
const { exec } = require('child_process');

// ----- Express App Configuration -----
const app = express();

// Middleware setup
app.use(cors());           // Enable CORS for all routes
app.use(express.json());   // For parsing application/json

// ----- Routes -----

// POST endpoint for song download
app.post('/api/download', (req, res) => {
    // Destructuring to get URL and format from the request body
    const { url, format } = req.body;

    // IMPORTANT: Always be cautious when running shell commands from user input.
    // Sanitize and validate the input to prevent malicious code execution.
    exec(`spotdl ${url}`, (error, stdout, stderr) => {
        if (error) {
            // Handle command execution errors
            return res.status(500).json({ error: 'Download failed' });
        }

        // Ideally, you'd return something more substantial here.
        // For example, you might return a download link or save the song info.
        res.status(200).json({ success: true, message: 'Downloaded successfully!' });
    });
});

// ----- Start the server -----
const PORT = 3001;
app.listen(PORT, () => {
    console.log(`Server running on http://localhost:${PORT}`);
});
```

**Diving into the Express Beats:**
- **Express and CORS:** Express is our stage, and CORS makes sure there are no unwanted interruptions (like security issues).
- **Child Process:** This lets our app run terminal commands, like a drummer hitting the beats.
- **API Endpoint:** The `/api/download` endpoint is the main act of our show. It uses `spotdl` to download songs and dances with the frontend.

---

### **Soundchecking with `httpie` 🎧**

Once you've set up the stage, you need a soundcheck. Testing our API with `httpie` is just that:

```bash
http POST http://localhost:3001/api/download url=<Spotify_URL> format=mp3
```

Here, replace `<Spotify_URL>` with a Spotify song's URL, and let the magic happen!

---

### **Encore: Further Learning 🌟**

Hungry for more? Here's how you can take this party to the next level:

1. **Dive Deeper into React:** Explore the React docs, and maybe even dabble with React Native for mobile magic.
2. **Express Middleware:** Learn how middleware can add more instruments to your backend band.
3. **Web Security:** Just like how a band needs security, your web app does too! Dive deep into web security practices.

---

### **Wrapping Up & Closing Notes**

That concludes our exhilarating dive into React, Express, and `spotdl`. I hope you've enjoyed this musical coding jam as much as I did crafting it for you. Always remember to groove responsibly and respect the art and the artist!

Beyond this guide, I'm passionate about offering insights, resources, and regular updates that enrich your tech journey. If this guide struck a chord with you, I'd be thrilled if you accompanied me on various platforms where the tech melodies continue.

📸 **Instagram**: Experience the vibrant pulse of the tech world with me. Follow [@Codinwithadi](https://www.instagram.com/Codinwithadi/) for daily inspirations, updates, and the harmonies of coding.

💻 **Websites**: 
- For in-depth guides, articles, and tutorials, visit [adeptlytech.tech](https://adeptlytech.tech/). It's a treasure trove designed to enhance your coding voyage.
- Looking for AI tools? Discover [ai-pool.web.app](https://ai-pool.web.app/#/), an AI finding platform built with Flutter and Dart, designed to pool the best AI resources for enthusiasts like you.

💌 **Email**: For feedback, questions, or just a good old chat about the wonders of tech and coding, feel free to drop a note at [adiatwork@outlook.com](mailto:adiatwork@outlook.com). Engaging with fellow tech enthusiasts always brightens my day!

Before I sign off, let me reiterate: The world of coding is vast and magnificent, and collaboration and shared learning are its pillars. Whether you have queries, need help, or wish to share your own insights, I'm always here, eager to listen and assist.

Stay curious, stay passionate, and let's keep fostering a community where every coder finds their rhythm. Happy coding! 🎵🚀