use super::*;
pub(super) fn build_style_fragments(ctx: &mut ExportContext) -> Vec<KfxFragment> {
let style_pairs = ctx.style_registry.drain_to_ion();
style_pairs
.into_iter()
.map(|(name, ion)| KfxFragment::new(KfxSymbol::Style, &name, ion))
.collect()
}
pub(super) fn build_metadata_fragment(ctx: &ExportContext) -> KfxFragment {
let sections: Vec<IonValue> = ctx
.section_ids
.iter()
.map(|&id| IonValue::Symbol(id))
.collect();
let reading_order = IonValue::Struct(vec![
(
KfxSymbol::ReadingOrderName as u64,
IonValue::Symbol(KfxSymbol::Default as u64),
),
(KfxSymbol::Sections as u64, IonValue::List(sections)),
]);
let reading_orders = IonValue::List(vec![reading_order]);
let metadata = IonValue::Struct(vec![(KfxSymbol::ReadingOrders as u64, reading_orders)]);
KfxFragment::singleton(KfxSymbol::Metadata, metadata)
}
pub(super) fn build_book_metadata_fragment(
book: &Book,
container_id: &str,
ctx: &ExportContext,
) -> KfxFragment {
let meta = book.metadata();
let cover_resource_name = meta.cover_image.as_ref().and_then(|path| {
if let Some(name) = ctx.resource_registry.get_name(path) {
return Some(name);
}
let with_prefix = format!("epub/{}", path);
if let Some(name) = ctx.resource_registry.get_name(&with_prefix) {
return Some(name);
}
let filename = std::path::Path::new(path)
.file_name()
.and_then(|n| n.to_str())?;
for (href, _) in ctx.resource_registry.iter() {
if href.ends_with(filename) {
return ctx.resource_registry.get_name(href);
}
}
None
});
let book_id = if !meta.identifier.is_empty() {
Some(generate_book_id(&meta.identifier))
} else {
None
};
let meta_ctx = MetadataContext {
version: Some(env!("CARGO_PKG_VERSION")),
cover_resource_name,
asset_id: Some(container_id),
book_id,
};
let categories = [
MetadataCategory::KindleEbook,
MetadataCategory::KindleTitle,
MetadataCategory::KindleAudit,
];
let categorised: Vec<IonValue> = categories
.iter()
.map(|&cat| {
let entries = build_category_entries(cat, meta, &meta_ctx);
let ion_entries: Vec<IonValue> = entries
.into_iter()
.map(|(k, v)| metadata_kv(k, &v))
.collect();
IonValue::Struct(vec![
(
KfxSymbol::Category as u64,
IonValue::String(cat.as_str().to_string()),
),
(KfxSymbol::Metadata as u64, IonValue::List(ion_entries)),
])
})
.collect();
let book_metadata = IonValue::Struct(vec![(
KfxSymbol::CategorisedMetadata as u64,
IonValue::List(categorised),
)]);
KfxFragment::singleton(KfxSymbol::BookMetadata, book_metadata)
}
pub(super) fn metadata_kv(key: &str, value: &str) -> IonValue {
IonValue::Struct(vec![
(KfxSymbol::Key as u64, IonValue::String(key.to_string())),
(KfxSymbol::Value as u64, IonValue::String(value.to_string())),
])
}
pub(super) fn build_content_features_fragment() -> KfxFragment {
let reflow_style = IonValue::Struct(vec![
(
KfxSymbol::Namespace as u64,
IonValue::String("com.amazon.yjconversion".to_string()),
),
(
KfxSymbol::Key as u64,
IonValue::String("reflow-style".to_string()),
),
(
KfxSymbol::VersionInfo as u64,
IonValue::Struct(vec![(
KfxSymbol::Version as u64,
IonValue::Struct(vec![
(KfxSymbol::MajorVersion as u64, IonValue::Int(6)),
(KfxSymbol::MinorVersion as u64, IonValue::Int(0)),
]),
)]),
),
]);
let canonical_format = IonValue::Struct(vec![
(
KfxSymbol::Namespace as u64,
IonValue::String("SDK.Marker".to_string()),
),
(
KfxSymbol::Key as u64,
IonValue::String("CanonicalFormat".to_string()),
),
(
KfxSymbol::VersionInfo as u64,
IonValue::Struct(vec![(
KfxSymbol::Version as u64,
IonValue::Struct(vec![
(KfxSymbol::MajorVersion as u64, IonValue::Int(1)),
(KfxSymbol::MinorVersion as u64, IonValue::Int(0)),
]),
)]),
),
]);
let yj_hdv = IonValue::Struct(vec![
(
KfxSymbol::Namespace as u64,
IonValue::String("com.amazon.yjconversion".to_string()),
),
(
KfxSymbol::Key as u64,
IonValue::String("yj_hdv".to_string()),
),
(
KfxSymbol::VersionInfo as u64,
IonValue::Struct(vec![(
KfxSymbol::Version as u64,
IonValue::Struct(vec![
(KfxSymbol::MajorVersion as u64, IonValue::Int(1)),
(KfxSymbol::MinorVersion as u64, IonValue::Int(0)),
]),
)]),
),
]);
let content_features = IonValue::Struct(vec![(
KfxSymbol::Features as u64,
IonValue::List(vec![reflow_style, canonical_format, yj_hdv]),
)]);
KfxFragment::singleton(KfxSymbol::ContentFeatures, content_features)
}
pub(super) fn build_document_data_fragment(ctx: &ExportContext) -> KfxFragment {
let sections: Vec<IonValue> = ctx
.section_ids
.iter()
.map(|&id| IonValue::Symbol(id))
.collect();
let reading_order = IonValue::Struct(vec![
(
KfxSymbol::ReadingOrderName as u64,
IonValue::Symbol(KfxSymbol::Default as u64),
),
(KfxSymbol::Sections as u64, IonValue::List(sections)),
]);
let max_id = ctx.max_eid();
let document_data = IonValue::Struct(vec![
(
KfxSymbol::Direction as u64,
IonValue::Symbol(KfxSymbol::Ltr as u64),
),
(
KfxSymbol::ColumnCount as u64,
IonValue::Symbol(KfxSymbol::Auto as u64),
),
(
KfxSymbol::FontSize as u64,
IonValue::Struct(vec![
(KfxSymbol::Value as u64, IonValue::Decimal("1".to_string())),
(
KfxSymbol::Unit as u64,
IonValue::Symbol(KfxSymbol::Em as u64),
),
]),
),
(
KfxSymbol::WritingMode as u64,
IonValue::Symbol(KfxSymbol::HorizontalTb as u64),
),
(
KfxSymbol::Selection as u64,
IonValue::Symbol(KfxSymbol::Enabled as u64),
),
(KfxSymbol::MaxId as u64, IonValue::Int(max_id as i64)),
(
KfxSymbol::LineHeight as u64,
IonValue::Struct(vec![
(
KfxSymbol::Value as u64,
IonValue::Decimal("1.2".to_string()),
),
(
KfxSymbol::Unit as u64,
IonValue::Symbol(KfxSymbol::Em as u64),
),
]),
),
(
KfxSymbol::SpacingPercentBase as u64,
IonValue::Symbol(KfxSymbol::Width as u64),
),
(
KfxSymbol::ReadingOrders as u64,
IonValue::List(vec![reading_order]),
),
]);
KfxFragment::singleton(KfxSymbol::DocumentData, document_data)
}