Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions crates/ersatztv-playout-generator/src/xmltv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,21 @@ fn read_existing_programmes(
let stop = OffsetDateTime::parse(&stop_s, &XMLTV_FMT)?;

let mut title = String::new();
let mut in_title = false;
loop {
match reader
.read_event_into(&mut inner_buf)
.map_err(std::io::Error::other)?
{
Event::Start(t) if t.name().as_ref() == b"title" => in_title = true,
Event::End(t) if t.name().as_ref() == b"title" => in_title = false,
Event::Text(t) if in_title => title.push_str(
&t.xml_content(XmlVersion::Implicit1_0)
.map_err(std::io::Error::other)?,
),
Event::Start(t) if t.name().as_ref() == b"title" => {
let mut text_buf = Vec::new();
let text_event = reader
.read_text_into(t.name(), &mut text_buf)
.map_err(std::io::Error::other)?;
let text = text_event.decode().map_err(std::io::Error::other)?;
title = quick_xml::escape::unescape(&text)
.map_err(std::io::Error::other)?
.into_owned();
}
Event::End(t) if t.name().as_ref() == b"programme" => break,
Event::Eof => break,
_ => {}
Expand Down
2 changes: 1 addition & 1 deletion crates/ersatztv/src/channel_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl ChannelSession {

let _ = child.wait().await;
watcher.abort();
log::debug!("channel {} exited", &channel_number);
log::debug!("channel {} exited", channel_number);
active.lock().await.remove(&channel_number);

if ready_file.exists() {
Expand Down
55 changes: 52 additions & 3 deletions crates/ersatztv/src/xmltv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn copy_programmes<R: BufRead, W: Write>(
buf: &mut Vec<u8>,
) -> std::io::Result<()> {
let mut reader = Reader::from_reader(reader);
reader.config_mut().trim_text(true);
reader.config_mut().trim_text(false);
let mut depth = 0u32;
loop {
match reader.read_event_into(buf).map_err(std::io::Error::other)? {
Expand All @@ -103,12 +103,61 @@ fn copy_programmes<R: BufRead, W: Write>(
Event::Empty(e) if e.name().as_ref() == b"programme" || depth > 0 => {
writer.write_event(Event::Empty(e))?
}
Event::Text(e) if depth > 0 => writer.write_event(Event::Text(e))?,
Event::CData(e) if depth > 0 => writer.write_event(Event::CData(e))?,
Event::Eof => return Ok(()),
other if depth > 0 => {
writer.write_event(other)?;
}
_ => {}
}

buf.clear();
}
}

#[cfg(test)]
mod tests {
use super::*;

// regression test for #172: entity/character references inside programmes were
// dropped because quick-xml emits them as separate `Event::GeneralRef`
// events that the copy loop did not forward.
#[test]
fn copy_programmes_preserves_entities_and_children() {
let input = r#"<?xml version="1.0" encoding="UTF-8"?>
<tv generator-info-name="ErsatzTV">
<programme start="20260630153000 -0600" stop="20260630160000 -0600" channel="tv.1">
<title lang="en">Mister Rogers&#39; Neighborhood</title>
<sub-title lang="en">DAY CARE &amp; NIGHT CARE</sub-title>
<desc lang="en">Line one.&#xA;&#xA;Line two.</desc>
<category lang="en">Kids</category>
<episode-num system="onscreen">S13E16</episode-num>
</programme>
</tv>"#;

let mut writer = Writer::new(Cursor::new(Vec::new()));
let mut buf = Vec::new();
copy_programmes(input.as_bytes(), &mut writer, &mut buf).unwrap();
let output = String::from_utf8(writer.into_inner().into_inner()).unwrap();

assert!(
output.contains("Mister Rogers&#39; Neighborhood"),
"apostrophe reference dropped: {output}"
);
assert!(
output.contains("DAY CARE &amp; NIGHT CARE"),
"ampersand reference dropped: {output}"
);
assert!(
output.contains("Line one.&#xA;&#xA;Line two."),
"newline references dropped: {output}"
);
assert!(
output.contains(r#"<sub-title lang="en">"#),
"child element dropped: {output}"
);
assert!(
output.contains(r#"<episode-num system="onscreen">S13E16</episode-num>"#),
"child element dropped: {output}"
);
}
}
3 changes: 1 addition & 2 deletions crates/ffpipeline/src/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,7 @@ impl std::fmt::Display for ProbeResult {
write!(
f,
"{}",
&self
.streams
self.streams
.iter()
.map(|s| s.to_string())
.collect::<Vec<String>>()
Expand Down