feat(subsonic): support form post (#1333)

* feat(subsonic): support form post

---------

Co-authored-by: jeffvli <jeffvictorli@gmail.com>
This commit is contained in:
Kendall Garner
2025-12-07 03:28:49 -08:00
committed by GitHub
parent 9dbee39d34
commit 9634d7c50d
3 changed files with 38 additions and 20 deletions
+28 -15
View File
@@ -1,13 +1,15 @@
import { initClient, initContract } from '@ts-rest/core'; import { initClient, initContract } from '@ts-rest/core';
import axios, { AxiosError, AxiosResponse, isAxiosError, Method } from 'axios'; import axios, { AxiosError, AxiosRequestConfig, AxiosResponse, isAxiosError } from 'axios';
import omitBy from 'lodash/omitBy'; import omitBy from 'lodash/omitBy';
import qs from 'qs'; import qs from 'qs';
import { z } from 'zod'; import { z } from 'zod';
import i18n from '/@/i18n/i18n'; import i18n from '/@/i18n/i18n';
import { ssType } from '/@/shared/api/subsonic/subsonic-types'; import { ssType } from '/@/shared/api/subsonic/subsonic-types';
import { hasFeature } from '/@/shared/api/utils';
import { toast } from '/@/shared/components/toast/toast'; import { toast } from '/@/shared/components/toast/toast';
import { ServerListItemWithCredential } from '/@/shared/types/domain-types'; import { ServerListItemWithCredential } from '/@/shared/types/domain-types';
import { ServerFeature } from '/@/shared/types/features-types';
const c = initContract(); const c = initContract();
@@ -312,7 +314,7 @@ export const ssApiClient = (args: {
const { server, signal, silent, url } = args; const { server, signal, silent, url } = args;
return initClient(contract, { return initClient(contract, {
api: async ({ body, headers, method, path }) => { api: async ({ headers, method, path }) => {
let baseUrl: string | undefined; let baseUrl: string | undefined;
const authParams: Record<string, any> = {}; const authParams: Record<string, any> = {};
@@ -334,25 +336,36 @@ export const ssApiClient = (args: {
baseUrl = url; baseUrl = url;
} }
try { const request: AxiosRequestConfig = {
const result = await axiosClient.request<
z.infer<typeof ssType._response.baseResponse>
>({
data: body,
headers, headers,
method: method as Method, signal,
params: { // In cases where we have a fallback, don't notify the error
transformResponse: silent ? silentlyTransformResponse : undefined,
url: `${baseUrl}/${api}`,
};
const data = {
c: 'Feishin', c: 'Feishin',
f: 'json', f: 'json',
v: '1.13.0', v: '1.13.0',
...authParams, ...authParams,
...params, ...params,
}, };
signal,
// In cases where we have a fallback, don't notify the error if (hasFeature(server, ServerFeature.OS_FORM_POST)) {
transformResponse: silent ? silentlyTransformResponse : undefined, headers['Content-Type'] = 'application/x-www-form-urlencoded';
url: `${baseUrl}/${api}`, request.method = 'POST';
}); request.data = qs.stringify(data, { arrayFormat: 'repeat' });
} else {
request.method = method;
request.params = data;
}
try {
const result =
await axiosClient.request<z.infer<typeof ssType._response.baseResponse>>(
request,
);
return { return {
body: result.data['subsonic-response'], body: result.data['subsonic-response'],
@@ -997,6 +997,10 @@ export const SubsonicController: InternalControllerEndpoint = {
features.lyricsMultipleStructured = [1]; features.lyricsMultipleStructured = [1];
} }
if (subsonicFeatures[SubsonicExtensions.FORM_POST]) {
features.formPost = [1];
}
return { features, id: apiClientProps.server?.id, version: ping.body.serverVersion }; return { features, id: apiClientProps.server?.id, version: ping.body.serverVersion };
}, },
getSimilarSongs: async (args) => { getSimilarSongs: async (args) => {
+1
View File
@@ -5,6 +5,7 @@ export enum ServerFeature {
LYRICS_MULTIPLE_STRUCTURED = 'lyricsMultipleStructured', LYRICS_MULTIPLE_STRUCTURED = 'lyricsMultipleStructured',
LYRICS_SINGLE_STRUCTURED = 'lyricsSingleStructured', LYRICS_SINGLE_STRUCTURED = 'lyricsSingleStructured',
MUSIC_FOLDER_MULTISELECT = 'musicFolderMultiselect', MUSIC_FOLDER_MULTISELECT = 'musicFolderMultiselect',
OS_FORM_POST = 'osFormPost',
PLAYLISTS_SMART = 'playlistsSmart', PLAYLISTS_SMART = 'playlistsSmart',
PUBLIC_PLAYLIST = 'publicPlaylist', PUBLIC_PLAYLIST = 'publicPlaylist',
SHARING_ALBUM_SONG = 'sharingAlbumSong', SHARING_ALBUM_SONG = 'sharingAlbumSong',