348 lines
11 KiB
Protocol Buffer
348 lines
11 KiB
Protocol Buffer
syntax = "proto3";
|
|
package crabidy.v1;
|
|
|
|
service CrabidyService {
|
|
// System
|
|
rpc Init(InitRequest) returns (InitResponse);
|
|
|
|
// Library
|
|
rpc GetLibraryNode(GetLibraryNodeRequest) returns (GetLibraryNodeResponse);
|
|
// Creates a child node under a creatable parent (LibraryNode.is_creatable).
|
|
// What creation means is provider-defined; under /tidal/search the title is
|
|
// a search term and the created node holds its results. Idempotent: an
|
|
// existing title returns the existing node.
|
|
rpc CreateLibraryNode(CreateLibraryNodeRequest) returns (CreateLibraryNodeResponse);
|
|
// Renames a node whose listing entry sets is_editable. For a search term
|
|
// the title is the query, so a rename re-runs the search; the node's path
|
|
// changes with the title. Renaming onto an existing sibling title merges
|
|
// with it. Returns the renamed node at its new path.
|
|
rpc RenameLibraryNode(RenameLibraryNodeRequest) returns (RenameLibraryNodeResponse);
|
|
// Deletes a node whose listing entry sets is_deletable, or a track
|
|
// whose parent node sets tracks_deletable. On filesystem-backed stores
|
|
// this removes the data from disk: a folder is deleted recursively, a
|
|
// track loses its metadata file and its local audio. Idempotent:
|
|
// deleting an already-gone node succeeds. Returns the refreshed parent.
|
|
rpc DeleteLibraryNode(DeleteLibraryNodeRequest) returns (DeleteLibraryNodeResponse);
|
|
// Captures the queueable subtree at `path` as the bookmark `name`: a
|
|
// structure-preserving snapshot under /bookmarks/<name> (folders per
|
|
// child node, link track files per track). Overwrites an existing
|
|
// bookmark of the same name; a *download* capture instead merges into an
|
|
// existing /captures/<name>, resuming what is not yet downloaded.
|
|
// Returns once the capture is accepted (name, store, and download
|
|
// blessing validated); the walk runs server-side and reports through
|
|
// CaptureProgress updates on GetUpdateStream, ending in one event with
|
|
// `finished` set (and `error` on failure).
|
|
rpc CaptureLibraryNode(CaptureLibraryNodeRequest) returns (CaptureLibraryNodeResponse);
|
|
|
|
// Queue
|
|
rpc Queue(QueueRequest) returns (QueueResponse);
|
|
rpc Replace(ReplaceRequest) returns (ReplaceResponse);
|
|
rpc Append(AppendRequest) returns (AppendResponse);
|
|
rpc Remove(RemoveRequest) returns (RemoveResponse);
|
|
rpc Insert(InsertRequest) returns (InsertResponse);
|
|
rpc ClearQueue(ClearQueueRequest) returns (ClearQueueResponse);
|
|
rpc SetCurrent(SetCurrentRequest) returns (SetCurrentResponse);
|
|
rpc ToggleShuffle(ToggleShuffleRequest) returns (ToggleShuffleResponse);
|
|
rpc ToggleRepeat(ToggleRepeatRequest) returns (ToggleRepeatResponse);
|
|
rpc GetUpdateStream(GetUpdateStreamRequest) returns (stream GetUpdateStreamResponse);
|
|
rpc SaveQueue(SaveQueueRequest) returns (SaveQueueResponse);
|
|
|
|
// Playback
|
|
rpc TogglePlay(TogglePlayRequest) returns (TogglePlayResponse);
|
|
rpc Stop(StopRequest) returns (StopResponse);
|
|
rpc ChangeVolume(ChangeVolumeRequest) returns (ChangeVolumeResponse);
|
|
rpc ToggleMute(ToggleMuteRequest) returns (ToggleMuteResponse);
|
|
rpc Next(NextRequest) returns (NextResponse);
|
|
rpc Prev(PrevRequest) returns (PrevResponse);
|
|
rpc RestartTrack(RestartTrackRequest) returns (RestartTrackResponse);
|
|
}
|
|
|
|
// System
|
|
message InitRequest {}
|
|
message InitResponse {
|
|
Queue queue = 1;
|
|
QueueModifiers mods = 2;
|
|
QueueTrack queue_track = 3;
|
|
PlayState play_state = 4;
|
|
float volume = 5;
|
|
bool mute = 6;
|
|
TrackPosition position = 7;
|
|
// Whether the server has any credentials configured (the auth on/off
|
|
// switch). Reachable anonymously, so a client that connected as the
|
|
// unauthenticated fallback role can learn a higher role is available
|
|
// and offer a login (architecture/roles-auth.md).
|
|
bool auth_enabled = 8;
|
|
}
|
|
|
|
// Library
|
|
message GetLibraryNodeRequest {
|
|
string path = 1;
|
|
}
|
|
message GetLibraryNodeResponse {
|
|
LibraryNode node = 1;
|
|
}
|
|
|
|
message CreateLibraryNodeRequest {
|
|
// Path of the creatable parent, e.g. /tidal/search.
|
|
string parent_path = 1;
|
|
// Human-entered name; becomes the node title. The path segment is a
|
|
// percent-encoded form of it, chosen by the provider.
|
|
string title = 2;
|
|
}
|
|
message CreateLibraryNodeResponse {
|
|
LibraryNode node = 1;
|
|
}
|
|
|
|
message RenameLibraryNodeRequest {
|
|
// Path of the node to rename.
|
|
string path = 1;
|
|
// New human-entered title; the provider derives the new path segment.
|
|
string new_title = 2;
|
|
}
|
|
message RenameLibraryNodeResponse {
|
|
// The renamed node, at its (possibly changed) path.
|
|
LibraryNode node = 1;
|
|
}
|
|
|
|
message DeleteLibraryNodeRequest {
|
|
// Path of the node to delete.
|
|
string path = 1;
|
|
}
|
|
message DeleteLibraryNodeResponse {
|
|
// The parent node with the deleted child gone — what a client should
|
|
// display after the delete, without a follow-up GetLibraryNode.
|
|
LibraryNode parent = 1;
|
|
}
|
|
|
|
message CaptureLibraryNodeRequest {
|
|
// Path of the queueable node (or track) to capture.
|
|
string path = 1;
|
|
// Capture name; becomes the top-level folder under /bookmarks (or
|
|
// /captures when download is set).
|
|
string name = 2;
|
|
// Download every track's audio into the capture instead of writing
|
|
// link files; the source node must set is_downloadable.
|
|
bool download = 3;
|
|
}
|
|
message CaptureLibraryNodeResponse {}
|
|
|
|
// Queue
|
|
message QueueRequest {
|
|
repeated string paths = 1;
|
|
}
|
|
message QueueResponse {}
|
|
|
|
message ReplaceRequest {
|
|
repeated string paths = 1;
|
|
}
|
|
message ReplaceResponse {}
|
|
|
|
message AppendRequest {
|
|
repeated string paths = 1;
|
|
}
|
|
message AppendResponse {}
|
|
|
|
message RemoveRequest {
|
|
repeated uint32 positions = 1;
|
|
}
|
|
message RemoveResponse {}
|
|
|
|
message InsertRequest {
|
|
uint32 position = 1;
|
|
repeated string paths = 2;
|
|
}
|
|
message InsertResponse {}
|
|
|
|
message SetCurrentRequest {
|
|
uint32 position = 1;
|
|
}
|
|
message SetCurrentResponse {}
|
|
|
|
message ToggleShuffleRequest {}
|
|
message ToggleShuffleResponse {}
|
|
|
|
message ToggleRepeatRequest {}
|
|
message ToggleRepeatResponse {}
|
|
|
|
message SaveQueueRequest {
|
|
string name = 1;
|
|
}
|
|
message SaveQueueResponse {}
|
|
|
|
message ClearQueueRequest {
|
|
bool exclude_current = 1;
|
|
}
|
|
message ClearQueueResponse {}
|
|
|
|
// Stream
|
|
message GetUpdateStreamRequest {}
|
|
message GetUpdateStreamResponse {
|
|
oneof update {
|
|
Queue queue = 1;
|
|
QueueModifiers mods = 2;
|
|
QueueTrack queue_track = 3;
|
|
PlayState play_state = 4;
|
|
float volume = 5;
|
|
bool mute = 6;
|
|
TrackPosition position = 7;
|
|
CaptureProgress capture_progress = 8;
|
|
SpectrumFrame spectrum = 9;
|
|
}
|
|
}
|
|
|
|
// One frame of the audio frequency spectrum (architecture/spectrum.md).
|
|
// Broadcast by the server at a low frame rate while audio is playing; an
|
|
// all-zero frame signals silence. Clients render `bins` as bars; they do
|
|
// no signal processing themselves.
|
|
message SpectrumFrame {
|
|
// Normalized magnitudes in [0, 1], low frequency first, log-spaced.
|
|
// The count is the server's bin resolution (a handful of bars).
|
|
repeated float bins = 1;
|
|
}
|
|
|
|
// Progress of a running capture (CaptureLibraryNode). Broadcast after each
|
|
// processed track; exactly one event per capture sets `finished` (with
|
|
// `error` on failure).
|
|
message CaptureProgress {
|
|
// The capture (or bookmark) name the user chose.
|
|
string name = 1;
|
|
// True for a download capture (W), false for a bookmark (w).
|
|
bool download = 2;
|
|
// Tracks settled so far (reused, downloaded, linked, or recorded as
|
|
// skipped) — reaches tracks_total on success.
|
|
uint32 tracks_done = 3;
|
|
// Total tracks discovered by the enumeration; 0 until it completes.
|
|
uint32 tracks_total = 4;
|
|
// Of the settled tracks, how many were recorded as skipped
|
|
// (uncapturable source) this run.
|
|
uint32 tracks_skipped = 5;
|
|
// Terminal event: the capture is over.
|
|
bool finished = 6;
|
|
// Why it failed; empty on success. Never carries URLs or file contents.
|
|
string error = 7;
|
|
}
|
|
|
|
// Playback
|
|
message TogglePlayRequest {}
|
|
message TogglePlayResponse {}
|
|
|
|
message StopRequest {}
|
|
message StopResponse {}
|
|
|
|
message ChangeVolumeRequest {
|
|
float delta = 1;
|
|
}
|
|
message ChangeVolumeResponse {}
|
|
|
|
message ToggleMuteRequest {}
|
|
message ToggleMuteResponse {}
|
|
|
|
message NextRequest {}
|
|
message NextResponse {}
|
|
|
|
message PrevRequest {}
|
|
message PrevResponse {}
|
|
|
|
message RestartTrackRequest {}
|
|
message RestartTrackResponse {}
|
|
|
|
// Data types
|
|
message LibraryNodeChild {
|
|
string path = 1;
|
|
string title = 2;
|
|
bool is_queable = 3;
|
|
// Children may be created under this node (see CreateLibraryNode).
|
|
bool is_creatable = 4;
|
|
// This node may be renamed (see RenameLibraryNode).
|
|
bool is_editable = 5;
|
|
// This node may be deleted (see DeleteLibraryNode).
|
|
bool is_deletable = 6;
|
|
// This node allows download captures (CaptureLibraryNode with download).
|
|
bool is_downloadable = 7;
|
|
// Every track and child node below this child is captured (fully local in
|
|
// the content store). Clients mark captured rows.
|
|
bool is_captured = 8;
|
|
}
|
|
|
|
message QueueModifiers {
|
|
bool shuffle = 1;
|
|
bool repeat = 2;
|
|
}
|
|
|
|
message Queue {
|
|
uint64 timestamp = 1;
|
|
uint32 current_position = 2;
|
|
// Without album
|
|
repeated Track tracks = 3;
|
|
// True while the server is still resolving queued paths into tracks: more
|
|
// tracks will arrive in subsequent Queue updates. Clients may show a
|
|
// loading indicator until an update carries resolving = false.
|
|
bool resolving = 4;
|
|
}
|
|
|
|
message QueueTrack {
|
|
uint32 queue_position = 1;
|
|
// With album
|
|
optional Track track = 2;
|
|
}
|
|
|
|
enum PlayState {
|
|
PLAY_STATE_UNSPECIFIED = 0;
|
|
PLAY_STATE_STOPPED = 1;
|
|
PLAY_STATE_LOADING = 2;
|
|
PLAY_STATE_PLAYING = 3;
|
|
PLAY_STATE_PAUSED = 4;
|
|
}
|
|
|
|
message TrackPosition {
|
|
uint32 duration = 1;
|
|
uint32 position = 2;
|
|
}
|
|
|
|
message Album {
|
|
string title = 1;
|
|
optional string release_date = 2;
|
|
}
|
|
|
|
message Track {
|
|
// Full library path including provider
|
|
string path = 1;
|
|
string artist = 2;
|
|
string title = 3;
|
|
optional uint32 duration = 4;
|
|
optional Album album = 5;
|
|
// The track has no playable audio (a capture recorded its source as
|
|
// uncapturable). Clients mark it; playback skips it.
|
|
bool is_skipped = 6;
|
|
// Provider-internal id that identifies this item inside its provider,
|
|
// independent of the path it was reached by (playlist, search, album…).
|
|
// Set by the owning provider; empty when unknown. Keys the content store.
|
|
string provider_item_id = 7;
|
|
// The content store already holds this track (by provider id or, once
|
|
// captured, as a store-backed playable). Set at listing time; clients
|
|
// mark captured rows. See architecture/crabidy-store.md.
|
|
bool is_captured = 8;
|
|
}
|
|
|
|
message LibraryNode {
|
|
// Full library path including provider
|
|
string path = 1;
|
|
string title = 2;
|
|
repeated LibraryNodeChild children = 3;
|
|
optional string parent = 4;
|
|
repeated Track tracks = 5;
|
|
bool is_queable = 6;
|
|
// Children may be created under this node (see CreateLibraryNode).
|
|
bool is_creatable = 7;
|
|
// This node allows download captures; its listed tracks inherit the
|
|
// flag (CaptureLibraryNode with download).
|
|
bool is_downloadable = 8;
|
|
// This node's listed tracks may be deleted (see DeleteLibraryNode) —
|
|
// like is_downloadable, tracks inherit the node's flag.
|
|
bool tracks_deletable = 9;
|
|
// Every track and child node below this node is captured (fully local in
|
|
// the content store). Clients mark captured nodes. See
|
|
// architecture/crabidy-store.md.
|
|
bool is_captured = 10;
|
|
}
|