Introduction
Music is a necessity nowadays. There are many music apps and platforms, Spotify, Apple Music, and Youtube Music for global users, but the subscription fee is a little high, and some countries can’t use them directly, such as China. Netease Cloud Music and QQ Music are two major platforms for the Chinese to listening music, but switching between them is a pain to listen want we want because the two platforms have their music library and do not share, and they always integrate a lot of social features into the app—follow each other, comment and so on. Sometimes, in fact, I just want to listen, I want a pure music-listening App, with no recommendations, and no sociability.
https://github.com/Sangwan5688/BlackHole is a great music app built by Flutter, but it’s not Chinese songs-friendly.
So I decided to build a music app that would reach my demand—I can manage my library and original audio, and it would support multiple platforms, and another important point: Free!
1. Requirements
- Play songs with thumbnail and synchronous lyric
- Playlist supported
- Ability to Play background
- Free—including storage and server
- Multiple platforms supported—at least Mac, iPhone, and iPad that I use now
- Allowed to upload local files
2. System Design
2.1 General Diagram
- Servers
- Query Server: query song information from DB or third-party APIs
- Upload Server: upload songs from thirty-party to my storage
- Frontend
- DB: store song information
2.2 Critical Path
Once a song has been uploaded to storage, the third-party service is no longer needed. In addition, the song can be uploaded from local files.
2.3 Technology Selection
2.3.1 Frontend
Flutter is the only selection that meets the demand for supporting cross-platform. React Native, Electron, Xamarin, and Tauri only achieves one site for mobile or desktop.
2.3.2 Server
Use Cloudflare Workers to host serverless functions, the free plan is enough for personal use. Of course, there are many free solutions—AWS Lambda, Google Cloud Function, etc. I have a server hosting in Cloudflare, so I keep using it.
2.3.3 Database
Due to the MongoDB Atlas needing another non-free app server, use Cloudflare D1 as the alternative, which is in the alpha stage and free temporarily.
~~MongoDB is a document-original NoSQL database and MongoDB Atlas offers a free cloud database server. 512MB of storage is enough for the songs’ information. We can also voluntarily select three types of cloud providers and multiple regions.~~
2.3.4 Storage
Use object storage to store audio files, click this article to learn more about cloud storage. Cloudflare R2 is a suitable product for this project. It provides 10GB of free storage, and the size of a 320K song in mp3 format is bout 10MB, R2 free plan can store about 1K audio files.
why did I choose this product please see the Comparison of free object storage products
3. Prototype/UI Design
4. API Design
4.1 Search Song
- Path: /song/search
- Method: GET
- Parameters
- *keyword: String
- source: storage/qq/netease [default: storage]
- Response [array[song_info]]
- id: Number
- name: String
- artist: String
- duration: String
- url: String
- origin_id: String
- source: String [storage/qq/net_ease]
4.2 Search Storage Song
- Parameters
- *keywords: String
- page: number
- Response [array[song_info]]
- id: Number
- name: String
- artist: String
- duration: String
- lyric_url: String
- audio_url: String
- source: storage
4.3 Search QQ Song
- Parameters
- *keywords: String
- page: number
- Response [array[song_info]]
- id: Number
- name: String
- artist: String
- duration: String
- source: qq
4.4 Search NetEase Song
- Parameters
- *keywords: String
- page: number
- Response [array[song_info]]
- id: Number
- name: String
- artist: String
- duration: String
- source: netease
4.5 Get Netease Lyric
- Parameters
- id: String
- Response
- lyric: string
- source: netease
4.6 Get Lyric
- Path: /lyric/get
- Method: GET
- Parameters
- id: String
- source: storage/qq/netease [default: storage]
- Response
- lyric: String
- source: storage/qq/netease [default: storage]
4.7 Sync Song
- Path: /song/sync
- Method: POST
- Parameters
- *name: String
- *artist: String
- Response
4.8 Get Storage Song
- path: /song/get
- method: GET
- Response
4.9 Add Likes
- path: /likes/add
- method: POST
- parameters
- id: number
- response
- true
4.10 Get Likes List
- path: /likes/get
- method: GET
- response
- song[]
4.11 Remove Likes
- path: /likes/remove
- method: POST
- parameters
- id: number
- response
- true