more methods

This commit is contained in:
Damien Elmes 2020-05-23 12:58:13 +10:00
parent 175afa9fee
commit 081a61a438
11 changed files with 196 additions and 169 deletions

View file

@ -29,6 +29,10 @@ message String {
string val = 1; string val = 1;
} }
message Bytes {
bytes val = 1;
}
// New style RPC definitions // New style RPC definitions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
@ -41,9 +45,16 @@ service BackendService {
rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut); rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut);
rpc CheckMedia (Empty) returns (CheckMediaOut); rpc CheckMedia (Empty) returns (CheckMediaOut);
rpc LocalMinutesWest (Int64) returns (Int32); rpc LocalMinutesWest (Int64) returns (Int32);
rpc StripAvTags (String) returns (String); rpc StripAVTags (String) returns (String);
rpc ExtractAVTags (ExtractAVTagsIn) returns (ExtractAVTagsOut); rpc ExtractAVTags (ExtractAVTagsIn) returns (ExtractAVTagsOut);
rpc ExtractLatex (ExtractLatexIn) returns (ExtractLatexOut); rpc ExtractLatex (ExtractLatexIn) returns (ExtractLatexOut);
rpc DeckTreeLegacy (Empty) returns (Bytes);
rpc CheckDatabase (Empty) returns (CheckDatabaseOut);
rpc GetEmptyCards (Empty) returns (EmptyCardsReport);
rpc SyncMedia (SyncMediaIn) returns (Empty);
rpc TrashMediaFiles (TrashMediaFilesIn) returns (Empty);
rpc GetDeckLegacy (Int64) returns (Bytes);
rpc GetDeckIDByName (String) returns (Int64);
} }
// Protobuf stored in .anki2 files // Protobuf stored in .anki2 files
@ -290,8 +301,6 @@ message I18nBackendInit {
message BackendInput { message BackendInput {
oneof value { oneof value {
AddMediaFileIn add_media_file = 26; AddMediaFileIn add_media_file = 26;
SyncMediaIn sync_media = 27;
TrashMediaFilesIn trash_media_files = 29;
TranslateStringIn translate_string = 30; TranslateStringIn translate_string = 30;
FormatTimeSpanIn format_time_span = 31; FormatTimeSpanIn format_time_span = 31;
StudiedTodayIn studied_today = 32; StudiedTodayIn studied_today = 32;
@ -320,7 +329,6 @@ message BackendInput {
int32 get_changed_notetypes = 56; int32 get_changed_notetypes = 56;
AddOrUpdateNotetypeIn add_or_update_notetype = 57; AddOrUpdateNotetypeIn add_or_update_notetype = 57;
Empty get_all_decks = 58; Empty get_all_decks = 58;
Empty check_database = 59;
StockNoteType get_stock_notetype_legacy = 60; StockNoteType get_stock_notetype_legacy = 60;
int64 get_notetype_legacy = 61; int64 get_notetype_legacy = 61;
Empty get_notetype_names = 62; Empty get_notetype_names = 62;
@ -331,14 +339,10 @@ message BackendInput {
AddNoteIn add_note = 67; AddNoteIn add_note = 67;
Note update_note = 68; Note update_note = 68;
int64 get_note = 69; int64 get_note = 69;
Empty get_empty_cards = 70;
int64 get_deck_legacy = 71;
string get_deck_id_by_name = 72;
GetDeckNamesIn get_deck_names = 73; GetDeckNamesIn get_deck_names = 73;
AddOrUpdateDeckLegacyIn add_or_update_deck_legacy = 74; AddOrUpdateDeckLegacyIn add_or_update_deck_legacy = 74;
bool new_deck_legacy = 75; bool new_deck_legacy = 75;
int64 remove_deck = 76; int64 remove_deck = 76;
Empty deck_tree_legacy = 77;
FieldNamesForNotesIn field_names_for_notes = 78; FieldNamesForNotesIn field_names_for_notes = 78;
FindAndReplaceIn find_and_replace = 79; FindAndReplaceIn find_and_replace = 79;
AfterNoteUpdatesIn after_note_updates = 80; AfterNoteUpdatesIn after_note_updates = 80;
@ -363,8 +367,6 @@ message BackendOutput {
// fallible commands // fallible commands
string add_media_file = 26; string add_media_file = 26;
Empty sync_media = 27;
Empty trash_media_files = 29;
Empty empty_trash = 34; Empty empty_trash = 34;
Empty restore_trash = 35; Empty restore_trash = 35;
Empty open_collection = 36; Empty open_collection = 36;
@ -388,7 +390,6 @@ message BackendOutput {
bytes get_changed_notetypes = 56; bytes get_changed_notetypes = 56;
int64 add_or_update_notetype = 57; int64 add_or_update_notetype = 57;
bytes get_all_decks = 58; bytes get_all_decks = 58;
CheckDatabaseOut check_database = 59;
bytes get_notetype_legacy = 61; bytes get_notetype_legacy = 61;
NoteTypeNames get_notetype_names = 62; NoteTypeNames get_notetype_names = 62;
NoteTypeUseCounts get_notetype_names_and_counts = 63; NoteTypeUseCounts get_notetype_names_and_counts = 63;
@ -398,14 +399,10 @@ message BackendOutput {
int64 add_note = 67; int64 add_note = 67;
Empty update_note = 68; Empty update_note = 68;
Note get_note = 69; Note get_note = 69;
EmptyCardsReport get_empty_cards = 70;
bytes get_deck_legacy = 71;
int64 get_deck_id_by_name = 72;
DeckNames get_deck_names = 73; DeckNames get_deck_names = 73;
int64 add_or_update_deck_legacy = 74; int64 add_or_update_deck_legacy = 74;
bytes new_deck_legacy = 75; bytes new_deck_legacy = 75;
Empty remove_deck = 76; Empty remove_deck = 76;
bytes deck_tree_legacy = 77;
FieldNamesForNotesOut field_names_for_notes = 78; FieldNamesForNotesOut field_names_for_notes = 78;
uint32 find_and_replace = 79; uint32 find_and_replace = 79;
Empty after_note_updates = 80; Empty after_note_updates = 80;

View file

@ -593,7 +593,7 @@ select id from notes where mid = ?) limit 1"""
""" """
self.save(trx=False) self.save(trx=False)
try: try:
problems = self.backend.check_database() problems = list(self.backend.check_database())
ok = not problems ok = not problems
problems.append(self.tr(TR.DATABASE_CHECK_REBUILT)) problems.append(self.tr(TR.DATABASE_CHECK_REBUILT))
except DBError as e: except DBError as e:

View file

@ -11,7 +11,7 @@ import anki.backend_pb2 as pb
from anki.consts import * from anki.consts import *
from anki.errors import DeckRenameError from anki.errors import DeckRenameError
from anki.lang import _ from anki.lang import _
from anki.rsbackend import DeckTreeNode from anki.rsbackend import DeckTreeNode, NotFoundError, from_json_bytes
from anki.utils import ids2str, intTime from anki.utils import ids2str, intTime
# legacy code may pass this in as the type argument to .id() # legacy code may pass this in as the type argument to .id()
@ -113,10 +113,13 @@ class DeckManager:
) )
def id_for_name(self, name: str) -> Optional[int]: def id_for_name(self, name: str) -> Optional[int]:
return self.col.backend.get_deck_id_by_name(name) return self.col.backend.get_deck_id_by_name(name) or None
def get_legacy(self, did: int) -> Optional[Dict]: def get_legacy(self, did: int) -> Optional[Dict]:
return self.col.backend.get_deck_legacy(did) try:
return from_json_bytes(self.col.backend.get_deck_legacy(did))
except NotFoundError:
return None
def have(self, id: int) -> bool: def have(self, id: int) -> bool:
return not self.get_legacy(int(id)) return not self.get_legacy(int(id))

View file

@ -246,17 +246,6 @@ class RustBackend:
) )
).add_media_file ).add_media_file
def sync_media(self, hkey: str, endpoint: str) -> None:
self._run_command(
pb.BackendInput(sync_media=pb.SyncMediaIn(hkey=hkey, endpoint=endpoint,)),
release_gil=True,
)
def trash_media_files(self, fnames: List[str]) -> None:
self._run_command(
pb.BackendInput(trash_media_files=pb.TrashMediaFilesIn(fnames=fnames))
)
def translate(self, key: TR, **kwargs: Union[str, int, float]) -> str: def translate(self, key: TR, **kwargs: Union[str, int, float]) -> str:
return self._run_command( return self._run_command(
pb.BackendInput(translate_string=translate_string_in(key, **kwargs)) pb.BackendInput(translate_string=translate_string_in(key, **kwargs))
@ -506,20 +495,6 @@ class RustBackend:
except NotFoundError: except NotFoundError:
return None return None
def empty_cards_report(self) -> pb.EmptyCardsReport:
return self._run_command(
pb.BackendInput(get_empty_cards=pb.Empty()), release_gil=True
).get_empty_cards
def get_deck_legacy(self, did: int) -> Optional[Dict]:
try:
bytes = self._run_command(
pb.BackendInput(get_deck_legacy=did)
).get_deck_legacy
return orjson.loads(bytes)
except NotFoundError:
return None
def get_deck_names_and_ids( def get_deck_names_and_ids(
self, skip_empty_default: bool, include_filtered: bool = True self, skip_empty_default: bool, include_filtered: bool = True
) -> Sequence[pb.DeckNameID]: ) -> Sequence[pb.DeckNameID]:
@ -551,30 +526,9 @@ class RustBackend:
).new_deck_legacy ).new_deck_legacy
return orjson.loads(jstr) return orjson.loads(jstr)
def get_deck_id_by_name(self, name: str) -> Optional[int]:
return (
self._run_command(
pb.BackendInput(get_deck_id_by_name=name)
).get_deck_id_by_name
or None
)
def remove_deck(self, did: int) -> None: def remove_deck(self, did: int) -> None:
self._run_command(pb.BackendInput(remove_deck=did)) self._run_command(pb.BackendInput(remove_deck=did))
def check_database(self) -> List[str]:
return list(
self._run_command(
pb.BackendInput(check_database=pb.Empty()), release_gil=True
).check_database.problems
)
def legacy_deck_tree(self) -> Sequence:
bytes = self._run_command(
pb.BackendInput(deck_tree_legacy=pb.Empty())
).deck_tree_legacy
return orjson.loads(bytes)[5]
def field_names_for_note_ids(self, nids: List[int]) -> Sequence[str]: def field_names_for_note_ids(self, nids: List[int]) -> Sequence[str]:
return self._run_command( return self._run_command(
pb.BackendInput(field_names_for_notes=pb.FieldNamesForNotesIn(nids=nids)), pb.BackendInput(field_names_for_notes=pb.FieldNamesForNotesIn(nids=nids)),
@ -725,7 +679,7 @@ class RustBackend:
output.ParseFromString(self._run_command2(9, input)) output.ParseFromString(self._run_command2(9, input))
return output.val return output.val
def extract_a_v_tags(self, text: str, question_side: bool) -> pb.ExtractAVTagsOut: def extract_av_tags(self, text: str, question_side: bool) -> pb.ExtractAVTagsOut:
input = pb.ExtractAVTagsIn(text=text, question_side=question_side) input = pb.ExtractAVTagsIn(text=text, question_side=question_side)
output = pb.ExtractAVTagsOut() output = pb.ExtractAVTagsOut()
output.ParseFromString(self._run_command2(10, input)) output.ParseFromString(self._run_command2(10, input))
@ -739,6 +693,48 @@ class RustBackend:
output.ParseFromString(self._run_command2(11, input)) output.ParseFromString(self._run_command2(11, input))
return output return output
def deck_tree_legacy(self) -> bytes:
input = pb.Empty()
output = pb.Bytes()
output.ParseFromString(self._run_command2(12, input))
return output.val
def check_database(self) -> Sequence[str]:
input = pb.Empty()
output = pb.CheckDatabaseOut()
output.ParseFromString(self._run_command2(13, input))
return output.problems
def get_empty_cards(self) -> pb.EmptyCardsReport:
input = pb.Empty()
output = pb.EmptyCardsReport()
output.ParseFromString(self._run_command2(14, input))
return output
def sync_media(self, hkey: str, endpoint: str) -> pb.Empty:
input = pb.SyncMediaIn(hkey=hkey, endpoint=endpoint)
output = pb.Empty()
output.ParseFromString(self._run_command2(15, input))
return output
def trash_media_files(self, fnames: Sequence[str]) -> pb.Empty:
input = pb.TrashMediaFilesIn(fnames=fnames)
output = pb.Empty()
output.ParseFromString(self._run_command2(16, input))
return output
def get_deck_legacy(self, val: int) -> bytes:
input = pb.Int64(val=val)
output = pb.Bytes()
output.ParseFromString(self._run_command2(17, input))
return output.val
def get_deck_id_by_name(self, val: str) -> int:
input = pb.String(val=val)
output = pb.Int64()
output.ParseFromString(self._run_command2(18, input))
return output.val
# @@AUTOGEN@@ # @@AUTOGEN@@

View file

@ -213,7 +213,7 @@ order by due"""
print( print(
"deckDueTree() is deprecated; use decks.deck_tree() for a tree without counts, or sched.deck_due_tree()" "deckDueTree() is deprecated; use decks.deck_tree() for a tree without counts, or sched.deck_due_tree()"
) )
return self.col.backend.legacy_deck_tree() return self.col.backend.deck_tree_legacy()
def deck_due_tree(self, top_deck_id: int = 0) -> DeckTreeNode: def deck_due_tree(self, top_deck_id: int = 0) -> DeckTreeNode:
"""Returns a tree of decks with counts. """Returns a tree of decks with counts.

View file

@ -215,10 +215,10 @@ class TemplateRenderContext:
) )
qtext = apply_custom_filters(partial.qnodes, self, front_side=None) qtext = apply_custom_filters(partial.qnodes, self, front_side=None)
qout = self.col().backend.extract_a_v_tags(qtext, True) qout = self.col().backend.extract_av_tags(qtext, True)
atext = apply_custom_filters(partial.anodes, self, front_side=qtext) atext = apply_custom_filters(partial.anodes, self, front_side=qtext)
aout = self.col().backend.extract_a_v_tags(atext, False) aout = self.col().backend.extract_av_tags(atext, False)
output = TemplateRenderOutput( output = TemplateRenderOutput(
question_text=qout.text, question_text=qout.text,

View file

@ -51,7 +51,7 @@ def test_genrem():
t = m["tmpls"][1] t = m["tmpls"][1]
t["qfmt"] = "{{Back}}" t["qfmt"] = "{{Back}}"
mm.save(m, templates=True) mm.save(m, templates=True)
rep = d.backend.empty_cards_report() rep = d.backend.get_empty_cards()
for note in rep.notes: for note in rep.notes:
d.remCards(note.card_ids) d.remCards(note.card_ids)
assert len(f.cards()) == 1 assert len(f.cards()) == 1

View file

@ -55,6 +55,17 @@ def python_type_inner(field):
raise Exception(f"unknown type: {type}") raise Exception(f"unknown type: {type}")
# get_deck_i_d -> get_deck_id etc
def fix_snakecase(name):
for fix in "a_v", "i_d":
name = re.sub(
f"(\w)({fix})(\w)",
lambda m: m.group(1) + m.group(2).replace("_", "") + m.group(3),
name,
)
return name
def get_input_args(msg): def get_input_args(msg):
fields = sorted(msg.fields, key=lambda x: x.number) fields = sorted(msg.fields, key=lambda x: x.number)
return ", ".join(["self"] + [f"{f.name}: {python_type(f)}" for f in fields]) return ", ".join(["self"] + [f"{f.name}: {python_type(f)}" for f in fields])
@ -68,7 +79,7 @@ def get_input_assign(msg):
def render_method(method, idx): def render_method(method, idx):
input_args = get_input_args(method.input_type) input_args = get_input_args(method.input_type)
input_assign = get_input_assign(method.input_type) input_assign = get_input_assign(method.input_type)
name = stringcase.snakecase(method.name) name = fix_snakecase(stringcase.snakecase(method.name))
if len(method.output_type.fields) == 1: if len(method.output_type.fields) == 1:
# unwrap single return arg # unwrap single return arg
f = method.output_type.fields[0] f = method.output_type.fields[0]

View file

@ -24,7 +24,7 @@ def show_empty_cards(mw: aqt.main.AnkiQt) -> None:
diag = EmptyCardsDialog(mw, report) diag = EmptyCardsDialog(mw, report)
diag.show() diag.show()
mw.taskman.run_in_background(mw.col.backend.empty_cards_report, on_done) mw.taskman.run_in_background(mw.col.backend.get_empty_cards, on_done)
class EmptyCardsDialog(QDialog): class EmptyCardsDialog(QDialog):

View file

@ -11,6 +11,7 @@ from typing import List
import anki import anki
import aqt import aqt
from anki.sound import SoundOrVideoTag from anki.sound import SoundOrVideoTag
from anki.template import av_tags_to_native
from aqt.theme import theme_manager from aqt.theme import theme_manager
# Routines removed from pylib/ # Routines removed from pylib/
@ -24,8 +25,12 @@ def bodyClass(col, card) -> str:
def allSounds(text) -> List: def allSounds(text) -> List:
print("allSounds() deprecated") print("allSounds() deprecated")
text, tags = aqt.mw.col.backend.extract_av_tags(text, True) out = aqt.mw.col.backend.extract_av_tags(text, True)
return [x.filename for x in tags if isinstance(x, SoundOrVideoTag)] return [
x.filename
for x in av_tags_to_native(out.av_tags)
if isinstance(x, SoundOrVideoTag)
]
def stripSounds(text) -> str: def stripSounds(text) -> str:

View file

@ -147,6 +147,30 @@ pub fn init_backend(init_msg: &[u8]) -> std::result::Result<Backend, String> {
Ok(Backend::new(i18n, input.server)) Ok(Backend::new(i18n, input.server))
} }
impl From<Vec<u8>> for pb::Bytes {
fn from(val: Vec<u8>) -> Self {
pb::Bytes { val }
}
}
impl From<String> for pb::String {
fn from(val: String) -> Self {
pb::String { val }
}
}
impl From<i64> for pb::Int64 {
fn from(val: i64) -> Self {
pb::Int64 { val }
}
}
impl From<()> for pb::Empty {
fn from(_val: ()) -> Self {
pb::Empty {}
}
}
impl BackendService for Backend { impl BackendService for Backend {
fn render_existing_card( fn render_existing_card(
&mut self, &mut self,
@ -310,6 +334,92 @@ impl BackendService for Backend {
.collect(), .collect(),
}) })
} }
fn check_database(&mut self, _input: pb::Empty) -> BackendResult<pb::CheckDatabaseOut> {
self.with_col(|col| {
col.check_database().map(|problems| pb::CheckDatabaseOut {
problems: problems.to_i18n_strings(&col.i18n),
})
})
}
fn deck_tree_legacy(&mut self, _input: pb::Empty) -> BackendResult<pb::Bytes> {
self.with_col(|col| {
let tree = col.legacy_deck_tree()?;
serde_json::to_vec(&tree)
.map_err(Into::into)
.map(Into::into)
})
}
fn get_empty_cards(&mut self, _input: pb::Empty) -> Result<pb::EmptyCardsReport> {
self.with_col(|col| {
let mut empty = col.empty_cards()?;
let report = col.empty_cards_report(&mut empty)?;
let mut outnotes = vec![];
for (_ntid, notes) in empty {
outnotes.extend(notes.into_iter().map(|e| pb::NoteWithEmptyCards {
note_id: e.nid.0,
will_delete_note: e.empty.len() == e.current_count,
card_ids: e.empty.into_iter().map(|(_ord, id)| id.0).collect(),
}))
}
Ok(pb::EmptyCardsReport {
report,
notes: outnotes,
})
})
}
fn get_deck_legacy(&mut self, input: pb::Int64) -> Result<pb::Bytes> {
self.with_col(|col| {
let deck: DeckSchema11 = col
.storage
.get_deck(DeckID(input.val))?
.ok_or(AnkiError::NotFound)?
.into();
serde_json::to_vec(&deck)
.map_err(Into::into)
.map(Into::into)
})
}
fn get_deck_id_by_name(&mut self, input: pb::String) -> Result<pb::Int64> {
self.with_col(|col| {
col.get_deck_id(&input.val)
.map(|d| d.map(|d| d.0).unwrap_or_default())
.map(Into::into)
})
}
fn sync_media(&mut self, input: SyncMediaIn) -> BackendResult<Empty> {
let mut guard = self.col.lock().unwrap();
let col = guard.as_mut().unwrap();
col.set_media_sync_running()?;
let folder = col.media_folder.clone();
let db = col.media_db.clone();
let log = col.log.clone();
drop(guard);
let res = self.sync_media_inner(input, folder, db, log);
self.with_col(|col| col.set_media_sync_finished())?;
res.map(Into::into)
}
fn trash_media_files(&mut self, input: pb::TrashMediaFilesIn) -> BackendResult<Empty> {
self.with_col(|col| {
let mgr = MediaManager::new(&col.media_folder, &col.media_db)?;
let mut ctx = mgr.dbctx();
mgr.remove_files(&mut ctx, &input.fnames)
})
.map(Into::into)
}
} }
impl Backend { impl Backend {
@ -403,14 +513,6 @@ impl Backend {
use pb::backend_output::Value as OValue; use pb::backend_output::Value as OValue;
Ok(match ival { Ok(match ival {
Value::AddMediaFile(input) => OValue::AddMediaFile(self.add_media_file(input)?), Value::AddMediaFile(input) => OValue::AddMediaFile(self.add_media_file(input)?),
Value::SyncMedia(input) => {
self.sync_media(input)?;
OValue::SyncMedia(Empty {})
}
Value::TrashMediaFiles(input) => {
self.remove_media_files(&input.fnames)?;
OValue::TrashMediaFiles(Empty {})
}
Value::TranslateString(input) => OValue::TranslateString(self.translate_string(input)), Value::TranslateString(input) => OValue::TranslateString(self.translate_string(input)),
Value::FormatTimeSpan(input) => OValue::FormatTimeSpan(self.format_time_span(input)), Value::FormatTimeSpan(input) => OValue::FormatTimeSpan(self.format_time_span(input)),
Value::StudiedToday(input) => OValue::StudiedToday(studied_today( Value::StudiedToday(input) => OValue::StudiedToday(studied_today(
@ -509,11 +611,6 @@ impl Backend {
OValue::UpdateNote(pb::Empty {}) OValue::UpdateNote(pb::Empty {})
} }
Value::GetNote(nid) => OValue::GetNote(self.get_note(nid)?), Value::GetNote(nid) => OValue::GetNote(self.get_note(nid)?),
Value::GetEmptyCards(_) => OValue::GetEmptyCards(self.get_empty_cards()?),
Value::GetDeckLegacy(did) => OValue::GetDeckLegacy(self.get_deck_legacy(did)?),
Value::GetDeckIdByName(name) => {
OValue::GetDeckIdByName(self.get_deck_id_by_name(&name)?)
}
Value::GetDeckNames(input) => OValue::GetDeckNames(self.get_deck_names(input)?), Value::GetDeckNames(input) => OValue::GetDeckNames(self.get_deck_names(input)?),
Value::AddOrUpdateDeckLegacy(input) => { Value::AddOrUpdateDeckLegacy(input) => {
OValue::AddOrUpdateDeckLegacy(self.add_or_update_deck_legacy(input)?) OValue::AddOrUpdateDeckLegacy(self.add_or_update_deck_legacy(input)?)
@ -526,8 +623,6 @@ impl Backend {
self.remove_deck(did)?; self.remove_deck(did)?;
pb::Empty {} pb::Empty {}
}), }),
Value::CheckDatabase(_) => OValue::CheckDatabase(self.check_database()?),
Value::DeckTreeLegacy(_) => OValue::DeckTreeLegacy(self.deck_tree_legacy()?),
Value::FieldNamesForNotes(input) => { Value::FieldNamesForNotes(input) => {
OValue::FieldNamesForNotes(self.field_names_for_notes(input)?) OValue::FieldNamesForNotes(self.field_names_for_notes(input)?)
} }
@ -625,25 +720,6 @@ impl Backend {
}) })
} }
fn sync_media(&mut self, input: SyncMediaIn) -> Result<()> {
let mut guard = self.col.lock().unwrap();
let col = guard.as_mut().unwrap();
col.set_media_sync_running()?;
let folder = col.media_folder.clone();
let db = col.media_db.clone();
let log = col.log.clone();
drop(guard);
let res = self.sync_media_inner(input, folder, db, log);
self.with_col(|col| col.set_media_sync_finished())?;
res
}
fn sync_media_inner( fn sync_media_inner(
&mut self, &mut self,
input: pb::SyncMediaIn, input: pb::SyncMediaIn,
@ -679,14 +755,6 @@ impl Backend {
} }
} }
fn remove_media_files(&self, fnames: &[String]) -> Result<()> {
self.with_col(|col| {
let mgr = MediaManager::new(&col.media_folder, &col.media_db)?;
let mut ctx = mgr.dbctx();
mgr.remove_files(&mut ctx, fnames)
})
}
fn translate_string(&self, input: pb::TranslateStringIn) -> String { fn translate_string(&self, input: pb::TranslateStringIn) -> String {
let key = match pb::FluentString::from_i32(input.key) { let key = match pb::FluentString::from_i32(input.key) {
Some(key) => key, Some(key) => key,
@ -1010,44 +1078,6 @@ impl Backend {
}) })
} }
fn get_empty_cards(&self) -> Result<pb::EmptyCardsReport> {
self.with_col(|col| {
let mut empty = col.empty_cards()?;
let report = col.empty_cards_report(&mut empty)?;
let mut outnotes = vec![];
for (_ntid, notes) in empty {
outnotes.extend(notes.into_iter().map(|e| pb::NoteWithEmptyCards {
note_id: e.nid.0,
will_delete_note: e.empty.len() == e.current_count,
card_ids: e.empty.into_iter().map(|(_ord, id)| id.0).collect(),
}))
}
Ok(pb::EmptyCardsReport {
report,
notes: outnotes,
})
})
}
fn get_deck_legacy(&self, did: i64) -> Result<Vec<u8>> {
self.with_col(|col| {
let deck: DeckSchema11 = col
.storage
.get_deck(DeckID(did))?
.ok_or(AnkiError::NotFound)?
.into();
serde_json::to_vec(&deck).map_err(Into::into)
})
}
fn get_deck_id_by_name(&self, human_name: &str) -> Result<i64> {
self.with_col(|col| {
col.get_deck_id(human_name)
.map(|d| d.map(|d| d.0).unwrap_or_default())
})
}
fn get_deck_names(&self, input: pb::GetDeckNamesIn) -> Result<pb::DeckNames> { fn get_deck_names(&self, input: pb::GetDeckNamesIn) -> Result<pb::DeckNames> {
self.with_col(|col| { self.with_col(|col| {
let names = if input.include_filtered { let names = if input.include_filtered {
@ -1094,21 +1124,6 @@ impl Backend {
self.with_col(|col| col.remove_deck_and_child_decks(DeckID(did))) self.with_col(|col| col.remove_deck_and_child_decks(DeckID(did)))
} }
fn check_database(&self) -> Result<pb::CheckDatabaseOut> {
self.with_col(|col| {
col.check_database().map(|problems| pb::CheckDatabaseOut {
problems: problems.to_i18n_strings(&col.i18n),
})
})
}
fn deck_tree_legacy(&self) -> Result<Vec<u8>> {
self.with_col(|col| {
let tree = col.legacy_deck_tree()?;
serde_json::to_vec(&tree).map_err(Into::into)
})
}
fn field_names_for_notes( fn field_names_for_notes(
&self, &self,
input: pb::FieldNamesForNotesIn, input: pb::FieldNamesForNotesIn,