Add a backend method to extract static media references (#2716)

* Add a backend method to extract static media references

* Extract into Notetype.gather_media_names()
This commit is contained in:
Abdo 2023-10-11 07:10:02 +03:00 committed by GitHub
parent 7b84348771
commit c052be9e25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 17 deletions

View File

@ -8,6 +8,7 @@ option java_multiple_files = true;
package anki.media; package anki.media;
import "anki/generic.proto"; import "anki/generic.proto";
import "anki/notetypes.proto";
service MediaService { service MediaService {
rpc CheckMedia(generic.Empty) returns (CheckMediaResponse); rpc CheckMedia(generic.Empty) returns (CheckMediaResponse);
@ -15,6 +16,8 @@ service MediaService {
rpc TrashMediaFiles(TrashMediaFilesRequest) returns (generic.Empty); rpc TrashMediaFiles(TrashMediaFilesRequest) returns (generic.Empty);
rpc EmptyTrash(generic.Empty) returns (generic.Empty); rpc EmptyTrash(generic.Empty) returns (generic.Empty);
rpc RestoreTrash(generic.Empty) returns (generic.Empty); rpc RestoreTrash(generic.Empty) returns (generic.Empty);
rpc ExtractStaticMediaFiles(notetypes.NotetypeId)
returns (generic.StringList);
} }
// Implicitly includes any of the above methods that are not listed in the // Implicitly includes any of the above methods that are not listed in the

View File

@ -8,7 +8,7 @@ import pprint
import re import re
import sys import sys
import time import time
from typing import Callable from typing import Callable, Sequence
from anki import media_pb2 from anki import media_pb2
from anki._legacy import DeprecatedNamesMixin, deprecated_keywords from anki._legacy import DeprecatedNamesMixin, deprecated_keywords
@ -149,6 +149,9 @@ class MediaManager(DeprecatedNamesMixin):
files.append(fname) files.append(fname)
return files return files
def extract_static_media_files(self, mid: NotetypeId) -> Sequence[str]:
return self.col._backend.extract_static_media_files(mid)
def transform_names(self, txt: str, func: Callable) -> str: def transform_names(self, txt: str, func: Callable) -> str:
for reg in self.regexps: for reg in self.regexps:
txt = re.sub(reg, func, txt) txt = re.sub(reg, func, txt)

View File

@ -16,8 +16,6 @@ use crate::revlog::RevlogEntry;
use crate::search::CardTableGuard; use crate::search::CardTableGuard;
use crate::search::NoteTableGuard; use crate::search::NoteTableGuard;
use crate::text::extract_media_refs; use crate::text::extract_media_refs;
use crate::text::extract_underscored_css_imports;
use crate::text::extract_underscored_references;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(super) struct ExchangeData { pub(super) struct ExchangeData {
@ -75,7 +73,7 @@ impl ExchangeData {
gather_media_names_from_note(note, &mut inserter, &svg_getter); gather_media_names_from_note(note, &mut inserter, &svg_getter);
} }
for notetype in self.notetypes.iter() { for notetype in self.notetypes.iter() {
gather_media_names_from_notetype(notetype, &mut inserter); notetype.gather_media_names(&mut inserter);
} }
Ok(()) Ok(())
} }
@ -158,19 +156,6 @@ fn gather_media_names_from_note(
} }
} }
fn gather_media_names_from_notetype(notetype: &Notetype, inserter: &mut impl FnMut(String)) {
for name in extract_underscored_css_imports(&notetype.config.css) {
inserter(name.to_string());
}
for template in &notetype.templates {
for template_side in [&template.config.q_format, &template.config.a_format] {
for name in extract_underscored_references(template_side) {
inserter(name.to_string());
}
}
}
}
fn svg_getter(notetypes: &[Notetype]) -> impl Fn(NotetypeId) -> bool { fn svg_getter(notetypes: &[Notetype]) -> impl Fn(NotetypeId) -> bool {
let svg_map: HashMap<NotetypeId, bool> = notetypes let svg_map: HashMap<NotetypeId, bool> = notetypes
.iter() .iter()

View File

@ -1,3 +1,5 @@
use std::collections::HashSet;
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use anki_proto::generic; use anki_proto::generic;
@ -7,7 +9,9 @@ use anki_proto::media::TrashMediaFilesRequest;
use crate::collection::Collection; use crate::collection::Collection;
use crate::error; use crate::error;
use crate::error::OrNotFound;
use crate::notes::service::to_i64s; use crate::notes::service::to_i64s;
use crate::notetype::NotetypeId;
impl crate::services::MediaService for Collection { impl crate::services::MediaService for Collection {
fn check_media(&mut self) -> error::Result<CheckMediaResponse> { fn check_media(&mut self) -> error::Result<CheckMediaResponse> {
@ -47,4 +51,19 @@ impl crate::services::MediaService for Collection {
fn restore_trash(&mut self) -> error::Result<()> { fn restore_trash(&mut self) -> error::Result<()> {
self.media_checker()?.restore_trash() self.media_checker()?.restore_trash()
} }
fn extract_static_media_files(
&mut self,
ntid: anki_proto::notetypes::NotetypeId,
) -> error::Result<generic::StringList> {
let ntid = NotetypeId::from(ntid);
let notetype = self.storage.get_notetype(ntid)?.or_not_found(ntid)?;
let mut files: HashSet<String> = HashSet::new();
let mut inserter = |name: String| {
files.insert(name);
};
notetype.gather_media_names(&mut inserter);
Ok(files.into_iter().collect::<Vec<_>>().into())
}
} }

View File

@ -58,6 +58,8 @@ use crate::storage::comma_separated_ids;
use crate::template::FieldRequirements; use crate::template::FieldRequirements;
use crate::template::ParsedTemplate; use crate::template::ParsedTemplate;
use crate::text::ensure_string_in_nfc; use crate::text::ensure_string_in_nfc;
use crate::text::extract_underscored_css_imports;
use crate::text::extract_underscored_references;
define_newtype!(NotetypeId, i64); define_newtype!(NotetypeId, i64);
@ -624,6 +626,19 @@ impl Notetype {
HashSet::new() HashSet::new()
} }
} }
pub(crate) fn gather_media_names(&self, inserter: &mut impl FnMut(String)) {
for name in extract_underscored_css_imports(&self.config.css) {
inserter(name.to_string());
}
for template in &self.templates {
for template_side in [&template.config.q_format, &template.config.a_format] {
for name in extract_underscored_references(template_side) {
inserter(name.to_string());
}
}
}
}
} }
/// True if the slice is empty or either template of the first tuple doesn't /// True if the slice is empty or either template of the first tuple doesn't