mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00

* add deck name field to metadata protobuf msg * fallback to creating new deck specified in `#deck:...` * update tests * create deck if it doesn't exist * plumbing * allow creating deck via `#deck:...` * apply suggestion for protobuf
230 lines
6 KiB
Protocol Buffer
230 lines
6 KiB
Protocol Buffer
// Copyright: Ankitects Pty Ltd and contributors
|
|
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
|
|
syntax = "proto3";
|
|
|
|
option java_multiple_files = true;
|
|
|
|
package anki.import_export;
|
|
|
|
import "anki/cards.proto";
|
|
import "anki/collection.proto";
|
|
import "anki/notes.proto";
|
|
import "anki/generic.proto";
|
|
|
|
service ImportExportService {
|
|
rpc ImportAnkiPackage(ImportAnkiPackageRequest) returns (ImportResponse);
|
|
rpc GetImportAnkiPackagePresets(generic.Empty)
|
|
returns (ImportAnkiPackageOptions);
|
|
rpc ExportAnkiPackage(ExportAnkiPackageRequest) returns (generic.UInt32);
|
|
rpc GetCsvMetadata(CsvMetadataRequest) returns (CsvMetadata);
|
|
rpc ImportCsv(ImportCsvRequest) returns (ImportResponse);
|
|
rpc ExportNoteCsv(ExportNoteCsvRequest) returns (generic.UInt32);
|
|
rpc ExportCardCsv(ExportCardCsvRequest) returns (generic.UInt32);
|
|
rpc ImportJsonFile(generic.String) returns (ImportResponse);
|
|
rpc ImportJsonString(generic.String) returns (ImportResponse);
|
|
}
|
|
|
|
// Implicitly includes any of the above methods that are not listed in the
|
|
// backend service.
|
|
service BackendImportExportService {
|
|
rpc ImportCollectionPackage(ImportCollectionPackageRequest)
|
|
returns (generic.Empty);
|
|
rpc ExportCollectionPackage(ExportCollectionPackageRequest)
|
|
returns (generic.Empty);
|
|
}
|
|
|
|
message ImportCollectionPackageRequest {
|
|
string col_path = 1;
|
|
string backup_path = 2;
|
|
string media_folder = 3;
|
|
string media_db = 4;
|
|
}
|
|
|
|
message ExportCollectionPackageRequest {
|
|
string out_path = 1;
|
|
bool include_media = 2;
|
|
bool legacy = 3;
|
|
}
|
|
|
|
enum ImportAnkiPackageUpdateCondition {
|
|
IMPORT_ANKI_PACKAGE_UPDATE_CONDITION_IF_NEWER = 0;
|
|
IMPORT_ANKI_PACKAGE_UPDATE_CONDITION_ALWAYS = 1;
|
|
IMPORT_ANKI_PACKAGE_UPDATE_CONDITION_NEVER = 2;
|
|
}
|
|
|
|
message ImportAnkiPackageOptions {
|
|
bool merge_notetypes = 1;
|
|
ImportAnkiPackageUpdateCondition update_notes = 2;
|
|
ImportAnkiPackageUpdateCondition update_notetypes = 3;
|
|
bool with_scheduling = 4;
|
|
bool with_deck_configs = 5;
|
|
}
|
|
|
|
message ImportAnkiPackageRequest {
|
|
string package_path = 1;
|
|
ImportAnkiPackageOptions options = 2;
|
|
}
|
|
|
|
message ImportResponse {
|
|
message Note {
|
|
notes.NoteId id = 1;
|
|
repeated string fields = 2;
|
|
}
|
|
message Log {
|
|
repeated Note new = 1;
|
|
repeated Note updated = 2;
|
|
repeated Note duplicate = 3;
|
|
repeated Note conflicting = 4;
|
|
repeated Note first_field_match = 5;
|
|
repeated Note missing_notetype = 6;
|
|
repeated Note missing_deck = 7;
|
|
repeated Note empty_first_field = 8;
|
|
CsvMetadata.DupeResolution dupe_resolution = 9;
|
|
uint32 found_notes = 10;
|
|
}
|
|
collection.OpChanges changes = 1;
|
|
Log log = 2;
|
|
}
|
|
|
|
message ExportAnkiPackageRequest {
|
|
string out_path = 1;
|
|
ExportAnkiPackageOptions options = 2;
|
|
ExportLimit limit = 3;
|
|
}
|
|
|
|
message ExportAnkiPackageOptions {
|
|
bool with_scheduling = 1;
|
|
bool with_deck_configs = 2;
|
|
bool with_media = 3;
|
|
bool legacy = 4;
|
|
}
|
|
|
|
message PackageMetadata {
|
|
enum Version {
|
|
VERSION_UNKNOWN = 0;
|
|
// When `meta` missing, and collection.anki2 file present.
|
|
VERSION_LEGACY_1 = 1;
|
|
// When `meta` missing, and collection.anki21 file present.
|
|
VERSION_LEGACY_2 = 2;
|
|
// Implies MediaEntry media map, and zstd compression.
|
|
// collection.21b file
|
|
VERSION_LATEST = 3;
|
|
}
|
|
|
|
Version version = 1;
|
|
}
|
|
|
|
message MediaEntries {
|
|
message MediaEntry {
|
|
string name = 1;
|
|
uint32 size = 2;
|
|
bytes sha1 = 3;
|
|
|
|
/// Legacy media maps may include gaps in the media list, so the original
|
|
/// file index is recorded when importing from a HashMap. This field is not
|
|
/// set when exporting.
|
|
optional uint32 legacy_zip_filename = 255;
|
|
}
|
|
|
|
repeated MediaEntry entries = 1;
|
|
}
|
|
|
|
message ImportCsvRequest {
|
|
string path = 1;
|
|
CsvMetadata metadata = 2;
|
|
}
|
|
|
|
message CsvMetadataRequest {
|
|
string path = 1;
|
|
optional CsvMetadata.Delimiter delimiter = 2;
|
|
optional int64 notetype_id = 3;
|
|
optional int64 deck_id = 4;
|
|
optional bool is_html = 5;
|
|
}
|
|
|
|
// Column indices are 1-based to make working with them in TS easier, where
|
|
// unset numerical fields default to 0.
|
|
message CsvMetadata {
|
|
enum DupeResolution {
|
|
UPDATE = 0;
|
|
PRESERVE = 1;
|
|
DUPLICATE = 2;
|
|
// UPDATE_IF_NEWER = 3;
|
|
}
|
|
// Order roughly in ascending expected frequency in note text, because the
|
|
// delimiter detection algorithm is stupidly picking the first one it
|
|
// encounters.
|
|
enum Delimiter {
|
|
TAB = 0;
|
|
PIPE = 1;
|
|
SEMICOLON = 2;
|
|
COLON = 3;
|
|
COMMA = 4;
|
|
SPACE = 5;
|
|
}
|
|
message MappedNotetype {
|
|
int64 id = 1;
|
|
// Source column indices for note fields. One-based. 0 means n/a.
|
|
repeated uint32 field_columns = 2;
|
|
}
|
|
Delimiter delimiter = 1;
|
|
bool is_html = 2;
|
|
repeated string global_tags = 3;
|
|
repeated string updated_tags = 4;
|
|
// Column names as defined by the file or empty strings otherwise. Also used
|
|
// to determine the number of columns.
|
|
repeated string column_labels = 5;
|
|
oneof deck {
|
|
// id of an existing deck
|
|
int64 deck_id = 6;
|
|
// One-based. 0 means n/a.
|
|
uint32 deck_column = 7;
|
|
// name of new deck to be created
|
|
string deck_name = 17;
|
|
}
|
|
oneof notetype {
|
|
// One notetype for all rows with given column mapping.
|
|
MappedNotetype global_notetype = 8;
|
|
// Row-specific notetypes with automatic mapping by index.
|
|
// One-based. 0 means n/a.
|
|
uint32 notetype_column = 9;
|
|
}
|
|
enum MatchScope {
|
|
NOTETYPE = 0;
|
|
NOTETYPE_AND_DECK = 1;
|
|
}
|
|
// One-based. 0 means n/a.
|
|
uint32 tags_column = 10;
|
|
bool force_delimiter = 11;
|
|
bool force_is_html = 12;
|
|
repeated generic.StringList preview = 13;
|
|
uint32 guid_column = 14;
|
|
DupeResolution dupe_resolution = 15;
|
|
MatchScope match_scope = 16;
|
|
}
|
|
|
|
message ExportCardCsvRequest {
|
|
string out_path = 1;
|
|
bool with_html = 2;
|
|
ExportLimit limit = 3;
|
|
}
|
|
|
|
message ExportNoteCsvRequest {
|
|
string out_path = 1;
|
|
bool with_html = 2;
|
|
bool with_tags = 3;
|
|
bool with_deck = 4;
|
|
bool with_notetype = 5;
|
|
bool with_guid = 6;
|
|
ExportLimit limit = 7;
|
|
}
|
|
|
|
message ExportLimit {
|
|
oneof limit {
|
|
generic.Empty whole_collection = 1;
|
|
int64 deck_id = 2;
|
|
notes.NoteIds note_ids = 3;
|
|
cards.CardIds card_ids = 4;
|
|
}
|
|
}
|