···11-# `tunz`: if `rsync` was ID3-aware
11+# Tunz
22+33+Tunz is a command-line tool designed to synchronize a music library to various destinations, including local folders and iPods. It manages a local database of your music, allowing for organized syncing, transcoding, and filtering.
44+55+## Features
66+77+- **Library Management**: Scans and indexes music files from specified source directories into a local SQLite database.
88+- **Synchronization**: Syncs your indexed music library to a destination folder or device.
99+- **iPod Support**: Supports syncing directly to iPods (requires `libgpod`), including database updates and automatic transcoding.
1010+- **Transcoding**: Automatically converts lossless files to lossy formats (AAC, MP3, OGG, Opus) during sync to save space or ensure compatibility. Uses FFMpeg for conversion.
1111+- **Filtering**: Allows writing custom scripts (using Rhai) to filter which tracks are synced based on metadata.
1212+- **Duplicate Detection**: Identifies albums that are stored in more than one audio format.
1313+- **Smart Updates**: Tracks changes in your source directories and updates the library accordingly.
1414+1515+## Installation
1616+1717+Tunz is written in Rust and requires a few system dependencies to build and run.
1818+1919+### Prerequisites
2020+2121+Ensure you have the following installed on your system:
2222+2323+- **Rust**: The Rust toolchain (cargo, rustc).
2424+- **FFmpeg**: Required at runtime for audio transcoding.
2525+- **libgpod**: Required for iPod support (`libgpod-dev` or equivalent package).
2626+- **Clang**: Required for generating bindings to libgpod.
2727+- **pkg-config**: Required for the build process to locate libraries.
22833-`tunz` synchronizes music files from a source to a destination, keeping a database for both.
2929+### Building from Source
43055-Tracks need to be added to the source database first, and then can be synced on the destination.
3131+Clone the repository and build the project using Cargo:
63277-There is no maximum amount of destinations you can have, each one will maintain its database and can be kept in sync
88-with the source.
3333+```sh
3434+cargo build --release
3535+```
9361010-The destination tree structure is ordered by artist, album, disc number, and track name, as detailed by each ID3 tag.
3737+The compiled binary will be located in `target/release/tunz`. You can move this to a directory in your `PATH` for easier access.
11381212-Pass `-h` to each subcommand to understand how to use it!
3939+## Usage
13401414-`tunz` can also create hardlinks instead of copies of your files: pass the `--link` flag to `sync` to do so.
4141+### 1. Adding Music to the Library
15421616-## Installing
4343+First, you need to populate the Tunz database with your music files.
17441845```sh
1919-cargo install tunz
4646+tunz add --source /path/to/your/music
2047```
21482222-### From sources
4949+You can specify multiple sources by repeating the `--source` flag.
23502424-You need a [Rust](https://rustup.rs/) compiler.
5151+To update the database later (e.g., if you added new files to the source directory):
25522626-Once you have that setup:
5353+```sh
5454+tunz update
5555+```
5656+5757+### 2. Synchronizing Music
5858+5959+To sync your library to a destination folder:
27602861```sh
2929-git clone https://github.com/gsora/tunz
3030-cd tunz
3131-cargo build --release
3232-./target/release/tunz -h
6262+tunz sync --destination /path/to/destination
3363```
34643535-## Filtering
6565+**Options:**
6666+- `--dry-run`: Preview what files will be copied or deleted without making changes.
6767+- `--no-delete`: Prevent Tunz from deleting files in the destination that are not in the source library.
6868+- `--threads`: Specify the number of threads to use for copying and transcoding (defaults to the number of available CPUs).
36693737-You might want to exclude some tracks from the syncing process, based on various assumption.
7070+### 3. Syncing to an iPod
38713939-Since this tool has been built primarily for my own consumption, I added a programmable way of defining filters.
7272+To sync to a mounted iPod:
40734141-Each destination can contain a filter written in the [Rhai](https://rhai.rs/): you have the full
4242-power of a regex matching function -- `regex_match` -- and a Turing-complete programming language, have fun!
7474+```sh
7575+tunz sync --destination /mnt/ipod --ipod
7676+```
7777+7878+This will automatically transcode files to a format compatible with the iPod (AAC VBR quality 5).
7979+8080+If this is a new iPod, you may need to initialize it first (requires root privileges to read metadata from the iPod ROM partition):
8181+8282+```sh
8383+sudo tunz settings initialize-ipod --path /mnt/ipod --model <MODEL_NUMBER>
8484+```
43854444-Filters can be created in-place or read from a file.
8686+### 4. Transcoding Settings
45874646-Each filter must define the `filter(track)` function in order to be evaluated:
8888+You can configure Tunz to transcode files when syncing to a standard folder (non-iPod).
47894848-```rhai
4949-fn filter(track) {
5050- // your logic goes here
5151- true
5252-}
9090+```sh
9191+tunz settings transcode --destination /path/to/destination --enabled true --codec mp3 --bitrate cbr:320k
5392```
54935555-As you can see, `filter` returns a boolean value:
5656- - `true`: copy this track
5757- - `false`: the opposite
9494+Supported codecs: `aac`, `mp3`, `ogg`, `opus`.
58955959-The `track` argument is an object that contains the following fields:
9696+**Supported bitrates:**
9797+- **Constant Bitrate (CBR):** Use format `cbr:<bitrate>k` (e.g., `cbr:320k`, `cbr:128k`).
9898+- **Variable Bitrate (VBR):** Use format `vbr:<quality>` (e.g., `vbr:5`, `vbr:2`). This corresponds to the FFmpeg `-q:a` quality level (range depends on the codec, e.g., 1-5 for AAC, 0-9 for MP3).
60996161-```rust
6262-pub struct BaseTrack {
6363- pub title: String,
6464- pub artist: String,
6565- pub album: String,
6666- pub number: i64,
6767- pub file_path: String,
6868- pub disc_number: i64,
6969- pub disc_total: i64,
7070- pub extension: String,
7171-}
100100+### 5. Filtering
101101+102102+You can filter which tracks get synced using [Rhai](https://github.com/rhaiscript/rhai) scripts. This allows for powerful, programmable rules to exclude specific content.
103103+104104+To edit the filter script for a destination:
105105+106106+```sh
107107+tunz settings filter --destination /path/to/destination
72108```
731097474-As you can see, there's lots of stuff you can do with this functionality.
110110+This will open your default editor. You must define a function named `filter` that takes a `track` object and returns `true` (to keep the track) or `false` (to exclude it).
111111+112112+**Available `track` fields:**
113113+- `title` (String)
114114+- `artist` (String)
115115+- `album` (String)
116116+- `number` (Integer)
117117+- `disc_number` (Integer)
118118+- `disc_total` (Integer)
119119+- `file_path` (String)
120120+- `extension` (String)
751217676-For example, here's a filter I built to avoid copying instrumental tracks from special edition albums:
122122+**Helper Functions:**
123123+- `regex_match(pattern, string)`: Returns `true` if the string matches the regex pattern.
124124+125125+**Examples:**
126126+127127+*Exclude specific artists and instrumental tracks:*
7712878129```rhai
79130fn filter(track) {
···98149}
99150```
100151101101-## A note on stability
152152+*Keep only FLAC files:*
102153103103-This is the first CLI tool I wrote in Rust, as a way of making myself familiar with the language: expect bugs.
154154+```rhai
155155+fn filter(track) {
156156+ return track.extension == "flac";
157157+}
158158+```
104159105105-The database schema might break suddenly, making your source and destination(s) libraries unusable: a `rescan` command
106106-is in the works -- I will make sure to keep those at a minimum.
160160+*Use Regex to exclude "Live" albums:*
107161108108-## conversion
162162+```rhai
163163+fn filter(track) {
164164+ if regex_match("(?i).*live.*", track.album) {
165165+ return false;
166166+ }
167167+ return true;
168168+}
169169+```
109170110110-Debian deps:
111111-- libavutil-dev
112112-- libavformat-dev
113113-- libavfilter-dev
114114-- libavdevice-dev
171171+### 6. Managing Duplicates
172172+173173+To find albums present in multiple formats within your library:
174174+175175+```sh
176176+tunz dupes
177177+```
178178+179179+### 7. Cleaning the Library
180180+181181+If a sync operation is interrupted, some files might be left in an inconsistent state (e.g., partially copied files). You can clean these up using:
182182+183183+```sh
184184+tunz clean --destination /path/to/destination
185185+```
186186+187187+This will search for and remove any tracks in the destination database that are marked as "copying" but never finished.