From a5a12f1658b44fc0f89e3eec7b45d489d4a2e567 Mon Sep 17 00:00:00 2001 From: Sam Chau Date: Sun, 28 Dec 2025 20:14:28 +1030 Subject: [PATCH] feat(delay-profiles): add delay profile queries and types for database integration --- .../server/pcd/queries/delayProfiles/index.ts | 9 ++ .../server/pcd/queries/delayProfiles/list.ts | 75 +++++++++++++ .../server/pcd/queries/delayProfiles/types.ts | 21 ++++ src/lib/server/pcd/schema.ts | 103 ++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 src/lib/server/pcd/queries/delayProfiles/index.ts create mode 100644 src/lib/server/pcd/queries/delayProfiles/list.ts create mode 100644 src/lib/server/pcd/queries/delayProfiles/types.ts diff --git a/src/lib/server/pcd/queries/delayProfiles/index.ts b/src/lib/server/pcd/queries/delayProfiles/index.ts new file mode 100644 index 0000000..8652e99 --- /dev/null +++ b/src/lib/server/pcd/queries/delayProfiles/index.ts @@ -0,0 +1,9 @@ +/** + * Delay Profile queries + */ + +// Export all types +export type { DelayProfileTableRow, PreferredProtocol } from './types.ts'; + +// Export query functions +export { list } from './list.ts'; diff --git a/src/lib/server/pcd/queries/delayProfiles/list.ts b/src/lib/server/pcd/queries/delayProfiles/list.ts new file mode 100644 index 0000000..f466cdb --- /dev/null +++ b/src/lib/server/pcd/queries/delayProfiles/list.ts @@ -0,0 +1,75 @@ +/** + * Delay profile list queries + */ + +import type { PCDCache } from '../../cache.ts'; +import type { Tag } from '../../types.ts'; +import type { DelayProfileTableRow, PreferredProtocol } from './types.ts'; + +/** + * Get delay profiles with full data for table/card views + */ +export async function list(cache: PCDCache): Promise { + const db = cache.kb; + + // 1. Get all delay profiles + const profiles = await db + .selectFrom('delay_profiles') + .select([ + 'id', + 'name', + 'preferred_protocol', + 'usenet_delay', + 'torrent_delay', + 'bypass_if_highest_quality', + 'bypass_if_above_custom_format_score', + 'minimum_custom_format_score' + ]) + .orderBy('name') + .execute(); + + if (profiles.length === 0) return []; + + const profileIds = profiles.map((p) => p.id); + + // 2. Get all tags for all profiles + const allTags = await db + .selectFrom('delay_profile_tags as dpt') + .innerJoin('tags as t', 't.id', 'dpt.tag_id') + .select([ + 'dpt.delay_profile_id', + 't.id as tag_id', + 't.name as tag_name', + 't.created_at as tag_created_at' + ]) + .where('dpt.delay_profile_id', 'in', profileIds) + .orderBy('dpt.delay_profile_id') + .orderBy('t.name') + .execute(); + + // Build tags map + const tagsMap = new Map(); + for (const tag of allTags) { + if (!tagsMap.has(tag.delay_profile_id)) { + tagsMap.set(tag.delay_profile_id, []); + } + tagsMap.get(tag.delay_profile_id)!.push({ + id: tag.tag_id, + name: tag.tag_name, + created_at: tag.tag_created_at + }); + } + + // Build the final result + return profiles.map((profile) => ({ + id: profile.id, + name: profile.name, + preferred_protocol: profile.preferred_protocol as PreferredProtocol, + usenet_delay: profile.usenet_delay, + torrent_delay: profile.torrent_delay, + bypass_if_highest_quality: profile.bypass_if_highest_quality === 1, + bypass_if_above_custom_format_score: profile.bypass_if_above_custom_format_score === 1, + minimum_custom_format_score: profile.minimum_custom_format_score, + tags: tagsMap.get(profile.id) || [] + })); +} diff --git a/src/lib/server/pcd/queries/delayProfiles/types.ts b/src/lib/server/pcd/queries/delayProfiles/types.ts new file mode 100644 index 0000000..a94a10e --- /dev/null +++ b/src/lib/server/pcd/queries/delayProfiles/types.ts @@ -0,0 +1,21 @@ +/** + * Delay Profile query-specific types + */ + +import type { Tag } from '../../types.ts'; + +/** Preferred protocol options */ +export type PreferredProtocol = 'prefer_usenet' | 'prefer_torrent' | 'only_usenet' | 'only_torrent'; + +/** Delay profile data for table/card views */ +export interface DelayProfileTableRow { + id: number; + name: string; + preferred_protocol: PreferredProtocol; + usenet_delay: number | null; + torrent_delay: number | null; + bypass_if_highest_quality: boolean; + bypass_if_above_custom_format_score: boolean; + minimum_custom_format_score: number | null; + tags: Tag[]; +} diff --git a/src/lib/server/pcd/schema.ts b/src/lib/server/pcd/schema.ts index d027a5a..08ab11d 100644 --- a/src/lib/server/pcd/schema.ts +++ b/src/lib/server/pcd/schema.ts @@ -39,6 +39,13 @@ export interface QualitiesTable { updated_at: Generated; } +export interface QualityApiMappingsTable { + quality_id: number; + arr_type: string; + api_name: string; + created_at: Generated; +} + export interface CustomFormatsTable { id: Generated; name: string; @@ -182,6 +189,93 @@ export interface ConditionYearsTable { max_year: number | null; } +// ============================================================================ +// DELAY PROFILES +// ============================================================================ + +export interface DelayProfilesTable { + id: Generated; + name: string; + preferred_protocol: string; + usenet_delay: number | null; + torrent_delay: number | null; + bypass_if_highest_quality: number; + bypass_if_above_custom_format_score: number; + minimum_custom_format_score: number | null; + created_at: Generated; + updated_at: Generated; +} + +export interface DelayProfileTagsTable { + delay_profile_id: number; + tag_id: number; +} + +// ============================================================================ +// MEDIA MANAGEMENT TABLES +// ============================================================================ + +export interface RadarrQualityDefinitionsTable { + quality_id: number; + min_size: number; + max_size: number; + preferred_size: number; + created_at: Generated; + updated_at: Generated; +} + +export interface SonarrQualityDefinitionsTable { + quality_id: number; + min_size: number; + max_size: number; + preferred_size: number; + created_at: Generated; + updated_at: Generated; +} + +export interface RadarrNamingTable { + id: number; + rename: number; + movie_format: string; + movie_folder_format: string; + replace_illegal_characters: number; + colon_replacement_format: string; + created_at: Generated; + updated_at: Generated; +} + +export interface SonarrNamingTable { + id: number; + rename: number; + standard_episode_format: string; + daily_episode_format: string; + anime_episode_format: string; + series_folder_format: string; + season_folder_format: string; + replace_illegal_characters: number; + colon_replacement_format: number; + custom_colon_replacement_format: string | null; + multi_episode_style: number; + created_at: Generated; + updated_at: Generated; +} + +export interface RadarrMediaSettingsTable { + id: number; + propers_repacks: string; + enable_media_info: number; + created_at: Generated; + updated_at: Generated; +} + +export interface SonarrMediaSettingsTable { + id: number; + propers_repacks: string; + enable_media_info: number; + created_at: Generated; + updated_at: Generated; +} + // ============================================================================ // DATABASE INTERFACE // ============================================================================ @@ -211,4 +305,13 @@ export interface PCDDatabase { condition_sizes: ConditionSizesTable; condition_release_types: ConditionReleaseTypesTable; condition_years: ConditionYearsTable; + delay_profiles: DelayProfilesTable; + delay_profile_tags: DelayProfileTagsTable; + quality_api_mappings: QualityApiMappingsTable; + radarr_quality_definitions: RadarrQualityDefinitionsTable; + sonarr_quality_definitions: SonarrQualityDefinitionsTable; + radarr_naming: RadarrNamingTable; + sonarr_naming: SonarrNamingTable; + radarr_media_settings: RadarrMediaSettingsTable; + sonarr_media_settings: SonarrMediaSettingsTable; }