Expose apkg export/import on backend

This commit is contained in:
RumovZ 2022-04-20 16:01:34 +02:00
parent 16f8c980a6
commit 6b85b5900f
3 changed files with 66 additions and 4 deletions

View file

@ -5,6 +5,9 @@ syntax = "proto3";
package anki.import_export;
import "anki/collection.proto";
import "anki/decks.proto";
import "anki/notes.proto";
import "anki/generic.proto";
service ImportExportService {
@ -12,6 +15,9 @@ service ImportExportService {
returns (generic.Empty);
rpc ExportCollectionPackage(ExportCollectionPackageRequest)
returns (generic.Empty);
rpc ImportAnkiPackage(ImportAnkiPackageRequest)
returns (collection.OpChanges);
rpc ExportAnkiPackage(ExportAnkiPackageRequest) returns (generic.Empty);
}
message ImportCollectionPackageRequest {
@ -26,6 +32,21 @@ message ExportCollectionPackageRequest {
bool legacy = 3;
}
message ImportAnkiPackageRequest {
string package_path = 1;
}
message ExportAnkiPackageRequest {
string out_path = 1;
bool with_scheduling = 2;
bool with_media = 3;
oneof selector {
generic.Empty whole_collection = 4;
decks.DeckId deck_id = 5;
notes.NoteIds note_ids = 6;
}
}
message PackageMetadata {
enum Version {
VERSION_UNKNOWN = 0;

View file

@ -4,9 +4,10 @@
use super::{progress::Progress, Backend};
pub(super) use crate::backend_proto::importexport_service::Service as ImportExportService;
use crate::{
backend_proto::{self as pb},
backend_proto::{self as pb, export_anki_package_request::Selector},
import_export::{package::import_colpkg, ImportProgress},
prelude::*,
search::SearchNode,
};
impl ImportExportService for Backend {
@ -43,6 +44,38 @@ impl ImportExportService for Backend {
)
.map(Into::into)
}
fn import_anki_package(&self, input: pb::ImportAnkiPackageRequest) -> Result<pb::OpChanges> {
self.with_col(|col| col.import_apkg(&input.package_path, &mut self.import_progress_fn()))
.map(Into::into)
}
fn export_anki_package(&self, input: pb::ExportAnkiPackageRequest) -> Result<pb::Empty> {
let selector = input
.selector
.ok_or_else(|| AnkiError::invalid_input("missing oneof"))?;
self.with_col(|col| {
col.export_apkg(
&input.out_path,
SearchNode::from_selector(selector),
input.with_scheduling,
input.with_media,
None,
self.export_progress_fn(),
)
})
.map(Into::into)
}
}
impl SearchNode {
fn from_selector(selector: Selector) -> Self {
match selector {
Selector::WholeCollection(_) => Self::WholeCollection,
Selector::DeckId(did) => Self::from_deck_id(did, true),
Selector::NoteIds(nids) => Self::from_note_ids(nids.note_ids),
}
}
}
impl Backend {

View file

@ -134,11 +134,11 @@ impl Default for SearchBuilder {
}
impl SearchNode {
pub fn from_deck_id(did: DeckId, with_children: bool) -> Self {
pub fn from_deck_id(did: impl Into<DeckId>, with_children: bool) -> Self {
if with_children {
Self::DeckIdWithChildren(did)
Self::DeckIdWithChildren(did.into())
} else {
Self::DeckIdWithoutChildren(did)
Self::DeckIdWithoutChildren(did.into())
}
}
@ -166,6 +166,14 @@ impl SearchNode {
name,
)))
}
pub fn from_note_ids<I: IntoIterator<Item = N>, N: Into<NoteId>>(ids: I) -> Self {
Self::NoteIds(ids.into_iter().map(Into::into).join(","))
}
pub fn from_card_ids<I: IntoIterator<Item = C>, C: Into<CardId>>(ids: I) -> Self {
Self::CardIds(ids.into_iter().map(Into::into).join(","))
}
}
impl<T: Into<SearchNode>> From<T> for Node {