mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-01-15 15:48:05 +00:00
325 lines
8.9 KiB
TypeScript
325 lines
8.9 KiB
TypeScript
import axios from "axios";
|
|
import type {
|
|
AddWatchlistItemResponse,
|
|
CreateWatchlistRequest,
|
|
CreateWatchlistResponse,
|
|
DeleteWatchlistResponse,
|
|
GetWatchlistItemsParams,
|
|
GetWatchlistsResponse,
|
|
RemoveWatchlistItemResponse,
|
|
StreamystatsRecommendationsFullResponse,
|
|
StreamystatsRecommendationsIdsResponse,
|
|
StreamystatsRecommendationsParams,
|
|
StreamystatsSearchFullResponse,
|
|
StreamystatsSearchIdsResponse,
|
|
StreamystatsSearchParams,
|
|
StreamystatsWatchlistDetailFullResponse,
|
|
StreamystatsWatchlistDetailIdsResponse,
|
|
StreamystatsWatchlistDetailParams,
|
|
StreamystatsWatchlistsFullResponse,
|
|
StreamystatsWatchlistsParams,
|
|
UpdateWatchlistRequest,
|
|
UpdateWatchlistResponse,
|
|
} from "./types";
|
|
|
|
interface StreamystatsApiConfig {
|
|
serverUrl: string;
|
|
jellyfinToken: string;
|
|
}
|
|
|
|
export const createStreamystatsApi = (config: StreamystatsApiConfig) => {
|
|
const { serverUrl, jellyfinToken } = config;
|
|
|
|
const baseUrl = serverUrl.endsWith("/") ? serverUrl.slice(0, -1) : serverUrl;
|
|
|
|
const headers = {
|
|
Authorization: `MediaBrowser Token="${jellyfinToken}"`,
|
|
};
|
|
|
|
const search = async (
|
|
params: StreamystatsSearchParams,
|
|
signal?: AbortSignal,
|
|
): Promise<
|
|
StreamystatsSearchIdsResponse | StreamystatsSearchFullResponse
|
|
> => {
|
|
const queryParams = new URLSearchParams();
|
|
queryParams.set("q", params.q);
|
|
|
|
if (params.limit) {
|
|
queryParams.set("limit", params.limit.toString());
|
|
}
|
|
if (params.format) {
|
|
queryParams.set("format", params.format);
|
|
}
|
|
if (params.type) {
|
|
queryParams.set("type", params.type);
|
|
}
|
|
|
|
const url = `${baseUrl}/api/search?${queryParams.toString()}`;
|
|
const response = await axios.get(url, { headers, signal });
|
|
|
|
return response.data;
|
|
};
|
|
|
|
const searchIds = async (
|
|
query: string,
|
|
type?: StreamystatsSearchParams["type"],
|
|
limit?: number,
|
|
signal?: AbortSignal,
|
|
): Promise<StreamystatsSearchIdsResponse> => {
|
|
return search(
|
|
{
|
|
q: query,
|
|
format: "ids",
|
|
type,
|
|
limit,
|
|
},
|
|
signal,
|
|
) as Promise<StreamystatsSearchIdsResponse>;
|
|
};
|
|
|
|
const searchFull = async (
|
|
query: string,
|
|
type?: StreamystatsSearchParams["type"],
|
|
limit?: number,
|
|
): Promise<StreamystatsSearchFullResponse> => {
|
|
return search({
|
|
q: query,
|
|
format: "full",
|
|
type,
|
|
limit,
|
|
}) as Promise<StreamystatsSearchFullResponse>;
|
|
};
|
|
|
|
const getRecommendations = async (
|
|
params: StreamystatsRecommendationsParams,
|
|
): Promise<
|
|
| StreamystatsRecommendationsIdsResponse
|
|
| StreamystatsRecommendationsFullResponse
|
|
> => {
|
|
const queryParams = new URLSearchParams();
|
|
|
|
if (params.serverId) {
|
|
queryParams.set("serverId", params.serverId.toString());
|
|
}
|
|
if (params.serverName) {
|
|
queryParams.set("serverName", params.serverName);
|
|
}
|
|
if (params.jellyfinServerId) {
|
|
queryParams.set("jellyfinServerId", params.jellyfinServerId);
|
|
}
|
|
if (params.limit) {
|
|
queryParams.set("limit", params.limit.toString());
|
|
}
|
|
if (params.type) {
|
|
queryParams.set("type", params.type);
|
|
}
|
|
if (params.range) {
|
|
queryParams.set("range", params.range);
|
|
}
|
|
if (params.format) {
|
|
queryParams.set("format", params.format);
|
|
}
|
|
if (params.includeBasedOn !== undefined) {
|
|
queryParams.set("includeBasedOn", params.includeBasedOn.toString());
|
|
}
|
|
if (params.includeReasons !== undefined) {
|
|
queryParams.set("includeReasons", params.includeReasons.toString());
|
|
}
|
|
|
|
const url = `${baseUrl}/api/recommendations?${queryParams.toString()}`;
|
|
const response = await axios.get(url, { headers });
|
|
|
|
return response.data;
|
|
};
|
|
|
|
const getRecommendationIds = async (
|
|
jellyfinServerId: string,
|
|
type?: StreamystatsRecommendationsParams["type"],
|
|
limit?: number,
|
|
): Promise<StreamystatsRecommendationsIdsResponse> => {
|
|
return getRecommendations({
|
|
jellyfinServerId,
|
|
format: "ids",
|
|
type,
|
|
limit,
|
|
includeBasedOn: false,
|
|
includeReasons: false,
|
|
}) as Promise<StreamystatsRecommendationsIdsResponse>;
|
|
};
|
|
|
|
const getPromotedWatchlists = async (
|
|
params: StreamystatsWatchlistsParams,
|
|
): Promise<StreamystatsWatchlistsFullResponse> => {
|
|
const queryParams = new URLSearchParams();
|
|
|
|
if (params.serverId) {
|
|
queryParams.set("serverId", params.serverId.toString());
|
|
}
|
|
if (params.serverName) {
|
|
queryParams.set("serverName", params.serverName);
|
|
}
|
|
if (params.serverUrl) {
|
|
queryParams.set("serverUrl", params.serverUrl);
|
|
}
|
|
if (params.jellyfinServerId) {
|
|
queryParams.set("jellyfinServerId", params.jellyfinServerId);
|
|
}
|
|
if (params.limit) {
|
|
queryParams.set("limit", params.limit.toString());
|
|
}
|
|
if (params.format) {
|
|
queryParams.set("format", params.format);
|
|
}
|
|
if (params.includePreview !== undefined) {
|
|
queryParams.set("includePreview", params.includePreview.toString());
|
|
}
|
|
|
|
const url = `${baseUrl}/api/watchlists/promoted?${queryParams.toString()}`;
|
|
const response = await axios.get(url, { headers });
|
|
|
|
return response.data;
|
|
};
|
|
|
|
const getWatchlistItemIds = async (
|
|
params: StreamystatsWatchlistDetailParams,
|
|
): Promise<StreamystatsWatchlistDetailIdsResponse> => {
|
|
const queryParams = new URLSearchParams();
|
|
queryParams.set("format", "ids");
|
|
|
|
if (params.serverId) {
|
|
queryParams.set("serverId", params.serverId.toString());
|
|
}
|
|
if (params.serverName) {
|
|
queryParams.set("serverName", params.serverName);
|
|
}
|
|
if (params.serverUrl) {
|
|
queryParams.set("serverUrl", params.serverUrl);
|
|
}
|
|
if (params.jellyfinServerId) {
|
|
queryParams.set("jellyfinServerId", params.jellyfinServerId);
|
|
}
|
|
|
|
const url = `${baseUrl}/api/watchlists/${params.watchlistId}?${queryParams.toString()}`;
|
|
const response = await axios.get(url, { headers });
|
|
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get all watchlists (own + public)
|
|
* GET /api/watchlists
|
|
*/
|
|
const getWatchlists = async (): Promise<GetWatchlistsResponse> => {
|
|
const url = `${baseUrl}/api/watchlists`;
|
|
const response = await axios.get(url, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Create a new watchlist
|
|
* POST /api/watchlists
|
|
*/
|
|
const createWatchlist = async (
|
|
data: CreateWatchlistRequest,
|
|
): Promise<CreateWatchlistResponse> => {
|
|
const url = `${baseUrl}/api/watchlists`;
|
|
const response = await axios.post(url, data, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get a single watchlist with items
|
|
* GET /api/watchlists/[id]
|
|
*/
|
|
const getWatchlistDetail = async (
|
|
watchlistId: number,
|
|
params?: GetWatchlistItemsParams,
|
|
): Promise<StreamystatsWatchlistDetailFullResponse> => {
|
|
const queryParams = new URLSearchParams();
|
|
queryParams.set("format", "full");
|
|
|
|
if (params?.type) {
|
|
queryParams.set("type", params.type);
|
|
}
|
|
if (params?.sort) {
|
|
queryParams.set("sort", params.sort);
|
|
}
|
|
|
|
const url = `${baseUrl}/api/watchlists/${watchlistId}?${queryParams.toString()}`;
|
|
const response = await axios.get(url, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Update a watchlist (owner only)
|
|
* PATCH /api/watchlists/[id]
|
|
*/
|
|
const updateWatchlist = async (
|
|
watchlistId: number,
|
|
data: UpdateWatchlistRequest,
|
|
): Promise<UpdateWatchlistResponse> => {
|
|
const url = `${baseUrl}/api/watchlists/${watchlistId}`;
|
|
const response = await axios.patch(url, data, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Delete a watchlist (owner only)
|
|
* DELETE /api/watchlists/[id]
|
|
*/
|
|
const deleteWatchlist = async (
|
|
watchlistId: number,
|
|
): Promise<DeleteWatchlistResponse> => {
|
|
const url = `${baseUrl}/api/watchlists/${watchlistId}`;
|
|
const response = await axios.delete(url, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Add an item to a watchlist (owner only)
|
|
* POST /api/watchlists/[id]/items
|
|
*/
|
|
const addWatchlistItem = async (
|
|
watchlistId: number,
|
|
itemId: string,
|
|
): Promise<AddWatchlistItemResponse> => {
|
|
const url = `${baseUrl}/api/watchlists/${watchlistId}/items`;
|
|
const response = await axios.post(url, { itemId }, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Remove an item from a watchlist (owner only)
|
|
* DELETE /api/watchlists/[id]/items/[itemId]
|
|
*/
|
|
const removeWatchlistItem = async (
|
|
watchlistId: number,
|
|
itemId: string,
|
|
): Promise<RemoveWatchlistItemResponse> => {
|
|
const url = `${baseUrl}/api/watchlists/${watchlistId}/items/${itemId}`;
|
|
const response = await axios.delete(url, { headers });
|
|
return response.data;
|
|
};
|
|
|
|
return {
|
|
search,
|
|
searchIds,
|
|
searchFull,
|
|
getRecommendations,
|
|
getRecommendationIds,
|
|
getPromotedWatchlists,
|
|
getWatchlistItemIds,
|
|
// Watchlist CRUD
|
|
getWatchlists,
|
|
createWatchlist,
|
|
getWatchlistDetail,
|
|
updateWatchlist,
|
|
deleteWatchlist,
|
|
addWatchlistItem,
|
|
removeWatchlistItem,
|
|
};
|
|
};
|
|
|
|
export type StreamystatsApi = ReturnType<typeof createStreamystatsApi>;
|