mfdok43 2 years ago
parent
commit
5b2cc41bb5

+ 89 - 0
package-lock.json

@@ -17,6 +17,7 @@
         "node-sass": "^7.0.1",
         "popper.js": "^1.16.1",
         "react": "^17.0.2",
+        "react-audio-spectrum": "^0.1.0",
         "react-dom": "^17.0.2",
         "react-dropzone": "^11.5.1",
         "react-redux": "^7.2.6",
@@ -14185,6 +14186,52 @@
         "node": ">=14"
       }
     },
+    "node_modules/react-audio-spectrum": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/react-audio-spectrum/-/react-audio-spectrum-0.1.0.tgz",
+      "integrity": "sha512-fF6n+kKecDU5UVKDA31xKp85lmlEHprwDN5wYNOka7DJ4OJLtrWozQOBB7pCZ3WajMDEp+uIefuPlvuNz5k2hQ==",
+      "dependencies": {
+        "prop-types": "^15.6.0",
+        "react": "^16.1.0",
+        "react-dom": "^16.1.0"
+      }
+    },
+    "node_modules/react-audio-spectrum/node_modules/react": {
+      "version": "16.14.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
+      "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1",
+        "prop-types": "^15.6.2"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/react-audio-spectrum/node_modules/react-dom": {
+      "version": "16.14.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
+      "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1",
+        "prop-types": "^15.6.2",
+        "scheduler": "^0.19.1"
+      },
+      "peerDependencies": {
+        "react": "^16.14.0"
+      }
+    },
+    "node_modules/react-audio-spectrum/node_modules/scheduler": {
+      "version": "0.19.1",
+      "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
+      "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
+      "dependencies": {
+        "loose-envify": "^1.1.0",
+        "object-assign": "^4.1.1"
+      }
+    },
     "node_modules/react-dev-utils": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",
@@ -28002,6 +28049,48 @@
         "whatwg-fetch": "^3.6.2"
       }
     },
+    "react-audio-spectrum": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/react-audio-spectrum/-/react-audio-spectrum-0.1.0.tgz",
+      "integrity": "sha512-fF6n+kKecDU5UVKDA31xKp85lmlEHprwDN5wYNOka7DJ4OJLtrWozQOBB7pCZ3WajMDEp+uIefuPlvuNz5k2hQ==",
+      "requires": {
+        "prop-types": "^15.6.0",
+        "react": "^16.1.0",
+        "react-dom": "^16.1.0"
+      },
+      "dependencies": {
+        "react": {
+          "version": "16.14.0",
+          "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
+          "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
+          "requires": {
+            "loose-envify": "^1.1.0",
+            "object-assign": "^4.1.1",
+            "prop-types": "^15.6.2"
+          }
+        },
+        "react-dom": {
+          "version": "16.14.0",
+          "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
+          "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
+          "requires": {
+            "loose-envify": "^1.1.0",
+            "object-assign": "^4.1.1",
+            "prop-types": "^15.6.2",
+            "scheduler": "^0.19.1"
+          }
+        },
+        "scheduler": {
+          "version": "0.19.1",
+          "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
+          "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
+          "requires": {
+            "loose-envify": "^1.1.0",
+            "object-assign": "^4.1.1"
+          }
+        }
+      }
+    },
     "react-dev-utils": {
       "version": "12.0.0",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.0.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "node-sass": "^7.0.1",
     "popper.js": "^1.16.1",
     "react": "^17.0.2",
+    "react-audio-spectrum": "^0.1.0",
     "react-dom": "^17.0.2",
     "react-dropzone": "^11.5.1",
     "react-redux": "^7.2.6",

+ 7 - 2
src/App.scss

@@ -208,11 +208,16 @@ right: 0px;
 }
 
 .Tracks {
-  min-width: 540px;
+  width: 800px;
   text-align: left;
-  padding: 2px;
+  padding: 8px;
   margin: 2px;
   border: 1px solid dodgerblue;
+  @media (max-width: $breakpoint-tablet) {
+    padding: 6px;
+    width: 600px;
+  }
+
 }
 
 

+ 12 - 12
src/pages/header/header-build.js

@@ -36,17 +36,17 @@ export function* setUserPasswordWatcher() {
     yield takeEvery ('SET_USER_PASSWORD',setUserPasswordWorker)
 }
 
-const ChangePasswordForm = ({onChangePassword}) => {
-    const [p, setP] = useState ('')
-    return (
-        <div>
-            <input className='change-password-input' type='password' placeholder='Введите пароль' onChange={e => setP(e.target.value)}></input>
-            <button className='dropdown-button' onClick={() => {onChangePassword(p); history.push('/')}}>Сменить пароль</button>
-        </div>
-    )
-}
-
-export const CChangePasswordForm = connect(null,{onChangePassword:actionSetUserPassword})(ChangePasswordForm)
+// const ChangePasswordForm = ({onChangePassword}) => {
+//     const [p, setP] = useState ('')
+//     return (
+//         <div>
+//             <input className='change-password-input' type='password' placeholder='Введите пароль' onChange={e => setP(e.target.value)}></input>
+//             <button className='dropdown-button' onClick={() => {onChangePassword(p); history.push('/')}}>Сменить пароль</button>
+//         </div>
+//     )
+// }
+//
+// export const CChangePasswordForm = connect(null,{onChangePassword:actionSetUserPassword})(ChangePasswordForm)
 
 
 export const Header = () =>
@@ -81,7 +81,7 @@ const LoginButtons = ({onLogout, history, token}) => {
                         <div className="dropdown-menu dropdown-menu-right">
                             <h2>{JSON.parse(atob(token.split(".")[1])).sub.login}</h2>
                             <CAvatarDropZone />
-                            <CChangePasswordForm/>
+                            {/*<CChangePasswordForm/>*/}
                             <button className='dropdown-button' onClick={() => {onLogout(); history.push('/')}}>Выйти</button>
                         </div>
                     </div>

+ 2 - 0
src/pages/my-tracks/hello-user-page.js

@@ -1,5 +1,6 @@
 import {LogoLarge} from "../header";
 import musicLoad from '../../music-load.png'
+import {Visualiser} from "../../reducers/playerReducer";
 
 export const MusicLoad = () =>
     <><img className='music-load-image' src={musicLoad} alt='musicLoad'/></>
@@ -11,5 +12,6 @@ export const HelloUserPage = () =>
         <div className='hello-column'>
         <LogoLarge/>
         <MusicLoad />
+        {/*<Visualiser />*/}
         </div>
     </div>

+ 63 - 56
src/pages/my-tracks/my-tracks.js

@@ -1,81 +1,88 @@
 import {SortableContainer,SortableElement} from "react-sortable-hoc";
 import {arrayMoveImmutable} from 'array-move';
-import {useState,useEffect} from "react";
+import {useState, useEffect, useRef, useCallback} from "react";
 import {connect} from "react-redux";
 import {CTrack} from "../track";
 import {CPlaylistDropZone} from "../tools";
 import {CPreloaded} from "../preloader";
 import {actionFullUploadPlaylists} from "../../actions";
 
-// const SortableItem = SortableElement(CTrack);
-//
-//
-// const SortableList = SortableContainer(({items}) => {
-//     return (
-//         <div>
-//             {items.map((value, index) =>
-//                 <SortableItem key={`item-${value}`} index={index} trackIndex={index} track={value}/>)}
-//         </div>
-//     )
-// });
-//
-// function SortableComponent({playlist:{name, tracks=[]}={},onLoad}) {
-//
-//     const [state, setState] = useState(tracks || [])
-//
-//     useEffect(() => {
-//         setState (tracks || [])
-//     },[tracks])
-//     const onSortEnd = ({oldIndex, newIndex}) => {
-//         setState((state) => (arrayMoveImmutable(state, oldIndex, newIndex)));
-//     };
-//     onLoad(state)
-//     return (
-//         <div>
-//             <h2>{name}</h2>
-//             <SortableList axis={'y'} items={state} onSortEnd={onSortEnd}/>
-//         </div>
-//     )
-// }
-//
-//
-//
-// const CSortableComponent = connect(state => ({ playlist: state?.promise?.playlistById?.payload || {}}),
-//     {onLoad:actionFullUploadPlaylists})
-// (SortableComponent)
-//
-//
-// export const MyPlaylistTracks = ({match:{params:{_id}}}) =>
-//     <>
-//         <CPlaylistDropZone >
-//             <CPreloaded promiseName='playlistById'>
-//                 <CSortableComponent />
-//             </CPreloaded>
-//         </CPlaylistDropZone >
-//     </>
+const SortableItem = SortableElement(CTrack);
+
+
+const SortableList = SortableContainer(({items}) => {
+    return (
+        <div>
+            {items.map((value, index) =>
+                <SortableItem key={`item-${value._id}`} index={index} trackIndex={index} track={value}/>)}
+        </div>
+    )
+});
 
+function SortableComponent({playlist:{name, tracks=[]}={},onLoad}) {
+
+    // const [state, setState] = useState(tracks || [])
+    const state = useRef(tracks || [])
+
+    useEffect(() => {
+        state.current = (tracks || [])
+    },[tracks])
+
+    const onSortEnd = useCallback(({oldIndex, newIndex}) => {
+        state.current = (arrayMoveImmutable(state.current, oldIndex, newIndex))
+        onLoad(state.current)
+    },[])
 
 
-const MyTracks = ({playlist={}}) => {
-    const{name, tracks=[]} = playlist
     return (
-        <div className='Category'>
+        <div>
             <h2>{name}</h2>
-            <CPreloaded promiseName='playlistById'>
-                {(tracks || []).map((track,index) => <CTrack key={index} trackIndex={index} track={track}/>)}
-            </CPreloaded>
+            <SortableList axis={'y'} items={state.current} onSortEnd={onSortEnd}/>
         </div>
     )
 }
 
-const CMyTracks = connect(state => ({playlist: state.promise.playlistById?.payload || {}}),)(MyTracks)
+
+const CSortableComponent = connect(state => ({ playlist: state?.promise?.playlistById?.payload || {}}),
+    {onLoad:actionFullUploadPlaylists})
+(SortableComponent)
 
 
 export const MyPlaylistTracks = ({match:{params:{_id}}}) =>
     <>
         <CPlaylistDropZone >
-            <CMyTracks />
-     </CPlaylistDropZone >
+            <CPreloaded promiseName='playlistById'>
+                <CSortableComponent />
+            </CPreloaded>
+        </CPlaylistDropZone >
     </>
 
 
+
+
+
+
+//
+// const MyTracks = ({playlist={}}) => {
+//     const{name, tracks=[]} = playlist
+//     return (
+//         <div className='Category'>
+//             <h2>{name}</h2>
+//             <CPreloaded promiseName='playlistById'>
+//                 {(tracks || []).map((track,index) => <CTrack key={index} trackIndex={index} track={track}/>)}
+//             </CPreloaded>
+//         </div>
+//     )
+// }
+//
+// const CMyTracks = connect(state => ({playlist: state.promise.playlistById?.payload || {}}),)(MyTracks)
+//
+//
+// export const MyPlaylistTracks = ({match:{params:{_id}}}) =>
+//     <>
+//         <CPlaylistDropZone >
+//             <CMyTracks />
+//      </CPlaylistDropZone >
+//     </>
+//
+

+ 8 - 6
src/pages/player.js

@@ -4,14 +4,15 @@ import next from '../next.svg'
 import prev from '../prev.svg'
 import {connect} from "react-redux";
 import {actionTrackPlay, actionTrackStop,actionTrackVolume,actionTrackCurrentTime,actionNextTrack,actionPreviousTrack} from "../reducers";
+import {useEffect, useState} from "react";
 
 
-export const Player = ({player:{volume,duration=0,currentTime=0,isPlaying,playlist={},playlistIndex=0},
+export const Player = ({player:{token,volume,duration=0,currentTime=0,isPlaying,playlist={},playlistIndex=0},
                                 trackPlay, trackStop,trackVolume,trackCurrentTime,trackNext,trackPrevious}) => {
 
 
-    let name = playlist[playlistIndex].originalFileName
-    console.log(playlist,playlistIndex,name)
+    let name = playlist[playlistIndex]?.originalFileName || ''
+
 
     let minutes = Math.floor(duration / 60);
     let seconds = Math.floor(parseInt((duration % 60) * 100) / 100);
@@ -50,15 +51,16 @@ export const Player = ({player:{volume,duration=0,currentTime=0,isPlaying,playli
                 max={1}
                 onChange={(e) => trackVolume(e.target.value)}
                 value={volume}/>
-                <h3>{name}</h3>
+                <h3>{name || ''}</h3>
         </div>
     )
 }
 
-export const CPlayer = connect(state => ({player: state.player}),
+export const CPlayer = connect(state => ({player: state.player,token: state.auth.token}),
     {trackPlay: actionTrackPlay,
                      trackStop: actionTrackStop,
                      trackVolume:actionTrackVolume,
                      trackCurrentTime:actionTrackCurrentTime,
                       trackNext:actionNextTrack,
-                      trackPrevious:actionPreviousTrack,})(Player)
+                      trackPrevious:actionPreviousTrack,})(Player)
+

+ 0 - 0
src/pages/visualiser/visualiser.css


+ 69 - 0
src/pages/visualiser/visualiser.js

@@ -0,0 +1,69 @@
+import React, { useState } from 'react';
+import AudioSpectrum from 'react-audio-spectrum'
+import {audio} from "../../reducers/playerReducer";
+
+import './visualiser.css';
+
+const onInputChange = (e) => {
+    var sound = document.getElementById('sound');
+    sound.src = URL.createObjectURL(e.target.files[0]);
+}
+
+const getLocalSettings = () => ({
+    capColor: localStorage.getItem('capColor') || ' ',
+    capHeight: Number(localStorage.getItem('capHeight') || 4),
+    meterWidth: Number(localStorage.getItem('meterWidth') || 3),
+    meterCount: Number(localStorage.getItem('meterCount') || 512),
+    gap: Number(localStorage.getItem('gap') || 5),
+    meterColor1: localStorage.getItem('meterColor1') || '#f00',
+    meterColor2: localStorage.getItem('meterColor2') || '#0C70FD',
+    meterColor3: localStorage.getItem('meterColor3') || '#0CFD70',
+})
+
+
+export const Visualiser = () => {
+    const [defaultSettings] = useState(getLocalSettings)
+
+    const [capColor, setCapColor] = useState(defaultSettings.capColor)
+    const [capHeight, setCapHeight] = useState(defaultSettings.capHeight)
+    const [meterWidth, setMeterWidth] = useState(defaultSettings.meterWidth)
+    const [meterCount, setMeterCount] = useState(defaultSettings.meterCount)
+    const [gap, setGap] = useState(defaultSettings.gap)
+    const [meterColor1, setMeterColor1] = useState(defaultSettings.meterColor1)
+    const [meterColor2, setMeterColor2] = useState(defaultSettings.meterColor2)
+    const [meterColor3, setMeterColor3] = useState(defaultSettings.meterColor3)
+    return (
+        <div className="Visualiser">
+
+            <div style={{
+                display: 'flex',
+            }}>
+                <div className="setting-section file">
+                    <input type="file" id="input" accept="audio/*" onChange={onInputChange} />
+                    <audio id="sound" controls></audio>
+                </div>
+
+            </div>
+            <AudioSpectrum
+                id="audio-canvas"
+                style={{
+                    padding: 10
+                }}
+                height={500}
+                width={900}
+                audioId={'sound'}
+                capColor={capColor}
+                capHeight={capHeight}
+                meterWidth={meterWidth}
+                meterCount={meterCount}
+                meterColor={[
+                    {stop: 0, color: meterColor1},
+                    {stop: 0.5, color: meterColor2},
+                    {stop: 1, color: meterColor3}
+                ]}
+                gap={gap}
+            />
+        </div>
+    );
+}
+

+ 73 - 29
src/reducers/playerReducer.js

@@ -2,11 +2,16 @@ import {backURL} from "../actions";
 import { select, put, takeEvery } from "redux-saga/effects";
 import {store} from "./store";
 
+import React, {useEffect, useRef, useState} from 'react';
+import AudioSpectrum from 'react-audio-spectrum'
+import {connect} from "react-redux";
+
+
 
 export const playerReducer = (
     state = {},
     {type,track,isPlaying=false,isPaused,duration,
-        playlist,playlistIndex,currentTime=0,volume=1,}) => {
+        playlist,playlistIndex,currentTime=0,volume=1,audio}) => {
 
     if (type === "NEXT_TRACK") {
         return {
@@ -38,6 +43,7 @@ export const playerReducer = (
             ...state,
             isPlaying,
             isPaused: !isPlaying,
+            audio,
         };
     }
 
@@ -87,7 +93,6 @@ audio.onended = () => store.dispatch (actionNextTrack())
 
 
 
-
 const trackActions = (urlVar) => {
     audio.src = backURL + '/'+ urlVar.url
     audio.load()
@@ -119,7 +124,7 @@ export const actionTrackPlay = () =>
     ({type:'ACTION_TRACK_PLAY'})
 export function* trackPlayWorker () {
     yield audio.play()
-    yield put({type:"TRACK_PLAY",isPlaying:true,isPaused:false})
+    yield put({type:"TRACK_PLAY",isPlaying:true,isPaused:false,audio:audio})
 }
 export function* trackPlayWatcher() {
     yield takeEvery ('ACTION_TRACK_PLAY',trackPlayWorker)
@@ -223,32 +228,6 @@ export const actionTrackCurrentTime = (e) => {
 }
 
 
-//
-// export const actionTrackCurrentTime = (e) =>
-//     ({type:'CURRENT_TIME', e})
-//
-//
-// export function* trackCurrentTimeWorker (action) {
-//     let {e} = action
-//     if (e) {
-//         audio.currentTime = e
-//         yield put({type:"TRACK_CURRENT_TIME", currentTime:e})
-//     } else {
-//        e = audio.currentTime
-//        yield put({type:"TRACK_CURRENT_TIME", currentTime:e})
-//     }
-//
-// }
-//
-// export function* trackCurrentTimeWatcher() {
-//     yield takeEvery('CURRENT_TIME', trackCurrentTimeWorker)
-// }
-
-
-
-
-
-
 
 
 
@@ -266,3 +245,68 @@ export function* setPlaylistWatcher() {
 }
 
 
+
+
+
+//
+// const onInputChange = (e) => {
+//     var sound = document.getElementById('sound');
+//     sound.src = URL.createObjectURL(e.target.files[0]);
+// }
+
+//
+// export const Visualiser = () => {
+//
+//     const track = useRef(audio || {})
+//
+//     useEffect(() => {
+//         track.current = (audio|| {})
+//     },[audio])
+//
+//     // let sound = document.getElementById('sound');
+//     const [capColor, setCapColor] = useState(' ')
+//     const [capHeight, setCapHeight] = useState(4)
+//     const [meterWidth, setMeterWidth] = useState(3)
+//     const [meterCount, setMeterCount] = useState(512)
+//     const [gap, setGap] = useState(5)
+//     const [meterColor1, setMeterColor1] = useState('#f00')
+//     const [meterColor2, setMeterColor2] = useState('#0C70FD')
+//     const [meterColor3, setMeterColor3] = useState('#0CFD70')
+//
+//     console.log(track.current,'111')
+//
+//     return (
+//         <div className="Visualiser">
+//
+//             {/*<div style={{*/}
+//             {/*    display: 'flex',*/}
+//             {/*}}>*/}
+//             {/*    <div className="setting-section file">*/}
+//             {/*        <input type="file" id="input" accept="audio/*" onChange={onInputChange} />*/}
+//             {/*        <audio id="sound" controls></audio>*/}
+//             {/*    </div>*/}
+//
+//             {/*</div>*/}
+//             <AudioSpectrum
+//                 id="audio-canvas"
+//                 style={{
+//                     padding: 10
+//                 }}
+//                 height={500}
+//                 width={900}
+//                 audioEle={track.current}
+//                 capColor={capColor}
+//                 capHeight={capHeight}
+//                 meterWidth={meterWidth}
+//                 meterCount={meterCount}
+//                 meterColor={[
+//                     {stop: 0, color: meterColor1},
+//                     {stop: 0.5, color: meterColor2},
+//                     {stop: 1, color: meterColor3}
+//                 ]}
+//                 gap={gap}
+//             />
+//         </div>
+//     );
+// }
+//