partial fixes

This commit is contained in:
phiresky 2020-06-12 00:09:37 +02:00
parent 2f580b135a
commit 766211edc4
7 changed files with 78 additions and 20 deletions

View File

@ -1,6 +1,6 @@
pub mod custom; pub mod custom;
pub mod decompress; pub mod decompress;
//pub mod ffmpeg; pub mod ffmpeg;
pub mod fns; pub mod fns;
//pub mod pdfpages; //pub mod pdfpages;
pub mod poppler; pub mod poppler;
@ -95,7 +95,7 @@ pub fn get_all_adapters(custom_adapters: Option<Vec<CustomAdapterConfig>>) -> Ad
} }
let internal_adapters: Vec<Rc<dyn FileAdapter>> = vec![ let internal_adapters: Vec<Rc<dyn FileAdapter>> = vec![
//Rc::new(ffmpeg::FFmpegAdapter::new()), Rc::new(ffmpeg::FFmpegAdapter::new()),
//Rc::new(zip::ZipAdapter::new()), //Rc::new(zip::ZipAdapter::new()),
Rc::new(decompress::DecompressAdapter::new()), Rc::new(decompress::DecompressAdapter::new()),
// Rc::new(tar::TarAdapter::new()), // Rc::new(tar::TarAdapter::new()),

View File

@ -3,9 +3,12 @@ use super::{
AdapterMeta, GetMetadata, AdapterMeta, GetMetadata,
}; };
use crate::matching::{FastMatcher, SlowMatcher}; use crate::matching::{FastMatcher, SlowMatcher};
use anyhow::{Context, Result};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::{Captures, Regex};
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::path::Path;
// mostly the same as AdapterMeta + SpawningFileAdapter // mostly the same as AdapterMeta + SpawningFileAdapter
#[derive(Debug, Deserialize, Serialize, JsonSchema, Default, PartialEq, Clone)] #[derive(Debug, Deserialize, Serialize, JsonSchema, Default, PartialEq, Clone)]
@ -115,17 +118,59 @@ impl GetMetadata for CustomSpawningFileAdapter {
&self.meta &self.meta
} }
} }
fn arg_replacer(arg: &str, filepath_hint: &Path) -> Result<String> {
lazy_static::lazy_static! {
static ref ARG_REP: Regex = Regex::new(r"\{([a-z_]+)\}").unwrap();
}
let mut err = None;
let r = ARG_REP.replace_all(arg, |m: &Captures| -> String {
let idx = m.get(0).unwrap().range();
if arg.chars().nth(idx.start - 1) == Some('{') {
// skip
return m.get(0).unwrap().as_str().to_string();
}
if arg.chars().nth(idx.end + 1) == Some('}') {
// skip
return m.get(0).unwrap().as_str().to_string();
}
let key = m.get(1).unwrap().as_str();
if key == "file_extension" {
return filepath_hint
.extension()
.map(|e| e.to_string_lossy().to_string())
.unwrap_or("".to_string());
}
err = Some(anyhow::anyhow!(
"Unknown arg replacement key '{}' in '{}'",
key,
arg
));
"".to_string()
//let
});
if let Some(err) = err {
Err(err)
} else {
Ok(r.to_string())
}
}
impl SpawningFileAdapterTrait for CustomSpawningFileAdapter { impl SpawningFileAdapterTrait for CustomSpawningFileAdapter {
fn get_exe(&self) -> &str { fn get_exe(&self) -> &str {
&self.binary &self.binary
} }
fn command( fn command(
&self, &self,
_filepath_hint: &std::path::Path, filepath_hint: &std::path::Path,
mut command: std::process::Command, mut command: std::process::Command,
) -> std::process::Command { ) -> Result<std::process::Command> {
command.args(&self.args); command.args(
command self.args
.iter()
.map(|arg| arg_replacer(arg, &filepath_hint))
.collect::<Result<Vec<_>>>()?,
);
log::debug!("running command {:?}", command);
Ok(command)
} }
} }
impl CustomAdapterConfig { impl CustomAdapterConfig {

View File

@ -2,9 +2,11 @@ use super::spawning::map_exe_error;
use super::*; use super::*;
use anyhow::*; use anyhow::*;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::io::BufReader; use std::io::BufReader;
use std::process::*; use std::process::*;
use writing::{WritingFileAdapter, WritingFileAdapterTrait};
// todo: // todo:
// maybe todo: read list of extensions from // maybe todo: read list of extensions from
// ffmpeg -demuxers | tail -n+5 | awk '{print $2}' | while read demuxer; do echo MUX=$demuxer; ffmpeg -h demuxer=$demuxer | grep 'Common extensions'; done 2>/dev/null // ffmpeg -demuxers | tail -n+5 | awk '{print $2}' | while read demuxer; do echo MUX=$demuxer; ffmpeg -h demuxer=$demuxer | grep 'Common extensions'; done 2>/dev/null
@ -26,12 +28,12 @@ lazy_static! {
}; };
} }
#[derive(Default)] #[derive(Default, Clone)]
pub struct FFmpegAdapter; pub struct FFmpegAdapter;
impl FFmpegAdapter { impl FFmpegAdapter {
pub fn new() -> FFmpegAdapter { pub fn new() -> WritingFileAdapter {
FFmpegAdapter WritingFileAdapter::new(Box::new(FFmpegAdapter))
} }
} }
impl GetMetadata for FFmpegAdapter { impl GetMetadata for FFmpegAdapter {
@ -48,12 +50,16 @@ struct FFprobeOutput {
struct FFprobeStream { struct FFprobeStream {
codec_type: String, // video,audio,subtitle codec_type: String, // video,audio,subtitle
} }
impl FileAdapter for FFmpegAdapter { impl WritingFileAdapterTrait for FFmpegAdapter {
fn adapt(&self, ai: AdaptInfo, _detection_reason: &SlowMatcher) -> Result<()> { fn adapt_write(
&self,
ai: AdaptInfo,
_detection_reason: &SlowMatcher,
oup: &mut dyn Write,
) -> Result<()> {
let AdaptInfo { let AdaptInfo {
is_real_file, is_real_file,
filepath_hint, filepath_hint,
oup,
line_prefix, line_prefix,
.. ..
} = ai; } = ai;
@ -80,7 +86,7 @@ impl FileAdapter for FFmpegAdapter {
"stream=codec_type", "stream=codec_type",
]) ])
.arg("-i") .arg("-i")
.arg(inp_fname) .arg(&inp_fname)
.output() .output()
.map_err(spawn_fail)?; .map_err(spawn_fail)?;
if !probe.status.success() { if !probe.status.success() {
@ -107,7 +113,7 @@ impl FileAdapter for FFmpegAdapter {
//"-count_packets", //"-count_packets",
]) ])
.arg("-i") .arg("-i")
.arg(inp_fname) .arg(&inp_fname)
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.spawn()?; .spawn()?;
for line in BufReader::new(probe.stdout.as_mut().unwrap()).lines() { for line in BufReader::new(probe.stdout.as_mut().unwrap()).lines() {
@ -125,7 +131,7 @@ impl FileAdapter for FFmpegAdapter {
.arg("-loglevel") .arg("-loglevel")
.arg("panic") .arg("panic")
.arg("-i") .arg("-i")
.arg(inp_fname) .arg(&inp_fname)
.arg("-f") .arg("-f")
.arg("webvtt") .arg("webvtt")
.arg("-"); .arg("-");

View File

@ -34,6 +34,7 @@ where
inner: R, inner: R,
next_read: Vec<u8>, next_read: Vec<u8>,
replacer: Box<dyn FnMut(u8) -> Vec<u8>>, replacer: Box<dyn FnMut(u8) -> Vec<u8>>,
haystacker: Box<dyn Fn(&[u8]) -> Option<usize>>,
} }
impl<R> ByteReplacer<R> impl<R> ByteReplacer<R>
@ -77,7 +78,7 @@ where
match read { match read {
Ok(u) => { Ok(u) => {
match memchr::memchr2(b'\n', b'\x0c', &buf[0..u]) { match (self.haystacker)(&buf[0..u]) {
Some(i) => { Some(i) => {
let data = (self.replacer)(buf[i]); let data = (self.replacer)(buf[i]);
@ -98,6 +99,7 @@ pub fn postprocB(_line_prefix: &str, inp: impl Read) -> Result<impl Read> {
Ok(ByteReplacer { Ok(ByteReplacer {
inner: inp, inner: inp,
next_read: Vec::new(), next_read: Vec::new(),
haystacker: Box::new(|buf| memchr::memchr2(b'\n', b'\x0c', buf)),
replacer: Box::new(move |b| match b { replacer: Box::new(move |b| match b {
b'\n' => format!("\nPage {}:", page_count).into_bytes(), b'\n' => format!("\nPage {}:", page_count).into_bytes(),
b'\x0c' => { b'\x0c' => {

View File

@ -2,6 +2,7 @@ use super::*;
use anyhow::*; use anyhow::*;
use encoding_rs_io::DecodeReaderBytesBuilder; use encoding_rs_io::DecodeReaderBytesBuilder;
use log::*; use log::*;
use regex::Regex;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::BufReader; use std::io::BufReader;
use std::process::Command; use std::process::Command;
@ -55,7 +56,7 @@ pub fn postproc_line_prefix(
} }
pub trait SpawningFileAdapterTrait: GetMetadata { pub trait SpawningFileAdapterTrait: GetMetadata {
fn get_exe(&self) -> &str; fn get_exe(&self) -> &str;
fn command(&self, filepath_hint: &Path, command: Command) -> Command; fn command(&self, filepath_hint: &Path, command: Command) -> Result<Command>;
/*fn postproc(&self, line_prefix: &str, inp: &mut dyn Read, oup: &mut dyn Write) -> Result<()> { /*fn postproc(&self, line_prefix: &str, inp: &mut dyn Read, oup: &mut dyn Write) -> Result<()> {
postproc_line_prefix(line_prefix, inp, oup) postproc_line_prefix(line_prefix, inp, oup)
@ -146,7 +147,10 @@ impl FileAdapter for SpawningFileAdapter {
} = ai; } = ai;
let cmd = Command::new(self.inner.get_exe()); let cmd = Command::new(self.inner.get_exe());
let cmd = self.inner.command(&filepath_hint, cmd); let cmd = self
.inner
.command(&filepath_hint, cmd)
.with_context(|| format!("Could not set cmd arguments for {}", self.inner.get_exe()))?;
debug!("executing {:?}", cmd); debug!("executing {:?}", cmd);
pipe_output(&line_prefix, cmd, &mut inp, self.inner.get_exe(), "") pipe_output(&line_prefix, cmd, &mut inp, self.inner.get_exe(), "")
} }

View File

@ -2,6 +2,7 @@ use super::{FileAdapter, GetMetadata, ReadBox};
use anyhow::Result; use anyhow::Result;
use std::io::Write; use std::io::Write;
// this trait / struct split is necessary because of "conflicting trait implementation" otherwise with SpawningFileAdapter
#[dyn_clonable::clonable] #[dyn_clonable::clonable]
pub trait WritingFileAdapterTrait: GetMetadata + Send + Clone { pub trait WritingFileAdapterTrait: GetMetadata + Send + Clone {
fn adapt_write( fn adapt_write(

View File

@ -16,7 +16,7 @@ fn main() -> anyhow::Result<()> {
std::env::current_dir()?.join(&filepath) std::env::current_dir()?.join(&filepath)
}; };
let i = File::open(&path)?; let i = File::open(&path).context("Specified input file not found")?;
let mut o = std::io::stdout(); let mut o = std::io::stdout();
let cache = if args.no_cache { let cache = if args.no_cache {
None None
@ -31,7 +31,7 @@ fn main() -> anyhow::Result<()> {
archive_recursion_depth: 0, archive_recursion_depth: 0,
config: PreprocConfig { cache, args }, config: PreprocConfig { cache, args },
}; };
let mut oup = rga_preproc(ai)?; let mut oup = rga_preproc(ai).context("during preprocessing")?;
std::io::copy(&mut oup, &mut o).context("copying adapter output to stdout")?; std::io::copy(&mut oup, &mut o).context("copying adapter output to stdout")?;
Ok(()) Ok(())
} }