Compare commits

..

No commits in common. "main" and "v0.2.0" have entirely different histories.
main ... v0.2.0

9 changed files with 150 additions and 520 deletions

View file

@ -1,35 +0,0 @@
name: Release Please
permissions:
pull-requests: write
contents: write
on:
push:
branches:
- main
env:
CARGO_TERM_COLOR: always
jobs:
release-plz:
name: Release-plz
runs-on: docker
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run release-plz release-pr
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: release-plz release-pr --backend gitea --git-token ${{ secrets.FORGEJO_TOKEN }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Run release-plz release
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: release-plz release --backend gitea --git-token ${{ secrets.FORGEJO_TOKEN }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

View file

@ -1,52 +0,0 @@
name: Rust
on:
push:
branches: ["next"]
pull_request:
branches: ["main"]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: docker
strategy:
matrix:
toolchain:
- name: stable
- name: nightly
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check TODOs
uses: https://git.kemitix.net/kemitix/forgejo-todo-checker@v1.1.0
- name: Machete
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: ${{ matrix.toolchain.name }} cargo machete
- name: Format
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: ${{ matrix.toolchain.name }} cargo fmt --all -- --check
- name: Clippy
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: ${{ matrix.toolchain.name }} cargo hack --feature-powerset clippy
- name: Build
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: ${{ matrix.toolchain.name }} cargo hack --feature-powerset build
- name: Test
uses: https://git.kemitix.net/kemitix/rust@v2.2.0
with:
args: ${{ matrix.toolchain.name }} cargo hack --feature-powerset test

View file

@ -1,22 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.3.1](https://git.kemitix.net/kemitix/refile-m4b/compare/v0.3.0...v0.3.1) - 2024-10-12
### Added
- group authors by first character
### Other
- add usage instructions to readme
- fix name of project refile-mp4 to refile-m4b
- Back out "chore: reset version to allow forgejo workflow to bump it correctly"
- bump rstest from 0.22 to 0.23
- reset version to allow forgejo workflow to bump it correctly

390
Cargo.lock generated
View file

@ -2,15 +2,6 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.11" version = "0.6.11"
@ -65,6 +56,16 @@ version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "auto-file-mp4"
version = "0.2.0"
dependencies = [
"anyhow",
"clap",
"mp4",
"taglib",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -72,10 +73,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "cfg-if" name = "byteorder"
version = "1.0.0" version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]] [[package]]
name = "clap" name = "clap"
@ -123,125 +130,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-timer"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.4.1"
@ -249,14 +137,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "indexmap" name = "itoa"
version = "2.5.0" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "libc" name = "libc"
@ -265,159 +149,115 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]] [[package]]
name = "memchr" name = "mp4"
version = "2.7.4" version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "c9ef834d5ed55e494a2ae350220314dc4aacd1c43a9498b00e320e0ea352a5c3"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [ dependencies = [
"diff", "byteorder",
"yansi", "bytes",
"num-rational",
"serde",
"serde_json",
"thiserror",
] ]
[[package]] [[package]]
name = "proc-macro-crate" name = "num-bigint"
version = "3.2.0" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [ dependencies = [
"toml_edit", "autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
"serde",
]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.87" version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.37" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "refile-m4b" name = "ryu"
version = "0.3.1" version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "serde"
version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [ dependencies = [
"anyhow", "serde_derive",
"clap",
"pretty_assertions",
"regex",
"rstest",
"taglib",
] ]
[[package]] [[package]]
name = "regex" name = "serde_derive"
version = "1.10.6" version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [ dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "relative-path"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
[[package]]
name = "rstest"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035"
dependencies = [
"futures",
"futures-timer",
"rstest_macros",
"rustc_version",
]
[[package]]
name = "rstest_macros"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a"
dependencies = [
"cfg-if",
"glob",
"proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"regex",
"relative-path",
"rustc_version",
"syn", "syn",
"unicode-ident",
] ]
[[package]] [[package]]
name = "rustc_version" name = "serde_json"
version = "0.4.1" version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [ dependencies = [
"semver", "itoa",
] "ryu",
"serde",
[[package]]
name = "semver"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "slab"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
dependencies = [
"autocfg",
] ]
[[package]] [[package]]
@ -428,9 +268,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.79" version = "2.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -457,27 +297,30 @@ dependencies = [
] ]
[[package]] [[package]]
name = "toml_datetime" name = "thiserror"
version = "0.6.8" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
dependencies = [
"thiserror-impl",
]
[[package]] [[package]]
name = "toml_edit" name = "thiserror-impl"
version = "0.22.22" version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
dependencies = [ dependencies = [
"indexmap", "proc-macro2",
"toml_datetime", "quote",
"winnow", "syn",
] ]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.13" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
@ -550,18 +393,3 @@ name = "windows_x86_64_msvc"
version = "0.52.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c52ac009d615e79296318c1bcce2d422aaca15ad08515e344feeda07df67a587"
dependencies = [
"memchr",
]
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"

View file

@ -1,18 +1,12 @@
[package] [package]
name = "refile-m4b" name = "auto-file-mp4"
version = "0.3.1" version = "0.2.0"
edition = "2021" edition = "2021"
description = "Refile a directory of m4b files by artist, album (where specified) and title. Used to refile m4b versions of converted aax files for use by Smart Audiobook Player."
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.75"
clap = { version = "4.4", features = ["derive", "cargo"] } clap = { version = "4.4", features = ["derive", "cargo"] }
regex = "1.10" mp4 = "0.14.0"
taglib = "1.0.0" taglib = "1.0.0"
anyhow = "1.0.75"
[dev-dependencies]
pretty_assertions = "1.4"
rstest = "0.23"

View file

@ -1,14 +1,3 @@
# Refile M4B
## Usage
```bash
refile-m4b DIR
```
This will refile all the `*.m4b` files in `DIR` and it's subdirectories by author, series (if given) and title.
The information in each files metadata is used.
## dependencies ## dependencies
### debian ### debian
@ -16,5 +5,3 @@ The information in each files metadata is used.
```bash ```bash
sudo apt install libtag1-dev libtagc0-dev sudo apt install libtag1-dev libtagc0-dev
``` ```
> Due to a typo, this was previously known as refile-mp4.

View file

@ -1,5 +1,2 @@
dry-run: default:
cargo run -- --dry-run ~/Nextcloud/Audible-Inbox/
run:
cargo run -- ~/Nextcloud/Audible-Inbox/ cargo run -- ~/Nextcloud/Audible-Inbox/

View file

@ -1,8 +1,3 @@
//
#[cfg(test)]
mod tests;
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use clap::{crate_version, Parser}; use clap::{crate_version, Parser};
use std::{ use std::{
@ -22,40 +17,30 @@ struct Arguments {
/// Path /// Path
path: Option<String>, path: Option<String>,
/// Dry-Run
#[clap(long)]
dry_run: bool,
}
impl Arguments {
fn not_dry_run(&self) -> bool {
!self.dry_run
}
} }
fn main() { fn main() {
let args = Arguments::parse(); let args = Arguments::parse();
if args.version { if args.version {
println!("Version {}", crate_version!()); println!("Version {}", crate_version!());
} else if let Some(path) = &args.directory { } else if let Some(path) = args.directory {
rename_files_in_directory(path.to_string(), &args); rename_files_in_directory(path);
} else if let Some(path) = &args.path { } else if let Some(path) = args.path {
rename_files_in_directory(path.to_string(), &args); rename_files_in_directory(path);
} else { } else {
eprintln!("Please provide a directory"); eprintln!("Please provide a directory");
} }
} }
fn rename_files_in_directory(directory: String, args: &Arguments) { fn rename_files_in_directory(directory: String) {
println!("Renaming files in {}", directory); println!("Renaming files in {}", directory);
match rename_files(&directory, &directory, args) { match rename_files(&directory, &directory) {
Ok(count) if args.not_dry_run() => println!("Renamed {} files", count), Ok(count) => println!("Renamed {} files", count),
Ok(_) => println!("Dry-Run complete"),
Err(e) => eprintln!("Error: {}", e), Err(e) => eprintln!("Error: {}", e),
} }
} }
fn rename_files(directory: &str, base: &str, args: &Arguments) -> Result<i32> { fn rename_files(directory: &str, base: &str) -> Result<i32> {
let entries = read_dir(directory).context("Failed to read directory")?; let entries = read_dir(directory).context("Failed to read directory")?;
let mut count = 0; let mut count = 0;
for entry in entries { for entry in entries {
@ -63,76 +48,42 @@ fn rename_files(directory: &str, base: &str, args: &Arguments) -> Result<i32> {
let path = entry.path(); let path = entry.path();
if path.is_dir() { if path.is_dir() {
if let Some(sub_dir) = path.to_str() { if let Some(sub_dir) = path.to_str() {
count += rename_files(sub_dir, base, args).context("Failed to rename files")?; count += rename_files(sub_dir, base).context("Failed to rename files")?;
} }
} }
if !path.is_file() { if path.is_file() {
continue; if let Ok(file) = taglib::File::new(&path) {
} if let Ok(tag) = file.tag() {
let Ok(file) = taglib::File::new(&path) else { if let Some(title) = tag.title() {
continue; if let Some(artist) = tag.artist() {
}; let album = parse_album(&title);
let Ok(tag) = file.tag() else { count += 1;
continue; let new_name = match album.len() {
}; 0 => format!("{artist}/{title}/{title}.m4b"),
let (Some(title), Some(artist)) = (tag.title(), tag.artist()) else { _ => format!("{artist}/{album}/{title}/{title}.m4b"),
continue; };
}; println!("Renaming {} to {}", path.display(), new_name);
let (bucket, _) = artist.split_at(1); let target_path = Path::new(&base).join(new_name);
let album = parse_album(&title); if !target_path.exists() {
count += 1; let dir = target_path.parent().with_context(|| {
let new_name = if album.is_empty() { format!("Failed to get parent: {:#?}", target_path)
format!("{bucket}/{artist}/{title}/{title}.m4b") })?;
} else { create_dir_all(dir).with_context(|| {
build_series_name(bucket, &artist, &album, &title) format!("Failed to create directory: {:#?}", dir)
}; })?;
println!("=============================="); }
println!("- artist: {artist}"); rename(&path, &target_path).with_context(|| {
println!("- album : {album}"); format!("Failed to rename file: {:#?}", target_path)
println!("- title : {title}"); })?;
println!("> {new_name}"); }
if args.not_dry_run() { }
let target_path = Path::new(&base).join(new_name); }
if !target_path.exists() {
let dir = target_path
.parent()
.with_context(|| format!("Failed to get parent: {:#?}", target_path))?;
create_dir_all(dir)
.with_context(|| format!("Failed to create directory: {:#?}", dir))?;
} }
rename(&path, &target_path)
.with_context(|| format!("Failed to rename file: {:#?}", target_path))?;
} }
} }
Ok(count) Ok(count)
} }
fn build_series_name(bucket: &str, artist: &str, album: &str, title: &str) -> String {
let index = parse_index(title);
let title = parse_title(title);
format!("{bucket}/{artist}/{album}/{index}. {title}/{index}. {title}.m4b")
}
fn parse_index(title: &str) -> String {
if let Ok(index_re) = regex::Regex::new(r", Book (?P<INDEX>\d+)") {
if let Some(captures) = index_re.captures(title) {
let index = captures.name("INDEX").map_or("", |m| m.as_str());
return index.to_string();
}
}
String::new()
}
fn parse_title(title: &str) -> String {
if let Ok(title_re) = regex::Regex::new(r"^(?P<TITLE>.*?):") {
if let Some(captures) = title_re.captures(title) {
let title = captures.name("TITLE").map_or("", |m| m.as_str());
return title.to_string();
}
}
title.to_string()
}
fn parse_album(title: &str) -> String { fn parse_album(title: &str) -> String {
let parts: Vec<&str> = title.split(':').collect(); let parts: Vec<&str> = title.split(':').collect();
match &parts[..] { match &parts[..] {

View file

@ -1,18 +0,0 @@
//
use super::*;
use pretty_assertions::assert_eq;
#[rstest::rstest]
#[case("Discworld", "The Truth: Discworld, Book 25", "25. The Truth")]
#[case(
"A Darker Shade of Magic",
"A Conjuring of Light: A Darker Shade of Magic, Book 3",
"3. A Conjuring of Light"
)]
fn parse_series_details(#[case] album: &str, #[case] title: &str, #[case] expected: &str) {
let expected_result = format!("B/Bob/{album}/{expected}/{expected}.m4b");
let result = build_series_name("B", "Bob", album, title);
assert_eq!(result, expected_result);
}