ddex_builder/presets/mod.rs
1//! # DDEX Configuration Presets
2//!
3//! This module provides pre-configured settings for DDEX message generation.
4//! Presets are community-maintained configuration templates that help ensure
5//! DDEX compliance and reduce configuration complexity.
6//!
7//! ## Available Presets
8//!
9//! ### Generic Industry-Standard Presets
10//! - **audio_album**: DDEX-compliant audio album configuration
11//! - **audio_single**: DDEX-compliant single track configuration
12//! - **video_single**: DDEX-compliant video release configuration
13//! - **compilation**: DDEX-compliant compilation album configuration
14//!
15//! ### Platform Presets (Based on Public Documentation)
16//! - **YouTube Music**: Audio and video releases (based on public Partner docs)
17//!
18//! ## Architecture
19//!
20//! ```text
21//! Preset System
22//! ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
23//! │ Base Config │───▶│ Partner Rules │───▶│ Final Settings │
24//! │ (DDEX defaults) │ │ (customizations) │ │ (ready to use) │
25//! └─────────────────┘ └──────────────────┘ └─────────────────┘
26//! │ │ │
27//! ▼ ▼ ▼
28//! ┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
29//! │ • Version │ │ • Required │ │ • Validation │
30//! │ • Profile │ │ • Validation │ │ • Defaults │
31//! │ • Schema │ │ • Territories │ │ • Mappings │
32//! │ • Defaults │ │ • Quality │ │ • Overrides │
33//! └─────────────┘ └─────────────────┘ └─────────────────┘
34//! ```
35//!
36//! ## Usage Example
37//!
38//! ```rust
39//! use ddex_builder::presets::*;
40//! use ddex_builder::Builder;
41//!
42//! // Use generic audio album preset
43//! let mut builder = Builder::new();
44//! builder.apply_preset(&generic::audio_album())?;
45//!
46//! // Use YouTube preset for video content
47//! builder.apply_preset(&youtube::youtube_video())?;
48//!
49//! // Load by name
50//! let presets = all_presets();
51//! let audio_album = &presets["audio_album"];
52//! builder.apply_partner_preset(audio_album)?;
53//!
54//! // List available presets
55//! for (name, preset) in all_presets() {
56//! println!("{}: {}", name, preset.description);
57//! }
58//! ```
59//!
60//! ## Preset Features
61//!
62//! Each preset includes:
63//!
64//! - **Schema Version**: DDEX ERN version (3.8.2, 4.2, 4.3)
65//! - **Message Profile**: Audio, Video, or Mixed content
66//! - **Required Fields**: Mandatory metadata fields
67//! - **Validation Rules**: Data format and quality requirements
68//! - **Default Values**: Common field defaults
69//! - **Territory Codes**: Allowed distribution territories
70//! - **Quality Standards**: Audio/video quality minimums
71//!
72//! ## Custom Presets
73//!
74//! Create your own preset for internal standards:
75//!
76//! ```rust
77//! use ddex_builder::presets::*;
78//! use indexmap::IndexMap;
79//!
80//! // Start with a generic preset as base
81//! let mut custom_preset = generic::audio_album();
82//! custom_preset.name = "my_label_preset".to_string();
83//! custom_preset.description = "My Record Label Requirements".to_string();
84//!
85//! // Add custom validation rules
86//! custom_preset.validation_rules.insert(
87//! "Genre".to_string(),
88//! ValidationRule::OneOf(vec!["Rock".to_string(), "Pop".to_string()])
89//! );
90//!
91//! // Add custom territory restrictions
92//! custom_preset.config.territory_codes = vec!["US".to_string(), "CA".to_string()];
93//! ```
94//!
95//! ## Validation Rules
96//!
97//! Presets support comprehensive validation:
98//!
99//! - **Required**: Field must be present
100//! - **MinLength/MaxLength**: String length constraints
101//! - **Pattern**: Regex pattern matching
102//! - **OneOf**: Value must be from allowed list
103//! - **AudioQuality**: Minimum bit depth and sample rate
104//! - **TerritoryCode**: Allowed distribution territories
105//! - **Custom**: Partner-specific validation logic
106
107pub mod generic;
108pub mod youtube;
109
110use indexmap::IndexMap;
111use serde::{Deserialize, Serialize};
112
113/// DDEX version for presets
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
115pub enum DdexVersion {
116 /// ERN 3.8.2
117 #[serde(rename = "ERN/3.8.2")]
118 Ern382,
119 /// ERN 4.2
120 #[serde(rename = "ERN/4.2")]
121 Ern42,
122 /// ERN 4.3
123 #[serde(rename = "ERN/4.3")]
124 Ern43,
125 /// ERN 4.1
126 #[serde(rename = "ERN/4.1")]
127 Ern41,
128}
129
130impl std::fmt::Display for DdexVersion {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 DdexVersion::Ern382 => write!(f, "ERN/3.8.2"),
134 DdexVersion::Ern42 => write!(f, "ERN/4.2"),
135 DdexVersion::Ern43 => write!(f, "ERN/4.3"),
136 DdexVersion::Ern41 => write!(f, "ERN/4.1"),
137 }
138 }
139}
140
141/// Message profile type
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
143pub enum MessageProfile {
144 /// Audio album release
145 AudioAlbum,
146 /// Audio single release
147 AudioSingle,
148 /// Video album release
149 VideoAlbum,
150 /// Video single release
151 VideoSingle,
152 /// Mixed content release
153 Mixed,
154}
155
156/// Validation rule for preset
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub enum ValidationRule {
159 /// Field is required
160 Required,
161 /// Minimum length requirement
162 MinLength(usize),
163 /// Maximum length requirement
164 MaxLength(usize),
165 /// Must match regex pattern
166 Pattern(String),
167 /// Must be one of specified values
168 OneOf(Vec<String>),
169 /// Audio quality requirements
170 AudioQuality {
171 /// Minimum bit depth in bits
172 min_bit_depth: u8,
173 /// Minimum sample rate in Hz
174 min_sample_rate: u32,
175 },
176 /// Territory code restrictions
177 TerritoryCode {
178 /// List of allowed territory codes
179 allowed: Vec<String>,
180 },
181 /// Custom validation rule
182 Custom(String),
183}
184
185/// Preset defaults configuration
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct PresetConfig {
188 /// DDEX version to use
189 pub version: DdexVersion,
190 /// Message profile type
191 pub profile: MessageProfile,
192 /// Required fields list
193 pub required_fields: Vec<String>,
194 /// Validation rules by field name
195 pub validation_rules: IndexMap<String, ValidationRule>,
196 /// Default values by field name
197 pub default_values: IndexMap<String, String>,
198 /// Custom field mappings
199 pub custom_mappings: IndexMap<String, String>,
200 /// Supported territory codes
201 pub territory_codes: Vec<String>,
202 /// Supported distribution channels
203 pub distribution_channels: Vec<String>,
204 /// Supported release types
205 pub release_types: Vec<String>,
206}
207
208/// Partner preset configuration
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct PartnerPreset {
211 /// Preset name
212 pub name: String,
213 /// Preset description
214 pub description: String,
215 /// Source of preset definition
216 pub source: PresetSource,
217 /// URL to documentation
218 pub provenance_url: Option<String>,
219 /// Preset version
220 pub version: String,
221 /// Whether preset is locked from editing
222 pub locked: bool,
223 /// Legal disclaimer
224 pub disclaimer: String,
225 /// Determinism configuration
226 pub determinism: super::determinism::DeterminismConfig,
227 /// Default values for preset
228 pub defaults: PresetDefaults,
229 /// Required fields that must be present for this partner
230 pub required_fields: Vec<String>,
231 /// Format overrides for specific fields (field_name -> format_string)
232 pub format_overrides: IndexMap<String, String>,
233 // Enhanced fields
234 /// Preset configuration settings
235 pub config: PresetConfig,
236 /// Validation rules specific to this partner
237 pub validation_rules: IndexMap<String, ValidationRule>,
238 /// Custom field mappings for partner-specific requirements
239 pub custom_mappings: IndexMap<String, String>,
240}
241
242/// Source of preset definition
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
244pub enum PresetSource {
245 /// Official public documentation from partner
246 PublicDocs,
247 /// Based on customer feedback and testing
248 CustomerFeedback,
249 /// Community-contributed preset
250 Community,
251}
252
253/// Preset configuration options
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct PresetDefaults {
256 /// Type of message control (e.g., "NewReleaseMessage")
257 pub message_control_type: Option<String>,
258 /// Territory codes this preset applies to
259 pub territory_code: Vec<String>,
260 /// Distribution channels (e.g., "Streaming", "Download")
261 pub distribution_channel: Vec<String>,
262}
263
264/// Get all built-in presets
265///
266/// Returns a collection of community-maintained DDEX configuration presets.
267/// These presets provide baseline DDEX-compliant configurations and platform-specific
268/// templates based on publicly available documentation.
269pub fn all_presets() -> IndexMap<String, PartnerPreset> {
270 let mut presets = IndexMap::new();
271
272 // Generic industry-standard presets
273 presets.extend(generic::all_generic_presets());
274
275 // Platform presets (based on public documentation)
276 presets.extend(youtube::all_youtube_presets());
277
278 presets
279}