Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/rfcs/RFC-012-library-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
below: [#298](https://github.com/InstaZDLL/waveflow-server/pull/298) (the
context menu and Properties, with `relative_path` on the track),
[#299](https://github.com/InstaZDLL/waveflow-server/pull/299) (download,
`?download=1` on the stream ticket) and the pull request adding uploaded
lyrics (`track_lyrics_upload`, the TTML parser, the order, and the lyrics
download). The *Status* field above never flips in this project; this line
is the one that says what is running.
`?download=1` on the stream ticket),
[#300](https://github.com/InstaZDLL/waveflow-server/pull/300) (uploaded
lyrics: `track_lyrics_upload`, the TTML parser, the order, and the lyrics
download) and the pull request adding the disk tree (`GET
/libraries/{id}/tree` and the Folders page). The *Status* field above never
flips in this project; this line is the one that says what is running.
- **Date**: 2026-10-21
- **Revised**: 2026-10-21, after review on #297: the **Received** folder's
contract, the depth check on a move, the folder cap that bounds the tree's
Expand Down
52 changes: 52 additions & 0 deletions src/api/libraries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,55 @@ pub async fn library_events(
.map(Json)
.map_err(service_error)
}

#[derive(Debug, Deserialize)]
pub struct DiskTreeQuery {
/// The folder to list, relative to the library; absent or empty for its
/// root, `.waveflow-managed` for the files received through uploads.
pub path: Option<String>,
pub offset: Option<i64>,
pub limit: Option<i64>,
}

/// One level of a library's disk tree (RFC-012 decision 1): the sub-folders
/// of `path` with their track counts, then the tracks directly in it, paged as
/// one list. Derived from the indexed paths, read-only, and open to every
/// member of the library.
#[utoipa::path(
get,
path = "/api/v2/libraries/{library_id}/tree",
tag = "catalog",
params(
("library_id" = Uuid, Path),
("path" = Option<String>, Query),
("offset" = Option<i64>, Query),
("limit" = Option<i64>, Query)
),
responses(
(status = 200, body = crate::services::DiskListing),
(status = 401, body = ErrorResponse),
(status = 404, body = ErrorResponse),
(status = 422, body = ErrorResponse)
)
)]
pub async fn library_tree(
State(state): State<AppState>,
Path(library_id): Path<Uuid>,
Query(query): Query<DiskTreeQuery>,
headers: HeaderMap,
) -> Result<Json<crate::services::DiskListing>, ApiError> {
let user = authenticated(&state, &headers, Access::Read).await?;
let page =
crate::services::BrowsePage::new(query.offset, query.limit).map_err(service_error)?;
state
.services
.disk_tree(
user.id,
library_id,
query.path.as_deref().unwrap_or(""),
page,
)
.await
.map(Json)
.map_err(service_error)
}
1 change: 1 addition & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ pub fn router(state: AppState) -> Router {
.route("/api/v2/scans/{scan_id}", get(scan_status))
.route("/api/v2/scans/{scan_id}/events", get(scan_events))
.route("/api/v2/libraries/{library_id}/tracks", get(list_tracks))
.route("/api/v2/libraries/{library_id}/tree", get(library_tree))
.route("/api/v2/libraries/{library_id}/events", get(library_events))
.route(
"/api/v2/libraries/{library_id}/events/ack",
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ fn chunk_body_limit(limits: &config::UploadLimits) -> usize {
api::upload_chunk,
api::commit_upload,
api::list_tracks,
api::library_tree,
api::get_track,
api::update_track,
api::get_track_lyrics,
Expand Down Expand Up @@ -296,6 +297,9 @@ fn chunk_body_limit(limits: &config::UploadLimits) -> usize {
api::SyncAckRequest,
api::SyncSnapshot,
services::LibraryEventPage,
services::DiskListing,
services::DiskFolder,
services::DiskTrack,
services::TrackMetadataPatch,
services::UploadOffer,
services::UploadVerdict,
Expand Down
Loading
Loading