jsmith / relar Goto Github PK
View Code? Open in Web Editor NEWThe Relar cloud music player repository.
Home Page: https://relar.app
License: Mozilla Public License 2.0
The Relar cloud music player repository.
Home Page: https://relar.app
License: Mozilla Public License 2.0
I want to know where people have come from when they visit the site. To do this, I should use some kind of reference identifier for all sites that I post the app on and send that information to Google Analytics.
This is a no brainer feature! As a user, I want to be able to create playlists to store collections of songs.
There are three solutions that I see:
We will not be adding the ability to sort playlists based on any attributes. By default, they will be sorted by the time they were added. Google Play does allow you to sort; however, Spotify does not.
Loading songs every time may turn out to be an expensive opration ($0.06 / 100,000 reads).
Create some kind of system that syncs changes to each device (CRDTs??).
As a user, I want to be able to create a queue of songs (albums, artists, entire libraries, custom). Additionally, for each song, I want to see where that song came from.
A queue will basically be a list of songs with a source.
interface SongQueue {
/** The current index into the queue */
current: number;
songs: SongQueueItem[];
}
interface SongQueueItem {
source: "album" | "custom" | "artist" | "library" | "playlist";
sourceId: string | undefined; // defined if source === "album" or source === "artist" or source === "playlist"
song: DocumentSnapshot<Song>;
}
A user will be able reorder the queue without losing the source information (the current
value will need to be updated when this happens). Furthermore, a user should be able to create a playlist from this queue.
Nothing here yet.
As the owner, I want to be able to understand how people are using the app.
Google Analytics is a great tool that integrates well with firebase. Use this documentation along with tutorials and such to add analytics to the web and mobile apps.
We should be tracking lots of things. For example:
This information will be critical to optimize usage before the release.
As the owner, I want to be able to quickly respond to user errors.
Sentry! Sentry is already integrated into the app but we should ensure that everything is correct configured and that we are capturing all errors.
This doesn't need to be too in depth. This tutorial looks like a good starting point to ensure everything is correctly integrated.
As a user, I want consistent branding.
Create a logo, ensure name is good, create favicon and other icon.
As a user, I want to be able to subscribe to increase the services I receive.
We need to integrate stripe into our app (especially firestore) to enable users to subscribe to our app.
If it's not too hard to set up, we should offer the subscription cost in different currencies. We also need to ensure we collect tax correctly. Also, we need to ensure we are complying with all legal requirements. Are there any issues with hosting the app in the USA but serving Canada/Europe? Should we restrict who can use this app?
As a user, I want to be able to organize my songs my artist.
Artists are actually super simple, they just contain a name! This makes them super easy to identify and look up. We'll store a collection of artists (where the unique ID is the name of the artist) with just a single attribute (the artist name).
We are not storing artwork for artists. This might be a nice feature though! Also, you will not be able to edit the name of an artist.
As a user, I want to be able to contact someone for support or to leave feedback.
We should add a contact form that users can use for support issues and feedback. This could be present in the account dropdown and automatically be linked to their account. We could also add a support page that could be accessed from the footer for users who don't have accounts.
We will not be doing anything fancy for feedback yet. Eventually, we might be able to use some kind of service to manage feedback and provide support.
Use Indie Hacker to improve home screen. Maybe add FAQ??
As a user, I want to follow updates to the app.
Have a public relar.app/updates
page which pulls data from a collection of updates with change logs, dates and versions.
We need a way to sync data across the app. React
is pretty good at this but there are particular instances where this is not sufficient. In addition to React state management (ie. useState
, useContext
), we are using react-query
to manage queries, mutations and frontend caching. This need stemmed from this user story:
As a user, I want to be able to like a song in the song table and have that automatically show up in other parts of the app (ie. the player).
Vue would particularly be a better fit to this task given their dependency tracking but of course... we are using React
. This synchronization feature will appear in other locations in the app too. For example, a user may change a song's metadata and expect that change to appear in other locations in the app, even if the old value had previously been cached.
The hardest part about this problem is the magnitude of data we could be dealing with (on the scale of tens of thousands). We could engineer a simpler solution using onSnapshot
but I think it would be a good idea to create a solution now.
This solution will attach onto the .doc
methods and .collection
methods to return DocumentReference
objects that have their update
, set
, and delete
methods wrapped. By wrapping these methods, we can be alerted when mutations occur. Once these mutations succeed, we will kick off a get
on the reference object to grab the latest data. This data will need to be stored for the lifetime of the app as other elements with stale data may attach at which point we should return the most up-to-date locally stored data. The second step to this solution is creating a hook that can be used to watch for updates. Then, for example, the Player
elements along with the SongTableRow
elements will be able to use this hook to receive the most up-to-date version of the object.
export interface SongTableRowProps {
/**
* The song. `undefined` means it is loading.
*/
song: firebase.firestore.QueryDocumentSnapshot<Song> | undefined;
}
export const SongTableRow = ({ song: original }: SongTableRowProps) => {
...
const song = useFirebaseUpdater(original);
...
}
This should be a fairly efficient solution. Unlike onSnapshot
, we are not listening for remote updates. Using hooks, we can easily dispose of listeners when components are unmounted.
This solution is for local changes only. This solution treats whats in the cache as the source of truth, not whats in the remote database. If a user mutates data on another device, they can just refresh the page. If we wanted local and remote changes, we could use the onSnapshot
method for document references. We will be supporting deletions (delete
), updates (update
), and sets (set
).
As a user, I want to be able to use the app while offline. All my songs/albums/artists/playlists should be available. Additionally, I want to be able to download specific songs/albums/artists/playlists and automatically download new songs.
To start, we should use firebase's offline support. This should work without have many changes to the codebase. To implement offline support, we can use capacitors filesystem and storage APIs to store JSON data (saying which files are downloaded) the associated files.
As a user, I need be able to play music from the app.
Build a player page that can be minimized/maximized while playing. This page should follow the tradition design of players (see SoundCloud, Google Play, Spotify, etc).
We should add CORS for relar.app
, staging.relar.app
and localhost:3000
!
As a user, I want to see all of my songs on mobile.
Create a songs list using the recycle view. Also build a nice navigation that allows you quickly jump to different sections of the songs by letter.
As a user, I want to ensure forms are accessible
When a song is uploaded, it should appear in the app.
We need a mobile app!
As a user, I want to be able to find the website by searching online.
Go through the optimization documentation from Google to optimize search. I'm really not sure how all of this actually works.
As a user, I want to view the queue on mobile.
The easiest and coolest solution is to replicate the views from Apple Music.
Emails will be sent to users when signing up, creating their account, confirming their email, resetting their password, etc. These need to be customized!
Customize the emails!
We will be doing nothing fancy :) Just simple text.
As a user, I want to be able to upgrade my account to improve my services.
Use stripe to implement subscription system. Firebase has a great tutorial. Be sure to integrate firebase analytics to be able to distinguish users by subscription level.
We need legal documents! This might be a good resource -> https://www.privacypolicygenerator.info/
As a user, I want to go to a page that I am familiar with to change my password/email.
Implement custom email action handlers. See the tutorial here.
Users will be able to upload lots of songs. Because of this, we don't want to load everything at once. Although infinite scroll is a hassle, I think it's worth the effort.
We will use firebase in addition to the infinite scroll of react-query
to implement this feature. No infinite scroll table has been chosen yet but note that we will have an accurate count of the number of songs in the database which is useful for correctly size the scrollbar.
This solution will take advantage of the work from #2 to ensure the data in the table is the most up-to-date data and changes are automatically propagated.
Depending on the complexity, sorting by title, artist, album, play count, like may or may not be supported.
We need to be able to store albums and have them linked to songs. One of the main questions we need to answer is, how do we uniquely identify an album? In the real world, this is done by an album name and an artist. This could lead to conflicts in practice but these situations can be ignored and left up to the user to deal with.
Uniquely identify an album by an album name and album artist. Album artists are purely for organizations purposes and are apart of the ID3 spec. See here for more information. In practice, this could lead to annoyances. If a user uploads a song with an album name but no album artist, an album artist but no album or an album name with an artist (no album artist), then we want to handle these situations as well. Here is a summary of the situations that may arise:
The above points are detailed enough to provide solutions for everything but they're good enough for now. One more problem is figuring out how we are going to query songs that belong to an album. One possibility is generating unique IDs for each album and then storing that in the db but a much nice solution is deriving the ID from the album name and album artist. This makes it super easy to lookup an album given an album name, artist name, and album artist name.
If the data of an album is changed, that information should be changed within all of the songs as well.
Nothing important to put here!
As a user, I want artist/album/playlist page titles to show the name of these items.
Use a hook system to set and unset the page title.
Users are going to do things they don't mean to do!
Either we make the user confirm actions or provide very basic undo functionality (or both). For certain operations (ie. changing email address), a confirmation works best; however, for things like removing a song from a playlist, undo might be the most user friendly option. Here is a non complete list:
As a user, I need to know that my data is safe.
Use builtin firebase tools to export data on a regular schedule.
As a user, I want to be able to shuffle playlists, artists, albums and my entire song library.
Shuffle will take the item being shuffled (ie. simple randomization) and then insert everything into the queue. This will be fairly easy for playlists, artists and albums but the entire song library poses a problem if we don't plan to load everything into memory at once. Because of this, I plan to change how we implement the frontend to actually load all songs during the loading process of the app. This will make the implementation of the shuffle much easier, along with other problems.
We will not be any kind of smart shuffle features. See the accepted answer of this SO post for more details but here is the gist of why this would make things harder:
• Users don't want to hear the same song multiple times in a row.
• Users don't want to the same artist/album played consecutively or too close together.
• Users want to hear 1-2 songs from every artist/genre in their collection before repeats occur.
• Random sequences that match established patterns are viewed as not random and disliked. This would be things like playing track 2 from albums A, B, C then playing track 3 from those albums, or playing track 1 from A, track 2 from B, track 3 from C. This would also be if songs followed a rock, country, rap, pop cycle or songs played in alphabetical order.
• Over playing less liked artists or under playing favorite artists creates dissatisfaction.
• Subsets of songs shouldn't be played in the same order as previous iterations. similarly the last X songs shouldn't be in the first X songs in the next iteration.
As a user, I want my data to be secure and not become messed up.
Ensure firebase rules are as strict as possible.
Add type checks and attribute checks for all create and update permissions.
We should detect duplicate songs and prevent them from being uploaded.
As a user, I want to be edit song metadata and then have those changes affect artists/albums.
One of the hardest parts about maintaining a song database per user (as appose to a streaming service like Spotify) is that the source of truth for all data is songs. For example, when a user uploads a new song with an album that doesn't exist yet, we need to create that album in the database so that it can be queried. Furthermore, if a user edits a song to change the album, we need to delete the old album if it's now empty and create a new album if that new album doesn't exist. The same things go for artists as well!
For this complex operation, we can create a cloud function using express. Obviously, this function will allow the user to edit the:
But if the album, artist, or album artist change, we may or may not need to delete/create albums/artist.
Users need to be able to search through their own libraries for songs, albums, and artists.
Algolia and Elasticsearch seem like two great options. Since the solution we choose needs to work with data on the scale of 20,000 songs / user, this immediately eliminates Algolia which charges $1 / month / 1,000 documents. The officially managed elasticsearch service from elasticsearch seems like a promising option. We'll need to run the numbers to be sure that this solution will work for the scale of data we will be using (ie. hopefully much less than $1 / month / user).
As a user, I want to be able to perform backups of my library to ensure my mp3 collection is always safe.
Provide a desktop tool that allows users to backup their library one song at a time.
As a user, I want to be able to control the app.
Create Settings page that allows users to sign out, directs them to the web app to control their account. Also, have streaming/downloading settings (related to #58) that allows users to configure "cache during playback", "clear cache", "stream via wifi only", "download via wifi only". Eventually, we can have stream/download quality settings as well.
As a user, I want to see my albums/playlists.
Build an albums/playlists page and an album/playlist/generated page. Similar to the web, this should show meta information and the list of songs.
As the owner, I want to be able to see how my app is performing.
Use firebase performance monitoring.
As a user, I want to be able to use keyboard shortcuts to navigate to different tabs and to perform different actions.
Examples
This should be pretty easy! We can just register a list of global keyboard shortcuts using something like react-hotkeys-hooks
. We should also create a nice modal that has all of the shortcuts.
The Soundcloud shortcut modal.
There will be no overly complex shortcuts that only apply if certain areas of the app are focused (like VS Code does).
As a user, I want to see my recently added songs and my recently liked songs.
We can easily query using firestore queries.
We'll limit the # of recently added songs to 1000.
I probably need legal things for legal reasons.
Use the internet in addition to docracy to find the documents I need.
As a user who uses screen readers, I want to be able to use the app.
We should review best practices and research how Spotify implements accessibility.
This does not need to be perfect by any means. Eventually, I might be able to bring in someone more knowledgable to evaluate the app once the low hanging fruit are taken care of.
We need to store the duration of the track for UI purposes. For example, this will be useful to quickly calculate the duration of a playlist and to display a duration in the song table.
Use this package to get the duration while uploading a song. Modify the SongType
accordingly to make the duration
property required.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.