refactor(domain): Row structs for from_persistence, ID newtypes, kill clippy.toml

- delete clippy.toml (too-many-arguments-threshold=20 hack)
- ChannelRow/MediaItemRow/LibraryItemRow structs for from_persistence
- SnapshotId/ActivityEventId/PlaybackRecordId newtypes
- DomainError variants use ChannelId/UserId instead of Uuid
- ActivityEvent.channel_id: Option<ChannelId> not Option<Uuid>
- InMemory repos key on newtype IDs
- AlgorithmicParams struct for schedule engine
- update all adapters/application/presentation callers
This commit is contained in:
2026-07-12 05:00:49 +02:00
parent 031cba5cfb
commit c0e685a4ee
65 changed files with 684 additions and 695 deletions

View File

@@ -21,6 +21,15 @@ struct BlockTimeWindow {
end: DateTime<Utc>,
}
struct AlgorithmicParams<'a> {
provider_id: &'a str,
filter: &'a MediaFilter,
strategy: &'a FillStrategy,
block_id: BlockId,
loop_on_finish: bool,
ignore_recycle_policy: bool,
}
struct RecycleContext<'a> {
history: &'a [PlaybackRecord],
policy: &'a RecyclePolicy,
@@ -59,7 +68,7 @@ impl ScheduleEngineService {
.channel_query
.find_by_id(channel_id)
.await?
.ok_or(DomainError::ChannelNotFound(channel_id.value()))?;
.ok_or(DomainError::ChannelNotFound(channel_id))?;
let tz: Tz = channel
.timezone()
@@ -259,14 +268,16 @@ impl ScheduleEngineService {
provider_id,
} => {
self.resolve_algorithmic(
provider_id,
filter,
strategy,
AlgorithmicParams {
provider_id,
filter,
strategy,
block_id: block.id(),
loop_on_finish: block.loop_on_finish(),
ignore_recycle_policy: block.ignore_recycle_policy(),
},
window,
recycle,
block.id(),
block.loop_on_finish(),
block.ignore_recycle_policy(),
)
.await
}
@@ -300,25 +311,20 @@ impl ScheduleEngineService {
async fn resolve_algorithmic(
&self,
provider_id: &str,
filter: &MediaFilter,
strategy: &FillStrategy,
params: AlgorithmicParams<'_>,
window: BlockTimeWindow,
recycle: RecycleContext<'_>,
block_id: BlockId,
loop_on_finish: bool,
ignore_recycle_policy: bool,
) -> DomainResult<Vec<ScheduledSlot>> {
let candidates = self
.provider_registry
.fetch_items(provider_id, filter)
.fetch_items(params.provider_id, params.filter)
.await?;
if candidates.is_empty() {
return Ok(vec![]);
}
let pool = if ignore_recycle_policy {
let pool = if params.ignore_recycle_policy {
candidates.clone()
} else {
recycle::apply_recycle_policy(&candidates, recycle.history, recycle.policy, recycle.generation)
@@ -328,9 +334,9 @@ impl ScheduleEngineService {
&candidates,
&pool,
target_secs,
strategy,
params.strategy,
recycle.last_item_id,
loop_on_finish,
params.loop_on_finish,
);
let mut slots = Vec::new();
@@ -342,7 +348,7 @@ impl ScheduleEngineService {
}
let item_end =
(cursor + Duration::seconds(item.duration_secs() as i64)).min(window.end);
slots.push(ScheduledSlot::new(cursor, item_end, item.clone(), block_id));
slots.push(ScheduledSlot::new(cursor, item_end, item.clone(), params.block_id));
cursor = item_end;
}