benwiley4000 / cassette

📼 A flexible media player component library for React that requires no up-front config
https://benwiley4000.github.io/cassette/styleguide
MIT License
184 stars 28 forks source link

Need help, not sure if I'm doing everything right. #432

Open Catsvilles opened 4 years ago

Catsvilles commented 4 years ago

Hi! I'm trying to build quite a complex audio platform and after days of looking for the right audio player, I think cassette might be the one I need. But I kinda stuck here and before I go deeper and start reinventing the wheels, I thought, I better ask for advice and guidance, and if available examples :)

So, I'm trying the get multiple audio players per page and one footer "main player", all the players will be customized and display waveforms (which I render serverside). Here is a simple example (even though here the footer player has just simple progress bar in my case it would have also a waveform) tracks-index-screenshot

From all the Cassette examples I see, that usually if there are multiple players per page - they are just simple play buttons without displaying the audio duration and so on. Can it be changed so every file has duration and progress and all the details?

I found this demo app https://github.com/benwiley4000/cassette-demo-app and tried to modify it's code a bit, to achieve what I'm looking for but unfortunately, I cannot get it to work right, even though I managed to attach a ProgressBar to the players I'm not sure how to give them unique ID or other RIGHT way of doing it, so when we change the progress of the main player the progress should also be changed only for the currently playing player in the playlist. Here is the screenshot and the code I managed to "compose": screenshot-localhost_3000-2019 10 05-16_49_15

import React, { Component } from 'react'; import './App.css';

import { PlayerContextProvider, FullscreenContextProvider, playerContextFilter, PlayerContextGroup } from '@cassette/core'; import { MediaPlayerControls } from '@cassette/player'; import { MediaProgressBar } from '@cassette/components'; import './player_styles.scss';

import playlist from './playlist';

function TrackPosition({ activeTrackIndex, playlist }) { return ( <div style={{ fontSize: '1rem', display: 'flex', alignItems: 'center', fontWeight: 'bold' }}

Track {activeTrackIndex + 1} / {playlist.length}

); }

function PlaylistMenu({ playlist, activeTrackIndex, onSelectTrackIndex }) { return ( <div style={{ width: '280px', marginTop: '2rem', marginBottom: '2rem', fontSize: '1.2rem' }}

Select a track:

{playlist.map((track, i) => { const playing = activeTrackIndex === i; TrackPosition({activeTrackIndex, playlist});

    return (
      <div
        key={i}
        style={{
          fontWeight: playing ? 'bold': undefined,
          margin: '0.5rem',
          padding: '0.5rem',
          borderRadius: '0.25rem',
          border: '2px solid white',
          cursor: 'pointer',
          textAlign: 'left',
          marginBottom: '2rem'
        }}
        onClick={() => onSelectTrackIndex(i)}
      >
        {playing && '▶️'} <i>{track.artist}</i> - {track.title}
        <MediaProgressBar
          style={{ background: 'black', height: 15 }}
          progressStyle={{ background: 'orange' }}
          progressDirection="right"
        />
      </div>
    );
  })}
</div>

); }

PlaylistMenu = playerContextFilter(PlaylistMenu, [ 'playlist', 'activeTrackIndex', 'onSelectTrackIndex' ]);

function FfwButton({ playbackRate, onSetPlaybackRate }) { return ( <div style={{ fontSize: '2rem', display: 'flex', alignItems: 'center', fontWeight: 'bold', WebkitUserSelect: 'none', MozUserSelect: 'none', msUserSelect: 'none', userSelect: 'none', WebkitTouchCallout: 'none' }} onTouchStart={() => onSetPlaybackRate(3)} onMouseDown={() => onSetPlaybackRate(3)} onMouseUp={() => onSetPlaybackRate(1)} onMouseLeave={() => onSetPlaybackRate(1)} onTouchEnd={() => onSetPlaybackRate(1)}

); }

FfwButton = playerContextFilter(FfwButton, [ 'playbackRate', 'onSetPlaybackRate' ]);

const secondPlaylist = [ { url: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4', title: 'Elephants Dream', artist: 'Orange Open Movie Project' } ];

class Player extends Component {

render() { return (

{ localStorage.setItem('media_snapshot', JSON.stringify(shot)); }} >
this.mediaContainerElem = elem} >
{this.state}
);

} }

export default Player;

Thanks a lot for reading through this!

P.S. on the docs website we got this "main" footer player, how do we actually build such kind of footer player? I cannot find examples of this. But from what I understand it's just a simple player which is fixed to the bottom of the page with css?

benwiley4000 commented 4 years ago

Hey! These are great questions, thanks for the detailed post.

To try to give you some quick tentative answers:

From all the Cassette examples I see, that usually if there are multiple players per page - they are just simple play buttons without displaying the audio duration and so on. Can it be changed so every file has duration and progress and all the details?

Yeah for sure, you can have multiple fully functional players on the same page. The docs page is an example of this. You can also see a version of that on my own website: https://benwiley.org/music. And I guess in your own code you've figured something out, at least partway.

I'm not sure how to give them unique ID or other RIGHT way of doing it, so when we change the progress of the main player the progress should also be changed only for the currently playing player in the playlist.

Yeah, good question! I ran into the same issue when I was designing the music page for my website, which I linked above. The problem is that the playerContext will only hold onto the currentTime for whichever media clip is loaded and doesn't retain state for other tracks. If you try to render a MediaProgressBar under each track of course you'll get some confusing UI.

I think the best solution (or at least what I came up with) is to only display the progress bar under the track that is currently playing, and to hide it if the track isn't playing. Alternatively, if you want to keep the progress bar rendered for a track that isn't playing, you can display a ProgressBar whose value is set to 0 for inactive tracks.

on the docs website we got this "main" footer player, how do we actually build such kind of footer player? I cannot find examples of this. But from what I understand it's just a simple player which is fixed to the bottom of the page with css?

Yeah, indeed it's just a simple player with some CSS to fix it to the bottom. Assuming your page is wrapped in a PlayerContextProvider, you can render a MediaPlayerControls from the @cassette/player package which will have a default look you can customize. Note that MediaPlayerControls will inherit the state of the surrounding media from the PlayerContextProvider but MediaPlayer would create its own playerContext, which probably wouldn't be what you would want.

~~

Does all that make sense? Let me know if you have more questions, and if it would be helpful I could try to apply what I'm talking about to the code you shared.

benwiley4000 commented 4 years ago

@Catsvilles do you have any more questions? Let me know if you'd like me to give you more concrete code examples.

Catsvilles commented 4 years ago

@benwiley4000 First of all - thank you very much for your detailed reply yesterday!

Since yesterday I'm trying to put together what we've discussed but unfortunately, I run into errors from Cassette's core all the time. So at the moment I even tried to put together a player based on your personal website player, but you rely on Gatsby and I tried to drop it as a dependency, for example in a playlist: import { withPrefix } from 'gatsby'

But once I remove withPrefix() from all the links I receive the following error:

Okay, that is funny and weird but once I ran 'npm start' to output the error to the console and copy/paste it here it actually started working lol So, I guess I will continue investigating for now. I don't want to bother you with my failures until I put together some solid investigation but I ran on some limitations all the time. Too bad this kind of functionality doesn't come out of the box in Cassette. So yeah, it would be nice if you would put a simple example of multiple players that are synced to one main/footer player with the ability to change the progress there and there and so on. Maybe we could merge this to the Cattesse's core functionality somehow. Because I feel many users would like such functionality but there are not many libraries that provide it out of the box. (Actually, I kinda went through all the github reps to find such one and now my hard drive is full with installed players but none of them can help me with this).

So, I'll wait for now for your reply and examples and will go from there. Thank you!

benwiley4000 commented 4 years ago

Ah, yeah we should find an example which doesn't rely on Gatsby. That might make things less confusing!

On the todo list is to have more basic use case examples for folks trying to learn Cassette. I'll try to throw something together for you, and if you end up wanting to contribute anything else, that would be great! I'll try to get back with you in the next day.. if I forget, please remind me.

benwiley4000 commented 4 years ago

Hey just want to shout out and say I realize I never got back on this and I'm sorry. It's been hard to find time for open source lately but I do plan to follow up on this as well as the rest of the 2.0 release backlog. I'm hoping to make time in my schedule in the next month to catch up. And always feel free to email me if there are high-priority concerns (you can find my email if you open up a GitHub commit url and add .patch to the end of it).

Catsvilles commented 4 years ago

@benwiley4000 Hi! thanks for getting back to me but this is already not actual to me as I moved completely from React and do things now in other lib and player, but I really hope this could be useful for someone! Well, at least you don't have to rush for sure anymore, anyway :) Feel free to close the issue if something :)