legacylisten 0.2.0

A simple CLI audio player with strange features.
Documentation
use std::{
    path::{Path, PathBuf},
    sync::{
        atomic::{AtomicBool, AtomicUsize},
        Arc, Mutex,
    },
};

use crossbeam_channel::{unbounded, Receiver, Sender};
use diskit::Diskit;
use id3::Tag;

use crate::{
    audio::{AudioHandler, ChannelAudio},
    commands::Command,
    conffile::Conffile,
    files::ensure_file_existence,
    l10n::{L10n, Writer},
    songs::Repeat,
    Error,
};

pub struct Config
{
    pub(crate) audio_handler: Box<dyn AudioHandler>,
    pub(crate) source: ChannelAudio,
    pub(crate) tx: Sender<(Command, u32)>,
    pub(crate) rx: Receiver<(Command, u32)>,
    pub(crate) rx_control: Receiver<()>,
    pub(crate) tx_paused: Sender<bool>,
    pub(crate) tx_path: Sender<(PathBuf, Option<Tag>)>,
    pub(crate) tag: Option<Result<Tag, id3::Error>>,
    pub(crate) num: u32,
    pub(crate) loud: f32,
    pub(crate) paused: bool,
    pub(crate) pause_after_song: bool,
    pub(crate) quit_after_song: bool,
    pub(crate) repeat: Repeat,
    pub(crate) songlist: Vec<usize>,
    pub(crate) song_index: usize,
    pub(crate) arc_config: Arc<ArcConfig>,
    pub(crate) l10n: L10n,
    pub(crate) unsuccessful_tries: u8,
}

// False positive of pedantic lint.  I think this is the best name.
#[allow(clippy::module_name_repetitions)]
pub struct ArcConfig
{
    pub pic_path: Mutex<Option<String>>,
    pub reading_paused: AtomicBool,
    pub update_dbus: AtomicBool,
    pub current_pos: AtomicUsize,
    pub current_len: AtomicUsize,
    pub sample_rate: AtomicUsize,
    pub channels: AtomicUsize,
    pub monotonic_song_index: AtomicUsize,
    pub home_dir: PathBuf,
    pub config_dir: PathBuf,
    pub conffile: Conffile,
    pub l10n: L10n,
}

impl ArcConfig
{
    fn new<C, D>(get_conffile: C, writer: Writer, diskit: D) -> Result<Self, Error>
    where
        C: Fn(&Path, D) -> Conffile,
        D: Diskit + Send + 'static,
    {
        let home_dir = home::home_dir().unwrap_or_else(|| PathBuf::from("./"));
        ensure_file_existence(&home_dir, diskit.clone())?;
        let conffile_dir = home_dir.join(PathBuf::from("./.zvavybir/legacylisten"));
        let conffile = get_conffile(&conffile_dir, diskit.clone());
        let l10n = L10n::new(conffile.lang.clone(), writer, diskit)?;

        Ok(Self {
            pic_path: Mutex::new(None),
            reading_paused: AtomicBool::new(false),
            update_dbus: AtomicBool::new(false),
            current_pos: AtomicUsize::new(0),
            current_len: AtomicUsize::new(0),
            sample_rate: AtomicUsize::new(1),
            channels: AtomicUsize::new(1),
            monotonic_song_index: AtomicUsize::new(0),
            home_dir,
            config_dir: conffile_dir,
            conffile,
            l10n,
        })
    }
}

impl Config
{
    pub fn new<C, A, D>(
        rx_control: Receiver<()>,
        tx_paused: Sender<bool>,
        tx_path: Sender<(PathBuf, Option<Tag>)>,
        get_conffile: C,
        writer: Writer,
        diskit: D,
    ) -> Result<Self, Error>
    where
        C: Fn(&Path, D) -> Conffile,
        A: AudioHandler,
        D: Diskit + Send + 'static,
    {
        let (tx, rx) = unbounded();
        let arc_config = Arc::new(ArcConfig::new(get_conffile, writer, diskit)?);
        let l10n = arc_config.l10n;

        Ok(Self {
            audio_handler: A::new(),
            source: ChannelAudio {
                sample_rate: 0,
                inner: None,
                config: arc_config.clone(),
            },
            tx,
            rx,
            rx_control,
            tx_paused,
            tx_path,
            tag: None,
            num: 0,
            loud: 0.0,
            paused: false,
            pause_after_song: false,
            quit_after_song: false,
            repeat: Repeat::Not,
            songlist: vec![],
            song_index: 0,
            arc_config,
            l10n,
            unsuccessful_tries: 0,
        })
    }
}