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