Setup base eframe application + serialization + arg parsing and configuration
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
# .cargo/config.toml
|
||||||
|
[env]
|
||||||
|
CMAKE_POLICY_VERSION_MINIMUM = "3.5"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Ignored default folder with query files
|
||||||
|
/queries/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/yt-offline.iml" filepath="$PROJECT_DIR$/.idea/yt-offline.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="EMPTY_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Generated
+6622
File diff suppressed because it is too large
Load Diff
+27
@@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "yt-offline"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "4.6.7", features = ["derive"] }
|
||||||
|
dirs = "7.0.0"
|
||||||
|
eframe = {version = "0.36.2", features = ["persistence"]}
|
||||||
|
egui-sharkplayer = "0.5.1"
|
||||||
|
serde = { version = "1.0.229", features = ["derive"] }
|
||||||
|
serde_json = "1.0.151"
|
||||||
|
tokio = {version = "1.53.1", features = ["macros", "rt-multi-thread"]}
|
||||||
|
tracing = "0.1.44"
|
||||||
|
tracing-subscriber = {version = "0.3.23", features = ["env-filter"]}
|
||||||
|
yt-dlp = "2.8.3"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = 3
|
||||||
|
lto = true
|
||||||
|
panic = 'abort'
|
||||||
|
overflow-checks = false
|
||||||
|
debug-assertions = false
|
||||||
|
incremental = false
|
||||||
|
rpath = false
|
||||||
|
codegen-units = 1
|
||||||
|
strip = true
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
use eframe::{egui, Frame, Storage, CreationContext};
|
||||||
|
use eframe::egui::{Context, Ui};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct Application {
|
||||||
|
settings: AppSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
|
struct AppSettings {
|
||||||
|
serialization_test_string: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Application {
|
||||||
|
pub fn new(cc: &CreationContext) -> Self {
|
||||||
|
let mut settings = AppSettings::default();
|
||||||
|
if let Some(storage) = cc.storage {
|
||||||
|
if let Some(stored_str) = storage.get_string("app_settings") {
|
||||||
|
if let Ok(parsed) = serde_json::from_str(&stored_str) {
|
||||||
|
settings = parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { settings }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl eframe::App for Application {
|
||||||
|
|
||||||
|
fn logic(&mut self, ctx: &Context, frame: &mut Frame) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui(&mut self, ui: &mut Ui, frame: &mut Frame) {
|
||||||
|
egui::CentralPanel::default().show(ui, |ui| {
|
||||||
|
ui.heading("Hello!");
|
||||||
|
ui.text_edit_singleline(&mut self.settings.serialization_test_string);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save(&mut self, _storage: &mut dyn Storage) {
|
||||||
|
if let Ok(serialized) = serde_json::to_string(&self.settings) {
|
||||||
|
_storage.set_string("app_settings", serialized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_exit(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn auto_save_interval(&self) -> Duration {
|
||||||
|
Duration::from_secs(5)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
use clap::Parser;
|
||||||
|
use crate::{args};
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
pub(crate) struct Args {
|
||||||
|
/// Override the state file location
|
||||||
|
pub(crate) state: Option<String>,
|
||||||
|
/// Override the default data dir
|
||||||
|
#[clap(short, long)]
|
||||||
|
pub(crate) data_dir: Option<String>,
|
||||||
|
/// Enable verbose logging
|
||||||
|
#[clap(short, long)]
|
||||||
|
pub(crate) verbose: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ArgsConfig {
|
||||||
|
pub(crate) state: String,
|
||||||
|
pub(crate) data_dir: String,
|
||||||
|
pub(crate) verbose: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_args() -> ArgsConfig {
|
||||||
|
let args = args::Args::parse();
|
||||||
|
let mut args_config = args::ArgsConfig {
|
||||||
|
state: "".to_string(),
|
||||||
|
data_dir: "".to_string(),
|
||||||
|
verbose: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if args.data_dir.is_none() {
|
||||||
|
let data_dir = dirs::data_dir().unwrap_or_else(|| "./".into());
|
||||||
|
args_config.data_dir = format!("{}/yt-offline", data_dir.into_string().expect("Failed to convert data directory into string"));
|
||||||
|
}
|
||||||
|
// TODO: add a check in case the passed in data dir as a / at the end
|
||||||
|
|
||||||
|
if args.state.is_some() {
|
||||||
|
args_config.state = format!("{}/{}", args_config.data_dir, args.state.expect("Failed to unwrap config arg"));
|
||||||
|
} else {
|
||||||
|
args_config.state = format!("{}/state.json", args_config.data_dir);
|
||||||
|
}
|
||||||
|
args_config
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
use tracing::log::LevelFilter;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
pub fn init(is_verbose: bool) {
|
||||||
|
let lvl_filter;
|
||||||
|
let directive;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
lvl_filter = LevelFilter::Info;
|
||||||
|
directive = "yt_offline=DEBUG";
|
||||||
|
}
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
{
|
||||||
|
if is_verbose{
|
||||||
|
lvl_filter = LevelFilter::Info;
|
||||||
|
directive = "yt_offline=INFO";
|
||||||
|
} else {
|
||||||
|
lvl_filter = LevelFilter::Warn;
|
||||||
|
directive = "yt_offline=WARN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter = EnvFilter::builder()
|
||||||
|
.with_default_directive(lvl_filter.as_str().parse().expect("Failed to parse lvl_filter into directive"))
|
||||||
|
.from_env().expect("Failed to parse env filter")
|
||||||
|
.add_directive(directive.parse().expect("Failed to parse directive"));
|
||||||
|
tracing_subscriber::fmt().with_env_filter(filter).compact().init();
|
||||||
|
debug!("Successfully setup tracing subscriber.");
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::exit;
|
||||||
|
use tracing::{debug, error};
|
||||||
|
mod logging;
|
||||||
|
mod args;
|
||||||
|
mod app;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args = args::parse_args();
|
||||||
|
logging::init(args.verbose);
|
||||||
|
debug!("Using args: \n{:#?}\n", args);
|
||||||
|
let data_dir_path = PathBuf::from(&args.data_dir);
|
||||||
|
if data_dir_path.is_file() {
|
||||||
|
error!("data_dir is a file... If you have set the data_dir manually, please pass in a directory. If you didn't pass in a path at all, please report this.");
|
||||||
|
error!("{:#?}", args);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if !data_dir_path.exists() {
|
||||||
|
if let Err(e) = fs::create_dir(data_dir_path.as_path()) {
|
||||||
|
error!("Failed to create data_dir path with fs error: {}", e);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut options = eframe::NativeOptions::default();
|
||||||
|
options.persistence_path = Some(args.state.parse().expect("Failed to parse state config file path into path"));
|
||||||
|
eframe::run_native(
|
||||||
|
"yt-offline",
|
||||||
|
options,
|
||||||
|
Box::new(|cc| {
|
||||||
|
Ok(Box::new(app::Application::new(cc)))
|
||||||
|
})).expect("TODO: panic message");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user