Socket.io 是一个基于 Node.js 的实时双向数据通信库,由于其易用性和高度可扩展性,已经成为构建实时应用的首选。
在本文中,我们将介绍如何使用 Socket.io 实现一个多人在线音乐播放网站。我们将涵盖以下内容:
- 前置条件
- 技术选择
- 实现步骤
- 示例代码
前置条件
在开始使用 Socket.io 实现多人在线音乐播放网站之前,您需要掌握以下技能:
- HTML、CSS 和 JavaScript 编程技能。
- Node.js 编程技能。
- 基本的节点和 Express 框架知识。
技术选择
在本文中,我们将使用以下技术来实现多人在线音乐播放网站:
- Node.js
- Express
- Socket.io
- MongoDB
- Mongoose
实现步骤
- 安装 Node.js 和 MongoDB。
- 创建一个空项目并安装以下包:
npm install express socket.io mongoose
- 创建一个 Express 应用程序,并设置路由,以便用户可以访问您的网站。
- 创建一个 MongoDB 数据库,并设置 Mongoose 模式和模型。
- 创建播放器和控制器对象,以便多个用户可以同时听取和控制音乐的播放。
- 创建 Socket.io 服务器,并使用它来处理从客户端发送的消息。
- 在客户端上创建 Socket.io 客户端,并使用它来向服务器发送消息。
示例代码
以下是一个使用 Socket.io 实现多人在线音乐播放网站的示例代码:
server.js
// www.javascriptcn.com code example
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const http = require("http").createServer(app);
const io = require("socket.io")(http);
const port = process.env.PORT || 3000;
const mongoURI = <your-mongo-uri>;
mongoose.connect(mongoURI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const musicSchema = new mongoose.Schema(
{
name: String,
artist: String,
album: String,
cover: String,
source: String
},
{ timestamps: true }
);
const Music = mongoose.model("Music", musicSchema);
class Player {
constructor() {
this.currentMusic = {};
this.isPlaying = false;
this.queue = [];
this.volume = 50;
this.timeout = null;
this.timeoutCallback = null;
}
play(music) {
this.currentMusic = music;
this.isPlaying = true;
this.broadcast("play", music);
this.timeout = setTimeout(() => {
this.timeoutCallback();
this.next();
}, music.duration * 1000 - this.currentMusic.position);
}
pause() {
this.isPlaying = false;
this.broadcast("pause");
clearTimeout(this.timeout);
this.timeout = null;
}
next() {
if (this.queue.length > 0) {
this.play(this.queue.shift());
} else {
this.currentMusic = {};
this.isPlaying = false;
this.broadcast("stop");
}
}
addToQueue(music) {
this.queue.push(music);
if (this.currentMusic === {}) {
this.play(this.queue.shift());
}
}
setVolume(volume) {
this.volume = volume;
this.broadcast("volume", volume);
}
setPosition(position) {
this.currentMusic.position = position;
this.broadcast("position", position);
}
setTimeoutCallback(callback) {
this.timeoutCallback = callback;
}
broadcast(command, data) {
io.emit(command, data);
}
}
class Controller {
constructor() {
this.volume = 50;
this.isPlaying = false;
this.timeout = null;
this.timeoutCallback = null;
}
play() {
this.isPlaying = true;
this.broadcast("play");
}
pause() {
this.isPlaying = false;
this.broadcast("pause");
}
next() {
this.broadcast("next");
}
setVolume(volume) {
this.volume = volume;
this.broadcast("volume", volume);
}
setPosition(position) {
this.broadcast("position", position);
}
setListeners(player) {
io.on("connection", socket => {
socket.emit("init", {
currentMusic: player.currentMusic,
isPlaying: player.isPlaying,
volume: player.volume,
queue: player.queue
});
socket.on("music:add", musicId => {
Music.findById(musicId, (err, music) => {
if (err) console.error(err);
player.addToQueue(music);
});
});
socket.on("play", () => {
this.play();
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.timeoutCallback();
player.next();
}, player.currentMusic.duration * 1000 - player.currentMusic.position);
});
socket.on("pause", () => {
this.pause();
clearTimeout(this.timeout);
this.timeout = null;
});
socket.on("next", () => {
this.next();
clearTimeout(this.timeout);
this.timeout = null;
});
socket.on("volume", volume => {
this.setVolume(volume);
});
socket.on("position", position => {
this.setPosition(position);
});
socket.on("disconnect", () => {
console.log(`User ${socket.id} disconnected`);
});
});
}
broadcast(command, data) {
io.emit(command, data);
}
}
(async () => {
const player = new Player();
const controller = new Controller();
try {
await Music.insertMany([
{
name: "Got It On Me",
artist: "Pop Smoke",
album: "Shoot for the Stars Aim for the Moon",
cover: "https://i.imgur.com/PZWpLKG.png",
source: "https://nighmares.ams3.digitaloceanspaces.com/gotitonme.mp3",
duration: 210
},
{
name: "Heartless",
artist: "The Weeknd",
album: "Heartless - Single",
cover: "https://i.imgur.com/5bihLV7.jpg",
source: "https://nighmares.ams3.digitaloceanspaces.com/heartless.mp3",
duration: 203
},
{
name: "What's Love Got to Do with It",
artist: "Kygo, Tina Turner",
album: "What's Love Got to Do with It - Single",
cover: "https://i.imgur.com/tslJUpu.jpg",
source: "https://nighmares.ams3.digitaloceanspaces.com/whatslove.mp3",
duration: 208
}
]);
console.log("Data inserted");
controller.setListeners(player);
http.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
});
} catch (err) {
console.error(err);
}
})();client.js
// www.javascriptcn.com code example
const socket = io();
let queue = [];
let currentMusic = {};
let isPlaying = false;
let volume = 50;
let sliderChanging = false;
const musicList = document.querySelector(".music-list");
const musicSlider = document.querySelector(".music-slider");
const volumeSlider = document.querySelector(".volume-slider");
const playButton = document.querySelector(".play-button");
const pauseButton = document.querySelector(".pause-button");
const nextButton = document.querySelector(".next-button");
const volumeUpButton = document.querySelector(".volume-up-button");
const volumeDownButton = document.querySelector(".volume-down-button");
const formatTime = seconds =>
new Date(seconds * 1000).toISOString().substr(11, 8);
const formatMusic = music => `
<li class="music-card">
<div class="music-card-body">
<img class="music-card-cover" src="${music.cover}" />
<div class="music-card-meta">
<p class="music-card-title">${music.name}</p>
<p class="music-card-artist">${music.artist}</p>
<p class="music-card-album">${music.album}</p>
</div>
</div>
<button class="music-card-play-button" data-id="${music._id}">
<i class="fas fa-play"></i>
</button>
</li>
`;
socket.on("init", data => {
currentMusic = data.currentMusic;
isPlaying = data.isPlaying;
volume = data.volume;
queue = data.queue;
musicSlider.max = currentMusic.duration;
musicSlider.value = currentMusic.position;
volumeSlider.value = volume;
if (isPlaying) {
playButton.classList.add("hidden");
pauseButton.classList.remove("hidden");
} else {
playButton.classList.remove("hidden");
pauseButton.classList.add("hidden");
}
while (musicList.firstChild) {
musicList.removeChild(musicList.firstChild);
}
queue.forEach(music => {
musicList.insertAdjacentHTML("beforeend", formatMusic(music));
});
});
socket.on("play", music => {
currentMusic = music;
isPlaying = true;
playButton.classList.add("hidden");
pauseButton.classList.remove("hidden");
});
socket.on("pause", () => {
isPlaying = false;
playButton.classList.remove("hidden");
pauseButton.classList.add("hidden");
});
socket.on("stop", () => {
isPlaying = false;
playButton.classList.remove("hidden");
pauseButton.classList.add("hidden");
currentMusic = {};
musicSlider.max = 0;
musicSlider.value = 0;
});
socket.on("volume", volume => {
volumeSlider.value = volume;
});
socket.on("position", position => {
sliderChanging = true;
musicSlider.value = position;
sliderChanging = false;
});
musicList.addEventListener("click", event => {
const button = event.target.closest("button");
if (button) {
const id = button.dataset.id;
socket.emit("music:add", id);
}
});
playButton.addEventListener("click", () => {
socket.emit("play");
});
pauseButton.addEventListener("click", () => {
socket.emit("pause");
});
nextButton.addEventListener("click", () => {
socket.emit("next");
});
volumeUpButton.addEventListener("click", () => {
if (volume < 100) {
volume++;
volumeSlider.value = volume;
socket.emit("volume", volume);
}
});
volumeDownButton.addEventListener("click", () => {
if (volume > 0) {
volume--;
volumeSlider.value = volume;
socket.emit("volume", volume);
}
});
volumeSlider.addEventListener("input", event => {
const value = event.target.value;
volume = value;
socket.emit("volume", volume);
});
musicSlider.addEventListener("mousedown", () => {
sliderChanging = true;
});
musicSlider.addEventListener("input", event => {
if (!sliderChanging) return;
const value = event.target.value;
socket.emit("position", value);
});
musicSlider.addEventListener("mouseup", () => {
sliderChanging = false;
});以上就是本文介绍的如何使用 Socket.io 实现一个多人在线音乐播放网站。希望本文对您有所帮助!
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/6781eab5935627c900efcd08