Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extend handlers for openUrl, load/save list #991

Merged

Conversation

tinchoz49
Copy link
Contributor

@tinchoz49 tinchoz49 commented May 18, 2020

This PR adds support for openUrl, load/save list handlers:

  • Update USAGE.MD
new Webamp({
  handleAddUrlEvent() {
    // return Tracks[] to load
  },
  handleLoadListEvent() {
    // return Tracks[] to load
  },
  handleSaveListEvent(tracks: PlaylistTrack[]) {
    // async operation to save the tracks
  },
})

@tinchoz49
Copy link
Contributor Author

also, do you think that we could allow the user to define the id of the track?

like:

webamp.appendTracks([
    { id: 'track1', url: 'https://example.com/track1.mp3'}
]);

here: https://github.com/captbaritone/webamp/blob/master/packages/webamp/js/actionCreators/files.ts#L224

const { id =  Utils.uniqueId(), defaultName, metaData, duration } = track;

This can be helpful for tracking the songs outside of the webamp app.

Copy link
Owner

@captbaritone captbaritone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start, and very close! A few comments but overall this looks good.

I don't think we can let the user supply the ID since we can't ensure it won't collide with values we've created. Could you explain, perhaps with an example, how being able to define the ID would be useful?

const tracks = await handleLoadListEvent();

if (tracks != null) {
await dispatch(removeAllTracks());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we awaiting here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. I don't know why I tought the removeAllTracks was async.

return async (dispatch, getState, { handleSaveListEvent }) => {
if (handleSaveListEvent) {
const state = getState();
const trackIds = getVisibleTrackIds(state);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns the ids of the tracks that are visible in the window. If the window is shorter this list is shorter. I think you want getTrackOrder.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tought it was a selector to get the non deleted tracks, changed to getTrackOrder worked,

onClick={() => alert("Not supported in Webamp")}
/>
<div className="save-list" onClick={() => saveFilesToList()} />
<div className="load-list" onClick={() => addFilesFromList()} />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need these arrow functions:

      <div className="save-list" onClick={saveFilesToList} />
      <div className="load-list" onClick={addFilesFromList} />

@@ -688,6 +688,9 @@ export interface Extras {
handleTrackDropEvent?: (
e: React.DragEvent<HTMLDivElement>
) => Track[] | null | Promise<Track[] | null>;
handleAddUrlEvent?: () => Track[] | null | Promise<Track[] | null>;
handleLoadListEvent?: () => Track[] | null | Promise<Track[] | null>;
handleSaveListEvent?: (tracks: PlaylistTrack[]) => Promise<undefined>;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the type PlaylistTrack is an internal type that is not really exposed in the public API. Could we convert these to Track before returning them to the user without losing anything valuable?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does asking the user to return a promise here add any value? Currently we don't do anything with the promise.

const state = getState();
const trackIds = getVisibleTrackIds(state);
const tracks = getTracks(state);
await handleSaveListEvent(trackIds.map((id) => tracks[id]));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to await here?

@@ -158,6 +158,29 @@ async function main() {
return null;
}
},
handleAddUrlEvent() {
const url = window.prompt("Paste your URL");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly due to CORs this won't work for most URLs. Thanks for including this in the PR so that we can see how it would be used, but lets remove them before we actually merge.

@captbaritone
Copy link
Owner

captbaritone commented May 19, 2020

@remigallego would this API be useful for https://winampify.io? If so, would this approach work?

@tinchoz49
Copy link
Contributor Author

I don't think we can let the user supply the ID since we can't ensure it won't collide with values we've created. Could you explain, perhaps with an example, how being able to define the ID would be useful?

Maybe I will not need it, I'm going to try a different approach.

My problem was that I'm going to load songs from a key/value store and then at some point I want to persist a playlist of the songs that I have loaded. I need to know which tracks I already have it in my drive and which one don't.

Using the title of the songs is not best option because you can have duplicate songs.

So that's why I thought a custom ID.

const webamp = new Webamp({
    handleSaveListEvent(tracks) {
      tracks.forEach(track => {
        if (!store.has(track.id)) {
           // persist the blob track 
        }
      })
      
      // save the playlist
    }
});

webamp.appendTracks([
  { 
    id: file.key, 
    blob: file
  }
]);

btw this is only a problem if I'm using blob tracks, I can identify a track by the url.

Copy link
Owner

@captbaritone captbaritone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very close. Just a few more things.

},
handleSaveListEvent(tracks) {
console.log(tracks);
},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove both of these as well.

yarn.lock Outdated
url "0.10.3"
uuid "3.3.2"
xml2js "0.4.19"

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these changes to yarn.lock are incorrect. I'm guessing you don't need any of them.

return {
url: track.url,
metaData: {
artist: track.artist || "",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm generally not a fan of || "". If the field is nullable, pass null, if it's not nullable then it's required and passing it an empty value is going to cause unexpected behavior. Could we just null out the entire metaData object if any of the required fields are missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I try to follow same paths than here:

artist: artist ? artist : "",

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Touché 😛

album: track.album,
albumArtUrl: track.albumArtUrl || "",
},
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For bonus points we could move the generation of this array of tracks into a selector in the selectors file. (Not required)

Copy link
Contributor Author

@tinchoz49 tinchoz49 May 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I name it getUserTracks since Track is an object type to interact with the playlist user and also because getTracks was already taked.

@captbaritone
Copy link
Owner

Looks great to me! Are you up to adding it to the usage.md docs?

@tinchoz49
Copy link
Contributor Author

Great, I updated the usage.

@captbaritone
Copy link
Owner

Fantastic! I’ll merge this now and try to push an alpha release to NPM later today for you to use/test.

Thanks for all your work on this. Great idea.

@captbaritone captbaritone merged commit 2101c74 into captbaritone:master May 24, 2020
@tinchoz49
Copy link
Contributor Author

thank you!!

@captbaritone
Copy link
Owner

I just published a beta version 1.4.1-beta03 and tried it out here. Seems to work well!

Would you take it for a spin in your project and report back to confirm that it worked? I'll be publishing a new release in a little bit and hopefully you can move there soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants