Skip to main content

baken_export/
error.rs

1use std::path::PathBuf;
2
3pub type Result<T> = std::result::Result<T, Error>;
4
5/// The searched paths, or a plain note when there was nowhere to look: no
6/// rekordbox directory exists on this machine, and on Linux none ever can.
7fn searched_paths(paths: &[PathBuf]) -> String {
8    if paths.is_empty() {
9        return "nothing; this machine has no rekordbox directory to look in".into();
10    }
11    paths
12        .iter()
13        .map(|p| p.display().to_string())
14        .collect::<Vec<_>>()
15        .join(", ")
16}
17
18/// What an error writing to the stick most likely means. Only errors about the
19/// stick as a whole get a hint; EIO has no `ErrorKind` of its own.
20fn device_hint(e: &std::io::Error) -> &'static str {
21    use std::io::ErrorKind::*;
22    match e.kind() {
23        PermissionDenied => ". Check that the stick is mounted there: an empty mount point usually belongs to root.",
24        ReadOnlyFilesystem => ". The stick is mounted read-only.",
25        StorageFull => ". The stick is full.",
26        _ if cfg!(unix) && e.raw_os_error() == Some(5) => ". The stick did not answer: check that it is plugged in and mounted. On Linux, a stick pulled out without unmounting leaves its mount behind; unmount it and mount it again.",
27        _ => "",
28    }
29}
30
31#[derive(Debug, thiserror::Error)]
32pub enum Error {
33    #[error("My Settings not found (MYSETTING.DAT, MYSETTING2.DAT, DJMMYSETTING.DAT). Searched: {}. In rekordbox, switch to EXPORT mode and open Preferences > DJ System > My Settings once so rekordbox writes them, or pass --settings-dir at a directory holding the files; the PIONEER folder of any stick rekordbox exported has them. Or pass --no-settings to write the stick without them, so the player keeps its own settings.", searched_paths(searched))]
34    SettingsNotFound { searched: Vec<PathBuf> },
35
36    #[error("Playlist not found: {0}")]
37    PlaylistNotFound(String),
38
39    #[error("Playlist '{path}' is not a TrackID-referenced playlist (KeyType={key_type}); only KeyType=\"0\" playlists can be exported")]
40    UnsupportedPlaylistType { path: String, key_type: String },
41
42    #[error("No exportable playlists selected")]
43    NoPlaylists,
44
45    #[error("No rekordbox analysis files found. Searched: {}. expressport copies the waveforms rekordbox analysed and cannot compute them from the XML, so every track needs its .DAT/.EXT in rekordbox's PIONEER/USBANLZ directory; pass --anlz-dir if it is somewhere this did not look, or --generate-analysis to compute the waveforms from the audio.", searched_paths(searched))]
46    NoAnlzRoot { searched: Vec<PathBuf> },
47
48    #[error("None of the selected tracks can be exported (missing source files or analysis)")]
49    NothingToExport,
50
51    #[error("Device path is not a directory: {}", .0.display())]
52    DeviceNotFound(PathBuf),
53
54    // `err`, not `source`: as a source, anyhow would print the OS message a second time.
55    #[error("Cannot write to the stick: {}: {err}{}", path.display(), device_hint(err))]
56    DeviceWrite { path: PathBuf, err: std::io::Error },
57
58    #[error("operation cancelled")]
59    Cancelled,
60
61    #[error(transparent)]
62    Io(#[from] std::io::Error),
63
64    #[error(transparent)]
65    Other(#[from] anyhow::Error),
66}