Strapi
Published in

Strapi

How to Build a Music Player with React and Strapi

This article teaches you on how to build a music player with React and Strapi

What is Strapi?

Strapi is an open-source content management system. It allows you to create customizable APIs in any frontend application. Strapi is so easy to use because it allows you to build flexible APIs with one-of-a-kind features that you’ll love.

Prerequisites

To follow through with this article, you must have the following:

  • Node.js installed (v14)
  • Npm or yarn installed (npm v6 is more suited to install Strapi). Note: If you have problems installing Strapi, I recommend clearing the npm cache completely and downgrading to node 14 (by completely uninstalling the higher version of node from your system and anywhere node may appear). Accept the extra installation (the python scripts etc.) It worked for me.

Project Scope

Before we proceed, it is very important to know the scope of our project. What we want to archieve is build a simple music player in which all its music and details including the name of the artist, name of song and image acting as the cover music. Our music App should also be able to show us the next song on the list and the artist.

Setting up Strapi

To get started, we’ll first need to install Strapi. Create a folder called strapi-musicplayer, cd into it in our terminal, and run either of the following commands below:

npx create-strapi-app@latest my-project --quickstart
#or
yarn create strapi-app my-project --quickstart
The Strapi Welcome Page
npm run devlop

Creating Our Collection Type

In order to create our collection type, on your admin homepage, go to Content-Type Builder and create a new collection type.

Creating collection types
Name of our collection type

Populate the Collection

In the top-left corner of the admin page, select Content Manager. This will navigate you to the page where we will add contents to our database.

A sample screenshot
Screenshot
Roles Page
Screenshot

Building the Frontend

For our frontend, we’ll be using React. Let’s get started by installing React and all the necessary packages.

npx create-react-app music-player
cd music-player
npm install axios
npm i --save @fortawesome/fontawesome-svg-core
npm install --save @fortawesome/free-solid-svg-icons
npm install --save @fortawesome/react-fontawesome
screenshot
screenshot
npm start

Creating Our Components

creating components is the next thing we’ll be doing. We’ll be creating three components, namely:

  • Player.js : This will be responsible for handling everything concerning our music player. Think of it as the captain of a squad, in which our Detials.js and Control.js are under because it’ll be using their info ( this will be our props) to work.
  • Details.js: This will contain details like the artist name and title of the song.
  • Controls.js This will be responsible for the controls like the play, pause, next, and previous.
import axios from "axios";
import { useEffect, useState } from "react";
import Player from "./Player";
const Index = () => {
const [songs, setsongs] = useState([]);
const [currentSongIndex, setCurrentSongIndex] = useState(0);
const [nextSongIndex, setNextSongIndex] = useState(0);
// fetching our api
useEffect(() => {
const fetchData = async () => {
try {
const { data: response } = await axios.get(
"http://localhost:1337/api/music-players?populate=*"
);
let _musics = response.data;
_musics.map((music) => {
let pload = {
title: music.attributes.title,
artist: music.attributes.artist,
img_src:
"http://localhost:1337" +
music.attributes.img_src.data[0].attributes.url,
src:
"http://localhost:1337" +
music.attributes.music_src.data[0].attributes.url,
};
setsongs((oldSongs) => [...oldSongs, pload]);
});
} catch (error) {
console.error(error);
}
};
fetchData();
}, []);
// .. calling
useEffect(() => {
setNextSongIndex(() => {
if (currentSongIndex + 1 > songs.length - 1) {
return 0;
} else {
return currentSongIndex + 1;
}
});
}, [currentSongIndex]);
// ..
return (
<div className="App">
{songs.length > 0 && (
<>
<Player
currentSongIndex={currentSongIndex}
setCurrentSongIndex={setCurrentSongIndex}
nextSongIndex={nextSongIndex}
songs={songs}
/>
</>
)}
</div>
);
};
export default Index;
import React, { useState, useRef, useEffect } from "react";
import Controls from "./Controls";
import Details from "./Details";
function Player(props) {
const audioEl = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
useEffect(() => {
if (isPlaying) {
audioEl.current.play();
} else {
audioEl.current.pause();
}
});
const SkipSong = (forwards = true) => {
if (forwards) {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp++;
if (temp > props.songs.length - 1) {
temp = 0;
}
return temp;
});
} else {
props.setCurrentSongIndex(() => {
let temp = props.currentSongIndex;
temp--;
if (temp < 0) {
temp = props.songs.length - 1;
}
return temp;
});
}
};
return (
<div className="my-player">
<audio
src={props.songs[props.currentSongIndex].src}
ref={audioEl}
></audio>
<h4>Playing now</h4>
<Details song={props.songs[props.currentSongIndex]} />
<Controls
isPlaying={isPlaying}
setIsPlaying={setIsPlaying}
SkipSong={SkipSong}
/>
<p>
Next up:{" "}
<span>
{props.songs[props.nextSongIndex].title} by{" "}
{props.songs[props.nextSongIndex].artist}
</span>
</p>
</div>
);
}
export default Player;
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faPlay,
faPause,
faForward,
faBackward,
} from "@fortawesome/free-solid-svg-icons";
function Controls(props) {
return (
<div className="my-player--controls">
<button className="skip-btn" onClick={() => props.SkipSong(false)}>
<FontAwesomeIcon icon={faBackward} />
</button>
<button
className="play-btn"
onClick={() => props.setIsPlaying(!props.isPlaying)}
>
<FontAwesomeIcon icon={props.isPlaying ? faPause : faPlay} />
</button>
<button className="skip-btn" onClick={() => props.SkipSong()}>
<FontAwesomeIcon icon={faForward} />
</button>
</div>
);
}
export default Controls;
import React from "react";
function Details(props) {
return (
<div className="my-player--details">
<div className="details-img">
<img src={props.song.img_src} alt="" />
</div>
<h3 className="details-title">{props.song.title}</h3>
<h4 className="details-artist">{props.song.artist}</h4>
</div>
);
}
export default Details;
  • For our player.js, we are importing our Details and Controls components. It houses both components. Here, we are configuring the functionalities for our song display, details and controls like he play, the pause,the skip song and the previous song.
  • Controls.js contains the control interface of our app like the play , pause and all. Our Player.js uses it’s props to configure the functionalities since it would be bulky if we included it all in the same file.
  • Details is used to display the details of the music played. Our Player.js also uses the its props.
import React from "react";
function Details(props) {
return (
<div className="my-player--details">
<div className="details-img">
<img src={props.song.img_src} alt="" />
</div>
<h3 className="details-title">{props.song.title}</h3>
<h4 className="details-artist">{props.song.artist}</h4>
</div>
);
}
export default Details;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Fira Sans", sans-serif;
}
body {
background-color: #DDD;
}
.App {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
}
.my-player {
display: block;
background-color: #313131;
display: block;
margin: 0px auto;
padding: 50px;
border-radius: 16px;
box-shadow: inset -6px -6px 12px rgba(0, 0, 0, 0.8), inset 6px 6px 12px rgba(255, 255, 255, 0.4);
}
.my-player > h4 {
color: #FFF;
font-size: 14px;
text-transform: uppercase;
font-weight: 500;
text-align: center;
}
.my-player > p {
color: #AAA;
font-size: 14px;
text-align: center;
font-weight: 600;
}
.my-player > p span {
font-weight: 400;
}
.my-player--details .details-img {
position: relative;
width: fit-content;
margin: 0 auto;
}
.my-player--details .details-img img {
display: block;
margin: 50px auto;
width: 100%;
max-width: 250px;
border-radius: 50%;
box-shadow: 6px 6px 12px rgba(0, 0, 0, 0.8), -6px -6px 12px rgba(255, 255, 255, 0.4);
}
.my-player--details .details-img:after {
content: '';
display: block;
position: absolute;
top: -25px;
left: -25px;
right: -25px;
bottom: -25px;
border-radius: 50%;
border: 3px dashed rgb(0,0,255);
}
.my-player--details .details-title {
color: #EEE;
font-size: 28px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8), -2px -2px 4px rgba(255,255,255,0.4);
text-align: center;
margin-bottom: 10px;
}
.my-player--details .details-artist {
color: #AAA;
font-size: 20px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8), -2px -2px 4px rgba(255,255,255,0.4);
text-align: center;
margin-bottom: 20px;
}
.my-player--controls {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 30px;
}
.my-player--controls .play-btn {
display: flex;
margin: 0 30px;
padding: 20px;
border-radius: 50%;
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.8), -4px -4px 10px rgba(255, 255, 255, 0.4), inset -4px -4px 10px rgba(0, 0, 0, 0.4), inset 4px 4px 10px rgba(255, 255, 255, 0.4);
border: none;
outline: none;
background-color: #0000FF;
color: #FFF;
font-size: 24px;
cursor: pointer;
}
.my-player--controls .skip-btn {
background: none;
border: none;
outline: none;
cursor: pointer;
color: #888;
font-size: 18px;
}
Screenshot

Conclusion

We have seen another innovative way to use Strapi by building a music player. Special thanks to Asaolu Elijah, who contributed to this article in a very crucial way.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store