Skip to main content

Quickstart Guide

Get Beat App up and running on your local machine in just a few minutes. This guide will walk you through the essential steps to start streaming music.
Prerequisites: Node.js v18 or higher and npm/yarn/pnpm installed on your system.

Installation

1

Clone the repository

First, clone the Beat App repository to your local machine:
git clone https://github.com/yourusername/beat-app.git
cd beat-app
2

Install dependencies

Install the required npm packages using your preferred package manager:
npm install
3

Configure environment variables

Copy the example environment file and configure your API credentials:
cp .env.example .env
Edit the .env file with your API credentials:
VITE_API_URL=http://localhost:3000
VITE_YOUTUBE_API_TOKEN=your_token_here
You’ll need a valid YouTube Music API token to stream music. Contact your API provider for credentials.
4

Start the development server

Launch the Vite development server:
npm run dev
The app will start at http://localhost:5173 by default.
Once the development server is running, try these actions:
1

Open the app

Navigate to http://localhost:5173 in your browser.
2

Search for a track

Use the search bar in the top navigation to search for your favorite artist or song.
3

Start playing

Click on any track to start playback. The player controls will appear at the bottom of the screen.
4

Manage your queue

Click the queue icon to open the queue drawer and see upcoming tracks. You can:
  • Add tracks to the queue
  • Play tracks next
  • Reorder the queue

Understanding the Player Store

Beat App uses Nanostores for state management. Here’s how the player store works:
// src/stores/playerStore.js
import { map } from "nanostores";
import audioEl from "../audioEl";

const initialState = {
  isPlaying: false,
  currentTrackIndex: -1,
  currentTrack: null,
  queue: [],
  isLoading: false,
  currentTime: 0,
  duration: 0,
  isQueueOpen: false,
};

export const playerStore = map(initialState);

export const playerActions = {
  playTrack: async (track, newQueue = null) => {
    playerStore.setKey("currentTrack", track);
    playerStore.setKey("isLoading", true);
    
    if (newQueue) {
      playerStore.setKey("queue", newQueue);
    }
    
    const audioUrl = await getAudioUrl(track.trackId);
    audioEl.src = audioUrl;
    audioEl.play();
  },
  
  togglePause: () => {
    if (audioEl.paused) audioEl.play();
    else audioEl.pause();
  },
  
  addToQueue: (track) => {
    const state = playerStore.get();
    playerStore.setKey("queue", [...state.queue, track]);
  },
};
The player store automatically syncs with the HTML5 Audio element and updates the Media Session API for native OS controls.

Using the Player in Components

Access player state and actions in any React component:
import { useStore } from '@nanostores/react';
import { playerStore, playerActions } from '../stores/playerStore';

function TrackItem({ track }) {
  const { currentTrack, isPlaying } = useStore(playerStore);
  const isCurrentTrack = currentTrack?.trackId === track.trackId;

  const handlePlay = () => {
    playerActions.playTrack(track, [track]);
  };

  const handleAddToQueue = () => {
    playerActions.addToQueue(track);
  };

  return (
    <div>
      <h3>{track.title}</h3>
      <p>{track.artists[0]?.name}</p>
      <button onClick={handlePlay}>
        {isCurrentTrack && isPlaying ? 'Pause' : 'Play'}
      </button>
      <button onClick={handleAddToQueue}>Add to Queue</button>
    </div>
  );
}

Searching for Music

The YouTube API service provides comprehensive search capabilities:
// src/services/youtube-api.js
import axios from 'axios';
import { YOUTUBE_API } from '../constants';

const HEADERS = { 
  Authorization: `Bearer ${import.meta.env.VITE_YOUTUBE_API_TOKEN}` 
};

export async function searchTracks(query) {
  try {
    const res = await axios.get(`${YOUTUBE_API}/search`, { 
      params: { q: query, filter: 'SONG' }, 
      headers: HEADERS 
    });
    return { 
      tracks: (res.data.data?.items || []).map(mapSong), 
      continuation: res.data.data?.continuation 
    };
  } catch (e) { 
    return { tracks: [] }; 
  }
}

export async function searchAlbums(query) {
  try {
    const res = await axios.get(`${YOUTUBE_API}/search`, { 
      params: { q: query, filter: 'ALBUM' }, 
      headers: HEADERS 
    });
    return { albums: (res.data.data?.items || []).map(mapAlbum) };
  } catch (e) { 
    return { albums: [] }; 
  }
}

export async function searchArtists(query) {
  try {
    const res = await axios.get(`${YOUTUBE_API}/search`, { 
      params: { q: query, filter: 'ARTIST' }, 
      headers: HEADERS 
    });
    return { artists: (res.data.data?.items || []).map(mapArtist) };
  } catch (e) { 
    return { artists: [] }; 
  }
}

Key Features to Explore

Search System

Search for tracks, albums, artists, and playlists with dedicated result pages

Queue Management

Build and manage your playback queue with play next/add to queue options

Media Controls

Control playback from your keyboard, OS media controls, or lock screen

Theme Toggle

Switch between light and dark modes with the theme toggle button

Next Steps

Installation Guide

Learn about advanced installation options and production builds

API Reference

Explore the complete API service and store documentation

Deployment

Deploy Beat App to production with Docker and NGINX

Architecture

Discover the component structure and architecture
Having issues? Check the browser console for error messages and ensure your API credentials are correctly configured.

Build docs developers (and LLMs) love