Update README, fix Cargo.toml for client, add bin/, add setup.sh

This commit is contained in:
Mark 2024-01-10 16:25:00 +01:00
parent 6f9535a28e
commit 404e9ce8ed
8 changed files with 131 additions and 77 deletions

130
README.md
View File

@ -1,104 +1,90 @@
# musicdb # musicdb
custom music player which can be controlled from other WiFi devices (phone/pc) A feature-rich music player consisting of a server and a client.
should perform pretty well (it runs well on my Pine A64 with 10k+ songs) ## Library
https://github.com/Dummi26/musicdb/assets/67615357/8ba85f00-27a5-4e41-8688-4816b8aaaff4 - search for artists, albums, songs
- apply filters to your search
- select multiple songs, albums, artists
- drag songs, albums, artists or your selection to add them to the queue
## why??? ## Queue
#### server/client - recursive structure, organized by how songs were added
+ adding an album puts the songs in a folder
+ if you add an album, you can drag the entire folder rather than individual songs
+ adding an artist adds a folder containing a folder for each album
- shuffle
+ works like a folder, but plays its contents in a random order
+ reshuffles as you add new songs
+ only shuffles elements that you didn't listen to yet, so you won't hear a song twice
+ can shuffle any element, so you could, for example, listen to random albums, but the songs in each album stay in the correct order
- repeat
+ can repeat its contents forever or n times
allows you to play music on any device you want while controlling playback from anywhere. ## Server
you can either run the client and server on the same machine or have them be in the same network
so that they can connect using TCP.
if one client makes a change, all other clients will be notified of it and update almost instantly. The server caches the next song before it is played,
so you get gapless playback even when loading songs from a very slow disk or network-attached storage (NAS).
it is also possible for a fake "client" to mirror the main server's playback, so you could sync up your entire house if you wanted to. It can be accessed using the client (TCP), or a website it can optionally host.
It should also be very easy to switch from TCP to any other protocol, since most of the code in this project just requires the `Read + Write` traits, not specifically a TCP connection.
#### complicated queue ## Clients
- allows more customization of playback (loops, custom shuffles, etc.) Multiple clients can connect to a server at the same time.
- is more organized (adding an album doesn't add 10-20 songs, it creates a folder so you can (re)move the entire album in/from the queue) All connected clients will be synchronized, so if you do something on one device, all other connected devices will show that change.
#### caching of songs The client can show a user interface (`gui`) or even connect to the server and mirror its playback (`syncplayer-*`).
for (almost) gapless playback, even when the data is stored on a NAS or cloud Using the `syncplayer` functionality, you can play the same music on multiple devices, in multiple different locations.
#### custom database file # Setup
when storing data on a cloud, it would take forever to load all songs and scan them for metadata. Review, then run the `setup.sh` script:
you would also run into issues with different file formats and where to store the cover images.
a custom database speeds up server startup and allows for more features.
## usage
### build
build `musicdb-server` and `musicdb-client` (and `musicdb-filldb`) using cargo.
Note: the client has a config file in ~/.config/musicdb-client/, which includes the path to a font. You need to set this manually or the client won't start.
The file and directory will be created when you first run the client in gui mode.
## setup
### prep
You need some directory where your music is located (mp3 files).
I will assume this is `/music` for simplicity.
You will also need a file that will hold your database.
I will assume this is `dbfile`.
Note: Instead of adding the executables (`musicdb-client` and `musicdb-server`) to your `$PATH`, you can run `cargo run --release -- ` followed by the arguments.
Since this is using cargo, you need to be in the source directory for whatever you want to run.
### database
`musicdb-filldb` will read all files in the /music directory and all of its subdirectories, read their metadata and try to figure out as much about these songs as possible. It will then generate a `dbfile` which `musicdb-server` can read.
You can make changes to the database later, but this should be the easiest way to get started:
```sh ```sh
musicdb-filldb /music ./setup.sh ~/my_dbdir ~/music
``` ```
### starting the server Where `~/music` is the directory containing your music (mp3 files).
Copy the `musicdb-server/assets` directory to `./assets`, then run: Confirm that all paths are correct, then press Enter when prompted.
You will probably have to add a valid font path to the client's gui config, for example
```toml
font = '/usr/share/fonts/...'
...
```
The script will start a server and client.
After closing the client, the server may still be running, so you may have to `pkill musicdb-server` if you want to stop it.
To open the player again:
```sh ```sh
musicdb-server dbfile /music --tcp 127.0.0.1:26314 --web 127.0.0.1:8080 musicdb-client 0.0.0.0:26002 gui
``` ```
Note: If you don't care about the HTML site, you can leave out the `--web 127.0.0.1:8080`. To start the server:
You also won't need the `assets` then.
And that's it - the rest should just work.
You can now open 127.0.0.1:8080 in a browser or use `musicdb-client`:
```sh ```sh
musicdb-client 127.0.0.1:26314 gui musicdb-server ~/my_dbdir ~/music --tcp 0.0.0.0:26002
``` ```
### syncplayer A simple script can start the server and then the client:
`musicdb-client` has a syncplayer mode, where it will play back songs in sync with the server.
It's usually easier to use syncplayer-network, which will get the song files from the server,
but syncplayer-local may be more stable and responsive, because it assumes you have a local copy of the server's music files (`/music`) somewhere, for example at `~/music`:
```sh ```sh
musicdb-client 127.0.0.1:26314 syncplayer-network # if the server is already running, this command will fail since 0.0.0.0:26002 is already in use,
# and you will never end up with 2+ servers running at the same time
musicdb-server ~/my_dbdir ~/music --tcp 0.0.0.0:26002 &
# wait for the server to load (on most systems, this should never take more than 0.1 seconds, but just in case...)
sleep 1
# now start the client
musicdb-client 0.0.0.0:26002 gui
``` ```
```sh You could use this script from a `.desktop` file to get a menu entry which simply opens the player.
musicdb-client 127.0.0.1:26314 syncplayer-local ~/music
```
# TODOs
If the server can't play a song, it seems to get stuck.
It should instead send a notification to all clients about the error and skip to the next song.
The clients should then display this notification to the user.
TODO: Figure out what to do when no user acknowledges the notification. Send it again later or just pretend nothing happened?

BIN
bin/musicdb-client Executable file

Binary file not shown.

BIN
bin/musicdb-filldb Executable file

Binary file not shown.

BIN
bin/musicdb-server Executable file

Binary file not shown.

View File

@ -12,9 +12,9 @@ musicdb-lib = { version = "0.1.0", path = "../musicdb-lib" }
regex = "1.9.3" regex = "1.9.3"
speedy2d = { version = "1.12.0", optional = true } speedy2d = { version = "1.12.0", optional = true }
toml = "0.7.6" toml = "0.7.6"
mers_lib = { path = "../../mers/mers_lib", optional = true } # mers_lib = { path = "../../mers/mers_lib", optional = true }
[features] [features]
default = ["speedy2d"] default = ["speedy2d"]
merscfg = ["mers_lib"]
playback = ["musicdb-lib/playback"] playback = ["musicdb-lib/playback"]
# merscfg = ["mers_lib"]

View File

@ -1,5 +1,5 @@
use std::{ use std::{
collections::{HashMap, HashSet}, collections::HashMap,
fs, fs,
io::Write, io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -89,7 +89,7 @@ fn main() {
} }
} }
eprintln!("\nloaded metadata of {} files.", songs.len()); eprintln!("\nloaded metadata of {} files.", songs.len());
let mut database = Database::new_empty(PathBuf::from("dbfile"), PathBuf::from(&lib_dir)); let mut database = Database::new_empty_in_dir(PathBuf::from("."), PathBuf::from(&lib_dir));
let unknown_artist = database.add_artist_new(Artist { let unknown_artist = database.add_artist_new(Artist {
id: 0, id: 0,
name: format!("<unknown>"), name: format!("<unknown>"),

View File

@ -1,6 +1,5 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::format,
fs::{self, File}, fs::{self, File},
io::{BufReader, Read, Write}, io::{BufReader, Read, Write},
path::PathBuf, path::PathBuf,

69
setup.sh Executable file
View File

@ -0,0 +1,69 @@
#!/usr/bin/sh
DBDIR=$1
MUSICDIR=$2
if [ ! -z "$VISUAL" ]; then
EDITOR="$VISUAL"
fi
echo "usage: ./setup.sh dbdir music-dir"
if [ ! -z "$DBDIR" ]; then
echo "dbdir: $DBDIR"
if [ ! -z "$MUSICDIR" ]; then
echo "music-dir: $MUSICDIR"
# set commands for filldb/server/client
if [ ! -f "$CMD_FILLDB" ]; then
CMD_FILLDB="musicdb-filldb/target/release/musicdb-filldb"
if [ ! -f "$CMD_FILLDB" ]; then
CMD_FILLDB="bin/musicdb-filldb"
if [ ! -f "$CMD_FILLDB" ]; then
echo "No command for filldb found, set CMD_FILLDB env var to the executable file or run \`cargo build --release\` in \`./musicdb-filldb\`."
return
fi
fi
fi
if [ ! -f "$CMD_SERVER" ]; then
CMD_SERVER="musicdb-server/target/release/musicdb-server"
if [ ! -f "$CMD_SERVER" ]; then
CMD_SERVER="bin/musicdb-server"
if [ ! -f "$CMD_SERVER" ]; then
echo "No command for server found, set CMD_SERVER env var to the executable file or run \`cargo build --release\` in \`./musicdb-server\`."
return
fi
fi
fi
if [ ! -f "$CMD_CLIENT" ]; then
CMD_CLIENT="musicdb-client/target/release/musicdb-client"
if [ ! -f "$CMD_CLIENT" ]; then
CMD_CLIENT="bin/musicdb-client"
if [ ! -f "$CMD_CLIENT" ]; then
echo "No command for client found, set CMD_CLIENT env var to the executable file or run \`cargo build --release\` in \`./musicdb-client\`."
return
fi
fi
fi
echo "CMD_FILLDB: $CMD_FILLDB (set CMD_FILLDB env var to override)"
echo "CMD_SERVER: $CMD_SERVER (set CMD_SERVER env var to override)"
echo "CMD_CLIENT: $CMD_CLIENT (set CMD_CLIENT env var to override)"
echo "EDITOR: $EDITOR (set EDITOR or VISUAL env var to override)"
# create DBDIR
mkdir "$DBDIR"
# create DBDIR/dbfile
echo
"$CMD_FILLDB" "$MUSICDIR" || return
mv "dbfile" "$DBDIR" || return
# start server
"$CMD_SERVER" "$DBDIR" "$MUSICDIR" --tcp 0.0.0.0:26002 &
sleep 1
# start client
# if starting fails once, prompt user to provide a font, then try again
"$CMD_CLIENT" 0.0.0.0:26002 gui || ("$EDITOR" "~/.config/musicdb-client/config_gui.toml"; "$CMD_CLIENT" 0.0.0.0:26002 gui) || return
fi
fi