diff --git a/src/features/api/features/current.ts b/src/features/api/features/current.ts index 8569114..4fc9350 100644 --- a/src/features/api/features/current.ts +++ b/src/features/api/features/current.ts @@ -3,7 +3,110 @@ import fs from "fs"; import { mediaInfo } from "../../../scripts/mediaInfo"; export const addCurrentInfo = (expressApp: Router) => { + /** + * @swagger + * tags: + * name: current + * description: The current media info API + * components: + * schemas: + * MediaInfo: + * type: object + * properties: + * title: + * type: string + * artists: + * type: string + * album: + * type: string + * icon: + * type: string + * format: uri + * playingFrom: + * type: string + * status: + * type: string + * url: + * type: string + * format: uri + * current: + * type: string + * currentInSeconds: + * type: integer + * duration: + * type: string + * durationInSeconds: + * type: integer + * image: + * type: string + * format: uri + * favorite: + * type: boolean + * player: + * type: object + * properties: + * status: + * type: string + * shuffle: + * type: boolean + * repeat: + * type: string + * artist: + * type: string + * example: + * title: "Sample Title" + * artists: "Sample Artist" + * album: "Sample Album" + * icon: "/path/to/sample/icon.jpg" + * playingFrom: "Sample Playlist" + * status: "playing" + * url: "https://tidal.com/browse/track/sample" + * current: "1:23" + * currentInSeconds: 83 + * duration: "3:45" + * durationInSeconds: 225 + * image: "https://example.com/sample-image.jpg" + * favorite: true + * player: + * status: "playing" + * shuffle: true + * repeat: "one" + * artist: "Sample Artist" + */ + + /** + * @swagger + * /current: + * get: + * summary: Get current media info + * tags: [current] + * responses: + * 200: + * description: Current media info + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/MediaInfo' + */ expressApp.get("/current", (req, res) => res.json({ ...mediaInfo, artist: mediaInfo.artists })); + + /** + * @swagger + * /current/image: + * get: + * summary: Get current media image + * tags: [current] + * responses: + * 200: + * description: Current media image + * content: + * image/png: + * schema: + * type: string + * format: binary + * 404: + * description: Not found + */ expressApp.get("/current/image", getCurrentImage); }; diff --git a/src/features/api/features/player.ts b/src/features/api/features/player.ts index 05c9e56..dd0722c 100644 --- a/src/features/api/features/player.ts +++ b/src/features/api/features/player.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import { BrowserWindow } from "electron"; import { Router } from "express"; import { globalEvents } from "../../../constants/globalEvents"; @@ -12,19 +11,113 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow const windowEvent = handleWindowEvent(mainWindow); const createRoute = (route: string) => `/player${route}`; + /** + * @swagger + * tags: + * name: player + * description: The player control API + * components: + * schemas: + * OkResponse: + * type: string + * example: "OK" + */ const createPlayerAction = (route: string, action: string) => { expressApp.post(createRoute(route), (req, res) => windowEvent(res, action)); }; if (settingsStore.get(settings.playBackControl)) { + /** + * @swagger + * /play: + * get: + * summary: Play action + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/play", globalEvents.play); + + /** + * @swagger + * /favorite/toggle: + * post: + * summary: Toggle favorite + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/favorite/toggle", globalEvents.toggleFavorite); + + /** + * @swagger + * /pause: + * get: + * summary: Pause action + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/pause", globalEvents.pause); + + /** + * @swagger + * /next: + * get: + * summary: Next action + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/next", globalEvents.next); + + /** + * @swagger + * /previous: + * get: + * summary: Previous action + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/previous", globalEvents.previous); + createPlayerAction("/shuffle/toggle", globalEvents.toggleShuffle); createPlayerAction("/repeat/toggle", globalEvents.toggleRepeat); + /** + * @swagger + * /playpause: + * get: + * summary: Toggle play/pause + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.post(createRoute("/playpause"), (req, res) => { if (mediaInfo.status === MediaStatus.playing) { windowEvent(res, globalEvents.pause); diff --git a/src/features/api/legacy.ts b/src/features/api/legacy.ts index 866013f..6c73db1 100644 --- a/src/features/api/legacy.ts +++ b/src/features/api/legacy.ts @@ -13,6 +13,23 @@ import { getCurrentImage } from "./features/current"; * @param mainWindow */ export const addLegacyApi = (expressApp: Router, mainWindow: BrowserWindow) => { + /** + * @swagger + * /image: + * get: + * summary: Get current image + * deprecated: true + * responses: + * 200: + * description: Current image + * content: + * image/png: + * schema: + * type: string + * format: binary + * 404: + * description: Not found + */ expressApp.get("/image", getCurrentImage); if (settingsStore.get(settings.playBackControl)) { diff --git a/src/features/api/swagger.json b/src/features/api/swagger.json index 75e3417..8c49f5f 100644 --- a/src/features/api/swagger.json +++ b/src/features/api/swagger.json @@ -18,6 +18,152 @@ "url": "swagger.json" }, "paths": { + "/current": { + "get": { + "summary": "Get current media info", + "tags": [ + "current" + ], + "responses": { + "200": { + "description": "Current media info", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MediaInfo" + } + } + } + } + } + } + }, + "/current/image": { + "get": { + "summary": "Get current media image", + "tags": [ + "current" + ], + "responses": { + "200": { + "description": "Current media image", + "content": { + "image/png": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Not found" + } + } + } + }, + "/play": { + "get": { + "summary": "Play action", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/favorite/toggle": { + "post": { + "summary": "Toggle favorite", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/pause": { + "get": { + "summary": "Pause action", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/next": { + "get": { + "summary": "Next action", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/previous": { + "get": { + "summary": "Previous action", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/playpause": { + "get": { + "summary": "Toggle play/pause", + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, "/settings/skipped-artists": { "get": { "summary": "get a list of artists that TIDAL Hi-Fi will skip if skipping is enabled", @@ -105,10 +251,121 @@ } } } + }, + "/image": { + "get": { + "summary": "Get current image", + "deprecated": true, + "responses": { + "200": { + "description": "Current image", + "content": { + "image/png": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Not found" + } + } + } } }, "components": { "schemas": { + "MediaInfo": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "artists": { + "type": "string" + }, + "album": { + "type": "string" + }, + "icon": { + "type": "string", + "format": "uri" + }, + "playingFrom": { + "type": "string" + }, + "status": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "current": { + "type": "string" + }, + "currentInSeconds": { + "type": "integer" + }, + "duration": { + "type": "string" + }, + "durationInSeconds": { + "type": "integer" + }, + "image": { + "type": "string", + "format": "uri" + }, + "favorite": { + "type": "boolean" + }, + "player": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "shuffle": { + "type": "boolean" + }, + "repeat": { + "type": "string" + } + } + }, + "artist": { + "type": "string" + } + }, + "example": { + "title": "Sample Title", + "artists": "Sample Artist", + "album": "Sample Album", + "icon": "/path/to/sample/icon.jpg", + "playingFrom": "Sample Playlist", + "status": "playing", + "url": "https://tidal.com/browse/track/sample", + "current": "1:23", + "currentInSeconds": 83, + "duration": "3:45", + "durationInSeconds": 225, + "image": "https://example.com/sample-image.jpg", + "favorite": true, + "player": { + "status": "playing", + "shuffle": true, + "repeat": "one" + }, + "artist": "Sample Artist" + } + }, + "OkResponse": { + "type": "string", + "example": "OK" + }, "StringArray": { "type": "array", "items": { @@ -122,6 +379,14 @@ } }, "tags": [ + { + "name": "current", + "description": "The current media info API" + }, + { + "name": "player", + "description": "The player control API" + }, { "name": "settings", "description": "The settings management API"