syntax = "proto3"; package BackendProto; // Generic containers /////////////////////////////////////////////////////////// message Empty {} message OptionalInt32 { sint32 val = 1; } message OptionalUInt32 { uint32 val = 1; } message Int32 { sint32 val = 1; } message UInt32 { uint32 val = 1; } message Int64 { int64 val = 1; } message String { string val = 1; } message Json { bytes json = 1; } message Bool { bool val = 1; } // IDs used in RPC calls /////////////////////////////////////////////////////////// message NoteTypeID { int64 ntid = 1; } message NoteID { int64 nid = 1; } message CardID { int64 cid = 1; } message CardIDs { repeated int64 cids = 1; } message DeckID { int64 did = 1; } message DeckConfigID { int64 dcid = 1; } // New style RPC definitions /////////////////////////////////////////////////////////// service BackendService { rpc LatestProgress (Empty) returns (Progress); rpc SetWantsAbort (Empty) returns (Empty); // card rendering rpc ExtractAVTags (ExtractAVTagsIn) returns (ExtractAVTagsOut); rpc ExtractLatex (ExtractLatexIn) returns (ExtractLatexOut); rpc GetEmptyCards (Empty) returns (EmptyCardsReport); rpc RenderExistingCard (RenderExistingCardIn) returns (RenderCardOut); rpc RenderUncommittedCard (RenderUncommittedCardIn) returns (RenderCardOut); rpc StripAVTags (String) returns (String); // searching rpc SearchCards (SearchCardsIn) returns (SearchCardsOut); rpc SearchNotes (SearchNotesIn) returns (SearchNotesOut); rpc FindAndReplace (FindAndReplaceIn) returns (UInt32); // scheduling rpc LocalMinutesWest (Int64) returns (Int32); rpc SetLocalMinutesWest (Int32) returns (Empty); rpc SchedTimingToday (Empty) returns (SchedTimingTodayOut); rpc StudiedToday (Empty) returns (String); rpc StudiedTodayMessage (StudiedTodayMessageIn) returns (String); rpc UpdateStats (UpdateStatsIn) returns (Empty); rpc ExtendLimits (ExtendLimitsIn) returns (Empty); rpc CountsForDeckToday (DeckID) returns (CountsForDeckTodayOut); rpc CongratsInfo (Empty) returns (CongratsInfoOut); rpc RestoreBuriedAndSuspendedCards (CardIDs) returns (Empty); rpc UnburyCardsInCurrentDeck (UnburyCardsInCurrentDeckIn) returns (Empty); rpc BuryOrSuspendCards (BuryOrSuspendCardsIn) returns (Empty); rpc EmptyFilteredDeck (DeckID) returns (Empty); rpc RebuildFilteredDeck (DeckID) returns (UInt32); rpc ScheduleCardsAsReviews (ScheduleCardsAsReviewsIn) returns (Empty); rpc ScheduleCardsAsNew (CardIDs) returns (Empty); rpc SortCards (SortCardsIn) returns (Empty); rpc SortDeck (SortDeckIn) returns (Empty); // stats rpc CardStats (CardID) returns (String); rpc Graphs(GraphsIn) returns (GraphsOut); // media rpc CheckMedia (Empty) returns (CheckMediaOut); rpc TrashMediaFiles (TrashMediaFilesIn) returns (Empty); rpc AddMediaFile (AddMediaFileIn) returns (String); rpc EmptyTrash (Empty) returns (Empty); rpc RestoreTrash (Empty) returns (Empty); // decks rpc AddOrUpdateDeckLegacy (AddOrUpdateDeckLegacyIn) returns (DeckID); rpc DeckTree (DeckTreeIn) returns (DeckTreeNode); rpc DeckTreeLegacy (Empty) returns (Json); rpc GetAllDecksLegacy (Empty) returns (Json); rpc GetDeckIDByName (String) returns (DeckID); rpc GetDeckLegacy (DeckID) returns (Json); rpc GetDeckNames (GetDeckNamesIn) returns (DeckNames); rpc NewDeckLegacy (Bool) returns (Json); rpc RemoveDeck (DeckID) returns (Empty); // deck config rpc AddOrUpdateDeckConfigLegacy (AddOrUpdateDeckConfigLegacyIn) returns (DeckConfigID); rpc AllDeckConfigLegacy (Empty) returns (Json); rpc GetDeckConfigLegacy (DeckConfigID) returns (Json); rpc NewDeckConfigLegacy (Empty) returns (Json); rpc RemoveDeckConfig (DeckConfigID) returns (Empty); // cards rpc GetCard (CardID) returns (Card); rpc UpdateCard (Card) returns (Empty); rpc AddCard (Card) returns (CardID); rpc RemoveCards (RemoveCardsIn) returns (Empty); rpc SetDeck (SetDeckIn) returns (Empty); // notes rpc NewNote (NoteTypeID) returns (Note); rpc AddNote (AddNoteIn) returns (NoteID); rpc UpdateNote (Note) returns (Empty); rpc GetNote (NoteID) returns (Note); rpc RemoveNotes (RemoveNotesIn) returns (Empty); rpc AddNoteTags (AddNoteTagsIn) returns (UInt32); rpc UpdateNoteTags (UpdateNoteTagsIn) returns (UInt32); rpc ClozeNumbersInNote (Note) returns (ClozeNumbersInNoteOut); rpc AfterNoteUpdates (AfterNoteUpdatesIn) returns (Empty); rpc FieldNamesForNotes (FieldNamesForNotesIn) returns (FieldNamesForNotesOut); rpc NoteIsDuplicateOrEmpty (Note) returns (NoteIsDuplicateOrEmptyOut); rpc CardsOfNote (NoteID) returns (CardIDs); // note types rpc AddOrUpdateNotetype (AddOrUpdateNotetypeIn) returns (NoteTypeID); rpc GetStockNotetypeLegacy (GetStockNotetypeIn) returns (Json); rpc GetNotetypeLegacy (NoteTypeID) returns (Json); rpc GetNotetypeNames (Empty) returns (NoteTypeNames); rpc GetNotetypeNamesAndCounts (Empty) returns (NoteTypeUseCounts); rpc GetNotetypeIDByName (String) returns (NoteTypeID); rpc RemoveNotetype (NoteTypeID) returns (Empty); // collection rpc OpenCollection (OpenCollectionIn) returns (Empty); rpc CloseCollection (CloseCollectionIn) returns (Empty); rpc CheckDatabase (Empty) returns (CheckDatabaseOut); // sync rpc SyncMedia (SyncAuth) returns (Empty); rpc AbortSync (Empty) returns (Empty); rpc AbortMediaSync (Empty) returns (Empty); rpc BeforeUpload (Empty) returns (Empty); rpc SyncLogin (SyncLoginIn) returns (SyncAuth); rpc SyncStatus (SyncAuth) returns (SyncStatusOut); rpc SyncCollection (SyncAuth) returns (SyncCollectionOut); rpc FullUpload (SyncAuth) returns (Empty); rpc FullDownload (SyncAuth) returns (Empty); // translation/messages rpc TranslateString (TranslateStringIn) returns (String); rpc FormatTimespan (FormatTimespanIn) returns (String); rpc I18nResources (Empty) returns (Json); // tags rpc RegisterTags (RegisterTagsIn) returns (Bool); rpc AllTags (Empty) returns (AllTagsOut); // config/preferences rpc GetConfigJson (String) returns (Json); rpc SetConfigJson (SetConfigJsonIn) returns (Empty); rpc RemoveConfig (String) returns (Empty); rpc SetAllConfig (Json) returns (Empty); rpc GetAllConfig (Empty) returns (Json); rpc GetPreferences (Empty) returns (Preferences); rpc SetPreferences (Preferences) returns (Empty); } // Protobuf stored in .anki2 files // These should be moved to a separate file in the future /////////////////////////////////////////////////////////// message DeckConfigInner { enum NewCardOrder { NEW_CARD_ORDER_DUE = 0; NEW_CARD_ORDER_RANDOM = 1; } enum LeechAction { LEECH_ACTION_SUSPEND = 0; LEECH_ACTION_TAG_ONLY = 1; } repeated float learn_steps = 1; repeated float relearn_steps = 2; reserved 3 to 8; uint32 new_per_day = 9; uint32 reviews_per_day = 10; float initial_ease = 11; float easy_multiplier = 12; float hard_multiplier = 13; float lapse_multiplier = 14; float interval_multiplier = 15; uint32 maximum_review_interval = 16; uint32 minimum_review_interval = 17; uint32 graduating_interval_good = 18; uint32 graduating_interval_easy = 19; NewCardOrder new_card_order = 20; LeechAction leech_action = 21; uint32 leech_threshold = 22; bool disable_autoplay = 23; uint32 cap_answer_time_to_secs = 24; uint32 visible_timer_secs = 25; bool skip_question_when_replaying_answer = 26; bool bury_new = 27; bool bury_reviews = 28; bytes other = 255; } message DeckCommon { bool study_collapsed = 1; bool browser_collapsed = 2; uint32 last_day_studied = 3; int32 new_studied = 4; int32 review_studied = 5; int32 milliseconds_studied = 7; // previously set in the v1 scheduler, // but not currently used for anything int32 learning_studied = 6; bytes other = 255; } message DeckKind { oneof kind { NormalDeck normal = 1; FilteredDeck filtered = 2; } } message NormalDeck { int64 config_id = 1; uint32 extend_new = 2; uint32 extend_review = 3; string description = 4; } message FilteredDeck { bool reschedule = 1; repeated FilteredSearchTerm search_terms = 2; // v1 scheduler only repeated float delays = 3; // v2 scheduler only uint32 preview_delay = 4; } message FilteredSearchTerm { enum FilteredSearchOrder { FILTERED_SEARCH_ORDER_OLDEST_FIRST = 0; FILTERED_SEARCH_ORDER_RANDOM = 1; FILTERED_SEARCH_ORDER_INTERVALS_ASCENDING = 2; FILTERED_SEARCH_ORDER_INTERVALS_DESCENDING = 3; FILTERED_SEARCH_ORDER_LAPSES = 4; FILTERED_SEARCH_ORDER_ADDED = 5; FILTERED_SEARCH_ORDER_DUE = 6; FILTERED_SEARCH_ORDER_REVERSE_ADDED = 7; FILTERED_SEARCH_ORDER_DUE_PRIORITY = 8; } string search = 1; uint32 limit = 2; FilteredSearchOrder order = 3; } message NoteFieldConfig { bool sticky = 1; bool rtl = 2; string font_name = 3; uint32 font_size = 4; bytes other = 255; } message CardTemplateConfig { string q_format = 1; string a_format = 2; string q_format_browser = 3; string a_format_browser= 4; int64 target_deck_id = 5; string browser_font_name = 6; uint32 browser_font_size = 7; bytes other = 255; } message NoteTypeConfig { enum Kind { KIND_NORMAL = 0; KIND_CLOZE = 1; } Kind kind = 1; uint32 sort_field_idx = 2; string css = 3; int64 target_deck_id = 4; string latex_pre = 5; string latex_post = 6; bool latex_svg = 7; repeated CardRequirement reqs = 8; bytes other = 255; } message CardRequirement { enum Kind { KIND_NONE = 0; KIND_ANY = 1; KIND_ALL = 2; } uint32 card_ord = 1; Kind kind = 2; repeated uint32 field_ords = 3; } // Containers for passing around database objects /////////////////////////////////////////////////////////// message Deck { int64 id = 1; string name = 2; uint32 mtime_secs = 3; int32 usn = 4; DeckCommon common = 5; oneof kind { NormalDeck normal = 6; FilteredDeck filtered = 7; } } message NoteType { int64 id = 1; string name = 2; uint32 mtime_secs = 3; sint32 usn = 4; NoteTypeConfig config = 7; repeated NoteField fields = 8; repeated CardTemplate templates = 9; } message NoteField { OptionalUInt32 ord = 1; string name = 2; NoteFieldConfig config = 5; } message CardTemplate { OptionalUInt32 ord = 1; string name = 2; uint32 mtime_secs = 3; sint32 usn = 4; CardTemplateConfig config = 5; } message Note { int64 id = 1; string guid = 2; int64 notetype_id = 3; uint32 mtime_secs = 4; int32 usn = 5; repeated string tags = 6; repeated string fields = 7; } message Card { int64 id = 1; int64 note_id = 2; int64 deck_id = 3; uint32 template_idx = 4; int64 mtime_secs = 5; sint32 usn = 6; uint32 ctype = 7; sint32 queue = 8; sint32 due = 9; uint32 interval = 10; uint32 ease_factor = 11; uint32 reps = 12; uint32 lapses = 13; uint32 remaining_steps = 14; sint32 original_due = 15; int64 original_deck_id = 16; uint32 flags = 17; string data = 18; } // Backend /////////////////////////////////////////////////////////// message BackendInit { repeated string preferred_langs = 1; string locale_folder_path = 2; bool server = 3; } message I18nBackendInit { repeated string preferred_langs = 4; string locale_folder_path = 5; } // Errors /////////////////////////////////////////////////////////// message BackendError { // localized error description suitable for displaying to the user string localized = 1; // error specifics oneof value { Empty invalid_input = 2; Empty template_parse = 3; Empty io_error = 4; Empty db_error = 5; NetworkError network_error = 6; SyncError sync_error = 7; // user interrupted operation Empty interrupted = 8; string json_error = 9; string proto_error = 10; Empty not_found_error = 11; Empty exists = 12; Empty deck_is_filtered = 13; } } message NetworkError { enum NetworkErrorKind { OTHER = 0; OFFLINE = 1; TIMEOUT = 2; PROXY_AUTH = 3; } NetworkErrorKind kind = 1; } message SyncError { enum SyncErrorKind { OTHER = 0; CONFLICT = 1; SERVER_ERROR = 2; CLIENT_TOO_OLD = 3; AUTH_FAILED = 4; SERVER_MESSAGE = 5; MEDIA_CHECK_REQUIRED = 6; RESYNC_REQUIRED = 7; CLOCK_INCORRECT = 8; DATABASE_CHECK_REQUIRED = 9; } SyncErrorKind kind = 1; } // Progress /////////////////////////////////////////////////////////// message Progress { oneof value { Empty none = 1; MediaSyncProgress media_sync = 2; string media_check = 3; FullSyncProgress full_sync = 4; NormalSyncProgress normal_sync = 5; DatabaseCheckProgress database_check = 6; } } message MediaSyncProgress { string checked = 1; string added = 2; string removed = 3; } message FullSyncProgress { uint32 transferred = 1; uint32 total = 2; } message MediaSyncUploadProgress { uint32 files = 1; uint32 deletions = 2; } message NormalSyncProgress { string stage = 1; string added = 2; string removed = 3; } message DatabaseCheckProgress { string stage = 1; uint32 stage_total = 2; uint32 stage_current = 3; } // Messages /////////////////////////////////////////////////////////// message SchedTimingTodayOut { uint32 days_elapsed = 1; int64 next_day_at = 2; } message DeckTreeIn { // if non-zero, counts for the provided timestamp will be included int64 now = 1; int64 top_deck_id = 2; } message DeckTreeNode { int64 deck_id = 1; string name = 2; repeated DeckTreeNode children = 3; uint32 level = 4; bool collapsed = 5; uint32 review_count = 6; uint32 learn_count = 7; uint32 new_count = 8; bool filtered = 16; } message RenderExistingCardIn { int64 card_id = 1; bool browser = 2; } message RenderUncommittedCardIn { Note note = 1; uint32 card_ord = 2; bytes template = 3; bool fill_empty = 4; } message RenderCardOut { repeated RenderedTemplateNode question_nodes = 1; repeated RenderedTemplateNode answer_nodes = 2; } message RenderedTemplateNode { oneof value { string text = 1; RenderedTemplateReplacement replacement = 2; } } message RenderedTemplateReplacement { string field_name = 1; string current_text = 2; repeated string filters = 3; } message ExtractAVTagsIn { string text = 1; bool question_side = 2; } message ExtractAVTagsOut { string text = 1; repeated AVTag av_tags = 2; } message AVTag { oneof value { string sound_or_video = 1; TTSTag tts = 2; } } message TTSTag { string field_text = 1; string lang = 2; repeated string voices = 3; float speed = 4; repeated string other_args = 5; } message ExtractLatexIn { string text = 1; bool svg = 2; bool expand_clozes = 3; } message ExtractLatexOut { string text = 1; repeated ExtractedLatex latex = 2; } message ExtractedLatex { string filename = 1; string latex_body = 2; } message AddMediaFileIn { string desired_name = 1; bytes data = 2; } message CheckMediaOut { repeated string unused = 1; repeated string missing = 2; string report = 3; bool have_trash = 4; } message TrashMediaFilesIn { repeated string fnames = 1; } message TranslateStringIn { int32 key = 2; map args = 3; } message TranslateArgValue { oneof value { string str = 1; double number = 2; } } message FormatTimespanIn { enum Context { PRECISE = 0; ANSWER_BUTTONS = 1; INTERVALS = 2; } float seconds = 1; Context context = 2; } message StudiedTodayMessageIn { uint32 cards = 1; double seconds = 2; } message CongratsLearnMessageIn { float next_due = 1; uint32 remaining = 2; } message OpenCollectionIn { string collection_path = 1; string media_folder_path = 2; string media_db_path = 3; string log_path = 4; } message SearchCardsIn { string search = 1; SortOrder order = 2; } message SearchCardsOut { repeated int64 card_ids = 1; } message SortOrder { oneof value { Empty from_config = 1; Empty none = 2; string custom = 3; BuiltinSearchOrder builtin = 4; } } message SearchNotesIn { string search = 1; } message SearchNotesOut { repeated int64 note_ids = 2; } message BuiltinSearchOrder { enum BuiltinSortKind { NOTE_CREATION = 0; NOTE_MOD = 1; NOTE_FIELD = 2; NOTE_TAGS = 3; NOTE_TYPE = 4; CARD_MOD = 5; CARD_REPS = 6; CARD_DUE = 7; CARD_EASE = 8; CARD_LAPSES = 9; CARD_INTERVAL = 10; CARD_DECK = 11; CARD_TEMPLATE = 12; } BuiltinSortKind kind = 1; bool reverse = 2; } message CloseCollectionIn { bool downgrade_to_schema11 = 1; } message AddOrUpdateDeckConfigLegacyIn { bytes config = 1; bool preserve_usn_and_mtime = 2; } message RegisterTagsIn { string tags = 1; bool preserve_usn = 2; int32 usn = 3; bool clear_first = 4; } message AllTagsOut { repeated TagUsnTuple tags = 1; } message TagUsnTuple { string tag = 1; sint32 usn = 2; } message GetChangedTagsOut { repeated string tags = 1; } message SetConfigJsonIn { string key = 1; bytes value_json = 2; } enum StockNoteType { STOCK_NOTE_TYPE_BASIC = 0; STOCK_NOTE_TYPE_BASIC_AND_REVERSED = 1; STOCK_NOTE_TYPE_BASIC_OPTIONAL_REVERSED = 2; STOCK_NOTE_TYPE_BASIC_TYPING = 3; STOCK_NOTE_TYPE_CLOZE = 4; } message GetStockNotetypeIn { StockNoteType kind = 1; } message NoteTypeNames { repeated NoteTypeNameID entries = 1; } message NoteTypeUseCounts { repeated NoteTypeNameIDUseCount entries = 1; } message NoteTypeNameID { int64 id = 1; string name = 2; } message NoteTypeNameIDUseCount { int64 id = 1; string name = 2; uint32 use_count = 3; } message AddOrUpdateNotetypeIn { bytes json = 1; bool preserve_usn_and_mtime = 2; } message AddNoteIn { Note note = 1; int64 deck_id = 2; } message EmptyCardsReport { string report = 1; repeated NoteWithEmptyCards notes = 2; } message NoteWithEmptyCards { int64 note_id = 1; repeated int64 card_ids = 2; bool will_delete_note = 3; } message DeckNames { repeated DeckNameID entries = 1; } message DeckNameID { int64 id = 1; string name = 2; } message AddOrUpdateDeckLegacyIn { bytes deck = 1; bool preserve_usn_and_mtime = 2; } message FieldNamesForNotesIn { repeated int64 nids = 1; } message FieldNamesForNotesOut { repeated string fields = 1; } message FindAndReplaceIn { repeated int64 nids = 1; string search = 2; string replacement = 3; bool regex = 4; bool match_case = 5; string field_name = 6; } message AfterNoteUpdatesIn { repeated int64 nids = 1; bool mark_notes_modified = 2; bool generate_cards = 3; } message AddNoteTagsIn { repeated int64 nids = 1; string tags = 2; } message UpdateNoteTagsIn { repeated int64 nids = 1; string tags = 2; string replacement = 3; bool regex = 4; } message CheckDatabaseOut { repeated string problems = 1; } message CollectionSchedulingSettings { enum NewReviewMix { DISTRIBUTE = 0; REVIEWS_FIRST = 1; NEW_FIRST = 2; } uint32 scheduler_version = 1; uint32 rollover = 2; uint32 learn_ahead_secs = 3; NewReviewMix new_review_mix = 4; bool show_remaining_due_counts = 5; bool show_intervals_on_buttons = 6; uint32 time_limit_secs = 7; // v2 only bool new_timezone = 8; bool day_learn_first = 9; } message Preferences { CollectionSchedulingSettings sched = 1; } message ClozeNumbersInNoteOut { repeated uint32 numbers = 1; } message GetDeckNamesIn { bool skip_empty_default = 1; // if unset, implies skip_empty_default bool include_filtered = 2; } message NoteIsDuplicateOrEmptyOut { enum State { NORMAL = 0; EMPTY = 1; DUPLICATE = 2; } State state = 1; } message SyncLoginIn { string username = 1; string password = 2; } message SyncStatusOut { enum Required { NO_CHANGES = 0; NORMAL_SYNC = 1; FULL_SYNC = 2; } Required required = 1; } message SyncCollectionOut { enum ChangesRequired { NO_CHANGES = 0; NORMAL_SYNC = 1; FULL_SYNC = 2; // local collection has no cards; upload not an option FULL_DOWNLOAD = 3; // remote collection has no cards; download not an option FULL_UPLOAD = 4; } uint32 host_number = 1; string server_message = 2; ChangesRequired required = 3; } message SyncAuth { string hkey = 1; uint32 host_number = 2; } message RemoveNotesIn { repeated int64 note_ids = 1; repeated int64 card_ids = 2; } message RemoveCardsIn { repeated int64 card_ids = 1; } message UpdateStatsIn { int64 deck_id = 1; int32 new_delta = 2; int32 review_delta = 4; int32 millisecond_delta = 5; } message ExtendLimitsIn { int64 deck_id = 1; int32 new_delta = 2; int32 review_delta = 3; } message CountsForDeckTodayOut { int32 new = 1; int32 review = 2; } message GraphsIn { string search = 1; uint32 days = 2; } message GraphsOut { repeated Card cards = 1; repeated RevlogEntry revlog = 2; uint32 days_elapsed = 3; // Based on rollover hour uint32 next_day_at_secs = 4; uint32 scheduler_version = 5; /// Seconds to add to UTC timestamps to get local time. int32 local_offset_secs = 7; } message RevlogEntry { enum ReviewKind { LEARNING = 0; REVIEW = 1; RELEARNING = 2; EARLY_REVIEW = 3; MANUAL = 4; } int64 id = 1; int64 cid = 2; int32 usn = 3; uint32 button_chosen = 4; int32 interval = 5; int32 last_interval = 6; uint32 ease_factor = 7; uint32 taken_millis = 8; ReviewKind review_kind = 9; } message CongratsInfoOut { uint32 learn_remaining = 1; uint32 secs_until_next_learn = 2; bool review_remaining = 3; bool new_remaining = 4; bool have_sched_buried = 5; bool have_user_buried = 6; bool is_filtered_deck = 7; bool bridge_commands_supported = 8; } message UnburyCardsInCurrentDeckIn { enum Mode { ALL = 0; SCHED_ONLY = 1; USER_ONLY = 2; } Mode mode = 1; } message BuryOrSuspendCardsIn { enum Mode { SUSPEND = 0; BURY_SCHED = 1; BURY_USER = 2; } repeated int64 card_ids = 1; Mode mode = 2; } message ScheduleCardsAsReviewsIn { repeated int64 card_ids = 1; uint32 min_interval = 2; uint32 max_interval = 3; } message SortCardsIn { repeated int64 card_ids = 1; uint32 starting_from = 2; uint32 step_size = 3; bool randomize = 4; bool shift_existing = 5; } message SortDeckIn { int64 deck_id = 1; bool randomize = 2; } message SetDeckIn { repeated int64 card_ids = 1; int64 deck_id = 2; }