Skip to content

Commit

Permalink
EBML: add generic conversion to MatroskaTagRef
Browse files Browse the repository at this point in the history
  • Loading branch information
Serial-ATA committed Nov 23, 2024
1 parent d99f902 commit 84bbc45
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 42 deletions.
24 changes: 14 additions & 10 deletions lofty/src/ebml/tag/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use super::{Language, MatroskaTag, SimpleTag, TargetType, TOMBSTONE_SIMPLE_TAG};
use crate::tag::items::Lang;
use crate::tag::{ItemKey, ItemValue, Tag, TagItem, TagType};

use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::LazyLock;

Expand Down Expand Up @@ -203,7 +204,7 @@ fn split_simple_tags(

pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag {
for item in tag.items {
let Some((simple_tag, target_type)) = simple_tag_for_item(item) else {
let Some((simple_tag, target_type)) = simple_tag_for_item(Cow::Owned(item)) else {
continue;
};

Expand All @@ -215,30 +216,33 @@ pub(super) fn merge_tag(tag: Tag, mut matroska_tag: MatroskaTag) -> MatroskaTag
matroska_tag
}

fn simple_tag_for_item(item: TagItem) -> Option<(SimpleTag<'static>, TargetType)> {
pub(super) fn simple_tag_for_item(
item: Cow<'_, TagItem>,
) -> Option<(SimpleTag<'static>, TargetType)> {
if !matches!(item.item_value, ItemValue::Text(_) | ItemValue::Locator(_)) {
return None;
}

let (target_type, simple_tag_name) = REVERSE_MAPPINGS.get(&item.item_key).copied()?;

let TagItem {
mut lang,
item_key,
item_value: ItemValue::Text(text) | ItemValue::Locator(text),
..
} = item
} = item.into_owned()
else {
return None;
};

let Some((target_type, simple_tag_name)) = REVERSE_MAPPINGS.get(&item_key) else {
return None;
};

// Matroska uses "und" for unknown languages
if lang == *b"XXX" {
lang = *b"und";
}

let lang_str = std::str::from_utf8(lang.as_slice()).unwrap_or("und");

let mut simple_tag = SimpleTag::new(simple_tag_name.to_string(), text);
let mut simple_tag = SimpleTag::new((*simple_tag_name).to_string(), text);
simple_tag.language = Language::Iso639_2(lang_str.to_string());

Some((simple_tag, *target_type))
Some((simple_tag, target_type))
}
47 changes: 30 additions & 17 deletions lofty/src/ebml/tag/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::tag::companion_tag::CompanionTag;
use crate::tag::{Accessor, MergeTag, SplitTag, TagExt, TagType};

use std::borrow::Cow;
use std::collections::HashMap;
use std::io::Write;
use std::ops::Deref;

Expand Down Expand Up @@ -405,39 +406,51 @@ impl From<crate::tag::Tag> for MatroskaTag {
}
}

pub(crate) struct MatroskaTagRef<'a, I, S>
pub(crate) struct MatroskaTagRef<'a, I>
where
I: Iterator<Item = TagRef<'a, S>>,
S: Iterator<Item = Cow<'a, SimpleTag<'a>>> + 'a,
I: Iterator<Item = TagRef<'a>>,
{
tags: I,
pub(crate) tags: I,
}

impl<'a, I, S> From<&'a crate::tag::Tag> for MatroskaTagRef<'a, I, S>
where
I: Iterator<Item = TagRef<'a, S>>,
S: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
{
fn from(_tag: &'a crate::tag::Tag) -> Self {
todo!()
pub(crate) fn simple_tags_for_tag(tag: &crate::tag::Tag) -> impl Iterator<Item = TagRef<'static>> {
let mut mapped_tags: HashMap<TargetType, Vec<Cow<'static, SimpleTag<'static>>>> =
HashMap::new();
for item in &tag.items {
if let Some((simple_tag, target_type)) = generic::simple_tag_for_item(Cow::Borrowed(item)) {
mapped_tags
.entry(target_type)
.or_default()
.push(Cow::Owned(simple_tag))
}
}

mapped_tags
.into_iter()
.map(|(target_type, simple_tags)| TagRef {
targets: TargetDescriptor::Basic(target_type),
simple_tags: Box::new(simple_tags.into_iter()),
})
}

impl<'a, I, S> MatroskaTagRef<'a, I, S>
impl<'a, I> MatroskaTagRef<'a, I>
where
I: Iterator<Item = TagRef<'a, S>>,
S: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
I: Iterator<Item = TagRef<'a>>,
{
pub(crate) fn write_to<F>(&mut self, _file: &mut F, _write_options: WriteOptions) -> Result<()>
where
F: FileLike,
LoftyError: From<<F as Truncate>::Error>,
LoftyError: From<<F as Length>::Error>,
{
todo!()
todo!("Writing matroska tags")
}

fn dump_to<W: Write>(&self, _writer: &mut W, _write_options: WriteOptions) -> Result<()> {
todo!()
pub(crate) fn dump_to<W: Write>(
&self,
_writer: &mut W,
_write_options: WriteOptions,
) -> Result<()> {
todo!("Dumping matroska tags")
}
}
7 changes: 2 additions & 5 deletions lofty/src/ebml/tag/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,7 @@ impl Tag<'static> {
}
}

pub(crate) struct TagRef<'a, I>
where
I: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
{
pub(crate) struct TagRef<'a> {
pub(crate) targets: TargetDescriptor<'a>,
pub(crate) simple_tags: &'a mut I,
pub(crate) simple_tags: Box<dyn Iterator<Item = Cow<'a, SimpleTag<'a>>>>,
}
8 changes: 2 additions & 6 deletions lofty/src/ebml/tag/write/elements/tags.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use crate::ebml::tag::write::{write_element, ElementWriterCtx, WriteableElement};
use crate::ebml::{ElementId, SimpleTag, TagRef};
use crate::ebml::{ElementId, TagRef};
use crate::io::FileLike;

use std::borrow::Cow;
use std::io::Cursor;

impl<'a, I> WriteableElement for TagRef<'a, I>
where
I: Iterator<Item = Cow<'a, SimpleTag<'a>>>,
{
impl WriteableElement for TagRef<'_> {
const ID: ElementId = ElementId(0x7373);

fn write_element<F: FileLike>(
Expand Down
7 changes: 4 additions & 3 deletions lofty/src/tag/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,10 @@ pub(crate) fn dump_tag<W: Write>(
}
}
.dump_to(writer, write_options),
TagType::Matroska => {
todo!("Dump EBML tags")
},
TagType::Matroska => ebml::tag::MatroskaTagRef {
tags: ebml::tag::simple_tags_for_tag(tag),
}
.dump_to(writer, write_options),
_ => Ok(()),
}
}
Expand Down
7 changes: 6 additions & 1 deletion lofty_attr/src/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ pub(crate) fn init_write_lookup(
.write_to(file, write_options)
});

insert!(map, Matroska, { todo!("Generated Matroska tag writer") });
insert!(map, Matroska, {
lofty::ebml::tag::MatroskaTagRef {
tags: lofty::ebml::tag::simple_tags_for_tag(tag),
}
.write_to(file, write_options)
});

insert!(map, Id3v1, {
Into::<lofty::id3::v1::tag::Id3v1TagRef<'_>>::into(tag).write_to(file, write_options)
Expand Down

0 comments on commit 84bbc45

Please sign in to comment.