Maintain a lower-bitrate copy of a music library in sync with the main copy.

msync

Maintain a lower-bitrate copy of your music library, in sync with the main copy. Think of it as rsync, but only for music files, and with the ability to transcode high-bitrate or lossless files to lower-bitrate files suitable for use on devices with less storage.

It's also more opinionated than rsync, with behaviors tailored for exactly this use case. For example, msync will always remove files from the destination which are missing from the source; whereas rsync won't do this unless you pass it the --delete flag.

Use Cases

I use msync to keep a secondary, 160 Kbps AAC copy of my music library. This is synchronized occasionally to my iPhone, which lacks the space for a music library consisting of lossless and higher-bitrate files.

I accomplish this by adding a launchd job for msync, which runs nightly on the Mac Mini server whic hosts the music library.

Installation

Requirements: at the moment, msync supports only macOS. This is because it uses macOS's built-in afinfo tool to determine music files' bitrates.

make install will build msync for your current OS/architecture and install it to /usr/local/bin.

Usage

Basic usage is msync -from ~/Music -to ~/MusicSmaller -max-kbps 192, but you should review the available options as you'll likely want to use some of them.

Options

  • -ask-trash-permission: Trigger the macOS permission dialog for removing files immediately when the sync process begins (instead of later in the process, when we actually start removing files).
  • -dry-run: Don't actually modify anything on the filesystem, but print what would happen, including an estimate of the final size of the destination music library.
  • -file-mode: Octal value specifying mode for copied music files. Must begin with '0' or '0o'.
  • -from: Path of the source music library.
  • -max-kbps: Maximum bitrate, in Kbps, for the destination music library. Any music files of higher quality will be transcoded from the source library to the destination at this bitrate.
  • -remove-nonmusic-from-dest: Remove any non-music files from the destination, even if they are present in the source directory tree.
  • -symlink: For music files which are already under the maximum bitrate, create symlinks instead of actual copies. This is useful if you're mirroring your music library somewhere on the same machine, rather than directly to a portable device.
  • -to: Path of the destination music library.
  • -verbose: Log detailed output to stderr. Suppresses fancy progress indicators.
  • -version: Print version and exit.

Complete Usage Example

The complete invocation I use to maintain a 160Kbps mirror of my music library is:

msync -from "/Users/cdzombak/Music/iTunes/iTunes Media/Music" -to /Users/cdzombak/Music/160Kbps -max-kbps 160 -symlink -remove-nonmusic-from-dest -ask-trash-permission

Launch Agent

The file com.dzombak.music-160-mirror.plist in this repository is the Launch Agent I use. It runs the msync invocation listed above nightly at 2 AM.

About

Owner
Comments
  • spinner results in a bunch of W chars

    spinner results in a bunch of W chars

    I don't know if this is because I appended an extremely long multiline text to the spinner, or because log output interrupted the spinner. Either way, fix it.

  • refactor

    refactor

    refactor, particularly main, to:

    • separate spinner & CLI concerns from program logic
    • make program logic less indenty
    • fix the myriad if verbose/dry run checks
    • log everything to stderr via log if verbose is selected
    • allow parallelizing transcoding and afinfo calls
  • show cursor even when aborted with ctrl-c

    show cursor even when aborted with ctrl-c

    capture SIGINT/SIGTERM (maybe SIGQUIT also) and make sure the spinner lib re-shows the cursor. this will be easier with a restructuring of main to separate core logic, program control flow, and spinner/status stuff.

  • parallelize afinfo calls & ffmpeg calls

    parallelize afinfo calls & ffmpeg calls

    The bulk of the time in scanning is spent in calling afinfo, and the bulk of the actual sync time is of course transcoding. Both of these could be parallelized easily, but it will require some restructuring: I'll need to separate the tree building/sync planning stages from the actual work, and the whole main function really needs some restructuring anyway.

  • Pick up on changed tags when determining what files to update

    Pick up on changed tags when determining what files to update

    For music under the limit, files are symlinked (if you use that option, anyway), which isn't a problem.

    But if files are copied or transcoded, and then the main copy's tags change (but not the name on disk), the copy/transcoded file is not updated.

  • allow customizing encoding approach

    allow customizing encoding approach

    rather than hardcoding ffmpeg, allow specifying eg. an encoding script that can call ffmpeg with whatever parameters you want. this also requires customizing the output file extension, since the program needs to know that to do sync-y things.

go-to64 analyzes Golang main package to convert int/uint to int64/uint64.

go-to64 About go-to64 analyzes Golang main package to convert int/uint to int64/uint64. This is an experiment tool, so be very careful. In a 32-bit en

Oct 31, 2021
A better Generic Pool (sync.Pool)
A better Generic Pool (sync.Pool)

This package is a thin wrapper over the Pool provided by the sync package. The Pool is an essential package to obtain maximum performance by reducing the number of memory allocations.

Dec 1, 2022
Copier for golang, copy value from struct to struct and more

Copier I am a copier, I copy everything from one to another Features Copy from field to field with same name Copy from method to field with same name

Jan 8, 2023
read copy update map for golang 1.18+

(R)ead-(C)opy-Update read copy update map for golang 1.18+ How it works This is a simple generic implementation for https://en.wikipedia.org/wiki/Read

Dec 11, 2022
Govalid is a data validation library that can validate most data types supported by golang

Govalid is a data validation library that can validate most data types supported by golang. Custom validators can be used where the supplied ones are not enough.

Apr 22, 2022
Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs.

go-attr Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs. This package provides user frien

Dec 16, 2022
Go library for HTTP content type negotiation

Content-Type support library for Go This library can be used to parse the value Content-Type header (if one is present) and select an acceptable media

Jul 10, 2022
A tool and library for using structural regular expressions.

Structural Regular Expressions sregx is a package and tool for using structural regular expressions as described by Rob Pike (link).

Dec 7, 2022
A super simple Lodash like utility library with essential functions that empowers the development in Go
A super simple Lodash like utility library with essential functions that empowers the development in Go

A simple Utility library for Go Go does not provide many essential built in functions when it comes to the data structure such as slice and map. This

Jan 4, 2023
go-sysinfo is a library for collecting system information.

go-sysinfo go-sysinfo is a library for collecting system information. This includes information about the host machine and processes running on the ho

Dec 26, 2022
Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner

Molecule Molecule is a Go library for parsing protobufs in an efficient and zero-allocation manner. The API is loosely based on this excellent Go JSON

Jan 5, 2023
A Go (golang) library for parsing and verifying versions and version constraints.

go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version can sort a collection of versions properly, handles prerelease/beta versions, can increment versions, etc.

Jan 9, 2023
A library for parsing ANSI encoded strings
 A library for parsing ANSI encoded strings

Go ANSI Parser converts strings with ANSI escape codes into a slice of structs that represent styled text

Sep 20, 2022
go generate based graphql server library
go generate based graphql server library

gqlgen What is gqlgen? gqlgen is a Go library for building GraphQL servers without any fuss. gqlgen is based on a Schema first approach — You get to D

Dec 29, 2022
This is Go library for building GraphQL client with gqlgen

gqlgenc What is gqlgenc ? This is Go library for building GraphQL client with gqlgen Motivation Now, if you build GraphQL api client for Go, have choi

Jan 7, 2023
A library for diffing golang structures

Diff A library for diffing golang structures and values. Utilizing field tags and reflection, it is able to compare two structures of the same type an

Dec 29, 2022
Go library for decoding generic map values into native Go structures and vice versa.

mapstructure mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling. This l

Dec 28, 2022
🍀 Go basic library. || Go语言基础库
🍀 Go basic library. || Go语言基础库

Go语言基础库 工程目录说明 pkg/ ...... 源码包 |-- bininfo/ ...... 将编译时源码的git版本信息(当前commit log的sha值和commit message),编译时间,Go版本,平台打入程序中

Dec 28, 2022
A well tested and comprehensive Golang statistics library package with no dependencies.

Stats - Golang Statistics Package A well tested and comprehensive Golang statistics library / package / module with no dependencies. If you have any s

Dec 30, 2022