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}