mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-04 19:51:40 +00:00
restructure files onto electron-vite boilerplate
This commit is contained in:
parent
91ce2cd8a1
commit
1cf587bc8f
457 changed files with 9927 additions and 11705 deletions
|
|
@ -1,15 +1,17 @@
|
|||
import { useAuthStore } from '/@/renderer/store';
|
||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||
import { initClient, initContract } from '@ts-rest/core';
|
||||
import axios, { AxiosError, AxiosResponse, isAxiosError, Method } from 'axios';
|
||||
import qs from 'qs';
|
||||
import { ServerListItem } from '/@/renderer/api/types';
|
||||
import omitBy from 'lodash/omitBy';
|
||||
import qs from 'qs';
|
||||
import { z } from 'zod';
|
||||
import { authenticationFailure, getClientType } from '/@/renderer/api/utils';
|
||||
import i18n from '/@/i18n/i18n';
|
||||
|
||||
import packageJson from '../../../../package.json';
|
||||
|
||||
import i18n from '/@/i18n/i18n';
|
||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||
import { ServerListItem } from '/@/renderer/api/types';
|
||||
import { authenticationFailure, getClientType } from '/@/renderer/api/utils';
|
||||
import { useAuthStore } from '/@/renderer/store';
|
||||
|
||||
const c = initContract();
|
||||
|
||||
export const contract = c.router({
|
||||
|
|
@ -356,14 +358,14 @@ export const createAuthHeader = (): string => {
|
|||
};
|
||||
|
||||
export const jfApiClient = (args: {
|
||||
server: ServerListItem | null;
|
||||
server: null | ServerListItem;
|
||||
signal?: AbortSignal;
|
||||
url?: string;
|
||||
}) => {
|
||||
const { server, url, signal } = args;
|
||||
const { server, signal, url } = args;
|
||||
|
||||
return initClient(contract, {
|
||||
api: async ({ path, method, headers, body }) => {
|
||||
api: async ({ body, headers, method, path }) => {
|
||||
let baseUrl: string | undefined;
|
||||
let token: string | undefined;
|
||||
|
||||
|
|
@ -395,7 +397,7 @@ export const jfApiClient = (args: {
|
|||
headers: result.headers as any,
|
||||
status: result.status,
|
||||
};
|
||||
} catch (e: Error | AxiosError | any) {
|
||||
} catch (e: any | AxiosError | Error) {
|
||||
if (isAxiosError(e)) {
|
||||
if (e.code === 'ERR_NETWORK') {
|
||||
throw new Error(
|
||||
|
|
|
|||
|
|
@ -1,23 +1,25 @@
|
|||
import chunk from 'lodash/chunk';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { jfNormalize } from './jellyfin-normalize';
|
||||
|
||||
import { ServerFeature } from '/@/renderer/api/features-types';
|
||||
import { JFSongListSort, JFSortOrder } from '/@/renderer/api/jellyfin.types';
|
||||
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||
import {
|
||||
albumArtistListSortMap,
|
||||
sortOrderMap,
|
||||
albumListSortMap,
|
||||
songListSortMap,
|
||||
playlistListSortMap,
|
||||
genreListSortMap,
|
||||
Song,
|
||||
Played,
|
||||
ControllerEndpoint,
|
||||
genreListSortMap,
|
||||
LibraryItem,
|
||||
Played,
|
||||
playlistListSortMap,
|
||||
Song,
|
||||
songListSortMap,
|
||||
sortOrderMap,
|
||||
} from '/@/renderer/api/types';
|
||||
import { jfApiClient } from '/@/renderer/api/jellyfin/jellyfin-api';
|
||||
import { jfNormalize } from './jellyfin-normalize';
|
||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||
import { z } from 'zod';
|
||||
import { JFSongListSort, JFSortOrder } from '/@/renderer/api/jellyfin.types';
|
||||
import { ServerFeature } from '/@/renderer/api/features-types';
|
||||
import { VersionInfo, getFeatures, hasFeature } from '/@/renderer/api/utils';
|
||||
import chunk from 'lodash/chunk';
|
||||
import { getFeatures, hasFeature, VersionInfo } from '/@/renderer/api/utils';
|
||||
|
||||
const formatCommaDelimitedString = (value: string[]) => {
|
||||
return value.join(',');
|
||||
|
|
@ -41,7 +43,7 @@ const VERSION_INFO: VersionInfo = [
|
|||
|
||||
export const JellyfinController: ControllerEndpoint = {
|
||||
addToPlaylist: async (args) => {
|
||||
const { query, body, apiClientProps } = args;
|
||||
const { apiClientProps, body, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -89,7 +91,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
createFavorite: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -108,7 +110,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return null;
|
||||
},
|
||||
createPlaylist: async (args) => {
|
||||
const { body, apiClientProps } = args;
|
||||
const { apiClientProps, body } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -132,7 +134,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
deleteFavorite: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -151,7 +153,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return null;
|
||||
},
|
||||
deletePlaylist: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).deletePlaylist({
|
||||
params: {
|
||||
|
|
@ -166,7 +168,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return null;
|
||||
},
|
||||
getAlbumArtistDetail: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -201,7 +203,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
);
|
||||
},
|
||||
getAlbumArtistList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).getAlbumArtistList({
|
||||
query: {
|
||||
|
|
@ -236,7 +238,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getAlbumDetail: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -274,7 +276,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
);
|
||||
},
|
||||
getAlbumList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -334,7 +336,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getArtistList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).getArtistList({
|
||||
query: {
|
||||
|
|
@ -404,7 +406,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
getLyrics: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -453,7 +455,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
getPlaylistDetail: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -477,7 +479,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return jfNormalize.playlist(res.body, apiClientProps.server);
|
||||
},
|
||||
getPlaylistList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -515,7 +517,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
query: { ...query, limit: 1, startIndex: 0 },
|
||||
}).then((result) => result!.totalRecordCount!),
|
||||
getPlaylistSongList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -547,7 +549,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
getRandomSongList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -668,7 +670,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
}, []);
|
||||
},
|
||||
getSongDetail: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const res = await jfApiClient(apiClientProps).getSongDetail({
|
||||
params: {
|
||||
|
|
@ -684,7 +686,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return jfNormalize.song(res.body, apiClientProps.server, '');
|
||||
},
|
||||
getSongList: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -864,7 +866,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
getTranscodingUrl: (args) => {
|
||||
const { base, format, bitrate } = args.query;
|
||||
const { base, bitrate, format } = args.query;
|
||||
let url = base.replace('transcodingProtocol=hls', 'transcodingProtocol=http');
|
||||
if (format) {
|
||||
url = url.replace('audioCodec=aac', `audioCodec=${format}`);
|
||||
|
|
@ -892,7 +894,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
}
|
||||
},
|
||||
removeFromPlaylist: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const chunks = chunk(query.songId, MAX_ITEMS_PER_PLAYLIST_ADD);
|
||||
|
||||
|
|
@ -914,7 +916,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return null;
|
||||
},
|
||||
scrobble: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
const position = query.position && Math.round(query.position);
|
||||
|
||||
|
|
@ -978,7 +980,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
return null;
|
||||
},
|
||||
search: async (args) => {
|
||||
const { query, apiClientProps } = args;
|
||||
const { apiClientProps, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
@ -1071,7 +1073,7 @@ export const JellyfinController: ControllerEndpoint = {
|
|||
};
|
||||
},
|
||||
updatePlaylist: async (args) => {
|
||||
const { query, body, apiClientProps } = args;
|
||||
const { apiClientProps, body, query } = args;
|
||||
|
||||
if (!apiClientProps.server?.userId) {
|
||||
throw new Error('No userId found');
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
import { nanoid } from 'nanoid';
|
||||
import { z } from 'zod';
|
||||
import { JFAlbum, JFPlaylist, JFMusicFolder, JFGenre } from '/@/renderer/api/jellyfin.types';
|
||||
|
||||
import { JFAlbum, JFGenre, JFMusicFolder, JFPlaylist } from '/@/renderer/api/jellyfin.types';
|
||||
import { jfType } from '/@/renderer/api/jellyfin/jellyfin-types';
|
||||
import {
|
||||
Song,
|
||||
LibraryItem,
|
||||
Album,
|
||||
AlbumArtist,
|
||||
Playlist,
|
||||
MusicFolder,
|
||||
Genre,
|
||||
LibraryItem,
|
||||
MusicFolder,
|
||||
Playlist,
|
||||
RelatedArtist,
|
||||
ServerListItem,
|
||||
ServerType,
|
||||
RelatedArtist,
|
||||
Song,
|
||||
} from '/@/renderer/api/types';
|
||||
|
||||
const getStreamUrl = (args: {
|
||||
|
|
@ -21,9 +22,9 @@ const getStreamUrl = (args: {
|
|||
eTag?: string;
|
||||
id: string;
|
||||
mediaSourceId?: string;
|
||||
server: ServerListItem | null;
|
||||
server: null | ServerListItem;
|
||||
}) => {
|
||||
const { id, server, deviceId } = args;
|
||||
const { deviceId, id, server } = args;
|
||||
|
||||
return (
|
||||
`${server?.url}/audio` +
|
||||
|
|
@ -122,9 +123,9 @@ const getPlaylistCoverArtUrl = (args: { baseUrl: string; item: JFPlaylist; size:
|
|||
);
|
||||
};
|
||||
|
||||
type AlbumOrSong = z.infer<typeof jfType._response.song> | z.infer<typeof jfType._response.album>;
|
||||
type AlbumOrSong = z.infer<typeof jfType._response.album> | z.infer<typeof jfType._response.song>;
|
||||
|
||||
const getPeople = (item: AlbumOrSong): Record<string, RelatedArtist[]> | null => {
|
||||
const getPeople = (item: AlbumOrSong): null | Record<string, RelatedArtist[]> => {
|
||||
if (item.People) {
|
||||
const participants: Record<string, RelatedArtist[]> = {};
|
||||
|
||||
|
|
@ -151,7 +152,7 @@ const getPeople = (item: AlbumOrSong): Record<string, RelatedArtist[]> | null =>
|
|||
return null;
|
||||
};
|
||||
|
||||
const getTags = (item: AlbumOrSong): Record<string, string[]> | null => {
|
||||
const getTags = (item: AlbumOrSong): null | Record<string, string[]> => {
|
||||
if (item.Tags) {
|
||||
const tags: Record<string, string[]> = {};
|
||||
for (const tag of item.Tags) {
|
||||
|
|
@ -166,7 +167,7 @@ const getTags = (item: AlbumOrSong): Record<string, string[]> | null => {
|
|||
|
||||
const normalizeSong = (
|
||||
item: z.infer<typeof jfType._response.song>,
|
||||
server: ServerListItem | null,
|
||||
server: null | ServerListItem,
|
||||
deviceId: string,
|
||||
imageSize?: number,
|
||||
): Song => {
|
||||
|
|
@ -252,7 +253,7 @@ const normalizeSong = (
|
|||
|
||||
const normalizeAlbum = (
|
||||
item: z.infer<typeof jfType._response.album>,
|
||||
server: ServerListItem | null,
|
||||
server: null | ServerListItem,
|
||||
imageSize?: number,
|
||||
): Album => {
|
||||
return {
|
||||
|
|
@ -312,7 +313,7 @@ const normalizeAlbumArtist = (
|
|||
item: z.infer<typeof jfType._response.albumArtist> & {
|
||||
similarArtists?: z.infer<typeof jfType._response.albumArtistList>;
|
||||
},
|
||||
server: ServerListItem | null,
|
||||
server: null | ServerListItem,
|
||||
imageSize?: number,
|
||||
): AlbumArtist => {
|
||||
const similarArtists =
|
||||
|
|
@ -361,7 +362,7 @@ const normalizeAlbumArtist = (
|
|||
|
||||
const normalizePlaylist = (
|
||||
item: z.infer<typeof jfType._response.playlist>,
|
||||
server: ServerListItem | null,
|
||||
server: null | ServerListItem,
|
||||
imageSize?: number,
|
||||
): Playlist => {
|
||||
const imageUrl = getPlaylistCoverArtUrl({
|
||||
|
|
@ -445,7 +446,7 @@ const getGenreCoverArtUrl = (args: {
|
|||
);
|
||||
};
|
||||
|
||||
const normalizeGenre = (item: JFGenre, server: ServerListItem | null): Genre => {
|
||||
const normalizeGenre = (item: JFGenre, server: null | ServerListItem): Genre => {
|
||||
return {
|
||||
albumCount: undefined,
|
||||
id: item.Id,
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ const imageBlurHashes = z.object({
|
|||
const userData = z.object({
|
||||
IsFavorite: z.boolean(),
|
||||
Key: z.string(),
|
||||
PlayCount: z.number(),
|
||||
PlaybackPositionTicks: z.number(),
|
||||
PlayCount: z.number(),
|
||||
Played: z.boolean(),
|
||||
});
|
||||
|
||||
|
|
@ -187,13 +187,13 @@ const sessionInfo = z.object({
|
|||
LastPlaybackCheckIn: z.string(),
|
||||
NowPlayingQueue: z.array(z.any()),
|
||||
NowPlayingQueueFullItems: z.array(z.any()),
|
||||
PlayableMediaTypes: z.array(z.any()),
|
||||
PlayState: z.object({
|
||||
CanSeek: z.boolean(),
|
||||
IsMuted: z.boolean(),
|
||||
IsPaused: z.boolean(),
|
||||
RepeatMode: z.string(),
|
||||
}),
|
||||
PlayableMediaTypes: z.array(z.any()),
|
||||
RemoteEndPoint: z.string(),
|
||||
ServerId: z.string(),
|
||||
SupportedCommands: z.array(z.any()),
|
||||
|
|
@ -223,10 +223,10 @@ const configuration = z.object({
|
|||
const policy = z.object({
|
||||
AccessSchedules: z.array(z.any()),
|
||||
AuthenticationProviderId: z.string(),
|
||||
BlockUnratedItems: z.array(z.any()),
|
||||
BlockedChannels: z.array(z.any()),
|
||||
BlockedMediaFolders: z.array(z.any()),
|
||||
BlockedTags: z.array(z.any()),
|
||||
BlockUnratedItems: z.array(z.any()),
|
||||
EnableAllChannels: z.boolean(),
|
||||
EnableAllDevices: z.boolean(),
|
||||
EnableAllFolders: z.boolean(),
|
||||
|
|
@ -234,6 +234,9 @@ const policy = z.object({
|
|||
EnableContentDeletion: z.boolean(),
|
||||
EnableContentDeletionFromFolders: z.array(z.any()),
|
||||
EnableContentDownloading: z.boolean(),
|
||||
EnabledChannels: z.array(z.any()),
|
||||
EnabledDevices: z.array(z.any()),
|
||||
EnabledFolders: z.array(z.any()),
|
||||
EnableLiveTvAccess: z.boolean(),
|
||||
EnableLiveTvManagement: z.boolean(),
|
||||
EnableMediaConversion: z.boolean(),
|
||||
|
|
@ -246,9 +249,6 @@ const policy = z.object({
|
|||
EnableSyncTranscoding: z.boolean(),
|
||||
EnableUserPreferenceAccess: z.boolean(),
|
||||
EnableVideoPlaybackTranscoding: z.boolean(),
|
||||
EnabledChannels: z.array(z.any()),
|
||||
EnabledDevices: z.array(z.any()),
|
||||
EnabledFolders: z.array(z.any()),
|
||||
ForceRemoteSourceTranscoding: z.boolean(),
|
||||
InvalidLoginAttemptCount: z.number(),
|
||||
IsAdministrator: z.boolean(),
|
||||
|
|
@ -414,8 +414,8 @@ const song = z.object({
|
|||
ImageTags: imageTags,
|
||||
IndexNumber: z.number(),
|
||||
IsFolder: z.boolean(),
|
||||
LUFS: z.number().optional(),
|
||||
LocationType: z.string(),
|
||||
LUFS: z.number().optional(),
|
||||
MediaSources: z.array(mediaSources),
|
||||
MediaType: z.string(),
|
||||
Name: z.string(),
|
||||
|
|
@ -654,8 +654,8 @@ const favorite = z.object({
|
|||
Key: z.string(),
|
||||
LastPlayedDate: z.string(),
|
||||
Likes: z.boolean(),
|
||||
PlayCount: z.number(),
|
||||
PlaybackPositionTicks: z.number(),
|
||||
PlayCount: z.number(),
|
||||
Played: z.boolean(),
|
||||
PlayedPercentage: z.number(),
|
||||
Rating: z.number(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue