Note
This article was automatically translated using Google
Because the last two months have been boring, I have been tossing my old NAS at home, [set up a music server](https://www.igerm.ee/experience/%E7%AE%A1%E7%90%86 %E7%BC%96%E8%BE%91%E5%88%86%E8%BD%A8%E6%AC%A3%E8%B5%8F%E6%9C%AC%E5%9C%B0%E9 %9F%B3%E4%B9%90%E4%B8%80%E6%9D%A1%E9%BE%99/), but I can’t find a particularly satisfactory player. There is also [Sonixd] on the desktop (https://github.com/jeffvli/sonixd) has a good appearance and no fancy functions, but I am not satisfied with the mobile phone. Only substreamer can be used. But not very pretty.
The most important thing is that these two players do not support lyrics, and they cannot search in fuzzy or simplified or traditional characters. For example, I want to listen to Jay Chou’s “Back Back”, but the name I searched is Back Back, so when I search, I need to switch to traditional Chinese to find it out, which is quite annoying.
My first reaction was to go to Github to find out if there are any ready-made multi-terminal wheels, but the ones I like are all played locally, or there is a music player imitating NetEase Cloud through the API of NetEase Cloud, which may be blocked at any time. Not to mention breaking it, and it doesn’t even support Navidrome or Subsonic’s API. I really can’t find it, so I gritted my teeth and stomped my feet to make one myself!
Subsonic API
Navidrome itself has a native API, but not many, and the author is planning to rewrite, but fortunately he has almost all support for Subsonic’s API, so even if Navidrome itself has no API documentation, look at [Subsonic’s documentation](http: //www.subsonic.org/pages/api.jsp) can also be put on Postman to try
Authentication Server
It’s a bit confusing at first glance, but it’s actually very simple. There are two types of verification: either pass in password, or pass in encrypted (password + six-digit salt value) plus six-digit salt value
First Ping
the server for testing (using dio: ^4.0.6 can save a lot of operations)
1 | try { |
After completing the two-step verification server and Subsonic’s api, you can save the server information. The subsequent apis are obtained using salt values. In fact, it doesn’t matter, they are all free.
Encrypted Login
Use
Rondom
to write a randomly generated 6-bit character1
2
3
4
5
6
7
8
9
10String generateRandomString() {
final_random = Random();
const _availableChars =
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
final randomString = List. generate(6,
(index) => _availableChars[_random.nextInt(_availableChars.length)])
.join();
return randomString;
}Then encrypt with MD5 after splicing
Save these two characters for later API use
Get directory
The directories in Subsonic are hierarchical from top to bottom like this
- music folder
- Artist folder
- Album
- songs
However, Navidrome seems to have only one music folder, so I directly use the second-level getIndexes
to make my directory master list, and then go down to the album list according to the musician ID
play music
Use ValueNotifier
for variable monitoring, do not use provider: ^6.0.5 lightly, although it is really convenient, there will always be various global variables The problem, especially when you rely on him and want to change the code back, the workload simply makes you rewrite it!
In fact, ValueNotifier
is also very convenient to use. It can be followed by <int>
parameters to specify the type of value, and you can also customize the monitoring data type. I am based on [this article](https://blog. csdn.net/Mr_Tony/article/details/112170758) to operate
Define the data monitor
ValueNotifier<String> activeSongValue = ValueNotifier<String>("1");
In theory, it can be placed in any file, but it is recommended to put it in a unified global variable definition file for easy management. Here I pass in the
id
of the song and filter it with a default value. If it is"1"
, it will be Do not call the interface to get song information (Null safety
is mandatory after flutter2.12, I didn’t adapt to it at first, but now I think it’s good)Change the value of the data
activeSongValue. value = _tem["id"];
You can use it directly, so it seems that it is actually simpler than
provider
Monitor data changes
Use the
ValueListenableBuilder
construct to construct the listening part1
2
3
4
5
6
7
8return ValueListenableBuilder<String>(
valueListenable: activeSongValue, //monitor
builder: ((context, value, child) {
if (value != "1") { // change the value
_setAudioSource(value); //Directly use id to query and other follow-up work
}
return Container()...Get song information
After you have the song
id
, you can usegetSong
to get the music information, usegetCoverArt
to get the album image, and then usestream
to get the streaming filePlay the music stream
Using just_audio: ^0.9.31 can greatly speed up the development progress, it is the second-ranked dependencies, the first is audioplayers, but just these days he updated the version , the address of the official document is lost, this is called fate
It is also extremely simple to use. If you don’t care about the display of controls such as button sliders, it only takes three lines of code from clicking the music to starting playback:
1
2
3
4
5
6
7
8
9
10
11//Define the component
final_player = AudioPlayer();
//The url of splicing stream
String _url = await getSongStreamUrl(_id);
// Get the stream and play it
try {
await _player.setAudioSource(AudioSource.uri(Uri.parse(_url)));
_player.play();
} catch (e) {
print("Error loading audio source: $e");
}
The above is the current progress, including the server test on the desktop, and then the directory enters the song level, and then plays the music.
There is still a lot of work in the future, but I have been paying attention to Flutter since the 1.x version. I once complained that Huawei’s engineers are useless if they don’t use Flutter. Just pay attention to the adaptation of the mobile terminal. After finishing writing, it is estimated that a simple adjustment of the mobile terminal will be enough. Currently, it is only for functions)
Here is the Github address, it’s good to be willing to come down and play, but it’s only for development, it’s far from normal use.