use std::sync::Arc;
use logoxide::{FsStorage, Project, manifest::MANIFEST};
use crate::{app, cmd::package::timings_report};
pub(crate) fn media_add(
file: &std::path::Path,
urls: &[String],
book: Option<&str>,
package: &std::path::Path,
) -> logoxide::Result<()> {
let bytes = std::fs::read(file)
.map_err(|e| logoxide::LogoxideError::io(&file.display().to_string(), e))?;
let name = file
.file_name()
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_default();
let (url, mirrors) = urls.split_first().ok_or_else(|| {
logoxide::LogoxideError::Media(String::from("where is it served? (--url)"))
})?;
let mut entry = logoxide::media::MediaFile::of(&name, url, &bytes);
entry.mirrors = mirrors.to_vec();
entry.book = book.map(str::to_uppercase);
let path = package.join(MANIFEST);
if !path.is_file() {
return Err(logoxide::LogoxideError::NotFound(format!(
"{} (the package's folder: --package)",
path.display()
)));
}
let mut manifest = Project::open(package)?;
manifest.add_media(&entry)?;
manifest.save_manifest()?;
outln!(
"listed {} ({:.1} MB, sha256 {}) in {}",
entry.path,
entry.size as f64 / 1e6,
&logoxide::media::sha256_digits(&entry.sha256)[..16],
path.display()
);
Ok(())
}
pub(crate) fn media_text(
dir: &std::path::Path,
package: &logoxide::Package,
library: &logoxide::Library,
) -> Option<logoxide::Package> {
let name = package.manifest().media.as_ref()?.text.clone()?;
match logoxide::Project::open(dir).and_then(|project| project.media_text(library)) {
Ok(text) => text,
Err(error) => {
errln!("warning: [media] text `{name}`: {error}; its timings' verses aren't checked");
None
}
}
}
pub(crate) fn media_check(
package: &std::path::Path,
offline: bool,
library: &logoxide::Library,
) -> logoxide::Result<()> {
let opened = logoxide::Package::open(Arc::new(FsStorage::new(package)), Default::default())?;
let files = (opened.manifest().media.as_ref())
.map(|m| m.files.clone())
.unwrap_or_default();
if files.is_empty() {
outln!("no media listed");
return Ok(());
}
let text = media_text(package, &opened, library);
let timings = logoxide::media::check_package_timings_with(&opened, text.as_ref())?;
if opened
.manifest()
.media
.as_ref()
.is_some_and(|m| m.timings.is_some())
&& timings.is_empty()
{
outln!("timings: ok");
}
timings_report(&timings)?;
if offline {
return Ok(());
}
let (mut checked, mut failed) = (0, 0);
for file in &files {
for url in file.urls() {
checked += 1;
let shown = match url == file.url {
true => file.path.clone(),
false => format!("{} (mirror {url})", file.path),
};
match logoxide_app::media::verify(app().http(), url, file) {
Ok(()) => outln!("ok: {shown}"),
Err(error) => {
failed += 1;
outln!("FAILED: {shown}: {error}");
}
}
}
}
match failed {
0 => Ok(()),
n => Err(logoxide::LogoxideError::network(
&package.display().to_string(),
format!("{n} of {checked} media downloads don't match"),
)),
}
}