diff --git a/software/src/microdot/tonberry.openapi.v1.yml b/software/src/microdot/tonberry.openapi.v1.yml new file mode 100644 index 0000000..b494cbe --- /dev/null +++ b/software/src/microdot/tonberry.openapi.v1.yml @@ -0,0 +1,471 @@ +openapi: 3.0.0 +info: + title: Tonberry API + description: API for managing audio files, playlists, and NFC tags on the Tonberry device + version: 1.0.0 + +servers: + - url: /v1 + description: Version 1 + +paths: + /api/filesystem: + get: + summary: List contents of a directory + parameters: + - name: path + in: query + required: false + description: Directory path relative to root. If omitted, lists root directory. + schema: + type: string + responses: + '200': + description: Directory contents + content: + application/json: + schema: + type: object + properties: + path: + type: string + directories: + type: array + items: + type: object + properties: + name: + type: string + path: + type: string + files: + type: array + items: + $ref: '#/components/schemas/AudioFile' + security: + - basicAuth: [] + + /api/filesystem/directory: + post: + summary: Create a new directory + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + path: + type: string + description: Full path of the directory to create + required: + - path + responses: + '201': + description: Directory created + delete: + summary: Delete a directory + parameters: + - name: path + in: query + required: true + schema: + type: string + responses: + '204': + description: Directory deleted + + /api/filesystem/files: + post: + summary: Upload one or more audio files + parameters: + - name: path + in: query + required: false + description: Target directory path. If omitted, files will be uploaded to root. + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + files: + type: array + items: + type: string + format: binary + responses: + '201': + description: Files uploaded. IDs are automatically generated. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AudioFile' + + /api/filesystem/files/{fileId}: + get: + summary: Get audio file details + parameters: + - name: fileId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Audio file details + content: + application/json: + schema: + $ref: '#/components/schemas/AudioFile' + delete: + summary: Delete an audio file + parameters: + - name: fileId + in: path + required: true + schema: + type: string + format: uuid + responses: + '204': + description: Audio file deleted + + /api/playlists: + get: + summary: List all playlists + responses: + '200': + description: List of playlists + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Playlist' + post: + summary: Create a new playlist + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + audio_files: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + description: ID of an existing audio file + required: + - name + - audio_files + responses: + '201': + description: Playlist created. ID is automatically generated. + content: + application/json: + schema: + $ref: '#/components/schemas/Playlist' + + /api/playlists/{playlistId}: + get: + summary: Get playlist details + parameters: + - name: playlistId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Playlist details + content: + application/json: + schema: + $ref: '#/components/schemas/Playlist' + put: + summary: Update a playlist + parameters: + - name: playlistId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + audio_files: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + description: ID of an existing audio file + required: + - name + - audio_files + responses: + '200': + description: Playlist updated + content: + application/json: + schema: + $ref: '#/components/schemas/Playlist' + delete: + summary: Delete a playlist + parameters: + - name: playlistId + in: path + required: true + schema: + type: string + format: uuid + responses: + '204': + description: Playlist deleted + + /api/nfc-tags: + get: + summary: List all NFC tags + responses: + '200': + description: List of NFC tags + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/NfcTag' + post: + summary: Register a new NFC tag + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NfcTag' + responses: + '201': + description: NFC tag registered + content: + application/json: + schema: + $ref: '#/components/schemas/NfcTag' + + /api/nfc-tags/{uid}: + get: + summary: Get NFC tag details + parameters: + - name: uid + in: path + required: true + schema: + type: string + responses: + '200': + description: NFC tag details + content: + application/json: + schema: + $ref: '#/components/schemas/NfcTag' + put: + summary: Update NFC tag + parameters: + - name: uid + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NfcTag' + responses: + '200': + description: NFC tag updated + content: + application/json: + schema: + $ref: '#/components/schemas/NfcTag' + delete: + summary: Unregister an NFC tag + parameters: + - name: uid + in: path + required: true + schema: + type: string + responses: + '204': + description: NFC tag unregistered + + /api/playback/control: + post: + summary: Control playback + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + action: + type: string + enum: [play, pause, stop, next, previous] + target_type: + type: string + enum: [audio_file, playlist] + target_id: + type: string + format: uuid + required: [action] + responses: + '200': + description: Playback control successful + +components: + schemas: + DirectoryEntry: + type: object + properties: + name: + type: string + path: + type: string + required: + - name + - path + + DirectoryListing: + type: object + properties: + path: + type: string + directories: + type: array + items: + $ref: '#/components/schemas/DirectoryEntry' + files: + type: array + items: + $ref: '#/components/schemas/AudioFile' + required: + - path + - directories + - files + + PlaybackPosition: + type: object + properties: + position_seconds: + type: number + device_uptime: + type: number + required: + - position_seconds + + AudioFile: + type: object + properties: + id: + type: string + format: uuid + readOnly: true + description: Server-generated unique identifier + filename: + type: string + size_bytes: + type: integer + duration_seconds: + type: number + last_played_uptime: + type: number + playback_position: + $ref: '#/components/schemas/PlaybackPosition' + status: + type: string + enum: [ready, playing, paused] + required: + - id + - filename + + Playlist: + type: object + properties: + id: + type: string + format: uuid + readOnly: true + description: Server-generated unique identifier + name: + type: string + audio_files: + type: array + items: + $ref: '#/components/schemas/AudioFile' + current_track_index: + type: integer + minimum: 0 + last_played_uptime: + type: number + playback_position: + $ref: '#/components/schemas/PlaybackPosition' + status: + type: string + enum: [ready, playing, paused] + required: + - id + - name + - audio_files + + NfcTag: + type: object + properties: + uid: + type: string + name: + type: string + linked_type: + type: string + enum: [audio_file, playlist] + linked_id: + type: string + format: uuid + required: + - uid + - linked_type + - linked_id + + securitySchemes: + basicAuth: + type: http + scheme: basic + description: Basic authentication using username and password + +security: + - basicAuth: [] diff --git a/software/src/microdot/tonberry.schema.json b/software/src/microdot/tonberry.schema.json new file mode 100644 index 0000000..628c8b6 --- /dev/null +++ b/software/src/microdot/tonberry.schema.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "PlaybackPosition": { + "type": "object", + "properties": { + "position_seconds": { "type": "number" }, + "device_uptime": { "type": "number" } + }, + "required": ["position_seconds"] + }, + "AudioFile": { + "type": "object", + "properties": { + "id": { "type": "string", "format": "uuid" }, + "filename": { "type": "string" }, + "size_bytes": { "type": "integer" }, + "duration_seconds": { "type": "number" }, + "last_played_uptime": { "type": "number" }, + "playback_position": { "$ref": "#/definitions/PlaybackPosition" }, + "status": { + "type": "string", + "enum": ["ready", "playing", "paused"] + } + }, + "required": ["id", "filename"] + }, + "Playlist": { + "type": "object", + "properties": { + "id": { "type": "string", "format": "uuid" }, + "name": { "type": "string" }, + "audio_files": { + "type": "array", + "items": { "$ref": "#/definitions/AudioFile" } + }, + "current_track_index": { "type": "integer", "minimum": 0 }, + "last_played_uptime": { "type": "number" }, + "playback_position": { "$ref": "#/definitions/PlaybackPosition" }, + "status": { + "type": "string", + "enum": ["ready", "playing", "paused"] + } + }, + "required": ["id", "name", "audio_files"] + }, + "NfcTag": { + "type": "object", + "properties": { + "uid": { "type": "string" }, + "name": { "type": "string" }, + "linked_type": { + "type": "string", + "enum": ["audio_file", "playlist"] + }, + "linked_id": { "type": "string", "format": "uuid" } + }, + "required": ["uid", "linked_type", "linked_id"] + }, + "DirectoryEntry": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "path": { "type": "string" } + }, + "required": ["name", "path"] + }, + "DirectoryListing": { + "type": "object", + "properties": { + "path": { "type": "string" }, + "directories": { + "type": "array", + "items": { "$ref": "#/definitions/DirectoryEntry" } + }, + "files": { + "type": "array", + "items": { "$ref": "#/definitions/AudioFile" } + } + }, + "required": ["path", "directories", "files"] + } + } + } \ No newline at end of file