Skip to content

Commit

Permalink
release: 0.2.10
Browse files Browse the repository at this point in the history
  • Loading branch information
joshstoik1 committed Oct 18, 2024
2 parents 9eb3677 + b58f4a1 commit 196beec
Show file tree
Hide file tree
Showing 12 changed files with 560 additions and 442 deletions.
29 changes: 15 additions & 14 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
# Project Dependencies
Package: riprip
Version: 0.2.9
Generated: 2024-09-06 02:45:24 UTC
Version: 0.2.10
Generated: 2024-10-18 02:34:12 UTC

| Package | Version | Author(s) | License |
| ---- | ---- | ---- | ---- |
| [ahash](https://github.com/tkaitchuck/ahash) | 0.8.11 | [Tom Kaitchuck](mailto:[email protected]) | Apache-2.0 or MIT |
| [argyle](https://github.com/Blobfolio/argyle) | 0.8.1 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [argyle](https://github.com/Blobfolio/argyle) | 0.10.0 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [block-buffer](https://github.com/RustCrypto/utils) | 0.10.4 | RustCrypto Developers | Apache-2.0 or MIT |
| [bytecount](https://github.com/llogiq/bytecount) | 0.6.8 | [Andre Bogus](mailto:[email protected]) and [Joshua Landau](mailto:[email protected]) | Apache-2.0 or MIT |
| [cdtoc](https://github.com/Blobfolio/cdtoc) | 0.5.0 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [cdtoc](https://github.com/Blobfolio/cdtoc) | 0.5.1 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [cfg-if](https://github.com/alexcrichton/cfg-if) | 1.0.0 | [Alex Crichton](mailto:[email protected]) | Apache-2.0 or MIT |
| [crc32fast](https://github.com/srijs/rust-crc32fast) | 1.4.2 | [Sam Rijs](mailto:[email protected]) and [Alex Crichton](mailto:[email protected]) | Apache-2.0 or MIT |
| [crypto-common](https://github.com/RustCrypto/traits) | 0.1.6 | RustCrypto Developers | Apache-2.0 or MIT |
| [ctrlc](https://github.com/Detegr/rust-ctrlc.git) | 3.4.5 | [Antti Keränen](mailto:[email protected]) | Apache-2.0 or MIT |
| [dactyl](https://github.com/Blobfolio/dactyl) | 0.7.3 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [dactyl](https://github.com/Blobfolio/dactyl) | 0.7.4 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [digest](https://github.com/RustCrypto/traits) | 0.10.7 | RustCrypto Developers | Apache-2.0 or MIT |
| [faster-hex](https://github.com/NervosFoundation/faster-hex) | 0.9.0 | [zhangsoledad](mailto:[email protected]) | MIT |
| [faster-hex](https://github.com/NervosFoundation/faster-hex) | 0.10.0 | [zhangsoledad](mailto:[email protected]) | MIT |
| [fastrand](https://github.com/smol-rs/fastrand) | 2.1.1 | [Stjepan Glavina](mailto:[email protected]) | Apache-2.0 or MIT |
| [fyi_msg](https://github.com/Blobfolio/fyi) | 0.14.0 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [fyi_msg](https://github.com/Blobfolio/fyi) | 1.1.1 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [generic-array](https://github.com/fizyk20/generic-array.git) | 0.14.7 | [Bartłomiej Kamiński](mailto:[email protected]) and [Aaron Trent](mailto:[email protected]) | MIT |
| [itoa](https://github.com/dtolnay/itoa) | 1.0.11 | [David Tolnay](mailto:[email protected]) | Apache-2.0 or MIT |
| [libcdio-sys](https://github.com/MonterraByte/libcdio-sys) | 0.5.1 | [Joaquim Monteiro](mailto:[email protected]) | GPL-3.0+ |
| [log](https://github.com/rust-lang/log) | 0.4.22 | The Rust Project Developers | Apache-2.0 or MIT |
| [minreq](https://github.com/neonmoe/minreq) | 2.12.0 | [Jens Pitkanen](mailto:[email protected]) | ISC |
| [once_cell](https://github.com/matklad/once_cell) | 1.19.0 | [Aleksey Kladov](mailto:[email protected]) | Apache-2.0 or MIT |
| [oxford_join](https://github.com/Blobfolio/oxford_join) | 0.2.10 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [riprip_core](https://github.com/Blobfolio/riprip) | 0.2.9 | [Josh Stoik](mailto:[email protected]) | WTFPL |
| [once_cell](https://github.com/matklad/once_cell) | 1.20.2 | [Aleksey Kladov](mailto:[email protected]) | Apache-2.0 or MIT |
| [oxford_join](https://github.com/Blobfolio/oxford_join) | 0.4.0 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [riprip_core](https://github.com/Blobfolio/riprip) | 0.2.10 | [Josh Stoik](mailto:[email protected]) | WTFPL |
| [serde](https://github.com/serde-rs/serde) | 1.0.210 | [Erick Tryzelaar](mailto:[email protected]) and [David Tolnay](mailto:[email protected]) | Apache-2.0 or MIT |
| [sha1](https://github.com/RustCrypto/hashes) | 0.10.6 | RustCrypto Developers | Apache-2.0 or MIT |
| [tempfile](https://github.com/Stebalien/tempfile) | 3.12.0 | [Steven Allen](mailto:[email protected]), The Rust Project Developers, [Ashley Mannix](mailto:[email protected]), and [Jason White](mailto:[email protected]) | Apache-2.0 or MIT |
| [terminal_size](https://github.com/eminence/terminal-size) | 0.3.0 | [Andrew Chin](mailto:[email protected]) | Apache-2.0 or MIT |
| [tempfile](https://github.com/Stebalien/tempfile) | 3.13.0 | [Steven Allen](mailto:[email protected]), The Rust Project Developers, [Ashley Mannix](mailto:[email protected]), and [Jason White](mailto:[email protected]) | Apache-2.0 or MIT |
| [terminal_size](https://github.com/eminence/terminal-size) | 0.4.0 | [Andrew Chin](mailto:[email protected]) | Apache-2.0 or MIT |
| [trimothy](https://github.com/Blobfolio/trimothy) | 0.3.1 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [typenum](https://github.com/paholg/typenum) | 1.17.0 | [Paho Lurie-Gregg](mailto:[email protected]) and [Andre Bogus](mailto:[email protected]) | Apache-2.0 or MIT |
| [unicode-width](https://github.com/unicode-rs/unicode-width) | 0.1.13 | [kwantam](mailto:[email protected]) and [Manish Goregaokar](mailto:[email protected]) | Apache-2.0 or MIT |
| [utc2k](https://github.com/Blobfolio/utc2k) | 0.9.1 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [unicode-width](https://github.com/unicode-rs/unicode-width) | 0.2.0 | [kwantam](mailto:[email protected]) and [Manish Goregaokar](mailto:[email protected]) | Apache-2.0 or MIT |
| [utc2k](https://github.com/Blobfolio/utc2k) | 0.10.0 | [Blobfolio, LLC.](mailto:[email protected]) | WTFPL |
| [zerocopy](https://github.com/google/zerocopy) | 0.7.35 | [Joshua Liebow-Feeser](mailto:[email protected]) | Apache-2.0, BSD-2-Clause, or MIT |
2 changes: 1 addition & 1 deletion release/completions/riprip.bash
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ _basher___riprip() {
return 0
fi
case "${prev}" in
-d|--dev)
--dev|-d)
if [ -z "$( declare -f _filedir )" ]; then
COMPREPLY=( $( compgen -f "${cur}" ) )
else
Expand Down
4 changes: 2 additions & 2 deletions release/man/riprip.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.TH "RIP RIP HOORAY!" "1" "September 2024" "Rip Rip Hooray! v0.2.9" "User Commands"
.TH "RIP RIP HOORAY!" "1" "October 2024" "riprip v0.2.10" "User Commands"
.SH NAME
Rip Rip Hooray! \- Manual page for riprip v0.2.9.
RIP RIP HOORAY! \- Manual page for riprip v0.2.10.
.SH DESCRIPTION
A specialized audio CD\-ripper optimized for incremental data recovery.
.SS USAGE:
Expand Down
13 changes: 8 additions & 5 deletions riprip/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "riprip"
version = "0.2.9"
version = "0.2.10"
license = "WTFPL"
authors = ["Josh Stoik <[email protected]>"]
edition = "2021"
Expand Down Expand Up @@ -125,15 +125,18 @@ label = "<NUM>"
description = "Rip one or more specific tracks (rather than the whole disc). Multiple tracks can be separated by commas (2,3), specified as an inclusive range (2-3), and/or given their own -t/--track (-t 2 -t 3). Track 0 can be used to rip the HTOA, if any. [default: the whole disc]"
duplicate = true

[build-dependencies]
argyle = "0.10.*"

[dependencies]
argyle = "0.8.*"
argyle = "0.10.*"
ctrlc = "=3.4.5"
dactyl = "0.7.*"
oxford_join = "0.2.*"
utc2k = "0.9.*"
oxford_join = "0.4.*"
utc2k = "0.10.*"

[dependencies.fyi_msg]
version = "0.14.*"
version = "1.1.*"
features = [ "progress" ]

[dependencies.riprip_core]
Expand Down
46 changes: 46 additions & 0 deletions riprip/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*!
# Rip Rip: Build
*/

use argyle::KeyWordsBuilder;
use std::path::PathBuf;



/// # Set Up CLI Arguments.
pub fn main() {
let mut builder = KeyWordsBuilder::default();
builder.push_keys([
"--backward", "--backwards",
"--flip-flop",
"-h", "--help",
"--no-resume",
"--no-rip",
"--no-summary",
"--reset",
"--status",
"--strict",
"--sync",
"-v", "--verbose",
"-V", "--version",
]);
builder.push_keys_with_values([
"-c", "--cache",
"-d", "--dev",
"--confidence",
"-o", "--offset",
"-p", "--pass", "--passes",
"-r", "--reread", "--rereads",
"-t", "--track", "--tracks",
]);
builder.save(out_path("argyle.rs"));
}

/// # Output Path.
///
/// Append the sub-path to OUT_DIR and return it.
fn out_path(stub: &str) -> PathBuf {
std::fs::canonicalize(std::env::var("OUT_DIR").expect("Missing OUT_DIR."))
.expect("Missing OUT_DIR.")
.join(stub)
}
214 changes: 214 additions & 0 deletions riprip/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*!
# Rip Rip Hooray: CLI
*/

use argyle::Argument;
use dactyl::traits::BytesToUnsigned;
use riprip_core::{
Disc,
DriveVendorModel,
ReadOffset,
RipRipError,
RipOptions,
};



/// # Options Return Type.
///
/// This is awful, but not quite awful enough to warrant a struct. Haha.
pub(super) type Parsed = (
RipOptions,
Disc,
Option<DriveVendorModel>,
bool,
bool,
bool,
);



/// # Parse Options.
pub(super) fn parse() -> Result<Parsed, RipRipError> {
let args = argyle::args()
.with_keywords(include!(concat!(env!("OUT_DIR"), "/argyle.rs")));

let mut opts = RipOptions::default();
let mut no_rip = false;
let mut no_summary = false;
let mut status = false;
let mut cache = None;
let mut dev = None;
let mut offset = None;
let mut tracks = String::new();
for arg in args {
match arg {
Argument::Key("--backward" | "--backwards") => {
opts = opts.with_backwards(true);
},
Argument::Key("--flip-flop") => {
opts = opts.with_flip_flop(true);
},
Argument::Key("-h" | "--help") => return Err(RipRipError::PrintHelp),
Argument::Key("--no-resume") => { opts = opts.with_resume(false); },
Argument::Key("--no-rip") => { no_rip = true; },
Argument::Key("--no-summary") => { no_summary = true; },
Argument::Key("--reset") => { opts = opts.with_reset(true); },
Argument::Key("--status") => { status = true; },
Argument::Key("--strict") => { opts = opts.with_strict(true); },
Argument::Key("--sync") => { opts = opts.with_sync(true); },
Argument::Key("-v" | "--verbose") => { opts = opts.with_verbose(true); },
Argument::Key("-V" | "--version") => return Err(RipRipError::PrintVersion),

Argument::KeyWithValue("-c" | "--cache", s) => {
let s = parse_rip_option_cache(s)?;
cache.replace(s);
},
Argument::KeyWithValue("-d" | "--dev", s) => { dev.replace(s); },
Argument::KeyWithValue("-o" | "--offset", s) => {
let s = ReadOffset::try_from(s.trim().as_bytes())
.map_err(|_| RipRipError::CliParse("-o/--offset"))?;
offset.replace(s);
},
Argument::KeyWithValue("-p" | "--pass" | "--passes", s) => {
let s = u8::btou(s.trim().as_bytes())
.ok_or(RipRipError::CliParse("-p/--passes"))?;
opts = opts.with_passes(s);
},
Argument::KeyWithValue("-r" | "--reread" | "--rereads", s) => {
let (a, b) = parse_rip_option_reread(s.as_bytes())?;
opts = opts.with_rereads(a, b);
},
Argument::KeyWithValue("-t" | "--track" | "--tracks", s) => {
if ! tracks.is_empty() { tracks.push(','); }
tracks.push_str(&s);
},

_ => {},
}
}

// Figure out the disc and drive.
let disc = Disc::new(dev)?;
let drivevendormodel = disc.drive_vendor_model();

// Set up some drive-dependent things.
if let Some(v) = cache.or_else(|| drivevendormodel.and_then(|vm| vm.detect_cache())) {
opts = opts.with_cache(v);
}
if let Some(v) = offset.or_else(|| drivevendormodel.and_then(|vm| vm.detect_offset())) {
opts = opts.with_offset(v);
}

// If we just want the status or didn't receive any -t, add everything.
if status || tracks.is_empty() {
let toc = disc.toc();
if toc.htoa().is_some() { opts = opts.with_track(0); }
for t in toc.audio_tracks() { opts = opts.with_track(t.number()); }
}
// Otherwise parse what we gathered earlier.
else { opts = parse_rip_option_tracks(&disc, opts, &tracks)?; }

Ok((
opts,
disc,
drivevendormodel,
no_rip,
no_summary,
status,
))
}



/// # Parse Cache Size.
fn parse_rip_option_cache(cache: String) -> Result<u16, RipRipError> {
let cache = cache.into_bytes();
cache.iter()
.position(|&b| matches!(b, b'm' | b'M'))
.map_or_else(
|| u16::btou(cache.trim_ascii()),
|pos| u16::btou(cache[..pos].trim_ascii()).and_then(|v| v.checked_mul(1024)),
)
.ok_or(RipRipError::CliParse("-c/--cache"))
}

/// # Parse Re-read Option.
fn parse_rip_option_reread(v: &[u8]) -> Result<(u8, u8), RipRipError> {
// Default.
let mut a = 2;
let mut b = 2;

// If there's a comma, there could be up to two values. Keep the
// default if either is omitted.
let v = v.trim_ascii();
if let Some(pos) = v.iter().position(|b| b','.eq(b)) {
let tmp = &v[..pos];
if ! tmp.is_empty() {
a = u8::btou(tmp).ok_or(RipRipError::CliParse("-r/--rereads"))?;
}
let tmp = &v[pos + 1..];
if ! tmp.is_empty() {
b = u8::btou(tmp).ok_or(RipRipError::CliParse("-r/--rereads"))?;
}
}
// A number by itself affects only the first part.
else {
a = u8::btou(v).ok_or(RipRipError::CliParse("-r/--rereads"))?;
}

Ok((a, b))
}

/// # Parse Rip Tracks.
fn parse_rip_option_tracks(disc: &Disc, mut opts: RipOptions, tracks: &str)
-> Result<RipOptions, RipRipError> {
for v in tracks.split(',') {
let v = v.as_bytes().trim_ascii();
if v.is_empty() { continue; }

// It might be a range.
if let Some(pos) = v.iter().position(|b| b'-'.eq(b)) {
// Split.
let a = v[..pos].trim_ascii();
let b = v[pos + 1..].trim_ascii();
if a.is_empty() || b.is_empty() {
return Err(RipRipError::CliParse("-t/--tracks"));
}

// Decode.
let a = u8::btou(a).ok_or(RipRipError::CliParse("-t/--tracks"))?;
let b = u8::btou(b).ok_or(RipRipError::CliParse("-t/--tracks"))?;

// Add them all!
if a <= b {
for idx in a..=b { opts = opts.with_track(idx); }
}
else { return Err(RipRipError::CliParse("-t/--tracks")); }
}
// Otherwise it should be a single index.
else {
let v = u8::btou(v).ok_or(RipRipError::CliParse("-t/--tracks"))?;
opts = opts.with_track(v);
}
}

// Make sure the desired tracks are actually on the disc.
let toc = disc.toc();
if opts.has_tracks() {
for idx in opts.tracks() {
// Make sure the track is valid.
let good =
if idx == 0 { toc.htoa().is_some() }
else { toc.audio_track(usize::from(idx)).is_some() };
if ! good { return Err(RipRipError::NoTrack(idx)); }
}
}
// If no tracks were specified, DO IT ALL.
else {
if toc.htoa().is_some() { opts = opts.with_track(0); }
for t in toc.audio_tracks() { opts = opts.with_track(t.number()); }
}

Ok(opts)
}
Loading

0 comments on commit 196beec

Please sign in to comment.