mirror of
https://github.com/ankitects/anki.git
synced 2025-09-20 15:02:21 -04:00
clean up invalid media DB entries on the fly, instead of requiring DB check
This commit is contained in:
parent
7ae6244f6a
commit
eddf9fdc44
1 changed files with 34 additions and 14 deletions
|
@ -309,8 +309,16 @@ where
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let zip_data = zip_files(&self.mgr.media_folder, &pending)?;
|
let zip_data = zip_files(&mut self.ctx, &self.mgr.media_folder, &pending)?;
|
||||||
let reply = self.send_zip_data(zip_data).await?;
|
if zip_data.is_none() {
|
||||||
|
self.progress.checked += pending.len();
|
||||||
|
self.maybe_fire_progress_cb()?;
|
||||||
|
// discard zip info and retry batch - not particularly efficient,
|
||||||
|
// but this is a corner case
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let reply = self.send_zip_data(zip_data.unwrap()).await?;
|
||||||
|
|
||||||
let (processed_files, processed_deletions): (Vec<_>, Vec<_>) = pending
|
let (processed_files, processed_deletions): (Vec<_>, Vec<_>) = pending
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -646,8 +654,13 @@ fn record_clean(ctx: &mut MediaDatabaseContext, clean: &[&String]) -> Result<()>
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zip_files(media_folder: &Path, files: &[MediaEntry]) -> Result<Vec<u8>> {
|
fn zip_files<'a>(
|
||||||
|
ctx: &mut MediaDatabaseContext,
|
||||||
|
media_folder: &Path,
|
||||||
|
files: &'a [MediaEntry],
|
||||||
|
) -> Result<Option<Vec<u8>>> {
|
||||||
let buf = vec![];
|
let buf = vec![];
|
||||||
|
let mut invalid_entries = vec![];
|
||||||
|
|
||||||
let w = std::io::Cursor::new(buf);
|
let w = std::io::Cursor::new(buf);
|
||||||
let mut zip = zip::ZipWriter::new(w);
|
let mut zip = zip::ZipWriter::new(w);
|
||||||
|
@ -666,17 +679,20 @@ fn zip_files(media_folder: &Path, files: &[MediaEntry]) -> Result<Vec<u8>> {
|
||||||
let normalized = normalize_filename(&file.fname);
|
let normalized = normalize_filename(&file.fname);
|
||||||
if let Cow::Owned(o) = normalized {
|
if let Cow::Owned(o) = normalized {
|
||||||
debug!("media check required: {} should be {}", &file.fname, o);
|
debug!("media check required: {} should be {}", &file.fname, o);
|
||||||
return Err(media_check_required());
|
invalid_entries.push(&file.fname);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_data = data_for_file(media_folder, &file.fname)?;
|
let file_data = data_for_file(media_folder, &file.fname)?;
|
||||||
|
|
||||||
if let Some(data) = &file_data {
|
if let Some(data) = &file_data {
|
||||||
if data.is_empty() {
|
if data.is_empty() {
|
||||||
return Err(media_check_required());
|
invalid_entries.push(&file.fname);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if data.len() > SYNC_SINGLE_FILE_MAX_BYTES {
|
if data.len() > SYNC_SINGLE_FILE_MAX_BYTES {
|
||||||
return Err(media_check_required());
|
invalid_entries.push(&file.fname);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
accumulated_size += data.len();
|
accumulated_size += data.len();
|
||||||
zip.start_file(format!("{}", idx), options)?;
|
zip.start_file(format!("{}", idx), options)?;
|
||||||
|
@ -703,26 +719,30 @@ fn zip_files(media_folder: &Path, files: &[MediaEntry]) -> Result<Vec<u8>> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !invalid_entries.is_empty() {
|
||||||
|
// clean up invalid entries; we'll build a new zip
|
||||||
|
ctx.transact(|ctx| {
|
||||||
|
for fname in invalid_entries {
|
||||||
|
ctx.remove_entry(fname)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let meta = serde_json::to_string(&entries)?;
|
let meta = serde_json::to_string(&entries)?;
|
||||||
zip.start_file("_meta", options)?;
|
zip.start_file("_meta", options)?;
|
||||||
zip.write_all(meta.as_bytes())?;
|
zip.write_all(meta.as_bytes())?;
|
||||||
|
|
||||||
let w = zip.finish()?;
|
let w = zip.finish()?;
|
||||||
|
|
||||||
Ok(w.into_inner())
|
Ok(Some(w.into_inner()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version_string() -> String {
|
fn version_string() -> String {
|
||||||
format!("anki,{},{}", version(), std::env::consts::OS)
|
format!("anki,{},{}", version(), std::env::consts::OS)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn media_check_required() -> AnkiError {
|
|
||||||
AnkiError::SyncError {
|
|
||||||
info: "".into(),
|
|
||||||
kind: SyncErrorKind::MediaCheckRequired,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::err::Result;
|
use crate::err::Result;
|
||||||
|
|
Loading…
Reference in a new issue