Skip to content

Commit

Permalink
feat: configurable headers (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
micielski authored Jul 8, 2024
1 parent f5c14ad commit 5709159
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 106 deletions.
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"]
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

0 comments on commit 5709159

Please sign in to comment.