refactor/tighten-architecture #26
41
Cargo.lock
generated
41
Cargo.lock
generated
@@ -921,13 +921,11 @@ dependencies = [
|
||||
"export",
|
||||
"image-converter",
|
||||
"importer",
|
||||
"jellyfin",
|
||||
"media-server",
|
||||
"metadata",
|
||||
"nats",
|
||||
"object-storage",
|
||||
"plex",
|
||||
"poster-fetcher",
|
||||
"poster-sync",
|
||||
"presentation",
|
||||
"rss 0.1.0",
|
||||
"sqlite",
|
||||
@@ -2852,15 +2850,6 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||
|
||||
[[package]]
|
||||
name = "jellyfin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"domain",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.22.4"
|
||||
@@ -3224,6 +3213,15 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "media-server"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"domain",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
@@ -3909,15 +3907,6 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||
|
||||
[[package]]
|
||||
name = "plex"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"domain",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.18.1"
|
||||
@@ -3962,16 +3951,6 @@ dependencies = [
|
||||
"reqwest 0.13.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "poster-sync"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"domain",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.5"
|
||||
|
||||
12
Cargo.toml
12
Cargo.toml
@@ -5,14 +5,13 @@ members = [
|
||||
"crates/adapters/metadata",
|
||||
"crates/adapters/poster-fetcher",
|
||||
"crates/adapters/object-storage",
|
||||
"crates/adapters/poster-sync",
|
||||
"crates/adapters/rss",
|
||||
"crates/adapters/sqlite",
|
||||
"crates/adapters/sqlite-federation",
|
||||
"crates/adapters/template-askama",
|
||||
"crates/adapters/activitypub",
|
||||
"crates/adapters/export",
|
||||
"crates/adapters/event-payload",
|
||||
"crates/event-payload",
|
||||
"crates/adapters/nats",
|
||||
"crates/api-types",
|
||||
"crates/application",
|
||||
@@ -25,8 +24,7 @@ members = [
|
||||
"crates/tui",
|
||||
"crates/worker",
|
||||
"crates/adapters/importer",
|
||||
"crates/adapters/jellyfin",
|
||||
"crates/adapters/plex",
|
||||
"crates/adapters/media-server",
|
||||
"crates/config",
|
||||
]
|
||||
resolver = "2"
|
||||
@@ -75,7 +73,6 @@ auth = { path = "crates/adapters/auth" }
|
||||
metadata = { path = "crates/adapters/metadata" }
|
||||
poster-fetcher = { path = "crates/adapters/poster-fetcher" }
|
||||
object-storage = { path = "crates/adapters/object-storage" }
|
||||
poster-sync = { path = "crates/adapters/poster-sync" }
|
||||
event-publisher = { path = "crates/adapters/event-publisher" }
|
||||
rss = { path = "crates/adapters/rss" }
|
||||
export = { path = "crates/adapters/export" }
|
||||
@@ -83,11 +80,10 @@ sqlite = { path = "crates/adapters/sqlite" }
|
||||
sqlite-federation = { path = "crates/adapters/sqlite-federation" }
|
||||
template-askama = { path = "crates/adapters/template-askama" }
|
||||
activitypub = { path = "crates/adapters/activitypub" }
|
||||
event-payload = { path = "crates/adapters/event-payload" }
|
||||
event-payload = { path = "crates/event-payload" }
|
||||
media-server = { path = "crates/adapters/media-server" }
|
||||
nats = { path = "crates/adapters/nats" }
|
||||
importer = { path = "crates/adapters/importer" }
|
||||
jellyfin = { path = "crates/adapters/jellyfin" }
|
||||
plex = { path = "crates/adapters/plex" }
|
||||
image-converter = { path = "crates/adapters/image-converter" }
|
||||
config = { path = "crates/config" }
|
||||
|
||||
|
||||
@@ -20,17 +20,15 @@ COPY Cargo.toml Cargo.lock ./
|
||||
COPY .cargo ./.cargo
|
||||
COPY crates/adapters/activitypub/Cargo.toml crates/adapters/activitypub/Cargo.toml
|
||||
COPY crates/adapters/auth/Cargo.toml crates/adapters/auth/Cargo.toml
|
||||
COPY crates/adapters/event-payload/Cargo.toml crates/adapters/event-payload/Cargo.toml
|
||||
COPY crates/event-payload/Cargo.toml crates/event-payload/Cargo.toml
|
||||
COPY crates/adapters/event-publisher/Cargo.toml crates/adapters/event-publisher/Cargo.toml
|
||||
COPY crates/adapters/nats/Cargo.toml crates/adapters/nats/Cargo.toml
|
||||
COPY crates/adapters/metadata/Cargo.toml crates/adapters/metadata/Cargo.toml
|
||||
COPY crates/adapters/poster-fetcher/Cargo.toml crates/adapters/poster-fetcher/Cargo.toml
|
||||
COPY crates/adapters/object-storage/Cargo.toml crates/adapters/object-storage/Cargo.toml
|
||||
COPY crates/adapters/poster-sync/Cargo.toml crates/adapters/poster-sync/Cargo.toml
|
||||
COPY crates/adapters/export/Cargo.toml crates/adapters/export/Cargo.toml
|
||||
COPY crates/adapters/importer/Cargo.toml crates/adapters/importer/Cargo.toml
|
||||
COPY crates/adapters/jellyfin/Cargo.toml crates/adapters/jellyfin/Cargo.toml
|
||||
COPY crates/adapters/plex/Cargo.toml crates/adapters/plex/Cargo.toml
|
||||
COPY crates/adapters/media-server/Cargo.toml crates/adapters/media-server/Cargo.toml
|
||||
COPY crates/adapters/rss/Cargo.toml crates/adapters/rss/Cargo.toml
|
||||
COPY crates/adapters/sqlite/Cargo.toml crates/adapters/sqlite/Cargo.toml
|
||||
COPY crates/adapters/sqlite-federation/Cargo.toml crates/adapters/sqlite-federation/Cargo.toml
|
||||
|
||||
@@ -104,16 +104,13 @@ adapters/
|
||||
metadata — TMDB / OMDb HTTP client
|
||||
poster-fetcher — downloads poster images
|
||||
object-storage — stores images (posters + user avatars) on local filesystem or S3-compatible storage
|
||||
poster-sync — event handler: triggers poster fetch+store on MovieDiscovered
|
||||
image-converter — optional background worker: converts stored images to AVIF or WebP; backfills existing images via a 24h periodic job
|
||||
tmdb-enrichment — TMDb HTTP client implementing MovieEnrichmentClient and PersonEnrichmentClient; event handlers (MovieEnrichmentHandler, PersonEnrichmentHandler) live in the application layer
|
||||
template-askama — Askama HTML rendering
|
||||
rss — RSS/Atom feed generation
|
||||
export — CSV and JSON diary serialization
|
||||
importer — CSV/TSV/JSON/XLSX parser and column mapper for bulk import
|
||||
jellyfin — Jellyfin webhook payload parser (MediaServerParser adapter)
|
||||
plex — Plex webhook payload parser (MediaServerParser adapter; requires Plex Pass)
|
||||
event-payload — shared event serialization DTOs (used by all event bus adapters)
|
||||
media-server — Jellyfin and Plex webhook payload parsers (MediaServerParser adapter; Plex requires Plex Pass)
|
||||
event-publisher — in-memory event channel (used in tests)
|
||||
nats — NATS Core / JetStream event publisher and consumer
|
||||
activitypub — ActivityPub federation adapter (follow, inbox/outbox, actor); delegates to k-ap for protocol internals
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "image-converter"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
config = { workspace = true }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "jellyfin"
|
||||
name = "media-server"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
|
||||
@@ -60,5 +60,5 @@ struct JellyfinPayload {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/lib.rs"]
|
||||
#[path = "tests/jellyfin.rs"]
|
||||
mod tests;
|
||||
5
crates/adapters/media-server/src/lib.rs
Normal file
5
crates/adapters/media-server/src/lib.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod jellyfin;
|
||||
mod plex;
|
||||
|
||||
pub use jellyfin::JellyfinParser;
|
||||
pub use plex::PlexParser;
|
||||
@@ -70,5 +70,5 @@ struct PlexGuid {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/lib.rs"]
|
||||
#[path = "tests/plex.rs"]
|
||||
mod tests;
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "plex"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
domain = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "poster-fetcher"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
config = { workspace = true }
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "poster-sync"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
domain = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
@@ -6,6 +6,7 @@ pub mod event_handler;
|
||||
pub mod get_movie_profile;
|
||||
pub mod get_movies;
|
||||
pub mod merge_duplicates;
|
||||
pub mod poster_sync;
|
||||
pub mod queries;
|
||||
pub mod reindex_search;
|
||||
pub mod request_enrichment;
|
||||
|
||||
@@ -22,14 +22,12 @@ auth = { workspace = true }
|
||||
metadata = { workspace = true }
|
||||
poster-fetcher = { workspace = true }
|
||||
object-storage = { workspace = true }
|
||||
poster-sync = { workspace = true }
|
||||
tmdb-enrichment = { workspace = true }
|
||||
image-converter = { workspace = true }
|
||||
export = { workspace = true }
|
||||
importer = { workspace = true }
|
||||
rss = { workspace = true }
|
||||
jellyfin = { workspace = true }
|
||||
plex = { workspace = true }
|
||||
media-server = { workspace = true }
|
||||
sqlite = { workspace = true }
|
||||
sqlx = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -210,8 +210,8 @@ pub fn build_deps(
|
||||
revoke_webhook_token: RevokeWebhookTokenDeps {
|
||||
webhook_token: repos.webhook_token.clone(),
|
||||
},
|
||||
jellyfin_parser: std::sync::Arc::new(jellyfin::JellyfinParser),
|
||||
plex_parser: std::sync::Arc::new(plex::PlexParser),
|
||||
jellyfin_parser: std::sync::Arc::new(media_server::JellyfinParser),
|
||||
plex_parser: std::sync::Arc::new(media_server::PlexParser),
|
||||
},
|
||||
movies: MoviesGroup {
|
||||
sync_poster: SyncPosterDeps {
|
||||
|
||||
@@ -167,7 +167,7 @@ pub async fn build_worker(config: &config::AppConfig) -> anyhow::Result<WorkerAp
|
||||
// ── Event handlers ────────────────────────────────────────────────────────
|
||||
|
||||
let handlers: Vec<Arc<dyn EventHandler>> = {
|
||||
let poster = Arc::new(poster_sync::PosterSyncHandler::new(
|
||||
let poster = Arc::new(application::movies::poster_sync::PosterSyncHandler::new(
|
||||
Arc::clone(&movie_command),
|
||||
Arc::clone(&movie_query),
|
||||
Arc::clone(&metadata),
|
||||
|
||||
Reference in New Issue
Block a user