Support flix collections

This commit is contained in:
2025-12-08 20:33:13 -08:00
parent c2fb43de30
commit dd2cf5c942
15 changed files with 277 additions and 137 deletions
Generated
+75 -64
View File
@@ -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",
]
+2 -2
View File
@@ -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 }
+12
View File
@@ -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,
},
}
+47 -5
View File
@@ -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<tmdb::Command> for BackendCommand {
impl From<flix::AddCommand> for AddCommand {
fn from(value: flix::AddCommand) -> Self {
Self::Flix { command: value }
}
}
impl From<tmdb::Command> 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<tmdb::Command> 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<tmdb::Command> for DeleteCommand {
fn from(value: tmdb::Command) -> Self {
Self::Tmdb { command: value }
}
+13 -15
View File
@@ -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<()> {
+41
View File
@@ -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<CollectionId, TransactionError<DbErr>> = 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(())
}
}
}
+1
View File
@@ -1 +1,2 @@
pub mod flix;
pub mod tmdb;
+22 -11
View File
@@ -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<CollectionId, TransactionError<DbErr>> = 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<MovieId, TransactionError<DbErr>> = 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")
}
+5 -4
View File
@@ -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),
};
}
+7 -6
View File
@@ -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),
};
}
+6 -6
View File
@@ -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;
+7 -6
View File
@@ -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),
};
}
+12 -11
View File
@@ -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::<SeasonNumber>() 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::<Result<Vec<_>, _>>()
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;
+7 -6
View File
@@ -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::<SeasonNumber>())
else {
yield Item {
path: path.to_owned(),
path: season_dir,
event: Err(Error::UnexpectedFolder),
};
continue;
+20 -1
View File
@@ -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<EpisodeNumber>);
@@ -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<EpisodeNumber> {
&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)
}
}
}