带有 auth0 和 cloudinary 的音乐应用程序
使用 CodeSandbox 创建
自诞生以来,流媒体音乐发展迅猛,如今已成为最受大众接受的音乐聆听方式之一。许多流媒体网站提供免费音乐,这不仅减少了盗版需求,也确保了艺术家获得公平的报酬。流媒体音乐也非常便捷,拥有无限可能。
在本教程中,我们将学习如何使用 Auth0 和 Cloudinary 开发音乐流应用程序。
该项目是在Codesandbox中完成的。如需快速入门,请 fork Codesandbox或运行该项目。
GitHub 存储库:
使用 CodeSandbox 创建
Auth0是一个可扩展的身份验证和授权系统,设置简单。它还提供了一个完整的身份和访问管理系统,开箱即用,并可根据需要定制、扩展和开发新功能。
Cloudinary提供安全全面的 API,可从服务器端、浏览器或移动应用快速高效地上传媒体文件。我们可以使用 Cloudinary 的 REST API 或客户端库 (SDK) 上传媒体资源。这些 SDK 封装了上传 API,使其更易于与网站和移动应用集成。
为了创建新项目,我们使用npx create-react-app
命令在我们选择的目录中搭建一个新项目。
要安装依赖项,我们将使用以下命令:
cd <project name>
npm install @auth0/auth0-react @supabase/supabase-js bootstrap moment react-audio-player react-bootstrap react-helmet
一旦创建了应用程序并安装了依赖项,我们将看到一条消息,其中包含导航到我们的网站并在本地运行它的说明。我们用命令来执行此操作。
npm start
React.js 将启动一个热重载开发环境,默认可从http://localhost:3000访问
如果您还没有注册,请访问Auth0进行注册,或者登录仪表板,单击Applications
下拉菜单application
,最后单击Create Application
如下所示的按钮:
我们现在可以创建我们的应用程序,如下所示:
如下所示,我们已经成功创建了我们的应用程序,但我们需要设置 URL 来指回我们的应用程序。
向下滚动到应用程序 URI 部分并设置以下内容
Allowed Callback URLs
= https://de7pd.csb.appAllowed Logout URLs
= https://de7pd.csb.appAllowed Web Origins
= https://de7pd.csb.app
将https://de7pd.csb.app替换为我们之前设置的应用程序 URL 或http://localhost:3000。在本教程的后面部分,我们将在应用程序中使用域和客户端 ID。
让我们导入并设置我们的应用程序,以使用我们安装的 bootstrap 依赖项。public/index.html
通过使用以下代码片段链接 bootstrap 的 CSS 和 js 来更新文件:
<!DOCTYPE html>
<html lang="en">
<head>
//...
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css"
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU"
crossorigin="anonymous"
/>
<title>Music Streaming App</title>
</head>
<body>
//...
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
//...
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script
src="https://unpkg.com/react/umd/react.production.min.js"
crossorigin
></script>
<script
src="https://unpkg.com/react-dom/umd/react-dom.production.min.js"
crossorigin
></script>
<script
src="https://unpkg.com/react-bootstrap@next/dist/react-bootstrap.min.js"
crossorigin
></script>
</body>
</html>
我们需要在主页上创建一个播放音乐的用户界面。我们将通过将app.js
文件更新为组件来实现这一点。由于 React 的传统是使用组件结构,因此我们将在文件夹components
中创建一个名为 的文件夹src
,并创建header.js
、music.js
和musicList.js
组件。
在components/music.js
文件中,让我们用下面的代码片段来更新它:
import ReactAudioPlayer from "react-audio-player";
import moment from "moment";
export default function Music({ musicList, index }) {
return (
<div className="col-md-4">
<div className="card p-3 mb-2" key={index}>
<div className="d-flex justify-content-between">
<div className="d-flex flex-row align-items-center">
<div className="icon">
{" "}
<i className="bx bxl-mailchimp"></i>{" "}
</div>
<div className="ms-2 c-details">
<h6 className="mb-0">{musicList.name}</h6>{" "}
<span>{moment(musicList.created_at).format("MMMM Do YYYY")}</span>
</div>
</div>
<div className="badge">
{" "}
<span role="img" aria-label="">
Hot 🔥
</span>{" "}
</div>
</div>
<div className="mt-2">
<h4 className="heading">{musicList.title}</h4>
<div className="mt-2">
<ReactAudioPlayer src={`${musicList.url}`} controls />
</div>
</div>
</div>
</div>
);
}
musicList
在上面的代码片段中,我们创建了一个包含和属性的单张音乐卡片组件index
。我们还分别导入了 ReactAudioPlayer 和 moment 来设置音频播放器和上传日期的格式。
在组件内部musicList.js
,我们将通过导入音乐组件并遍历示例 musicList 数组,使用下面的代码片段对其进行更新。
import Music from "./music";
export default function App() {
const musicList = [
{
name: "olanetsoft",
title: "Bang Bang",
url: "https://res.cloudinary.com/demo/video/upload/dog.mp3",
created_at:"2021-10-04T23:30:01.000Z",
}
]
return (
<div className="row">
{musicList.map((m, key) => (
<Music musicList={m} index={key} />
))}
</div>
);
}
header.js
让我们用下面的代码片段更新我们之前创建的组件:
import { Button } from "react-bootstrap";
export default function Header() {
return (
<div className="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
<h5 className="my-0 mr-md-auto font-weight-normal">
Music Streaming App with Auth0 and Cloudinary
</h5>
<nav className="my-2 my-md-0 mr-md-3">
<a className="p-2 text-success" href="/">
Home
</a>
<a className="p-2 text-danger" href="/">
Trending
</a>
<a className="p-2 text-info" href="/">
Top Songs
</a>
</nav>
<Button
id="btnUpload"
className="btn margin"
variant="primary"
>
Upload Song
</Button>
</div>
);
}
我们现在可以更新我们的src/app.js
文件,如下所示:
import MusicList from "../components/musicList";
import "./styles.css";
export default function App() {
return (
<div className="container mt-5 mb-3">
<Header />
<MusicList />
</div>
);
}
当前的用户界面看起来不太美观,我们将使用 CSS 添加一些样式。我们将src/styles.css
在此 GitHub Gist 中使用以下内容更新文件。
.App { | |
font-family: sans-serif; | |
text-align: center; | |
} | |
body { | |
background-color: #00284e; | |
} | |
.card { | |
border: none; | |
border-radius: 25px; | |
} | |
.c-details span { | |
font-weight: 200; | |
font-size: 13px; | |
} | |
.badge span { | |
background-color: #fffbec; | |
width: 80px; | |
height: 30px; | |
padding-bottom: 5px; | |
border-radius: 5px; | |
display: flex; | |
color: #ff3c00; | |
justify-content: center; | |
align-items: center; | |
} | |
.spinner { | |
border: 1px solid; | |
position: fixed; | |
z-index: 1; | |
left: 0; | |
right: 0; | |
top: 0; | |
bottom: 0; | |
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 50 50'%3E%3Cpath d='M28.43 6.378C18.27 4.586 8.58 11.37 6.788 21.533c-1.791 10.161 4.994 19.851 15.155 21.643l.707-4.006C14.7 37.768 9.392 30.189 10.794 22.24c1.401-7.95 8.981-13.258 16.93-11.856l.707-4.006z'%3E%3CanimateTransform attributeType='xml' attributeName='transform' type='rotate' from='0 25 25' to='360 25 25' dur='0.6s' repeatCount='indefinite'/%3E%3C/path%3E%3C/svg%3E") | |
center / 50px no-repeat; | |
} | |
.heading { | |
margin: 10px 0 5px; | |
text-transform: capitalize; | |
font-weight: 300; | |
font-size: 20px; | |
} |
我们的应用程序现在在http://localhost:3000/ 上看起来应该是这样的:
我们目前正在处理样本数据,效果并不理想。我们应该能够上传和播放其他人上传的歌曲。
我们将使用 Auth0 来跟踪谁上传了新歌曲,然后我们将使用 Cloudinary 进行实际上传,再将其保存到数据库。
让我们.env
在项目的根目录中创建文件,并使用以下代码片段从我们的 Auth0 仪表板填充域和客户端 ID:
AUTH0_DOMAIN=dev-9hbpo12k.us.auth0.com
AUTH0_CLIENT_ID=tdYpNQ8Qqjymi0dOC7wZdGGWlYCN6FR3
src/index.js
让我们使用下面的代码片段导入并Auth0Provider
设置我们的应用程序:
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Auth0Provider } from "@auth0/auth0-react";
const domain = process.env.AUTH0_DOMAIN;
const clientId = process.env.AUTH0_CLIENT_ID;
const rootElement = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<Auth0Provider
domain={domain}
clientId={clientId}
redirectUri={window.location.origin}
>
<App />
</Auth0Provider>
,
</StrictMode>,
rootElement
);
我们现在可以使用下面的代码片段分别在文件夹中login-button.js
创建logout-button.js
和loading.js
组件:components
里面components/login-button.js
import { useAuth0 } from "@auth0/auth0-react";
import { Button } from "react-bootstrap";
export default function Login() {
const { loginWithRedirect } = useAuth0();
return (
<Button
id="btnLogin"
className="btn margin"
onClick={() => loginWithRedirect()}
variant="primary"
>
Upload Music
</Button>
);
}
components/logout-button.js
import { useAuth0 } from "@auth0/auth0-react";
import { Button } from "react-bootstrap";
export default function Logout() {
const { logout } = useAuth0();
return (
<Button
id="btnLogin"
className="btn margin"
onClick={() => logout()}
variant="danger"
>
Logout
</Button>
);
}
然后里面components/loading.js
import "../src/styles.css";
export default function Loading() {
return <div className="spinner"></div>;
}
我们可以继续导入之前创建的文件中的组件login
,如下所示:logout
header.js
import { useState, useEffect } from "react";
import { Button } from "react-bootstrap";
import { useAuth0 } from "@auth0/auth0-react";
import Login from "../components/login-button";
import Logout from "../components/logout-button";
export default function Header() {
const { isAuthenticated } = useAuth0();
return (
<div className="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
{/* */}
{isAuthenticated ? (
<>
<div>
<Button
id="btnUpload"
className="btn margin"
variant="primary"
>
Upload Song
</Button>
<Logout />
</div>
</>
) : (
<Login />
)}
</div>
);
}
更新src/app.js
//...
import Loading from "../components/loading";
export default function App() {
const { isLoading } = useAuth0();
if (isLoading) {
return <Loading />;
}
return (
//....
);
}
让我们测试我们的应用程序,单击按钮后我们应该得到类似于下面的内容Upload Song
。
在上面的屏幕截图中,我们已成功登录,您会注意到标题中的 UI 已更改为包含注销按钮。
我们将使用 Cloudinary 的上传小部件,因为它可以让我们从多个来源(包括 Dropbox、Facebook、Instagram)上传媒体资产。
创建一个免费的 cloudinary 帐户来获取您的云名称和 upload_preset。
上传预设使我们能够集中定义一组资产上传选项,而无需在每次上传调用时都提供它们。Cloudinary 云名称是与我们的 Cloudinary 帐户关联的唯一标识符。
首先,我们将通过内容分发网络 (CDN) 将 Cloudinary 小部件的 JavaScript 文件添加到位于 的 index.js 中。我们使用react-helmet的组件src/app.
js
来包含此文件,该组件允许我们在 React 中将数据添加到 HTML 文档的 Head 部分。<Helmet>
//..
import "./styles.css";
import { Helmet } from "react-helmet";
export default function App() {
//...
return (
<div className="container mt-5 mb-3">
<Helmet>
<meta charSet="utf-8" />
<script
src="https://widget.Cloudinary.com/v2.0/global/all.js"
type="text/javascript"
></script>
//...
</div>
);
}
该小部件需要我们的 Cloudinarycloud_name
和uploadPreset
。该createWidget()
函数创建一个新的上传小部件,并在成功上传视频或音频后,将资产的 public_id 分配给相关的状态变量。
为了获得我们的cloudname
,uploadPreset
我们按照以下步骤操作:
云名称是从我们的 Cloudinary 仪表板获得的,如下所示。
我们可以在我们的 Cloudinary 设置页面的“上传”选项卡中找到上传预设,我们可以通过单击仪表板页面右上角的齿轮图标来访问它。
然后我们点击Upload
设置页面上的标签:
我们向下滚动到页面底部的上传预设部分,在那里我们可以看到我们的上传预设,或者如果我们没有的话,可以看到创建预设的选项。
让我们components/header.js
用下面的代码片段来更新我们的:
让我们在浏览器中打开我们的应用程序并单击Upload Song
按钮;我们应该看到如下内容:
我们可以使用本文档中的更多信息进一步定制小部件。
我们已经在应用程序中成功配置和设置了 cloudinary,但我们还将集成一个supabase数据库来保存用户上传的所有歌曲。
让我们创建client.js
将 supabase 与下面的 sippet 集成在一起的:
import { createClient } from "@supabase/supabase-js";
const URL = "https://kpriwlucrliyacagwjvk.supabase.co";
const ANNON_PUBLIC_SECRET = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzMzM2NzU2OSwiZXhwIjoxOTQ4OTQzNgY5fQ.uBBXtyxbwKixUgql4tiYUsqOgSPyB4mLSc2kybqPCPI";
export const supabase = createClient(
URL,
ANNON_PUBLIC_SECRET
);
要获取url
密钥annon public
,请创建一个supabasesettings
帐户,启动一个新项目,然后转到Api
选项卡。
我们将在侧边栏的表格编辑器选项卡中创建一个名为 的新表,其中songs
包含 、 和 的列url
。name
确保title
所有创建的列的列类型均为文本。
成功创建表后,让我们components/header.js
使用下面的代码片段更新文件:
在上面的代码行中,
createSong
,它连接到中的歌曲表Supabase
,然后我们输入数据。createPost
然后,我们在使用该方法将变量保存到数据库之前验证变量以确保它们不是未定义的。让我们更新 musicList 组件以使用下面显示的代码片段检索所有上传的歌曲:
import { useState, useEffect } from "react";
import { supabase } from "../client";
import Music from "./music";
export default function App() {
const [musicList, setMusicList] = useState([]);
useEffect(() => {
fetchSongs();
}, []);
async function fetchSongs() {
const { data } = await supabase.from("songs").select();
setMusicList(data);
}
return (
<div className="row">
{musicList.map((m, key) => (
<Music musicList={m} index={key} />
))}
</div>
);
}
瞧🥳 一切就绪;我们现在可以成功上传歌曲、播放歌曲等。
本文介绍如何使用 Auth0 和 Cloudinary 构建利用 Cloudinary 小部件功能的音乐流应用程序。
使用Auth0和Cloudinary为Hackmamba Jamstack Content Hackathon创建的内容
文章来源:https://dev.to/hackmamba/how-to-build-a-music-streaming-app-with-react-using-auth0-and-cloudinary-6k9