getJSON private

This commit is contained in:
simojenki
2025-02-17 07:01:34 +00:00
parent b97590dd36
commit e29d5c5d24
2 changed files with 43 additions and 49 deletions

View File

@@ -1,4 +1,4 @@
import { option as O } from "fp-ts"; import { option as O, taskEither as TE } from "fp-ts";
import * as A from "fp-ts/Array"; import * as A from "fp-ts/Array";
import { ordString } from "fp-ts/lib/Ord"; import { ordString } from "fp-ts/lib/Ord";
import { pipe } from "fp-ts/lib/function"; import { pipe } from "fp-ts/lib/function";
@@ -15,6 +15,7 @@ import {
Encoding, Encoding,
albumToAlbumSummary, albumToAlbumSummary,
TrackSummary, TrackSummary,
AuthFailure
} from "./music_library"; } from "./music_library";
import sharp from "sharp"; import sharp from "sharp";
import _ from "underscore"; import _ from "underscore";
@@ -531,10 +532,9 @@ export class Subsonic {
} else return response; } else return response;
}); });
// todo: make private
// todo: should I put a catch in here and force a subsonic fail status? // todo: should I put a catch in here and force a subsonic fail status?
// or there is a catch above, that then throws, perhaps can go in there? // or there is a catch above, that then throws, perhaps can go in there?
getJSON = async <T>( private getJSON = async <T>(
{ username, password }: Credentials, { username, password }: Credentials,
path: string, path: string,
q: {} = {} q: {} = {}
@@ -547,6 +547,17 @@ export class Subsonic {
else return json as unknown as T; else return json as unknown as T;
}); });
ping = (credentials: Credentials): TE.TaskEither<AuthFailure, { authenticated: Boolean, type: string}> =>
TE.tryCatch(
() => this.getJSON<PingResponse>(credentials, "/rest/ping.view")
.then(it => ({
authenticated: it.status == "ok",
type: it.type
})),
(e) => new AuthFailure(e as string)
)
getArtists = ( getArtists = (
credentials: Credentials credentials: Credentials
): Promise<(IdName & { albumCount: number; image: BUrn | undefined })[]> => ): Promise<(IdName & { albumCount: number; image: BUrn | undefined })[]> =>
@@ -862,4 +873,18 @@ export class Subsonic {
(it.topSongs.song || []).map(it => asTrackSummary(it, this.customPlayers)) (it.topSongs.song || []).map(it => asTrackSummary(it, this.customPlayers))
); );
} getInternetRadioStations = (credentials: Credentials) =>
this.getJSON<GetInternetRadioStationsResponse>(
credentials,
"/rest/getInternetRadioStations"
)
.then((it) => it.internetRadioStations.internetRadioStation || [])
.then((stations) =>
stations.map((it) => ({
id: it.id,
name: it.name,
url: it.streamUrl,
homePage: it.homePageUrl,
}))
);
};

View File

@@ -19,12 +19,10 @@ import {
import { import {
Subsonic, Subsonic,
CustomPlayers, CustomPlayers,
PingResponse,
NO_CUSTOM_PLAYERS, NO_CUSTOM_PLAYERS,
asToken, asToken,
parseToken, parseToken,
artistImageURN, artistImageURN,
GetInternetRadioStationsResponse,
asYear, asYear,
isValidImage isValidImage
} from "./subsonic"; } from "./subsonic";
@@ -48,39 +46,23 @@ export class SubsonicMusicService implements MusicService {
generateToken = ( generateToken = (
credentials: Credentials credentials: Credentials
): TE.TaskEither<AuthFailure, AuthSuccess> => { ): TE.TaskEither<AuthFailure, AuthSuccess> =>
const x: TE.TaskEither<AuthFailure, PingResponse> = TE.tryCatch(
() =>
this.subsonic.getJSON<PingResponse>(
_.pick(credentials, "username", "password"),
"/rest/ping.view"
),
(e) => new AuthFailure(e as string)
);
return pipe(
x,
TE.flatMap(({ type }) =>
pipe( pipe(
TE.tryCatch( this.subsonic.ping(credentials),
() => this.libraryFor({ ...credentials, type }), TE.flatMap(({ type }) => TE.tryCatch(
() => this.libraryFor({ ...credentials, type }).then(library => ({ type, library })),
() => new AuthFailure("Failed to get library") () => new AuthFailure("Failed to get library")
), )),
TE.map((library) => ({ type, library })) TE.flatMap(({ library, type }) => pipe(
)
),
TE.flatMap(({ library, type }) =>
pipe(
library.bearerToken(credentials), library.bearerToken(credentials),
TE.map((bearer) => ({ bearer, type })) TE.map(bearer => ({ bearer, type }))
) )),
),
TE.map(({ bearer, type}) => ({ TE.map(({ bearer, type}) => ({
serviceToken: asToken({ ...credentials, bearer, type }), serviceToken: asToken({ ...credentials, bearer, type }),
userId: credentials.username, userId: credentials.username,
nickname: credentials.username, nickname: credentials.username,
})) }))
); );
};
refreshToken = (serviceToken: string) => refreshToken = (serviceToken: string) =>
this.generateToken(parseToken(serviceToken)); this.generateToken(parseToken(serviceToken));
@@ -310,20 +292,7 @@ export class SubsonicMusicLibrary implements MusicLibrary {
); );
radioStations = async () => radioStations = async () =>
this.subsonic this.subsonic.getInternetRadioStations(this.credentials);
.getJSON<GetInternetRadioStationsResponse>(
this.credentials,
"/rest/getInternetRadioStations"
)
.then((it) => it.internetRadioStations.internetRadioStation || [])
.then((stations) =>
stations.map((it) => ({
id: it.id,
name: it.name,
url: it.streamUrl,
homePage: it.homePageUrl,
}))
);
radioStation = async (id: string) => radioStation = async (id: string) =>
this.radioStations().then((it) => it.find((station) => station.id === id)!); this.radioStations().then((it) => it.find((station) => station.id === id)!);