From 403354186e05bac7b504bb5132c5bc9e532ed50a Mon Sep 17 00:00:00 2001 From: TimesZ <44286581+Times-Z@users.noreply.github.com> Date: Fri, 21 Jun 2024 19:08:27 +0200 Subject: [PATCH 1/5] doc: update swagger with all routes & deprecated old image api route --- src/features/api/features/current.ts | 103 +++++++++++ src/features/api/features/player.ts | 95 +++++++++- src/features/api/legacy.ts | 17 ++ src/features/api/swagger.json | 265 +++++++++++++++++++++++++++ 4 files changed, 479 insertions(+), 1 deletion(-) 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" From 22b46686398f6e7a1b0e9514737bcd02f84b0853 Mon Sep 17 00:00:00 2001 From: Rick van Lieshout Date: Tue, 25 Jun 2024 09:46:45 +0200 Subject: [PATCH 2/5] docs: updated swagger docs for player and legacy --- src/features/api/features/player.ts | 81 ++++++--- src/features/api/legacy.ts | 96 +++++++++++ src/features/api/swagger.json | 255 ++++++++++++++++++++++++---- src/pages/settings/settings.html | 4 +- src/preload.ts | 6 +- 5 files changed, 380 insertions(+), 62 deletions(-) diff --git a/src/features/api/features/player.ts b/src/features/api/features/player.ts index dd0722c..64f9fed 100644 --- a/src/features/api/features/player.ts +++ b/src/features/api/features/player.ts @@ -29,12 +29,13 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow if (settingsStore.get(settings.playBackControl)) { /** * @swagger - * /play: - * get: - * summary: Play action + * /player/play: + * post: + * summary: Play the current media + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: @@ -44,12 +45,13 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow /** * @swagger - * /favorite/toggle: + * /player/favorite/toggle: * post: - * summary: Toggle favorite + * summary: Add the current media to your favorites, or remove it if its already added to your favorites + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: @@ -59,12 +61,13 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow /** * @swagger - * /pause: - * get: - * summary: Pause action + * /player/pause: + * post: + * summary: Pause the current media + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: @@ -74,12 +77,13 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow /** * @swagger - * /next: - * get: - * summary: Next action + * /player/next: + * post: + * summary: Play the next song + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: @@ -89,12 +93,13 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow /** * @swagger - * /previous: - * get: - * summary: Previous action + * /player/previous: + * post: + * summary: Play the previous song + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: @@ -102,17 +107,47 @@ export const addPlaybackControl = (expressApp: Router, mainWindow: BrowserWindow */ createPlayerAction("/previous", globalEvents.previous); + /** + * @swagger + * /player/shuffle/toggle: + * post: + * summary: Play the previous song + * tags: [player] + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/shuffle/toggle", globalEvents.toggleShuffle); + + /** + * @swagger + * /player/repeat/toggle: + * post: + * summary: Toggle the repeat status, toggles between "off" , "single" and "all" + * tags: [player] + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ createPlayerAction("/repeat/toggle", globalEvents.toggleRepeat); /** * @swagger - * /playpause: - * get: - * summary: Toggle play/pause + * /player/playpause: + * post: + * summary: Start playing the media if paused, or pause the media if playing + * tags: [player] * responses: * 200: - * description: Action performed + * description: Ok * content: * text/plain: * schema: diff --git a/src/features/api/legacy.ts b/src/features/api/legacy.ts index 6c73db1..fdec402 100644 --- a/src/features/api/legacy.ts +++ b/src/features/api/legacy.ts @@ -18,6 +18,7 @@ export const addLegacyApi = (expressApp: Router, mainWindow: BrowserWindow) => { * /image: * get: * summary: Get current image + * tags: [legacy] * deprecated: true * responses: * 200: @@ -36,13 +37,108 @@ export const addLegacyApi = (expressApp: Router, mainWindow: BrowserWindow) => { addLegacyControls(); } function addLegacyControls() { + /** + * @swagger + * /play: + * get: + * summary: Play the current media + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Action performed + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.get("/play", ({ res }) => handleGlobalEvent(res, globalEvents.play)); + + /** + * @swagger + * /favorite/toggle: + * get: + * summary: Add the current media to your favorites, or remove it if its already added to your favorites + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.post("/favorite/toggle", (req, res) => handleGlobalEvent(res, globalEvents.toggleFavorite) ); + + /** + * @swagger + * /pause: + * get: + * summary: Pause the current media + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.get("/pause", (req, res) => handleGlobalEvent(res, globalEvents.pause)); + + /** + * @swagger + * /next: + * get: + * summary: Play the next song + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.get("/next", (req, res) => handleGlobalEvent(res, globalEvents.next)); + + /** + * @swagger + * /previous: + * get: + * summary: Play the previous song + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.get("/previous", (req, res) => handleGlobalEvent(res, globalEvents.previous)); + + /** + * @swagger + * /playpause: + * get: + * summary: Toggle play/pause + * tags: [legacy] + * deprecated: true + * responses: + * 200: + * description: Ok + * content: + * text/plain: + * schema: + * $ref: '#/components/schemas/OkResponse' + */ expressApp.get("/playpause", (req, res) => { if (mediaInfo.status === MediaStatus.playing) { handleGlobalEvent(res, globalEvents.pause); diff --git a/src/features/api/swagger.json b/src/features/api/swagger.json index 8c49f5f..0b655a0 100644 --- a/src/features/api/swagger.json +++ b/src/features/api/swagger.json @@ -62,29 +62,15 @@ } } }, - "/play": { - "get": { - "summary": "Play action", - "responses": { - "200": { - "description": "Action performed", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/OkResponse" - } - } - } - } - } - } - }, - "/favorite/toggle": { + "/player/play": { "post": { - "summary": "Toggle favorite", + "summary": "Play action", + "tags": [ + "player" + ], "responses": { "200": { - "description": "Action performed", + "description": "Ok", "content": { "text/plain": { "schema": { @@ -96,12 +82,35 @@ } } }, - "/pause": { - "get": { + "/player/favorite/toggle": { + "post": { + "summary": "Add the current song to your favorites, or remove it if its already added to your favorites", + "tags": [ + "player" + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/player/pause": { + "post": { "summary": "Pause action", + "tags": [ + "player" + ], "responses": { "200": { - "description": "Action performed", + "description": "Ok", "content": { "text/plain": { "schema": { @@ -113,12 +122,15 @@ } } }, - "/next": { - "get": { - "summary": "Next action", + "/player/next": { + "post": { + "summary": "Play the next song", + "tags": [ + "player" + ], "responses": { "200": { - "description": "Action performed", + "description": "Ok", "content": { "text/plain": { "schema": { @@ -130,12 +142,35 @@ } } }, - "/previous": { - "get": { + "/player/previous": { + "post": { + "summary": "Play the previous song", + "tags": [ + "player" + ], + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/player/shuffle/toggle": { + "post": { "summary": "Previous action", + "tags": [ + "player" + ], "responses": { "200": { - "description": "Action performed", + "description": "Ok", "content": { "text/plain": { "schema": { @@ -147,12 +182,35 @@ } } }, - "/playpause": { - "get": { - "summary": "Toggle play/pause", + "/player/repeat/toggle": { + "post": { + "summary": "Toggle the repeat status, toggles between \"off\" , \"single\" and \"all\"", + "tags": [ + "player" + ], "responses": { "200": { - "description": "Action performed", + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/player/playpause": { + "post": { + "summary": "Toggle play/pause", + "tags": [ + "player" + ], + "responses": { + "200": { + "description": "Ok", "content": { "text/plain": { "schema": { @@ -255,6 +313,9 @@ "/image": { "get": { "summary": "Get current image", + "tags": [ + "legacy" + ], "deprecated": true, "responses": { "200": { @@ -273,6 +334,132 @@ } } } + }, + "/play": { + "get": { + "summary": "Play action", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Action performed", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/favorite/toggle": { + "get": { + "summary": "Add the current song to your favorites, or remove it if its already added to your favorites", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/pause": { + "get": { + "summary": "Pause action", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/next": { + "get": { + "summary": "Play the next song", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/previous": { + "get": { + "summary": "Play the previous song", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } + }, + "/playpause": { + "get": { + "summary": "Toggle play/pause", + "tags": [ + "legacy" + ], + "deprecated": true, + "responses": { + "200": { + "description": "Ok", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/OkResponse" + } + } + } + } + } + } } }, "components": { diff --git a/src/pages/settings/settings.html b/src/pages/settings/settings.html index a39aa58..e697580 100644 --- a/src/pages/settings/settings.html +++ b/src/pages/settings/settings.html @@ -147,7 +147,7 @@

API

- TIDAL Hi-Fi has a built-in web API to allow users to get current song information. + TIDAL Hi-Fi has a built-in web API to allow users to get current media information. You can optionally enable playback control as well.

@@ -246,7 +246,7 @@

Show song

-

Show the current song in the Discord client

+

Show the current media in the Discord client