mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
Expose apkg export/import on backend
This commit is contained in:
parent
16f8c980a6
commit
6b85b5900f
3 changed files with 66 additions and 4 deletions
|
@ -5,6 +5,9 @@ syntax = "proto3";
|
||||||
|
|
||||||
package anki.import_export;
|
package anki.import_export;
|
||||||
|
|
||||||
|
import "anki/collection.proto";
|
||||||
|
import "anki/decks.proto";
|
||||||
|
import "anki/notes.proto";
|
||||||
import "anki/generic.proto";
|
import "anki/generic.proto";
|
||||||
|
|
||||||
service ImportExportService {
|
service ImportExportService {
|
||||||
|
@ -12,6 +15,9 @@ service ImportExportService {
|
||||||
returns (generic.Empty);
|
returns (generic.Empty);
|
||||||
rpc ExportCollectionPackage(ExportCollectionPackageRequest)
|
rpc ExportCollectionPackage(ExportCollectionPackageRequest)
|
||||||
returns (generic.Empty);
|
returns (generic.Empty);
|
||||||
|
rpc ImportAnkiPackage(ImportAnkiPackageRequest)
|
||||||
|
returns (collection.OpChanges);
|
||||||
|
rpc ExportAnkiPackage(ExportAnkiPackageRequest) returns (generic.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
message ImportCollectionPackageRequest {
|
message ImportCollectionPackageRequest {
|
||||||
|
@ -26,6 +32,21 @@ message ExportCollectionPackageRequest {
|
||||||
bool legacy = 3;
|
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 {
|
message PackageMetadata {
|
||||||
enum Version {
|
enum Version {
|
||||||
VERSION_UNKNOWN = 0;
|
VERSION_UNKNOWN = 0;
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
use super::{progress::Progress, Backend};
|
use super::{progress::Progress, Backend};
|
||||||
pub(super) use crate::backend_proto::importexport_service::Service as ImportExportService;
|
pub(super) use crate::backend_proto::importexport_service::Service as ImportExportService;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend_proto::{self as pb},
|
backend_proto::{self as pb, export_anki_package_request::Selector},
|
||||||
import_export::{package::import_colpkg, ImportProgress},
|
import_export::{package::import_colpkg, ImportProgress},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
search::SearchNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl ImportExportService for Backend {
|
impl ImportExportService for Backend {
|
||||||
|
@ -43,6 +44,38 @@ impl ImportExportService for Backend {
|
||||||
)
|
)
|
||||||
.map(Into::into)
|
.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 {
|
impl Backend {
|
||||||
|
|
|
@ -134,11 +134,11 @@ impl Default for SearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SearchNode {
|
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 {
|
if with_children {
|
||||||
Self::DeckIdWithChildren(did)
|
Self::DeckIdWithChildren(did.into())
|
||||||
} else {
|
} else {
|
||||||
Self::DeckIdWithoutChildren(did)
|
Self::DeckIdWithoutChildren(did.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +166,14 @@ impl SearchNode {
|
||||||
name,
|
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 {
|
impl<T: Into<SearchNode>> From<T> for Node {
|
||||||
|
|
Loading…
Reference in a new issue