mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-31 06:40:50 +01:00
fix: remove scoring streaming
This commit is contained in:
@@ -22,9 +22,8 @@
|
||||
},
|
||||
"tasks": {
|
||||
"dev": "APP_BASE_PATH=./dist/dev deno run -A npm:vite dev",
|
||||
"build": "APP_BASE_PATH=./dist/build deno run -A npm:vite build",
|
||||
"build": "APP_BASE_PATH=./dist/build deno run -A npm:vite build && deno compile --no-check --allow-net --allow-read --allow-write --allow-env --allow-ffi --allow-run --target x86_64-unknown-linux-gnu --output dist/build/profilarr dist/build/mod.ts",
|
||||
"preview": "APP_BASE_PATH=./dist/data ./dist/build/profilarr",
|
||||
"compile": "deno compile --no-check --allow-net --allow-read --allow-write --allow-env --allow-ffi --allow-run --target x86_64-unknown-linux-gnu --output dist/build/profilarr dist/build/mod.ts",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"test": "APP_BASE_PATH=./dist/test deno test src/tests --allow-read --allow-write --allow-env",
|
||||
|
||||
@@ -45,7 +45,8 @@ export async function list(cache: PCDCache): Promise<QualityProfileTableRow[]> {
|
||||
't.created_at as tag_created_at'
|
||||
])
|
||||
.where('qpt.quality_profile_id', 'in', profileIds)
|
||||
.orderBy(['qpt.quality_profile_id', 't.name'])
|
||||
.orderBy('qpt.quality_profile_id')
|
||||
.orderBy('t.name')
|
||||
.execute();
|
||||
|
||||
// 3. Get custom format counts grouped by arr_type
|
||||
@@ -72,7 +73,8 @@ export async function list(cache: PCDCache): Promise<QualityProfileTableRow[]> {
|
||||
'qg.name as group_name'
|
||||
])
|
||||
.where('qpq.quality_profile_id', 'in', profileIds)
|
||||
.orderBy(['qpq.quality_profile_id', 'qpq.position'])
|
||||
.orderBy('qpq.quality_profile_id')
|
||||
.orderBy('qpq.position')
|
||||
.execute();
|
||||
|
||||
// 5. Get languages for all profiles
|
||||
|
||||
@@ -4,12 +4,14 @@
|
||||
|
||||
import type { PCDCache } from '../../cache.ts';
|
||||
import type { QualityProfileScoring } from '../../types.ts';
|
||||
import { logger } from '$logger/logger.ts';
|
||||
|
||||
/**
|
||||
* Get quality profile scoring data
|
||||
* Returns all custom formats with their scores per arr type
|
||||
*/
|
||||
export async function scoring(cache: PCDCache, databaseId: number, profileId: number): Promise<QualityProfileScoring> {
|
||||
await logger.debug('scoring query called', { source: 'scoring', meta: { databaseId, profileId } });
|
||||
const db = cache.kb;
|
||||
|
||||
// 1. Get profile settings
|
||||
@@ -88,7 +90,7 @@ export async function scoring(cache: PCDCache, databaseId: number, profileId: nu
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
const result = {
|
||||
databaseId,
|
||||
arrTypes,
|
||||
customFormats: customFormatScoring,
|
||||
@@ -96,4 +98,8 @@ export async function scoring(cache: PCDCache, databaseId: number, profileId: nu
|
||||
upgrade_until_score: profile.upgrade_until_score,
|
||||
upgrade_score_increment: profile.upgrade_score_increment
|
||||
};
|
||||
|
||||
await logger.debug('scoring query completed', { source: 'scoring', meta: { customFormatCount: customFormatScoring.length } });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { ServerLoad } from '@sveltejs/kit';
|
||||
import { pcdManager } from '$pcd/pcd.ts';
|
||||
import * as qualityProfileQueries from '$pcd/queries/qualityProfiles/index.ts';
|
||||
|
||||
export const load: ServerLoad = async ({ params, isDataRequest }) => {
|
||||
export const load: ServerLoad = async ({ params }) => {
|
||||
const { databaseId, id } = params;
|
||||
|
||||
// Validate params exist
|
||||
@@ -29,23 +29,9 @@ export const load: ServerLoad = async ({ params, isDataRequest }) => {
|
||||
throw error(500, 'Database cache not available');
|
||||
}
|
||||
|
||||
// Always return synchronous data at top level, stream the heavy data
|
||||
if (isDataRequest) {
|
||||
// Client-side navigation - stream the data
|
||||
return {
|
||||
loaded: true, // Synchronous data to enable instant navigation
|
||||
streamed: {
|
||||
scoring: qualityProfileQueries.scoring(cache, currentDatabaseId, profileId)
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// Initial page load - await the data for SEO
|
||||
const scoringData = await qualityProfileQueries.scoring(cache, currentDatabaseId, profileId);
|
||||
return {
|
||||
loaded: true,
|
||||
streamed: {
|
||||
scoring: Promise.resolve(scoringData)
|
||||
}
|
||||
};
|
||||
}
|
||||
const scoringData = await qualityProfileQueries.scoring(cache, currentDatabaseId, profileId);
|
||||
|
||||
return {
|
||||
scoring: scoringData
|
||||
};
|
||||
};
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
let upgradeScoreIncrement = 0;
|
||||
let customFormatScores: Record<number, Record<string, number | null>> = {};
|
||||
let customFormatEnabled: Record<number, Record<string, boolean>> = {};
|
||||
let scoringData: any = null;
|
||||
|
||||
// Track initial values
|
||||
let initialMinimumScore = 0;
|
||||
@@ -306,25 +305,51 @@
|
||||
return arrTypeColors[arrType] || '#3b82f6'; // default to blue
|
||||
}
|
||||
|
||||
$: scoring = data.scoring;
|
||||
|
||||
// Compute filtered and sorted formats
|
||||
$: searchQuery = ($searchStore.query ?? '').trim().toLowerCase();
|
||||
$: filteredCustomFormats = scoring?.customFormats.filter((format) => {
|
||||
if (searchQuery && !format.name?.toLowerCase().includes(searchQuery)) {
|
||||
return false;
|
||||
}
|
||||
if (hideUnscoredFormats) {
|
||||
const hasAnyScore = scoring.arrTypes.some((arrType) => format.scores[arrType] !== null);
|
||||
if (!hasAnyScore) return false;
|
||||
}
|
||||
return true;
|
||||
}) || [];
|
||||
|
||||
$: sortedCustomFormats = sortFormats(filteredCustomFormats, state, sortState);
|
||||
$: groupedFormats = groupFormats(sortedCustomFormats, selectedGroups);
|
||||
|
||||
// Apply default sort
|
||||
$: if (scoring && !sortState) {
|
||||
const defaultSortKey = (scoring.arrTypes.includes('radarr') ? 'radarr' : scoring.arrTypes[0]) as SortKey;
|
||||
if (defaultSortKey) {
|
||||
sortState = { key: defaultSortKey, direction: 'desc' };
|
||||
}
|
||||
}
|
||||
|
||||
// Reactive state - initialize from data
|
||||
$: if (scoringData) {
|
||||
minimumScore = scoringData.minimum_custom_format_score;
|
||||
upgradeUntilScore = scoringData.upgrade_until_score;
|
||||
upgradeScoreIncrement = scoringData.upgrade_score_increment;
|
||||
$: if (scoring) {
|
||||
minimumScore = scoring.minimum_custom_format_score;
|
||||
upgradeUntilScore = scoring.upgrade_until_score;
|
||||
upgradeScoreIncrement = scoring.upgrade_score_increment;
|
||||
|
||||
// Save initial values
|
||||
initialMinimumScore = scoringData.minimum_custom_format_score;
|
||||
initialUpgradeUntilScore = scoringData.upgrade_until_score;
|
||||
initialUpgradeScoreIncrement = scoringData.upgrade_score_increment;
|
||||
initialMinimumScore = scoring.minimum_custom_format_score;
|
||||
initialUpgradeUntilScore = scoring.upgrade_until_score;
|
||||
initialUpgradeScoreIncrement = scoring.upgrade_score_increment;
|
||||
|
||||
// Initialize scores and enabled state from data
|
||||
const newScores: Record<number, Record<string, number | null>> = {};
|
||||
const newEnabled: Record<number, Record<string, boolean>> = {};
|
||||
|
||||
scoringData.customFormats.forEach((cf: any) => {
|
||||
scoring.customFormats.forEach((cf: any) => {
|
||||
newScores[cf.id] = { ...cf.scores };
|
||||
newEnabled[cf.id] = {};
|
||||
scoringData.arrTypes.forEach((arrType: string) => {
|
||||
scoring.arrTypes.forEach((arrType: string) => {
|
||||
newEnabled[cf.id][arrType] = cf.scores[arrType] !== null;
|
||||
});
|
||||
});
|
||||
@@ -437,78 +462,8 @@
|
||||
|
||||
<UnsavedChangesModal />
|
||||
|
||||
{#await data.streamed.scoring}
|
||||
<!-- Loading skeleton -->
|
||||
<div class="mt-6 space-y-6 animate-pulse">
|
||||
<!-- Profile-level Score Settings Skeleton -->
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||
{#each [1, 2, 3] as _}
|
||||
<div class="space-y-2">
|
||||
<div class="h-5 w-32 rounded bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
<div class="h-4 w-48 rounded bg-neutral-100 dark:bg-neutral-800"></div>
|
||||
<div class="h-10 w-full rounded-lg bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Section Header Skeleton -->
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="space-y-2">
|
||||
<div class="h-5 w-48 rounded bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
<div class="h-4 w-64 rounded bg-neutral-100 dark:bg-neutral-800"></div>
|
||||
</div>
|
||||
<div class="h-8 w-16 rounded-lg bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
</div>
|
||||
|
||||
<!-- Table Skeleton -->
|
||||
<div class="overflow-x-auto rounded-lg border border-neutral-200 dark:border-neutral-800">
|
||||
<div class="w-full">
|
||||
<div class="border-b border-neutral-200 bg-neutral-50 p-6 dark:border-neutral-800 dark:bg-neutral-800">
|
||||
<div class="flex gap-4">
|
||||
<div class="h-4 w-48 rounded bg-neutral-300 dark:bg-neutral-600"></div>
|
||||
<div class="h-4 w-24 rounded bg-neutral-300 dark:bg-neutral-600"></div>
|
||||
<div class="h-4 w-24 rounded bg-neutral-300 dark:bg-neutral-600"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2 p-6">
|
||||
{#each [1, 2, 3, 4, 5] as _}
|
||||
<div class="flex gap-4">
|
||||
<div class="h-10 w-48 rounded bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
<div class="h-10 w-24 rounded bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
<div class="h-10 w-24 rounded bg-neutral-200 dark:bg-neutral-700"></div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:then scoring}
|
||||
{@const _ = (scoringData = scoring, null)}
|
||||
{@const searchQuery = ($searchStore.query ?? '').trim().toLowerCase()}
|
||||
{@const filteredCustomFormats = scoring.customFormats.filter((format) => {
|
||||
// Filter by search
|
||||
if (searchQuery && !format.name?.toLowerCase().includes(searchQuery)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filter unscored formats if option is enabled
|
||||
if (hideUnscoredFormats) {
|
||||
const hasAnyScore = scoring.arrTypes.some((arrType) => format.scores[arrType] !== null);
|
||||
if (!hasAnyScore) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})}
|
||||
{@const defaultSortKey = (scoring.arrTypes.includes('radarr') ? 'radarr' : scoring.arrTypes[0]) as SortKey}
|
||||
{@const _applyDefaultSort = (() => {
|
||||
if (!sortState && defaultSortKey) {
|
||||
sortState = { key: defaultSortKey, direction: 'desc' };
|
||||
}
|
||||
return null;
|
||||
})()}
|
||||
{@const sortedCustomFormats = sortFormats(filteredCustomFormats, state, sortState)}
|
||||
{@const groupedFormats = groupFormats(sortedCustomFormats, selectedGroups)}
|
||||
<div class="mt-6 space-y-6" on:change={() => unsavedChanges.markDirty()}>
|
||||
{#if scoring}
|
||||
<div class="mt-6 space-y-6" on:change={() => unsavedChanges.markDirty()}>
|
||||
<!-- Profile-level Score Settings -->
|
||||
<div class="grid grid-cols-1 gap-6 md:grid-cols-3">
|
||||
<div class="space-y-2">
|
||||
@@ -855,7 +810,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
<InfoModal bind:open={showInfoModal} header="Custom Format Scoring">
|
||||
<div class="space-y-4 text-sm text-neutral-600 dark:text-neutral-400">
|
||||
|
||||
Reference in New Issue
Block a user