MERN GridFS get audio from database MongoDB

20 Views Asked by At

How to correctly play audio on a page in a browser (GridFS). Uploading audio to the database MongoDB is in progress.I have structure MERN server-> 1.controllers-> auth.js , meditation.js , mood.js , program.js , steps.js , test.js 2.data -> meditations.js , questsions.js 3.models -> Meditation.js , Combination.js , Mood.js , Levels.js , Qustsions.js , Result.js , Reward.js , SevedMeditation.js , Steps.js , User.js4.multer -> multer.js 5.routes -> auth.js , meditation.js , mood.js , steps.js , test.js 6.utils-> checkAuth.js ; client -> 1.components , 2.database , 3.hooks , 4.pages-> all pages for example meditation.jsx , main.jsx , mood.jsx , 5.redux-> store.js , authSlice.js , meditationSlice , mood_reducer , moodSlice , questsions_reducer , result_reducer , utils-> axios.js and App.js

//multer.js
import multer from 'multer';
import mongoose from 'mongoose';
import gridfs from 'gridfs-stream';

const connection = mongoose.connection;
gridfs.mongo = mongoose.mongo;

let gfs;

connection.once('open', () => {
  gfs = gridfs(connection.db);
});

const storage = multer.memoryStorage();

const upload = multer({ storage: storage });

export { upload, gfs };


//controlers meditation.js
import meditation from "../data/meditation.js";

import User from "../models/User.js";

import Meditation from "../models/Meditation.js";
import SavedMeditation from "../models/SavedMeditation.js";
import mongoose from 'mongoose';
import { MongoClient, ObjectId } from 'mongodb';
import fs from 'fs';
import stream from 'stream';
import path from 'path';
const connectionUri = 'mongodb+srv://test:[email protected]/';
const dbName = 'test';  // Replace with your actual database name
import { streamFile } from '../multer/multer.js';
import { gfs } from '../multer/multer.js';

//get meditations from db
export const getMeditations= async (req, res) => {
  try {
   
   const m =  await Meditation.find();
      res.json(m)
  
} catch (error) {
  res.json({ error })
}
}

//get One meditations from db
export const getOneMeditation= async (req, res) => {
  try {
    const meditation = await Meditation.findById(req.params.meditationId)
   
   
      res.json(meditation)
  
} catch (error) {
  res.json({ error })
}
}
// Dodanie medytacji
export const insertMeditations = async (req, res) => {
  try {
    await Meditation.insertMany( meditation );
    res.json({ msg: "Data Saved Successfully...!" });
  } catch (error) {
    res.json({ error });
  }
};
//Dodanie auio do medytacji
export const insertAudioToMeditations = async (req, res) => {
  try {
   
   const meditations = ["65525551782459e2a11e271a","65525551782459e2a11e271b",
                        "65525551782459e2a11e271c","65525551782459e2a11e271d",
                        "65525551782459e2a11e271e","65525551782459e2a11e271f",
                        "65525551782459e2a11e2720","65525551782459e2a11e2721"
                       ];
   const filePaths = ["D:\\study\\dyplom\\server\\data\\M1.MP3","D:\\study\\dyplom\\server\\data\\M2.MP3",
                       "D:\\study\\dyplom\\server\\data\\M3.MP3","D:\\study\\dyplom\\server\\data\\M4.MP3",
                       "D:\\study\\dyplom\\server\\data\\M5.MP3","D:\\study\\dyplom\\server\\data\\M5.MP3",
                       "D:\\study\\dyplom\\server\\data\\M5.MP3","D:\\study\\dyplom\\server\\data\\M5.MP3"
                      ];
                     
const client = new MongoClient(connectionUri, { useNewUrlParser: true, useUnifiedTopology: true });

await client.connect();

const database = client.db(dbName);

    // Access the GridFS bucket
    const bucket = new mongoose.mongo.GridFSBucket(database);

    for (let i = 0; i < filePaths.length; i++) {
      const filePath = filePaths[i];
      const meditationId = meditations[i];
      console.log(meditationId)
      console.log(filePath)
      
      // Read file content
      const buffer = fs.readFileSync(filePath);

      // Create a readable stream from the buffer
      const bufferStream = new stream.PassThrough().end(buffer);

      // Extract filename from the path
      const filename = path.basename(filePath);

      // Create a write stream to GridFS
      const uploadStream = bucket.openUploadStream(filename);
      bufferStream.pipe(uploadStream);

      // Wait for the upload to complete
      await new Promise((resolve, reject) => {
        uploadStream.on('finish', resolve);
        uploadStream.on('error', reject);
      });
      
      // Update the meditation with the new audio information
      await Meditation.updateOne(
        { _id: meditationId },
        { $set: { audio: { file_id: uploadStream.id, filename } } }
      );
    }


    res.json({ msg: "Audio Saved Successfully...!" });
  } catch (error) {
    res.json({ error });
  }
};
//dodanie zapisanej medytacji do user
export const insertSavedMeditations = async (req, res) => {

    try {
        const user = await User.findById(req.body.userId);
        const meditation = await Meditation.findById(req.body.meditationId);
        //const {title, description} = req.body
        if (!user) {
            throw new Error('User not found Meditation not saved');
          } 
          if (!meditation) {
            throw new Error('Meditation not found Meditation not saved');
          } 
          const newSavedMeditation = new SavedMeditation({
            username: user.username,
            title: meditation.title,
            description: meditation.description,
            meditationId: meditation._id,
            userId: user._id,
        })
        
        await newSavedMeditation.save()
          await User.findByIdAndUpdate(req.body.userId, {
            $push: { savedMeditations: newSavedMeditation },
        })
      res.json({ msg: "Data Saved Successfully...!" });
      console.log(newSavedMeditation);
    } catch (error) {
      res.json({ msg: 'Error w controllers' });
    }
  };

  //Get user SavedMeditation
  export const getMySavedMeditations = async (req, res) => {
    try {
      const user = await User.findById(req.query.userId);
      if (!user) {
        return res.status(404).json({ message: 'User not found' });
      }
  
      const list = await Promise.all(
        user.savedMeditations.map((savedMeditation) => {
          return SavedMeditation.findById(savedMeditation._id);
        })
      );
  
      res.json(list);
    } catch (error) {
      res.status(500).json({ message: 'Something went wrong' });
    }
  };
  //Delete SavedMeditation
  export const removeSavedMeditation = async (req, res) => {
    try {
        const savedMeditation = await SavedMeditation.findByIdAndDelete(req.params.savedMeditationId)
        console.log(`SavedMeditationId   ${req.params.savedMeditationId}`)
        console.log(`UserId   ${req.query.id}`)
        console.log(`REQ body ${req.query}`)
        if (!savedMeditation) return res.json({ message: 'Takiej medytacji nie istnieje' })
        //const user = await User.findById(req.query.userId);
        await User.findByIdAndUpdate(req.query.id, {
            $pull: { savedMeditations: req.params.savedMeditationId },
        })
        
        res.json({ message: 'Zapisana medytacja została usunięta.' })
    } catch (error) {
        res.json({ message: 'Coś poszło nie tak.' })
    }
}

export const streamAudio = async (req, res) => {
  try {
    const fileId = req.params.fileId;
    const audioStream = gfs.createReadStream({ _id: mongoose.Types.ObjectId(fileId) });

    // Set appropriate headers
    res.set('Content-Type', 'audio/mpeg');

    // Pipe the audio stream to the response
    audioStream.pipe(res);
  } catch (error) {
    res.status(500).json({ error: 'Error streaming audio' });
  }
};



import { Router } from 'express'
import { checkAuth } from '../utils/checkAuth.js'
import { getMeditations, getMySavedMeditations, insertMeditations, insertSavedMeditations, removeSavedMeditation , insertAudioToMeditations, getOneMeditation , streamAudio} from '../controllers/meditation.js'
import {upload} from '../multer/multer.js'


const router = new Router()

//Get all meditations
router.get('/meditations',getMeditations)
//Get One meditation
router.get('/:meditationId',getOneMeditation)
// insert meditations
// http://localhost:3002/api/test
router.post('/meditations',insertMeditations)

//dodanie zapisanej medytacji do user
router.post('/',insertSavedMeditations)

//Dodanie auio do medytacji
router.post('/audioMeditationsSaved', upload.single('audio'),insertAudioToMeditations)

//Get user SavedMeditation
router.get('/',getMySavedMeditations)

//Delete SavedMeditation
router.delete('/:savedMeditationId',removeSavedMeditation)
 export default router

 //router.get('/stream/:meditationId/audio', streamAudio);

 router.get('/stream/:fileId', streamAudio);

import React, { useState, useEffect, useRef } from 'react';
import { useDispatch , useSelector} from 'react-redux';
import styles from './styles.module.css';
import star from './images/star.png';
import Play from './images/Play.png';
import Stop from './images/Stop.png';
import axios from 'axios';

import Next from './images/Next.png';


import { getOneMeditation } from '../../redux/features/meditationSlice';

import { useParams } from 'react-router-dom';

function Meditation() {
  const state = useSelector(state => state)
  const {meditations, savedMeditation} = useSelector((state) => state.meditation);
  const { meditationId } = useParams();
  console.log(state);
  console.log(meditationId);
  let yourAudioFile;
 let meditationOne ;
meditations.forEach((meditation, i) => {
  // Użyj tutaj składni warunkowej
  if (meditation._id === meditationId) {
    // Tutaj użyj yourAudioFile
    meditationOne = meditation;
    yourAudioFile = meditation.audio.filename; //ЦЕ НАЗВА АУДИО ФАЙЛА!!!!!!!!!!
  }
});

console.log(meditationOne);
console.log(yourAudioFile);

  const numStars = 170; 

  const [cloudElements] = useState([]);
  const audioRef = useRef(null);
  const [isPlaying, setIsPlaying] = useState(false); 
  const [audioPosition, setAudioPosition] = useState(0); 
  const [starsAnimated, setStarsAnimated] = useState(true); 
  const [isAudioLoaded, setIsAudioLoaded] = useState(false); 
  const [isAudioEnded, setIsAudioEnded] = useState(false); 
  const [showNextButton, setShowNextButton] = useState(false);
  const [audioDuration, setAudioDuration] = useState(0);
  const [highlightAudio, setHighlightAudio] = useState(false);

  
  const starElements = [];
  for (let i = 0; i < numStars; i++) {
    const starStyle = {
      top: `${25 + Math.random() * 60}vh`,
      left: `${15 + Math.random() * 80}vw`,
      animationDelay: `${Math.random() * 5}s`,
      animationPlayState: starsAnimated ? 'running' : 'paused', // Control animation state
    };

    starElements.push(
      <img
        key={`star-${i}`}
        src={star}
        alt={`Star ${i}`}
        className={styles.star}
        style={starStyle}
      />
    );
  }


  useEffect(() => {
    if (audioRef.current) {
      if (isPlaying) {
        audioRef.current.pause();
      } else {
        audioRef.current.currentTime = 0;
        audioRef.current.play();
      }
      setIsPlaying(!isPlaying);
      setStarsAnimated(!isPlaying);
    }
  }, [isPlaying, audioRef.current]);
  

  useEffect(() => {
    const audio = new Audio(yourAudioFile);

    const handleCanPlayThrough = () => {
      setIsAudioLoaded(true);
    };
console.log(`AUDIO ${audio}`)
    const handleEnded = () => {
      setIsPlaying(false);
      setStarsAnimated(true);
      setIsAudioEnded(true); // Встанови стан, що аудіо відтворено до кінця
      setShowNextButton(true); // Покажи кнопку "Далі" після завершення відтворення
    };

    audio.addEventListener('canplaythrough', handleCanPlayThrough);
    audio.addEventListener('ended', handleEnded);

    audioRef.current = audio;

    return () => {
      audio.removeEventListener('canplaythrough', handleCanPlayThrough);
      audio.removeEventListener('ended', handleEnded);
    };
  }, [yourAudioFile]);

  const handleTogglePlay = () => {
    if (audioRef.current && isAudioLoaded) {
      if (isPlaying) {
        audioRef.current.pause();
      } else {
        audioRef.current.currentTime = 0;
        audioRef.current.play();
      }
  
      setIsPlaying(!isPlaying);
      setStarsAnimated(!isPlaying);
    }
  };
  
  
  



  useEffect(() => {
    const audio = new Audio();
  
    const handleCanPlayThrough = () => {
      setIsAudioLoaded(true);
    };
  
    const handleEnded = () => {
      setIsPlaying(false);
      setStarsAnimated(true);
      setIsAudioEnded(true);
      setShowNextButton(true);
    };
  
    audio.addEventListener('canplaythrough', handleCanPlayThrough);
    audio.addEventListener('ended', handleEnded);
  
    audioRef.current = audio;
  
    return () => {
      audio.removeEventListener('canplaythrough', handleCanPlayThrough);
      audio.removeEventListener('ended', handleEnded);
    };
  }, [yourAudioFile]);
  

  useEffect(() => {
    if (audioRef.current) {
      const handleLoadedData = () => {
        setIsAudioLoaded(true);
      };
  
      audioRef.current.addEventListener('loadeddata', handleLoadedData);
  
      return () => {
        audioRef.current.removeEventListener('loadeddata', handleLoadedData);
      };
    }
  }, [audioRef.current]);
  
  
  
  
  
  const streamAudio = async (fileId) => {
    try {
      const response = await axios.get(`/api/meditations/stream/${fileId}`, {
        responseType: 'arraybuffer',
      });
  
      const blob = new Blob([response.data], { type: 'audio/mpeg' });
      const blobUrl = URL.createObjectURL(blob);
  
      const audio = new Audio(blobUrl);
  
      audio.addEventListener('loadeddata', () => {
        audio.play();
        setIsPlaying(true);
        setStarsAnimated(false);
      });
  
      audio.addEventListener('ended', () => {
        setIsPlaying(false);
        setStarsAnimated(true);
        setIsAudioEnded(true);
        setShowNextButton(true);
      });
  
      audioRef.current = audio;
    } catch (error) {
      console.error('Error streaming audio:', error);
    }
  };
  
 
  
const fileId = meditationOne.audio.file_id;
  return (
    <div className={styles.container}>
      {starElements}
      {cloudElements}
      
    
      <div className={styles.textOverlay}>
  <h1>{meditationOne.title}</h1>
</div>


<button onClick={() => streamAudio(meditationOne.audio.file_id)}>Play</button>



      
    </div>
  );
}

export default Meditation;
0

There are 0 best solutions below