Files
silo-server/web/src/lib/profile-management.ts
T

148 lines
4.3 KiB
TypeScript

import type { CreateProfileRequest, Profile } from "@/api/types";
import { avatarPresetRef, parseProfileAvatarPresetRef } from "@/lib/profile-avatars";
import {
formatPlaybackQualityPreset,
playbackQualityPresetFromValue,
playbackQualityValueFromPreset,
type PlaybackQualityPreset,
} from "@/lib/playback-quality";
export interface ProfileDraft {
name: string;
avatarPreset: string;
pin: string;
clearPin: boolean;
isChild: boolean;
maxContentRating: string;
maxPlaybackQuality: PlaybackQualityPreset;
libraryRestrictionsEnabled: boolean;
allowedLibraryIDs: number[];
}
export interface ContentRatingOption {
value: string;
label: string;
summary: string;
}
export interface ProfileAccessSummary {
contentRating: string;
libraries: string;
playbackQuality: string;
text: string;
}
export const CONTENT_RATING_OPTIONS: ContentRatingOption[] = [
{ value: "", label: "Any content", summary: "Any content" },
{ value: "G", label: "G / TV-G", summary: "G max" },
{ value: "PG", label: "PG / TV-PG / TV-Y7", summary: "PG max" },
{ value: "PG-13", label: "PG-13 / TV-14", summary: "PG-13 max" },
{ value: "R", label: "R / TV-MA / NC-17", summary: "R max" },
];
function sortUniqueLibraryIDs(ids: number[] | null | undefined): number[] {
if (!ids || ids.length === 0) {
return [];
}
return [...new Set(ids.filter((id) => Number.isInteger(id) && id > 0))].sort((a, b) => a - b);
}
export function createProfileDraft(profile?: Profile | null): ProfileDraft {
return {
name: profile?.name ?? "",
avatarPreset: parseProfileAvatarPresetRef(profile?.avatar),
pin: "",
clearPin: false,
isChild: profile?.is_child ?? false,
maxContentRating: profile?.max_content_rating ?? "",
maxPlaybackQuality: playbackQualityPresetFromValue(profile?.max_playback_quality),
libraryRestrictionsEnabled: profile?.library_restrictions_enabled ?? false,
allowedLibraryIDs: sortUniqueLibraryIDs(profile?.allowed_library_ids),
};
}
export function buildProfileRequestFromDraft(draft: ProfileDraft): CreateProfileRequest {
const body: CreateProfileRequest = {
name: draft.name.trim(),
avatar: draft.avatarPreset ? avatarPresetRef(draft.avatarPreset) : "",
is_child: draft.isChild,
max_content_rating: draft.maxContentRating,
max_playback_quality: playbackQualityValueFromPreset(draft.maxPlaybackQuality),
library_restrictions_enabled: draft.libraryRestrictionsEnabled,
allowed_library_ids: draft.libraryRestrictionsEnabled
? sortUniqueLibraryIDs(draft.allowedLibraryIDs)
: [],
};
if (draft.clearPin) {
body.pin = "";
} else if (draft.pin.trim() !== "") {
body.pin = draft.pin.trim();
}
return body;
}
export function buildProfileAccessSummary(
profile: Pick<
Profile,
| "max_content_rating"
| "library_restrictions_enabled"
| "allowed_library_ids"
| "max_playback_quality"
>,
): ProfileAccessSummary {
const contentRating =
CONTENT_RATING_OPTIONS.find((option) => option.value === profile.max_content_rating)?.summary ??
"Any content";
const libraryCount = sortUniqueLibraryIDs(profile.allowed_library_ids).length;
const libraries = profile.library_restrictions_enabled
? `${libraryCount} ${libraryCount === 1 ? "library" : "libraries"}`
: "All libraries";
const qualityLabel = formatPlaybackQualityPreset(profile.max_playback_quality);
const playbackQuality = `${qualityLabel} quality`;
return {
contentRating,
libraries,
playbackQuality,
text: [contentRating, libraries, playbackQuality].join(" · "),
};
}
export function applyKidsPreset(
draft: ProfileDraft,
options: {
contentRatingTouched: boolean;
libraryAccessTouched: boolean;
},
): ProfileDraft {
const next: ProfileDraft = {
...draft,
isChild: true,
};
if (!options.contentRatingTouched && next.maxContentRating === "") {
next.maxContentRating = "PG";
}
if (!options.libraryAccessTouched && !next.libraryRestrictionsEnabled) {
next.libraryRestrictionsEnabled = true;
next.allowedLibraryIDs = [];
}
return next;
}
export function clearKidsPreset(draft: ProfileDraft): ProfileDraft {
return {
...draft,
isChild: false,
maxContentRating: "",
maxPlaybackQuality: "any",
libraryRestrictionsEnabled: false,
allowedLibraryIDs: [],
};
}