diff --git a/Cargo.lock b/Cargo.lock index 3126135..f17d848 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,22 +75,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -124,7 +124,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -135,7 +135,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -235,7 +235,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -274,15 +274,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cc" -version = "1.2.45" +version = "1.2.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" +checksum = "b97463e1064cb1b1c1384ad0a0b9c8abd0988e2a91f52606c80ef14aadb63e36" dependencies = [ "find-msvc-tools", "shlex", @@ -343,7 +343,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -420,9 +420,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -448,7 +448,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -459,7 +459,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -500,7 +500,7 @@ checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "unicode-xid", ] @@ -524,7 +524,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -572,9 +572,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "flix" @@ -677,6 +677,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -786,9 +792,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.9" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -829,16 +835,16 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "governor" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "444405bbb1a762387aa22dd569429533b54a1d8759d35d3b64cb39b0293eaa19" +checksum = "6e23d5986fd4364c2fb7498523540618b4b8d92eec6c36a02e565f66748e2f79" dependencies = [ "cfg-if", "futures-sink", "futures-timer", "futures-util", "getrandom 0.3.4", - "hashbrown 0.15.5", + "hashbrown 0.16.0", "nonzero_ext", "parking_lot", "portable-atomic", @@ -865,7 +871,7 @@ checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", - "foldhash", + "foldhash 0.1.5", ] [[package]] @@ -873,6 +879,11 @@ name = "hashbrown" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] [[package]] name = "hashlink" @@ -970,9 +981,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", @@ -1008,9 +1019,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" dependencies = [ "base64", "bytes", @@ -1189,7 +1200,7 @@ checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -1372,9 +1383,9 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ "lazy_static", "libm", @@ -1464,7 +1475,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -1617,7 +1628,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -1637,7 +1648,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "version_check", "yansi", ] @@ -1927,9 +1938,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "40a0376c50d0358279d9d643e4bf7b7be212f1f4ff1da9070a7b54d22ef75c88" dependencies = [ "const-oid", "digest", @@ -2030,7 +2041,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2094,7 +2105,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.109", + "syn 2.0.110", "unicode-ident", ] @@ -2114,9 +2125,9 @@ dependencies = [ [[package]] name = "sea-query" -version = "1.0.0-rc.17" +version = "1.0.0-rc.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d190945ff6b2914ef0631c1933ef67ee142b15f00b72d40bf241147d24b522" +checksum = "1c71f6d768c8bb1003bbfce01431374f677abbcf7582d6a0ec4ea4c5ae20adbb" dependencies = [ "bigdecimal", "chrono", @@ -2139,7 +2150,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "thiserror", ] @@ -2161,9 +2172,9 @@ dependencies = [ [[package]] name = "sea-schema" -version = "0.17.0-rc.12" +version = "0.17.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cb79f2d0fe3a3ca7852eb1c61590452674700fdeb9f07656b9eb16f8d1990b" +checksum = "59f99598cda516443eb35c06fe5b4496d60c8f7afca708bd998087b63ac56775" dependencies = [ "async-trait", "sea-query", @@ -2181,7 +2192,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2227,7 +2238,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2443,7 +2454,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2466,7 +2477,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.109", + "syn 2.0.110", "tokio", "url", ] @@ -2642,9 +2653,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.109" +version = "2.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" dependencies = [ "proc-macro2", "quote", @@ -2668,7 +2679,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2694,7 +2705,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2785,7 +2796,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -2917,7 +2928,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -3126,7 +3137,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "wasm-bindgen-shared", ] @@ -3208,7 +3219,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -3219,7 +3230,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -3523,7 +3534,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "synstructure", ] @@ -3544,7 +3555,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] [[package]] @@ -3564,7 +3575,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", "synstructure", ] @@ -3604,5 +3615,5 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.109", + "syn 2.0.110", ] diff --git a/Cargo.toml b/Cargo.toml index bb6c380..c2f8c3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,8 @@ flix-tmdb = { path = "crates/tmdb", version = "=0.0.15", default-features = fals seamantic = { version = "0.0.10", default-features = false } -sea-orm = { version = "2.0.0-rc.17", default-features = false } -sea-orm-migration = { version = "2.0.0-rc.17", default-features = false } +sea-orm = { version = "2.0.0-rc.18", default-features = false } +sea-orm-migration = { version = "2.0.0-rc.18", default-features = false } anyhow = { version = "^1", default-features = false } async-stream = { version = "^0.3", default-features = false } diff --git a/crates/cli/src/cli/flix.rs b/crates/cli/src/cli/flix.rs new file mode 100644 index 0000000..b1ec517 --- /dev/null +++ b/crates/cli/src/cli/flix.rs @@ -0,0 +1,12 @@ +use clap::Subcommand; + +#[derive(Subcommand)] +pub enum AddCommand { + /// Process a flix collection + Collection { + #[arg(value_name = "TITLE")] + title: String, + #[arg(value_name = "OVERVIEW")] + overview: String, + }, +} diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index d572d85..bfbab4b 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use anyhow::{Result, anyhow}; use clap::{Parser, Subcommand}; +pub mod flix; pub mod tmdb; #[derive(Parser)] @@ -57,17 +58,17 @@ pub enum Command { /// Add new items to the database Add { #[command(subcommand)] - command: BackendCommand, + command: AddCommand, }, /// Update an existing item in the database Update { #[command(subcommand)] - command: BackendCommand, + command: UpdateCommand, }, /// Delete an existing item in the database Delete { #[command(subcommand)] - command: BackendCommand, + command: DeleteCommand, }, /// Create a toml backup of the database Backup { @@ -84,7 +85,12 @@ pub enum Command { } #[derive(Subcommand)] -pub enum BackendCommand { +pub enum AddCommand { + /// Use the flix backend + Flix { + #[command(subcommand)] + command: flix::AddCommand, + }, /// Use the TMDB backend Tmdb { #[command(subcommand)] @@ -92,7 +98,43 @@ pub enum BackendCommand { }, } -impl From for BackendCommand { +impl From for AddCommand { + fn from(value: flix::AddCommand) -> Self { + Self::Flix { command: value } + } +} + +impl From for AddCommand { + fn from(value: tmdb::Command) -> Self { + Self::Tmdb { command: value } + } +} + +#[derive(Subcommand)] +pub enum UpdateCommand { + /// Use the TMDB backend + Tmdb { + #[command(subcommand)] + command: tmdb::Command, + }, +} + +impl From for UpdateCommand { + fn from(value: tmdb::Command) -> Self { + Self::Tmdb { command: value } + } +} + +#[derive(Subcommand)] +pub enum DeleteCommand { + /// Use the TMDB backend + Tmdb { + #[command(subcommand)] + command: tmdb::Command, + }, +} + +impl From for DeleteCommand { fn from(value: tmdb::Command) -> Self { Self::Tmdb { command: value } } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 303587a..01468b2 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -7,7 +7,7 @@ use clap::Parser; use tokio::fs; mod cli; -use cli::{BackendCommand, Cli, Command}; +use cli::{AddCommand, Cli, Command, DeleteCommand, UpdateCommand}; mod config; use config::Config; @@ -53,11 +53,14 @@ async fn exec_init(database_path: String) -> Result<()> { Ok(()) } -async fn exec_add(client: Client, database_path: String, command: BackendCommand) -> Result<()> { +async fn exec_add(client: Client, database_path: String, command: AddCommand) -> Result<()> { let database = db::open(database_path).await?; match command { - BackendCommand::Tmdb { command } => { + AddCommand::Flix { command } => { + run::flix::add(database.as_ref(), command).await?; + } + AddCommand::Tmdb { command } => { run::tmdb::add(client, database.as_ref(), command).await?; } } @@ -65,11 +68,11 @@ async fn exec_add(client: Client, database_path: String, command: BackendCommand Ok(()) } -async fn exec_update(client: Client, database_path: String, command: BackendCommand) -> Result<()> { +async fn exec_update(client: Client, database_path: String, command: UpdateCommand) -> Result<()> { let database = db::open(database_path).await?; match command { - BackendCommand::Tmdb { command } => { + UpdateCommand::Tmdb { command } => { run::tmdb::update(client, database.as_ref(), command).await?; } } @@ -77,16 +80,11 @@ async fn exec_update(client: Client, database_path: String, command: BackendComm Ok(()) } -async fn exec_delete(client: Client, database_path: String, command: BackendCommand) -> Result<()> { - let database = db::open(database_path).await?; - - match command { - BackendCommand::Tmdb { command } => { - run::tmdb::delete(client, database.as_ref(), command).await?; - } - } - - Ok(()) +async fn exec_delete(client: Client, database_path: String, command: DeleteCommand) -> Result<()> { + _ = client; + _ = database_path; + _ = command; + unimplemented!() } async fn exec_backup(database_path: String, output: PathBuf) -> Result<()> { diff --git a/crates/cli/src/run/flix.rs b/crates/cli/src/run/flix.rs new file mode 100644 index 0000000..06cf2b7 --- /dev/null +++ b/crates/cli/src/run/flix.rs @@ -0,0 +1,41 @@ +use flix::db::entity; +use flix::model::id::CollectionId; + +use anyhow::Result; +use sea_orm::ActiveValue::{NotSet, Set}; +use sea_orm::{ActiveModelTrait, DatabaseConnection, DbErr, TransactionError, TransactionTrait}; + +use crate::cli::flix::AddCommand; + +pub async fn add(db: &DatabaseConnection, command: AddCommand) -> Result<()> { + match command { + AddCommand::Collection { title, overview } => { + let result: Result> = db + .transaction(|txn| { + let title = title.clone(); + + Box::pin(async move { + let flix = entity::info::collections::ActiveModel { + id: NotSet, + title: Set(title), + overview: Set(overview), + } + .insert(txn) + .await?; + + Ok(flix.id) + }) + }) + .await; + + let flix_id = match result { + Ok(id) => id, + Err(TransactionError::Connection(err)) => Err(err)?, + Err(TransactionError::Transaction(err)) => Err(err)?, + }; + println!("Created Collection: {} [{}]", title, flix_id.into_raw()); + + Ok(()) + } + } +} diff --git a/crates/cli/src/run/mod.rs b/crates/cli/src/run/mod.rs index 93cfeb6..9acb9e7 100644 --- a/crates/cli/src/run/mod.rs +++ b/crates/cli/src/run/mod.rs @@ -1 +1,2 @@ +pub mod flix; pub mod tmdb; diff --git a/crates/cli/src/run/tmdb.rs b/crates/cli/src/run/tmdb.rs index cd68982..64fb9ee 100644 --- a/crates/cli/src/run/tmdb.rs +++ b/crates/cli/src/run/tmdb.rs @@ -9,7 +9,7 @@ use flix::tmdb::model::id::{ }; use anyhow::{Context, Result, bail}; -use chrono::Utc; +use chrono::{Datelike, Utc}; use sea_orm::ActiveValue::{NotSet, Set}; use sea_orm::{ ActiveModelTrait, DatabaseConnection, DbErr, EntityTrait, TransactionError, TransactionTrait, @@ -35,6 +35,8 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R .await .with_context(|| format!("collections().get_details({})", id.into_raw()))?; + let title = collection.title.clone(); + let result: Result> = db .transaction(|txn| { Box::pin(async move { @@ -65,7 +67,7 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R Err(TransactionError::Connection(err)) => Err(err)?, Err(TransactionError::Transaction(err)) => Err(err)?, }; - println!("Created Collection: {}", flix_id.into_raw()); + println!("Created Collection: {} [{}]", title, flix_id.into_raw()); Ok(()) } @@ -83,6 +85,9 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R .await .with_context(|| format!("movies().get_details({})", id.into_raw()))?; + let title = movie.title.clone(); + let year = movie.release_date.year(); + let result: Result> = db .transaction(|txn| { Box::pin(async move { @@ -116,7 +121,12 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R Err(TransactionError::Connection(err)) => Err(err)?, Err(TransactionError::Transaction(err)) => Err(err)?, }; - println!("Created Movie: {}", flix_id.into_raw()); + println!( + "Created Movie: {} ({}) [{}]", + title, + year, + flix_id.into_raw(), + ); Ok(()) } @@ -136,6 +146,9 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R let mut seasons = Vec::new(); let mut episodes = HashMap::new(); + let title = show.title.clone(); + let year = show.first_air_date.year(); + for season in 1..=show.number_of_seasons { let season = client .seasons() @@ -264,7 +277,12 @@ pub async fn add(client: Client, db: &DatabaseConnection, command: Command) -> R Err(TransactionError::Connection(err)) => Err(err)?, Err(TransactionError::Transaction(err)) => Err(err)?, }; - println!("Created Show: {}", flix_id.into_raw()); + println!( + "Created Show: {} ({}) [{}]", + title, + year, + flix_id.into_raw() + ); Ok(()) } @@ -498,10 +516,3 @@ pub async fn update(client: Client, database: &DatabaseConnection, command: Comm _ = command; unimplemented!("updates") } - -pub async fn delete(client: Client, database: &DatabaseConnection, command: Command) -> Result<()> { - _ = client; - _ = database; - _ = command; - unimplemented!("deletions") -} diff --git a/crates/fs/src/scanner/collection.rs b/crates/fs/src/scanner/collection.rs index 5e331db..ec3a4d1 100644 --- a/crates/fs/src/scanner/collection.rs +++ b/crates/fs/src/scanner/collection.rs @@ -215,18 +215,19 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; } }; - let path = dir.path(); if filetype.is_dir() { subdirs_to_scan.push(path); continue; @@ -236,7 +237,7 @@ impl Scanner { is_image_extension!() => { if poster_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicatePosterFile), }; continue; @@ -248,7 +249,7 @@ impl Scanner { } Some(_) | None => { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFile), }; } diff --git a/crates/fs/src/scanner/episode.rs b/crates/fs/src/scanner/episode.rs index c00b070..ac7054b 100644 --- a/crates/fs/src/scanner/episode.rs +++ b/crates/fs/src/scanner/episode.rs @@ -60,11 +60,13 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; @@ -72,18 +74,17 @@ impl Scanner { }; if !filetype.is_file() { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedNonFile), }; continue; } - let path = dir.path(); match path.extension().and_then(OsStr::to_str) { is_media_extension!() => { if media_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicateMediaFile), }; continue; @@ -97,7 +98,7 @@ impl Scanner { is_image_extension!() => { if poster_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicatePosterFile), }; continue; @@ -109,7 +110,7 @@ impl Scanner { } Some(_) | None => { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFile), }; } diff --git a/crates/fs/src/scanner/generic.rs b/crates/fs/src/scanner/generic.rs index 1caa3db..fe2ae20 100644 --- a/crates/fs/src/scanner/generic.rs +++ b/crates/fs/src/scanner/generic.rs @@ -211,7 +211,7 @@ impl Scanner { } let media_folder_re = MEDIA_FOLDER_REGEX.get_or_init(|| { - Regex::new(r"^[[[:alnum:]] -]+ \([[:digit:]]+\) \[[[:digit:]]+\]$") + Regex::new(r"^[[[:alnum:]]' -]+ \([[:digit:]]+\) \[[[:digit:]]+\]$") .unwrap_or_else(|err| panic!("regex is invalid: {err}")) }); let season_folder_re = SEASON_FOLDER_REGEX.get_or_init(|| { @@ -257,11 +257,13 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; @@ -271,11 +273,9 @@ impl Scanner { continue; } - let dir_path = dir.path(); - let Some(folder_name) = dir_path.file_name().and_then(OsStr::to_str) - else { + let Some(folder_name) = path.file_name().and_then(OsStr::to_str) else { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFolder), }; continue; diff --git a/crates/fs/src/scanner/movie.rs b/crates/fs/src/scanner/movie.rs index f513dbf..69afda2 100644 --- a/crates/fs/src/scanner/movie.rs +++ b/crates/fs/src/scanner/movie.rs @@ -56,11 +56,13 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; @@ -68,18 +70,17 @@ impl Scanner { }; if !filetype.is_file() { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedNonFile), }; continue; } - let path = dir.path(); match path.extension().and_then(OsStr::to_str) { is_media_extension!() => { if media_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicateMediaFile), }; continue; @@ -93,7 +94,7 @@ impl Scanner { is_image_extension!() => { if poster_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicatePosterFile), }; continue; @@ -105,7 +106,7 @@ impl Scanner { } Some(_) | None => { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFile), }; } diff --git a/crates/fs/src/scanner/season.rs b/crates/fs/src/scanner/season.rs index 84501f0..086ce8d 100644 --- a/crates/fs/src/scanner/season.rs +++ b/crates/fs/src/scanner/season.rs @@ -89,18 +89,19 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; } }; - let path = dir.path(); if filetype.is_dir() { episode_dirs_to_scan.push(path); continue; @@ -110,7 +111,7 @@ impl Scanner { is_image_extension!() => { if poster_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicatePosterFile), }; continue; @@ -122,7 +123,7 @@ impl Scanner { } Some(_) | None => { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFile), }; } @@ -149,7 +150,7 @@ impl Scanner { for episode_dir in episode_dirs_to_scan { let Some(episode_dir_name) = episode_dir.file_name().and_then(OsStr::to_str) else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; @@ -157,14 +158,14 @@ impl Scanner { let Some((_, s_e_str)) = episode_dir_name.split_once('S') else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; }; let Some((s_str, e_str)) = s_e_str.split_once('E') else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; @@ -172,14 +173,14 @@ impl Scanner { let Ok(season_number) = s_str.parse::() else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; }; if season_number != season { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::Inconsistent), }; continue; @@ -191,14 +192,14 @@ impl Scanner { .collect::, _>>() else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; }; let Ok(episode_numbers) = EpisodeNumbers::try_from(episode_numbers.as_ref()) else { yield Item { - path: path.to_owned(), + path: episode_dir, event: Err(Error::UnexpectedFolder), }; continue; diff --git a/crates/fs/src/scanner/show.rs b/crates/fs/src/scanner/show.rs index bafb8ad..32f5215 100644 --- a/crates/fs/src/scanner/show.rs +++ b/crates/fs/src/scanner/show.rs @@ -107,18 +107,19 @@ impl Scanner { for await dir in ReadDirStream::new(dirs) { match dir { Ok(dir) => { + let path = dir.path(); + let filetype = match dir.file_type().await { Ok(filetype) => filetype, Err(err) => { yield Item { - path: path.to_owned(), + path, event: Err(Error::FileType(err)), }; continue; } }; - let path = dir.path(); if filetype.is_dir() { season_dirs_to_scan.push(path); continue; @@ -128,7 +129,7 @@ impl Scanner { is_image_extension!() => { if poster_file_name.is_some() { yield Item { - path: path.to_owned(), + path, event: Err(Error::DuplicatePosterFile), }; continue; @@ -140,7 +141,7 @@ impl Scanner { } Some(_) | None => { yield Item { - path: path.to_owned(), + path, event: Err(Error::UnexpectedFile), }; } @@ -167,7 +168,7 @@ impl Scanner { for season_dir in season_dirs_to_scan { let Some(season_dir_name) = season_dir.file_name().and_then(OsStr::to_str) else { yield Item { - path: path.to_owned(), + path: season_dir, event: Err(Error::UnexpectedFolder), }; continue; @@ -178,7 +179,7 @@ impl Scanner { .map(|(_, s)| s.parse::()) else { yield Item { - path: path.to_owned(), + path: season_dir, event: Err(Error::UnexpectedFolder), }; continue; diff --git a/crates/model/src/numbers.rs b/crates/model/src/numbers.rs index 6f3cd1f..e9e6163 100644 --- a/crates/model/src/numbers.rs +++ b/crates/model/src/numbers.rs @@ -20,7 +20,7 @@ pub enum Error { } /// A wrapper for handling single and multi-episode entries -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EpisodeNumbers(RangeInclusive); @@ -53,8 +53,27 @@ impl TryFrom<&[EpisodeNumber]> for EpisodeNumbers { } impl EpisodeNumbers { + /// Create an [EpisodeNumbers] from a starting number and a count. + /// `count` should be zero for single episodes. + pub fn new(start: EpisodeNumber, count: u8) -> Self { + Self(start..=start.saturating_add(count.into())) + } + /// Get the range of episodes pub fn as_range(&self) -> &RangeInclusive { &self.0 } + + /// Render this [EpisodeNumbers] as a range. If only one episode is + /// is present it renders as `01`, if multiple it renders as `01-02` + pub fn range_string(&self) -> String { + let start = self.0.start(); + let end = self.0.end(); + + if start == end { + format!("{:02}", start) + } else { + format!("{:02}-{:02}", start, end) + } + } }