Fix frontend entrypoint for Vite build
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import { Playlist, ServerType, ApiResponse, PlexServerConnection, PlexConnectionSettings, PlexLibrary, RegexReplacement, SyncStrategy } from '../types';
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL || '';
|
||||
|
||||
const MODE_TO_STRATEGY: Record<string, SyncStrategy> = {
|
||||
local_force: SyncStrategy.LOCAL_OVERWRITE,
|
||||
remote_force: SyncStrategy.CLOUD_OVERWRITE,
|
||||
merge_local_primary: SyncStrategy.MERGE_LOCAL,
|
||||
merge_remote_primary: SyncStrategy.MERGE_CLOUD,
|
||||
};
|
||||
|
||||
const STRATEGY_TO_MODE: Record<SyncStrategy, string> = {
|
||||
[SyncStrategy.LOCAL_OVERWRITE]: 'local_force',
|
||||
[SyncStrategy.CLOUD_OVERWRITE]: 'remote_force',
|
||||
[SyncStrategy.MERGE_LOCAL]: 'merge_local_primary',
|
||||
[SyncStrategy.MERGE_CLOUD]: 'merge_remote_primary',
|
||||
};
|
||||
|
||||
const handleResponse = async <T>(response: Response): Promise<ApiResponse<T>> => {
|
||||
try {
|
||||
const data = await response.json();
|
||||
if (!response.ok) {
|
||||
return { data: data as T, status: 'error', message: (data as any)?.detail || response.statusText };
|
||||
}
|
||||
return { data, status: 'success' };
|
||||
} catch (error: any) {
|
||||
return { data: {} as T, status: 'error', message: error?.message || 'Unexpected error' };
|
||||
}
|
||||
};
|
||||
|
||||
const mapPlaylist = (item: any): Playlist => ({
|
||||
id: item.id || `${item.title}-${item.trackCount}`,
|
||||
title: item.title ?? item.name ?? 'Unknown',
|
||||
trackCount: item.trackCount ?? item.track_count ?? 0,
|
||||
lastUpdated: item.lastUpdated || item.last_updated || new Date().toISOString(),
|
||||
});
|
||||
|
||||
const mapLibrary = (item: any): PlexLibrary => ({
|
||||
id: item.id ?? item.title,
|
||||
title: item.title ?? item.id,
|
||||
type: item.type ?? 'artist',
|
||||
});
|
||||
|
||||
const mapRegexRules = (rules: any[]): RegexReplacement[] =>
|
||||
(rules || []).map((rule, index) => ({
|
||||
id: rule.id || `${rule.pattern || 'rule'}-${index}`,
|
||||
pattern: rule.pattern || '',
|
||||
replacement: rule.replacement || '',
|
||||
}));
|
||||
|
||||
export const apiService = {
|
||||
async getSettings(): Promise<ApiResponse<{ strategy: SyncStrategy; regex: RegexReplacement[]; connection: PlexConnectionSettings; localPath: string }>> {
|
||||
const response = await fetch(`${API_BASE}/api/settings`);
|
||||
const result = await handleResponse<any>(response);
|
||||
if (result.status === 'success') {
|
||||
const mode = result.data.sync_mode as string;
|
||||
const strategy = MODE_TO_STRATEGY[mode] || SyncStrategy.LOCAL_OVERWRITE;
|
||||
const regex = mapRegexRules(result.data.path_rules || []);
|
||||
const connection: PlexConnectionSettings = {
|
||||
protocol: (result.data.scheme as 'http' | 'https') || 'https',
|
||||
address: result.data.server_url || '',
|
||||
port: result.data.port || '32400',
|
||||
token: result.data.token || '',
|
||||
libraryName: result.data.library_name || '',
|
||||
};
|
||||
return { status: 'success', data: { strategy, regex, connection, localPath: result.data.local_path || '' } };
|
||||
}
|
||||
return result as ApiResponse<any> as ApiResponse<{ strategy: SyncStrategy; regex: RegexReplacement[]; connection: PlexConnectionSettings; localPath: string }>;
|
||||
},
|
||||
|
||||
async updateSyncStrategy(strategy: SyncStrategy): Promise<ApiResponse<{ sync_mode: string }>> {
|
||||
const payload = { mode: STRATEGY_TO_MODE[strategy] };
|
||||
const response = await fetch(`${API_BASE}/api/settings/sync-mode`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
return handleResponse(response);
|
||||
},
|
||||
|
||||
async saveRegexRules(replacements: RegexReplacement[]): Promise<ApiResponse<{ rules: RegexReplacement[] }>> {
|
||||
const payload = { rules: replacements.map(({ pattern, replacement }) => ({ pattern, replacement })) };
|
||||
const response = await fetch(`${API_BASE}/api/settings/regex-rules`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
return handleResponse(response);
|
||||
},
|
||||
|
||||
async updateLibrary(libraryName: string): Promise<ApiResponse<{ library_name: string }>> {
|
||||
const response = await fetch(`${API_BASE}/api/settings/library`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ library_name: libraryName }),
|
||||
});
|
||||
return handleResponse(response);
|
||||
},
|
||||
|
||||
async getPlaylists(serverType: ServerType, signal?: AbortSignal, localPath?: string): Promise<ApiResponse<Playlist[]>> {
|
||||
const params = new URLSearchParams({ server: serverType.toLowerCase() });
|
||||
if (serverType === ServerType.LOCAL && localPath) {
|
||||
params.append('local_path', localPath);
|
||||
}
|
||||
const response = await fetch(`${API_BASE}/api/playlists?${params.toString()}`, { signal });
|
||||
const result = await handleResponse<any>(response);
|
||||
if (result.status === 'success' && (result.data as any)?.playlists) {
|
||||
return { data: (result.data.playlists as any[]).map(mapPlaylist), status: 'success' };
|
||||
}
|
||||
return result as ApiResponse<Playlist[]>;
|
||||
},
|
||||
|
||||
async getServerStatus(signal?: AbortSignal): Promise<ApiResponse<PlexServerConnection>> {
|
||||
const response = await fetch(`${API_BASE}/api/server`, { signal });
|
||||
const result = await handleResponse<any>(response);
|
||||
if (result.status === 'success') {
|
||||
const info = result.data.serverInfo || {};
|
||||
const libraries: PlexLibrary[] = (result.data.libraries || []).map(mapLibrary);
|
||||
return {
|
||||
status: 'success',
|
||||
data: {
|
||||
isConnected: !!info.isConnected,
|
||||
name: info.name,
|
||||
ip: info.ip,
|
||||
port: info.port ? Number(info.port) : undefined,
|
||||
libraryName: info.libraryName,
|
||||
libraries,
|
||||
},
|
||||
};
|
||||
}
|
||||
return result as ApiResponse<PlexServerConnection>;
|
||||
},
|
||||
|
||||
async connectToPlex(settings: PlexConnectionSettings, signal?: AbortSignal): Promise<ApiResponse<{ token: string; serverInfo: PlexServerConnection }>> {
|
||||
const response = await fetch(`${API_BASE}/api/connect`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
protocol: settings.protocol,
|
||||
address: settings.address,
|
||||
port: settings.port,
|
||||
token: settings.token,
|
||||
username: settings.username,
|
||||
password: settings.password,
|
||||
library_name: settings.libraryName,
|
||||
timeout: settings.timeout,
|
||||
}),
|
||||
signal,
|
||||
});
|
||||
const result = await handleResponse<any>(response);
|
||||
if (result.status === 'success') {
|
||||
const info = result.data.serverInfo;
|
||||
info.libraries = (info.libraries || []).map(mapLibrary);
|
||||
return { status: 'success', data: { token: result.data.token, serverInfo: info } };
|
||||
}
|
||||
return result as ApiResponse<{ token: string; serverInfo: PlexServerConnection }>;
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user