Features & functionality
- Responsive, functions the same on mobile.
- Search page
- Accounts
- Uses sign in with Google
- Each account can have playlists and saved songs
- Fully functional playlists
- Playlists have visibility settings (i.e only the user can see the playlist or they can make it public)
- Shuffling playlists & albums
- Album views
- Backend
- Assigns each requested song a youtube video (optimized to not return music videos that have added distracting parts)
- Spotify API token distribution
- Full screen player view
- Caches recently played tracks' info using localstorage (streaming url, youtube ID)
- Settings
- Streams audio, programmatically controlls the playback from any part of the application
- Note: Octave does not actually play music, it only plays royalty-free audio to demonstrate the playback capabilities
Architecture
- Next.js
- Typescript
- Firebase
- Firestore: User account info, playlists, saves tracks with a corresponding youtube idc
- Cloud Functions: Serverless Node.js-based functions to act as my backend
- App Hosting
- Authentication
- Tailwind CSS
- Onedrive file hosting: Streaming royalty-free audio
- Spoitfy API: Search for songs and albums, get album for album views
Problems Faced
Maintaining a Long-Term project
- I originally used the React-Router framework in 2021 & 2022, but updated to Next.js in early 2024.
- During which, I updated my fully javascript codebase to typescript. This was a much needed change.
- I ported the application from a self-hosted version, to Google Cloud's experimental firebase hosting with Next.js, and now to the officially supported Firebase app hosting
Hosting on Firebase using Next.js 14
- Every time I navigated using
<Link>
there would be a full page reload - This behavior reset the app state between pages
- Caused the app to completely forget the currently playing song, and had to re-fetch the authentication state
- Solution: force-dynamic on the root route:
// app/layout.tsx
export const dynamic = "force-dynamic"
- This was a flaw in Firebase experimental hosting with Next.js, and has been fixed since moving to the officially supported version