Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

configurable headers #48 #55

Merged
merged 13 commits into from
Jul 8, 2024
54 changes: 54 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ rss = "2"
reqwest = "0.12"
regex = "1"
thiserror = "1"
chrono = "0.4"

# Async
tokio = { version = "1", features = ["macros", "sync"] }
Expand Down
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,22 @@ headers_hide = false
[connection]
url = "http://CHANGE_ME:9091/transmission/rpc" # REQUIRED!

# Refresh timings (in seconds)
torrents_refresh = 5
stats_refresh = 5
free_space_refresh = 10

# If you need username and password to authenticate:
# username = "CHANGE_ME"
# password = "CHANGE_ME"

# Refresh timings (in seconds)
torrents_refresh = 5
stats_refresh = 10
free_space_refresh = 10
[torrents_tab]
# Available fields:
# Id, Name, SizeWhenDone, Progress, DownloadRate, UploadRate, DownloadDir,
# Padding, UploadRatio, UploadedEver, AddedDate, ActivityDate, PeersConnected
# SmallStatus
headers = ["Name", "SizeWhenDone", "Progress", "DownloadRate", "UploadRate"]

```

There's also a self-documenting keymap config located at `~/.config/rustmission/keymap.toml` with sane defaults.
Expand Down
1 change: 1 addition & 0 deletions rm-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ url.workspace = true
ratatui.workspace = true
crossterm.workspace = true
thiserror.workspace = true
transmission-rpc.workspace = true
16 changes: 12 additions & 4 deletions rm-config/defaults/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ headers_hide = false
[connection]
url = "http://CHANGE_ME:9091/transmission/rpc" # REQUIRED!

# Refresh timings (in seconds)
torrents_refresh = 5
stats_refresh = 5
free_space_refresh = 10

# If you need username and password to authenticate:
# username = "CHANGE_ME"
# password = "CHANGE_ME"

# Refresh timings (in seconds)
torrents_refresh = 5
stats_refresh = 10
free_space_refresh = 10

[torrents_tab]
# Available fields:
# Id, Name, SizeWhenDone, Progress, DownloadRate, UploadRate, DownloadDir,
# Padding, UploadRatio, UploadedEver, AddedDate, ActivityDate, PeersConnected
# SmallStatus
headers = ["Name", "SizeWhenDone", "Progress", "DownloadRate", "UploadRate"]
aidanaden marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 3 additions & 1 deletion rm-config/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod keymap;
mod main_config;
pub mod main_config;
mod utils;

use std::path::PathBuf;
Expand All @@ -11,6 +11,7 @@ use main_config::MainConfig;
pub struct Config {
pub general: main_config::General,
pub connection: main_config::Connection,
pub torrents_tab: main_config::TorrentsTab,
pub keybindings: KeymapConfig,
pub directories: Directories,
}
Expand All @@ -33,6 +34,7 @@ impl Config {
Ok(Self {
general: main_config.general,
connection: main_config.connection,
torrents_tab: main_config.torrents_tab,
keybindings: keybindings.clone(),
directories,
})
Expand Down
112 changes: 99 additions & 13 deletions rm-config/src/main_config.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
use std::{path::PathBuf, sync::OnceLock};
use std::{io::ErrorKind, path::PathBuf, sync::OnceLock};

use anyhow::Result;
use ratatui::style::Color;
use ratatui::{layout::Constraint, style::Color};
use serde::{Deserialize, Serialize};
use url::Url;

use crate::utils::{self, put_config};
use crate::utils::{self};

#[derive(Serialize, Deserialize)]
#[derive(Deserialize)]
pub struct MainConfig {
pub general: General,
pub connection: Connection,
#[serde(default)]
pub torrents_tab: TorrentsTab,
}

#[derive(Debug, Serialize, Deserialize)]
#[derive(Deserialize)]
pub struct General {
#[serde(default)]
pub auto_hide: bool,
Expand All @@ -33,7 +35,7 @@ fn default_beginner_mode() -> bool {
true
}

#[derive(Debug, Serialize, Deserialize)]
#[derive(Deserialize)]
pub struct Connection {
pub username: Option<String>,
pub password: Option<String>,
Expand All @@ -50,19 +52,103 @@ fn default_refresh() -> u64 {
5
}

#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Copy)]
pub enum Header {
Name,
SizeWhenDone,
Progress,
Eta,
DownloadRate,
UploadRate,
DownloadDir,
Padding,
UploadRatio,
UploadedEver,
Id,
ActivityDate,
AddedDate,
PeersConnected,
SmallStatus,
}

impl Header {
pub fn default_constraint(&self) -> Constraint {
match self {
Self::Name => Constraint::Max(70),
Self::SizeWhenDone => Constraint::Length(12),
Self::Progress => Constraint::Length(12),
Self::Eta => Constraint::Length(12),
Self::DownloadRate => Constraint::Length(12),
Self::UploadRate => Constraint::Length(12),
Self::DownloadDir => Constraint::Max(70),
Self::Padding => Constraint::Length(2),
Self::UploadRatio => Constraint::Length(6),
Self::UploadedEver => Constraint::Length(12),
Self::Id => Constraint::Length(4),
Self::ActivityDate => Constraint::Length(14),
Self::AddedDate => Constraint::Length(12),
Self::PeersConnected => Constraint::Length(6),
Self::SmallStatus => Constraint::Length(1),
}
}

pub fn header_name(&self) -> &'static str {
match *self {
Self::Name => "Name",
Self::SizeWhenDone => "Size",
Self::Progress => "Progress",
Self::Eta => "ETA",
Self::DownloadRate => "Download",
Self::UploadRate => "Upload",
Self::DownloadDir => "Directory",
Self::Padding => "",
Self::UploadRatio => "Ratio",
Self::UploadedEver => "Up Ever",
Self::Id => "Id",
Self::ActivityDate => "Last active",
Self::AddedDate => "Added",
Self::PeersConnected => "Peers",
Self::SmallStatus => "",
}
}
}

#[derive(Deserialize)]
pub struct TorrentsTab {
pub headers: Vec<Header>,
}

impl Default for TorrentsTab {
fn default() -> Self {
Self {
headers: vec![
Header::Name,
Header::SizeWhenDone,
Header::Progress,
Header::Eta,
Header::DownloadRate,
Header::UploadRate,
],
}
}
}

impl MainConfig {
pub(crate) const FILENAME: &'static str = "config.toml";
const DEFAULT_CONFIG: &'static str = include_str!("../defaults/config.toml");

pub(crate) fn init() -> Result<Self> {
let Ok(config) = utils::fetch_config(Self::FILENAME) else {
put_config(Self::DEFAULT_CONFIG, Self::FILENAME)?;
// TODO: check if the user really changed the config.
println!("Update {:?} and start rustmission again", Self::path());
std::process::exit(0);
match utils::fetch_config::<Self>(Self::FILENAME) {
Ok(config) => return Ok(config),
Err(e) => match e {
utils::ConfigFetchingError::Io(e) if e.kind() == ErrorKind::NotFound => {
utils::put_config::<Self>(Self::DEFAULT_CONFIG, Self::FILENAME)?;
println!("Update {:?} and start rustmission again", Self::path());
std::process::exit(0);
}
_ => anyhow::bail!(e),
},
};

Ok(config)
}

pub(crate) fn path() -> &'static PathBuf {
Expand Down
4 changes: 2 additions & 2 deletions rm-config/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ pub fn fetch_config<T: DeserializeOwned>(config_name: &str) -> Result<T, ConfigF
pub fn put_config<T: DeserializeOwned>(
content: &'static str,
filename: &str,
) -> Result<T, io::Error> {
) -> Result<T, ConfigFetchingError> {
let config_path = get_config_path(filename);
let mut config_file = File::create(config_path)?;
config_file.write_all(content.as_bytes())?;
Ok(toml::from_str(content).expect("default configs are correct"))
Ok(toml::from_str(content)?)
}
1 change: 1 addition & 0 deletions rm-main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ rss.workspace = true
reqwest.workspace = true
regex.workspace = true
throbber-widgets-tui.workspace = true
chrono.workspace = true
4 changes: 4 additions & 0 deletions rm-main/src/transmission/fetchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ pub async fn torrents(ctx: app::Ctx, table_manager: Arc<Mutex<TableManager>>) {
TorrentGetField::RateDownload,
TorrentGetField::Status,
TorrentGetField::DownloadDir,
TorrentGetField::UploadedEver,
TorrentGetField::ActivityDate,
TorrentGetField::AddedDate,
TorrentGetField::PeersConnected,
];
let rpc_response = ctx
.client
Expand Down
2 changes: 1 addition & 1 deletion rm-main/src/ui/tabs/torrents/bottom_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl Component for BottomStats {
let download = bytes_to_human_format(stats.download_speed);
let upload = bytes_to_human_format(stats.upload_speed);

let mut text = format!(" {download} | {upload}");
let mut text = format!(" {download} | {upload}");

if let Some(free_space) = &*self.free_space.lock().unwrap() {
let free_space = bytes_to_human_format(free_space.size_bytes);
Expand Down
6 changes: 2 additions & 4 deletions rm-main/src/ui/tabs/torrents/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,10 @@ impl TorrentsTab {
.accent_color);

let table_widget = {
let table = Table::new(torrent_rows, table_manager_lock.widths)
let table = Table::new(torrent_rows, &table_manager_lock.widths)
.highlight_style(highlight_table_style);
if !self.ctx.config.general.headers_hide {
table.header(Row::new(
table_manager_lock.header().iter().map(|s| s.as_str()),
))
table.header(Row::new(table_manager_lock.header().iter().cloned()))
} else {
table
}
Expand Down
Loading
Loading