chore: refactor

This commit is contained in:
Fredrik Burmester
2024-08-06 23:53:00 +02:00
parent 415db8f1c2
commit d4d3cbbc43
28 changed files with 1075 additions and 1445 deletions

View File

@@ -0,0 +1,18 @@
import { Api } from "@jellyfin/sdk";
import { getImageApi } from "@jellyfin/sdk/lib/utils/api";
export const getPrimaryImage = async (
api: Api,
itemId: string,
): Promise<string> => {
const image = await getImageApi(api).getItemImage({
itemId,
imageType: "Primary",
quality: 90,
width: 1000,
});
console.log("getPrimaryImage ~", image.data);
return image.data;
};

View File

@@ -0,0 +1,46 @@
import { Api } from "@jellyfin/sdk";
import {
getMediaInfoApi,
getUserLibraryApi,
} from "@jellyfin/sdk/lib/utils/api";
/**
* Fetches the media info for a given item.
*
* @param {Api} api - The Jellyfin API instance.
* @param {string} itemId - The ID of the media to fetch info for.
* @param {string} userId - The ID of the user to fetch info for.
*
* @returns {Promise<BaseItemDto>} - The media info.
*/
export const getUserItemData = async ({
api,
itemId,
userId,
}: {
api: Api | null | undefined;
itemId: string | null | undefined;
userId: string | null | undefined;
}) => {
if (!api || !itemId || !userId) {
return null;
}
return (await getUserLibraryApi(api).getItem({ itemId, userId })).data;
};
export const getPlaybackInfo = async (
api?: Api | null | undefined,
itemId?: string | null | undefined,
userId?: string | null | undefined,
) => {
if (!api || !itemId || !userId) {
return null;
}
const a = await getMediaInfoApi(api).getPlaybackInfo({
itemId,
userId,
});
return a.data;
};

View File

@@ -0,0 +1,8 @@
import { Api } from "@jellyfin/sdk";
/**
* Generates the authorization headers for Jellyfin API requests.
*/
export const getAuthHeaders = (api: Api) => ({
Authorization: `MediaBrowser DeviceId="${api.deviceInfo.id}", Token="${api.accessToken}"`,
});

View File

@@ -0,0 +1,47 @@
import { Api } from "@jellyfin/sdk";
import { AxiosError } from "axios";
interface MarkAsNotPlayedParams {
api: Api | null | undefined;
itemId: string | null | undefined;
userId: string | null | undefined;
}
/**
* Marks a media item as not played for a specific user.
*
* @param params - The parameters for marking an item as not played
* @returns A promise that resolves to true if the operation was successful, false otherwise
*/
export const markAsNotPlayed = async ({
api,
itemId,
userId,
}: MarkAsNotPlayedParams): Promise<boolean> => {
if (!api || !itemId || !userId) {
console.error("Invalid parameters for markAsNotPlayed");
return false;
}
try {
const response = await api.axiosInstance.delete(
`${api.basePath}/UserPlayedItems/${itemId}`,
{
params: { userId },
headers: {
Authorization: `MediaBrowser DeviceId="${api.deviceInfo.id}", Token="${api.accessToken}"`,
},
},
);
return response.status === 200;
} catch (error) {
const axiosError = error as AxiosError;
console.error(
"Failed to mark item as not played:",
axiosError.message,
axiosError.response?.status,
);
return false;
}
};

View File

@@ -0,0 +1,50 @@
import { Api } from "@jellyfin/sdk";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { AxiosError } from "axios";
import { getAuthHeaders } from "../jellyfin";
interface MarkAsPlayedParams {
api: Api | null | undefined;
item: BaseItemDto | null | undefined;
userId: string | null | undefined;
}
/**
* Marks a media item as played and updates its progress to completion.
*
* @param params - The parameters for marking an item as played
* @returns A promise that resolves to true if the operation was successful, false otherwise
*/
export const markAsPlayed = async ({
api,
item,
userId,
}: MarkAsPlayedParams): Promise<boolean> => {
if (!api || !item?.Id || !userId || !item.RunTimeTicks) {
console.error("Invalid parameters for markAsPlayed");
return false;
}
try {
const [playedResponse, progressResponse] = await Promise.all([
api.axiosInstance.post(
`${api.basePath}/UserPlayedItems/${item.Id}`,
{ userId, datePlayed: new Date().toISOString() },
{ headers: getAuthHeaders(api) },
),
api.axiosInstance.post(
`${api.basePath}/Sessions/Playing/Progress`,
{
ItemId: item.Id,
PositionTicks: item.RunTimeTicks,
MediaSourceId: item.Id,
},
{ headers: getAuthHeaders(api) },
),
]);
return playedResponse.status === 200 && progressResponse.status === 200;
} catch (error) {
return false;
}
};

View File

@@ -0,0 +1,44 @@
import { Api } from "@jellyfin/sdk";
import { AxiosError } from "axios";
import { getAuthHeaders } from "../jellyfin";
interface ReportPlaybackProgressParams {
api: Api | null | undefined;
sessionId: string | null | undefined;
itemId: string | null | undefined;
positionTicks: number | null | undefined;
}
/**
* Reports playback progress to the Jellyfin server.
*
* @param params - The parameters for reporting playback progress
* @throws {Error} If any required parameter is missing
*/
export const reportPlaybackProgress = async ({
api,
sessionId,
itemId,
positionTicks,
}: ReportPlaybackProgressParams): Promise<void> => {
if (!api || !sessionId || !itemId || positionTicks == null) {
throw new Error("Missing required parameters for reportPlaybackProgress");
}
try {
await api.axiosInstance.post(
`${api.basePath}/Sessions/Playing/Progress`,
{
ItemId: itemId,
PlaySessionId: sessionId,
IsPaused: false,
PositionTicks: Math.round(positionTicks),
CanSeek: true,
MediaSourceId: itemId,
},
{ headers: getAuthHeaders(api) },
);
} catch (error) {
console.log(error);
}
};

View File

@@ -0,0 +1,61 @@
import { Api } from "@jellyfin/sdk";
import { AxiosError } from "axios";
import { getAuthHeaders } from "../jellyfin";
interface PlaybackStoppedParams {
api: Api | null | undefined;
sessionId: string | null | undefined;
itemId: string | null | undefined;
positionTicks: number | null | undefined;
}
/**
* Reports playback stopped event to the Jellyfin server.
*
* @param {PlaybackStoppedParams} params - The parameters for the report.
* @param {Api} params.api - The Jellyfin API instance.
* @param {string} params.sessionId - The session ID.
* @param {string} params.itemId - The item ID.
* @param {number} params.positionTicks - The playback position in ticks.
*/
export const reportPlaybackStopped = async ({
api,
sessionId,
itemId,
positionTicks,
}: PlaybackStoppedParams): Promise<void> => {
// Validate input parameters
if (!api || !sessionId || !itemId || !positionTicks) {
console.log("Missing required parameters", {
api,
sessionId,
itemId,
positionTicks,
});
return;
}
try {
const url = `${api.basePath}/PlayingItems/${itemId}`;
const params = {
playSessionId: sessionId,
positionTicks: Math.round(positionTicks),
mediaSourceId: itemId,
};
const headers = getAuthHeaders(api);
// Send DELETE request to report playback stopped
await api.axiosInstance.delete(url, { params, headers });
} catch (error) {
// Log the error with additional context
if (error instanceof AxiosError) {
console.error(
"Failed to report playback progress",
error.message,
error.response?.data,
);
} else {
console.error("Failed to report playback progress", error);
}
}
};

View File

@@ -0,0 +1,45 @@
import { Api } from "@jellyfin/sdk";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { AxiosError } from "axios";
import { getAuthHeaders } from "../jellyfin";
interface NextUpParams {
itemId?: string | null;
userId?: string | null;
api?: Api | null;
}
/**
* Fetches the next up episodes for a series or all series for a user.
*
* @param params - The parameters for fetching next up episodes
* @returns A promise that resolves to an array of BaseItemDto representing the next up episodes
*/
export const nextUp = async ({
itemId,
userId,
api,
}: NextUpParams): Promise<BaseItemDto[]> => {
if (!userId || !api) {
console.error("Invalid parameters for nextUp: missing userId or api");
return [];
}
try {
const response = await api.axiosInstance.get<{ Items: BaseItemDto[] }>(
`${api.basePath}/Shows/NextUp`,
{
params: {
SeriesId: itemId || undefined,
UserId: userId,
Fields: "MediaSourceCount",
},
headers: getAuthHeaders(api),
},
);
return response.data.Items;
} catch (error) {
return [];
}
};