A tool to sync music with your favorite devices
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

*: new readme

Gee Sawra c8cd4ed3 2520781c

+129 -56
+129 -56
README.md
··· 1 - # `tunz`: if `rsync` was ID3-aware 1 + # Tunz 2 + 3 + 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. 4 + 5 + ## Features 6 + 7 + - **Library Management**: Scans and indexes music files from specified source directories into a local SQLite database. 8 + - **Synchronization**: Syncs your indexed music library to a destination folder or device. 9 + - **iPod Support**: Supports syncing directly to iPods (requires `libgpod`), including database updates and automatic transcoding. 10 + - **Transcoding**: Automatically converts lossless files to lossy formats (AAC, MP3, OGG, Opus) during sync to save space or ensure compatibility. Uses FFMpeg for conversion. 11 + - **Filtering**: Allows writing custom scripts (using Rhai) to filter which tracks are synced based on metadata. 12 + - **Duplicate Detection**: Identifies albums that are stored in more than one audio format. 13 + - **Smart Updates**: Tracks changes in your source directories and updates the library accordingly. 14 + 15 + ## Installation 16 + 17 + Tunz is written in Rust and requires a few system dependencies to build and run. 18 + 19 + ### Prerequisites 20 + 21 + Ensure you have the following installed on your system: 22 + 23 + - **Rust**: The Rust toolchain (cargo, rustc). 24 + - **FFmpeg**: Required at runtime for audio transcoding. 25 + - **libgpod**: Required for iPod support (`libgpod-dev` or equivalent package). 26 + - **Clang**: Required for generating bindings to libgpod. 27 + - **pkg-config**: Required for the build process to locate libraries. 2 28 3 - `tunz` synchronizes music files from a source to a destination, keeping a database for both. 29 + ### Building from Source 4 30 5 - Tracks need to be added to the source database first, and then can be synced on the destination. 31 + Clone the repository and build the project using Cargo: 6 32 7 - There is no maximum amount of destinations you can have, each one will maintain its database and can be kept in sync 8 - with the source. 33 + ```sh 34 + cargo build --release 35 + ``` 9 36 10 - The destination tree structure is ordered by artist, album, disc number, and track name, as detailed by each ID3 tag. 37 + The compiled binary will be located in `target/release/tunz`. You can move this to a directory in your `PATH` for easier access. 11 38 12 - Pass `-h` to each subcommand to understand how to use it! 39 + ## Usage 13 40 14 - `tunz` can also create hardlinks instead of copies of your files: pass the `--link` flag to `sync` to do so. 41 + ### 1. Adding Music to the Library 15 42 16 - ## Installing 43 + First, you need to populate the Tunz database with your music files. 17 44 18 45 ```sh 19 - cargo install tunz 46 + tunz add --source /path/to/your/music 20 47 ``` 21 48 22 - ### From sources 49 + You can specify multiple sources by repeating the `--source` flag. 23 50 24 - You need a [Rust](https://rustup.rs/) compiler. 51 + To update the database later (e.g., if you added new files to the source directory): 25 52 26 - Once you have that setup: 53 + ```sh 54 + tunz update 55 + ``` 56 + 57 + ### 2. Synchronizing Music 58 + 59 + To sync your library to a destination folder: 27 60 28 61 ```sh 29 - git clone https://github.com/gsora/tunz 30 - cd tunz 31 - cargo build --release 32 - ./target/release/tunz -h 62 + tunz sync --destination /path/to/destination 33 63 ``` 34 64 35 - ## Filtering 65 + **Options:** 66 + - `--dry-run`: Preview what files will be copied or deleted without making changes. 67 + - `--no-delete`: Prevent Tunz from deleting files in the destination that are not in the source library. 68 + - `--threads`: Specify the number of threads to use for copying and transcoding (defaults to the number of available CPUs). 36 69 37 - You might want to exclude some tracks from the syncing process, based on various assumption. 70 + ### 3. Syncing to an iPod 38 71 39 - Since this tool has been built primarily for my own consumption, I added a programmable way of defining filters. 72 + To sync to a mounted iPod: 40 73 41 - Each destination can contain a filter written in the [Rhai](https://rhai.rs/): you have the full 42 - power of a regex matching function -- `regex_match` -- and a Turing-complete programming language, have fun! 74 + ```sh 75 + tunz sync --destination /mnt/ipod --ipod 76 + ``` 77 + 78 + This will automatically transcode files to a format compatible with the iPod (AAC VBR quality 5). 79 + 80 + If this is a new iPod, you may need to initialize it first (requires root privileges to read metadata from the iPod ROM partition): 81 + 82 + ```sh 83 + sudo tunz settings initialize-ipod --path /mnt/ipod --model <MODEL_NUMBER> 84 + ``` 43 85 44 - Filters can be created in-place or read from a file. 86 + ### 4. Transcoding Settings 45 87 46 - Each filter must define the `filter(track)` function in order to be evaluated: 88 + You can configure Tunz to transcode files when syncing to a standard folder (non-iPod). 47 89 48 - ```rhai 49 - fn filter(track) { 50 - // your logic goes here 51 - true 52 - } 90 + ```sh 91 + tunz settings transcode --destination /path/to/destination --enabled true --codec mp3 --bitrate cbr:320k 53 92 ``` 54 93 55 - As you can see, `filter` returns a boolean value: 56 - - `true`: copy this track 57 - - `false`: the opposite 94 + Supported codecs: `aac`, `mp3`, `ogg`, `opus`. 58 95 59 - The `track` argument is an object that contains the following fields: 96 + **Supported bitrates:** 97 + - **Constant Bitrate (CBR):** Use format `cbr:<bitrate>k` (e.g., `cbr:320k`, `cbr:128k`). 98 + - **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). 60 99 61 - ```rust 62 - pub struct BaseTrack { 63 - pub title: String, 64 - pub artist: String, 65 - pub album: String, 66 - pub number: i64, 67 - pub file_path: String, 68 - pub disc_number: i64, 69 - pub disc_total: i64, 70 - pub extension: String, 71 - } 100 + ### 5. Filtering 101 + 102 + 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. 103 + 104 + To edit the filter script for a destination: 105 + 106 + ```sh 107 + tunz settings filter --destination /path/to/destination 72 108 ``` 73 109 74 - As you can see, there's lots of stuff you can do with this functionality. 110 + 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). 111 + 112 + **Available `track` fields:** 113 + - `title` (String) 114 + - `artist` (String) 115 + - `album` (String) 116 + - `number` (Integer) 117 + - `disc_number` (Integer) 118 + - `disc_total` (Integer) 119 + - `file_path` (String) 120 + - `extension` (String) 75 121 76 - For example, here's a filter I built to avoid copying instrumental tracks from special edition albums: 122 + **Helper Functions:** 123 + - `regex_match(pattern, string)`: Returns `true` if the string matches the regex pattern. 124 + 125 + **Examples:** 126 + 127 + *Exclude specific artists and instrumental tracks:* 77 128 78 129 ```rhai 79 130 fn filter(track) { ··· 98 149 } 99 150 ``` 100 151 101 - ## A note on stability 152 + *Keep only FLAC files:* 102 153 103 - This is the first CLI tool I wrote in Rust, as a way of making myself familiar with the language: expect bugs. 154 + ```rhai 155 + fn filter(track) { 156 + return track.extension == "flac"; 157 + } 158 + ``` 104 159 105 - The database schema might break suddenly, making your source and destination(s) libraries unusable: a `rescan` command 106 - is in the works -- I will make sure to keep those at a minimum. 160 + *Use Regex to exclude "Live" albums:* 107 161 108 - ## conversion 162 + ```rhai 163 + fn filter(track) { 164 + if regex_match("(?i).*live.*", track.album) { 165 + return false; 166 + } 167 + return true; 168 + } 169 + ``` 109 170 110 - Debian deps: 111 - - libavutil-dev 112 - - libavformat-dev 113 - - libavfilter-dev 114 - - libavdevice-dev 171 + ### 6. Managing Duplicates 172 + 173 + To find albums present in multiple formats within your library: 174 + 175 + ```sh 176 + tunz dupes 177 + ``` 178 + 179 + ### 7. Cleaning the Library 180 + 181 + 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: 182 + 183 + ```sh 184 + tunz clean --destination /path/to/destination 185 + ``` 186 + 187 + This will search for and remove any tracks in the destination database that are marked as "copying" but never finished.