bugfixes
This commit is contained in:
parent
fd0bab67fb
commit
fa7df129f4
@ -1,2 +1,2 @@
|
||||
HTTPS_ENABLED=0
|
||||
HTTPS_ENABLED=1
|
||||
AUTH_RP_ORIGINS=https://l14pbbk95100006.tegdssd.de:9999,https://l14pbbk95100006.tegdssd.de:5173,https://localhost:9999,https://127.0.0.1:9999,https://10.0.1.25:9999,http://localhost:5173,http://127.0.0.1:5173,http://10.0.1.25:5173
|
||||
@ -8,7 +8,7 @@ import Tabs, { type TabItem } from './components/ui/Tabs'
|
||||
import RecorderSettings from './components/ui/RecorderSettings'
|
||||
import FinishedDownloads from './components/ui/FinishedDownloads'
|
||||
import Player from './components/ui/Player'
|
||||
import type { RecordJob } from './types'
|
||||
import type { RecordJob, JobEvent, RecorderSettingsState, TaskStateEvent, AnalysisProgressEvent, BackgroundSplitProgress } from './types'
|
||||
import Downloads from './components/ui/Downloads'
|
||||
import ModelsTab from './components/ui/ModelsTab'
|
||||
import ProgressBar from './components/ui/ProgressBar'
|
||||
@ -57,118 +57,6 @@ async function apiJSON<T>(url: string, init?: RequestInit): Promise<T> {
|
||||
return res.json() as Promise<T>
|
||||
}
|
||||
|
||||
type RecorderSettingsState = {
|
||||
recordDir: string
|
||||
doneDir: string
|
||||
ffmpegPath?: string
|
||||
autoAddToDownloadList?: boolean
|
||||
autoStartAddedDownloads?: boolean
|
||||
enableConcurrentDownloadsLimit?: boolean
|
||||
maxConcurrentDownloads?: number
|
||||
useChaturbateApi?: boolean
|
||||
useMyFreeCamsWatcher?: boolean
|
||||
autoDeleteSmallDownloads?: boolean
|
||||
autoDeleteSmallDownloadsBelowMB?: number
|
||||
blurPreviews?: boolean
|
||||
teaserPlayback?: 'still' | 'hover' | 'all'
|
||||
teaserAudio?: boolean
|
||||
lowDiskPauseBelowGB?: number
|
||||
enableNotifications?: boolean
|
||||
}
|
||||
|
||||
type JobEvent = {
|
||||
type?: 'job_upsert' | 'job_remove'
|
||||
model?: string
|
||||
jobId?: string
|
||||
status?: string
|
||||
phase?: string
|
||||
progress?: number
|
||||
sourceUrl?: string
|
||||
output?: string
|
||||
startedAt?: string
|
||||
startedAtMs?: number
|
||||
endedAt?: string
|
||||
endedAtMs?: number
|
||||
sizeBytes?: number
|
||||
durationSeconds?: number
|
||||
previewState?: string
|
||||
roomStatus?: string
|
||||
isOnline?: boolean
|
||||
modelImageUrl?: string
|
||||
modelChatRoomUrl?: string
|
||||
ts?: number
|
||||
error?: string
|
||||
|
||||
postWorkKey?: string
|
||||
postWork?: {
|
||||
state?: string
|
||||
position?: number
|
||||
waiting?: number
|
||||
running?: number
|
||||
maxParallel?: number
|
||||
}
|
||||
|
||||
// ✅ neu für finished_postwork
|
||||
file?: string
|
||||
assetId?: string
|
||||
queue?: 'postwork' | 'enrich'
|
||||
state?: 'queued' | 'running' | 'done' | 'error' | 'missing'
|
||||
label?: string
|
||||
position?: number
|
||||
waiting?: number
|
||||
running?: number
|
||||
maxParallel?: number
|
||||
}
|
||||
|
||||
type TaskStateEvent = {
|
||||
type?: 'task_state'
|
||||
generateAssetsRunning?: boolean
|
||||
regenerateAssetsRunning?: boolean
|
||||
checkVideosRunning?: boolean
|
||||
cleanupRunning?: boolean
|
||||
anyRunning?: boolean
|
||||
ts?: number
|
||||
}
|
||||
|
||||
type AnalysisProgressEvent = {
|
||||
type?: 'analysis_progress'
|
||||
scope?: string
|
||||
requestId?: string
|
||||
analysisRequestId?: string
|
||||
running?: boolean
|
||||
phase?: 'starting' | 'running' | 'done' | 'error' | string
|
||||
progress?: number
|
||||
current?: number
|
||||
total?: number
|
||||
file?: string
|
||||
sourceFile?: string
|
||||
message?: string
|
||||
error?: string
|
||||
startedAtMs?: number
|
||||
finishedAtMs?: number
|
||||
durationMs?: number
|
||||
ts?: number
|
||||
}
|
||||
|
||||
type BackgroundSplitProgress = {
|
||||
phase: 'preparing' | 'splitting' | 'done' | 'error'
|
||||
total: number
|
||||
current: number
|
||||
completed: number
|
||||
segmentProgress?: number
|
||||
overallProgress?: number
|
||||
message?: string
|
||||
segment?: {
|
||||
index: number
|
||||
label: string
|
||||
start: number
|
||||
end: number
|
||||
duration: number
|
||||
}
|
||||
startedAtMs: number
|
||||
sourceFile: string
|
||||
}
|
||||
|
||||
const DEFAULT_RECORDER_SETTINGS: RecorderSettingsState = {
|
||||
recordDir: 'records',
|
||||
doneDir: 'records/done',
|
||||
|
||||
@ -2274,15 +2274,18 @@ export default function FinishedDownloads({
|
||||
showOnlyCorrupt
|
||||
|
||||
const globalFilterActive = searchActiveForGlobalFetch
|
||||
const effectiveAllMode = globalFilterActive || loadMode === 'all'
|
||||
const mobileCardStackMode = isSmall && view === 'cards'
|
||||
|
||||
const shouldLoadAllDoneJobs =
|
||||
globalFilterActive || loadMode === 'all' || mobileCardStackMode
|
||||
|
||||
const effectiveAllMode = shouldLoadAllDoneJobs
|
||||
|
||||
const DEFAULT_GALLERY_PAGE_SIZE = 8
|
||||
const [galleryPageSize, setGalleryPageSize] = useState<number>(
|
||||
DEFAULT_GALLERY_PAGE_SIZE
|
||||
)
|
||||
|
||||
const lastGalleryScaleIndexRef = useRef(galleryCardScaleIndex)
|
||||
|
||||
const handleGalleryRecommendedPageSizeChange = useCallback((rawSize: number) => {
|
||||
const rounded = Math.round(Number(rawSize))
|
||||
if (!Number.isFinite(rounded) || rounded <= 0) return
|
||||
@ -2290,23 +2293,16 @@ export default function FinishedDownloads({
|
||||
const next = Math.max(1, Math.min(24, rounded))
|
||||
|
||||
setGalleryPageSize((current) => {
|
||||
const scaleChanged = lastGalleryScaleIndexRef.current !== galleryCardScaleIndex
|
||||
|
||||
if (scaleChanged) {
|
||||
lastGalleryScaleIndexRef.current = galleryCardScaleIndex
|
||||
return next
|
||||
}
|
||||
|
||||
// Wichtig:
|
||||
// Nach Page-Wechsel/ResizeObserver kann kurz 8 statt 10 gemeldet werden.
|
||||
// Nicht automatisch verkleinern, sonst verschwinden bereits geladene Cards.
|
||||
if (next < current) {
|
||||
return current
|
||||
}
|
||||
|
||||
if (current === next) return current
|
||||
return next
|
||||
})
|
||||
}, [galleryCardScaleIndex])
|
||||
|
||||
onPageSizeChange?.(next)
|
||||
|
||||
if (page !== 1) {
|
||||
onPageChange(1)
|
||||
}
|
||||
}, [onPageSizeChange, onPageChange, page])
|
||||
|
||||
const effectivePageSize =
|
||||
view === 'gallery'
|
||||
@ -2314,12 +2310,12 @@ export default function FinishedDownloads({
|
||||
: pageSize
|
||||
|
||||
const doneJobsPage =
|
||||
globalFilterActive
|
||||
shouldLoadAllDoneJobs
|
||||
? (allDoneJobs ?? doneJobs)
|
||||
: doneJobs
|
||||
|
||||
const doneTotalPage =
|
||||
globalFilterActive
|
||||
shouldLoadAllDoneJobs
|
||||
? (allDoneJobs?.length ?? doneTotal)
|
||||
: doneTotal
|
||||
|
||||
@ -2578,12 +2574,12 @@ export default function FinishedDownloads({
|
||||
return visibleRows.slice(start, end)
|
||||
}
|
||||
|
||||
if (view === 'gallery') {
|
||||
return visibleRows.slice(0, effectivePageSize)
|
||||
}
|
||||
|
||||
return visibleRows
|
||||
}, [visibleRows, page, effectivePageSize, effectiveAllMode, view])
|
||||
}, [visibleRows, page, effectivePageSize, effectiveAllMode])
|
||||
|
||||
const cardRows = mobileCardStackMode ? visibleRows : pageRows
|
||||
|
||||
const activeVisibleRows = pageRows
|
||||
|
||||
const emptyFolder =
|
||||
!finishedDownloadsLoading &&
|
||||
@ -2605,10 +2601,10 @@ export default function FinishedDownloads({
|
||||
|
||||
const allPageSelected = useMemo(() => {
|
||||
return (
|
||||
pageRows.length > 0 &&
|
||||
pageRows.every((j) => selectionStore.isSelected(keyFor(j)))
|
||||
activeVisibleRows.length > 0 &&
|
||||
activeVisibleRows.every((j) => selectionStore.isSelected(keyFor(j)))
|
||||
)
|
||||
}, [pageRows, keyFor, selectionStore, selectionVersion])
|
||||
}, [activeVisibleRows, keyFor, selectionStore, selectionVersion])
|
||||
|
||||
const hasSearchQuery = (searchQuery || '').trim() !== ''
|
||||
const selectionActionsVisible = selectedCount > 0 && selectionActionsOpen
|
||||
@ -2617,7 +2613,7 @@ export default function FinishedDownloads({
|
||||
const selectedKeys = useMemo(() => {
|
||||
const next = new Set<string>()
|
||||
|
||||
for (const j of pageRows) {
|
||||
for (const j of activeVisibleRows) {
|
||||
const k = keyFor(j)
|
||||
if (selectionStore.isSelected(k)) {
|
||||
next.add(k)
|
||||
@ -2625,7 +2621,7 @@ export default function FinishedDownloads({
|
||||
}
|
||||
|
||||
return next
|
||||
}, [pageRows, keyFor, selectionStore, selectionVersion])
|
||||
}, [activeVisibleRows, keyFor, selectionStore, selectionVersion])
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// callbacks
|
||||
@ -3801,7 +3797,7 @@ export default function FinishedDownloads({
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
useEffect(() => {
|
||||
if (!globalFilterActive) {
|
||||
if (!shouldLoadAllDoneJobs) {
|
||||
setAllDoneJobs(null)
|
||||
setAllDoneJobsLoading(false)
|
||||
return
|
||||
@ -3832,7 +3828,7 @@ export default function FinishedDownloads({
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [globalFilterActive, loadAllDoneJobs])
|
||||
}, [shouldLoadAllDoneJobs, loadAllDoneJobs])
|
||||
|
||||
useEffect(() => {
|
||||
if (!showOnlyCorrupt) return
|
||||
@ -5421,7 +5417,7 @@ export default function FinishedDownloads({
|
||||
{view === 'cards' && (
|
||||
<div className={isSmall ? ['relative z-0 pt-10', cardsMobileOffsetTopClass, cardsMobileOffsetBottomClass].filter(Boolean).join(' ') : ''}>
|
||||
<FinishedDownloadsCardsView
|
||||
rows={pageRows}
|
||||
rows={cardRows}
|
||||
selectionStore={selectionStore}
|
||||
onToggleSelected={toggleSelected}
|
||||
onToggleSelectAllPage={handleToggleSelectAllPage}
|
||||
@ -5596,30 +5592,32 @@ export default function FinishedDownloads({
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div className="fixed inset-x-0 bottom-4 z-[70] flex justify-center px-4 pointer-events-none">
|
||||
<div className="pointer-events-auto flex w-full max-w-fit flex-col items-center gap-3">
|
||||
<div className="shadow-2xl">
|
||||
<Pagination
|
||||
page={page}
|
||||
pageSize={effectivePageSize}
|
||||
totalItems={totalItemsForPagination}
|
||||
onPageChange={(p) => {
|
||||
flushSync(() => {
|
||||
setInlinePlay(null)
|
||||
setTeaserKey(null)
|
||||
setHoverTeaserKey(null)
|
||||
})
|
||||
scrollFinishedListToTop()
|
||||
onPageChange(p)
|
||||
}}
|
||||
showSummary={false}
|
||||
prevLabel="Zurück"
|
||||
nextLabel="Weiter"
|
||||
className="mt-0"
|
||||
/>
|
||||
{!mobileCardStackMode ? (
|
||||
<div className="fixed inset-x-0 bottom-4 z-[70] flex justify-center px-4 pointer-events-none">
|
||||
<div className="pointer-events-auto flex w-full max-w-fit flex-col items-center gap-3">
|
||||
<div className="shadow-2xl">
|
||||
<Pagination
|
||||
page={page}
|
||||
pageSize={effectivePageSize}
|
||||
totalItems={totalItemsForPagination}
|
||||
onPageChange={(p) => {
|
||||
flushSync(() => {
|
||||
setInlinePlay(null)
|
||||
setTeaserKey(null)
|
||||
setHoverTeaserKey(null)
|
||||
})
|
||||
scrollFinishedListToTop()
|
||||
onPageChange(p)
|
||||
}}
|
||||
showSummary={false}
|
||||
prevLabel="Zurück"
|
||||
nextLabel="Weiter"
|
||||
className="mt-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1010,11 +1010,13 @@ function FinishedDownloadsCardsView({
|
||||
}, [isSmall, mobileOrderedRows, keyFor])
|
||||
|
||||
const mobileStackDepth = 3
|
||||
const mobilePreloadDepth = mobileStackDepth + 3
|
||||
|
||||
const mobileLoadedStackRows = isSmall ? mobileOrderedRows.slice(0, mobilePreloadDepth) : []
|
||||
const mobileVisibleStackRows = mobileLoadedStackRows.slice(0, mobileStackDepth)
|
||||
const mobilePreloadedRow = mobileLoadedStackRows[mobileStackDepth] ?? null
|
||||
const mobileLoadedStackRows = isSmall
|
||||
? mobileOrderedRows.slice(0, mobileStackDepth)
|
||||
: []
|
||||
|
||||
const mobileVisibleStackRows = mobileLoadedStackRows
|
||||
const mobilePreloadedRow = null
|
||||
const mobileTopRow = mobileVisibleStackRows[0] ?? null
|
||||
|
||||
const mobileTopKey = isSmall && mobileVisibleStackRows[0]
|
||||
|
||||
@ -193,8 +193,7 @@ function FinishedDownloadsGalleryView({
|
||||
Math.floor((containerWidth + gapPx) / (minCardWidth + gapPx))
|
||||
)
|
||||
|
||||
// mobil etwas mehr vertikale Füllung, desktop wie bisher ca. 2 Reihen
|
||||
const rowsPerPage = containerWidth < 640 ? 3 : 2
|
||||
const rowsPerPage = 2
|
||||
|
||||
const nextPageSize = clamp(columns * rowsPerPage, rowsPerPage, 24)
|
||||
|
||||
|
||||
@ -809,7 +809,7 @@ function TrainingStageOverlay(props: {
|
||||
aria-hidden="true"
|
||||
draggable={false}
|
||||
className={[
|
||||
'absolute inset-0 z-0 h-full w-full scale-105 object-cover blur-[1px]',
|
||||
'absolute inset-0 z-0 h-full w-full object-contain blur-[1px]',
|
||||
'transition-opacity duration-500 ease-out will-change-opacity motion-reduce:transition-none',
|
||||
backgroundVisible ? 'opacity-80' : 'opacity-0',
|
||||
].join(' ')}
|
||||
@ -4955,7 +4955,7 @@ export default function TrainingTab(props: {
|
||||
<div className="min-w-0 lg:flex lg:h-full lg:min-h-0 lg:flex-col lg:overflow-hidden">
|
||||
<section
|
||||
className={[
|
||||
'min-w-0 rounded-xl border border-gray-200 bg-white p-2 shadow-sm dark:border-white/10 dark:bg-gray-900/60 sm:p-3',
|
||||
'min-w-0 w-full rounded-xl border border-gray-200 bg-white p-2 shadow-sm dark:border-white/10 dark:bg-gray-900/60 sm:p-3',
|
||||
imageExpanded
|
||||
? 'lg:grid lg:h-full lg:min-h-0 lg:grid-rows-[minmax(0,1fr)_auto] lg:gap-3 lg:overflow-hidden'
|
||||
: 'lg:self-start'
|
||||
@ -5666,6 +5666,7 @@ export default function TrainingTab(props: {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{ /* Rechte Seite */ }
|
||||
<div
|
||||
ref={mobileLabelsScrollRef}
|
||||
className="min-h-0 h-full flex-1 overflow-y-auto overscroll-contain p-3 scroll-smooth"
|
||||
|
||||
@ -251,6 +251,8 @@ export type RecorderSettingsState = {
|
||||
ffmpegPath?: string
|
||||
autoAddToDownloadList?: boolean
|
||||
autoStartAddedDownloads?: boolean
|
||||
enableConcurrentDownloadsLimit?: boolean
|
||||
maxConcurrentDownloads?: number
|
||||
useChaturbateApi?: boolean
|
||||
useMyFreeCamsWatcher?: boolean
|
||||
autoDeleteSmallDownloads?: boolean
|
||||
@ -283,6 +285,7 @@ export type JobEvent = {
|
||||
modelImageUrl?: string
|
||||
modelChatRoomUrl?: string
|
||||
ts?: number
|
||||
error?: string
|
||||
|
||||
postWorkKey?: string
|
||||
postWork?: {
|
||||
@ -293,10 +296,11 @@ export type JobEvent = {
|
||||
maxParallel?: number
|
||||
}
|
||||
|
||||
// ✅ neu für finished_postwork
|
||||
file?: string
|
||||
assetId?: string
|
||||
queue?: FinishedPostworkQueue
|
||||
state?: FinishedPostworkState
|
||||
queue?: 'postwork' | 'enrich'
|
||||
state?: 'queued' | 'running' | 'done' | 'error' | 'missing'
|
||||
label?: string
|
||||
position?: number
|
||||
waiting?: number
|
||||
@ -304,6 +308,55 @@ export type JobEvent = {
|
||||
maxParallel?: number
|
||||
}
|
||||
|
||||
export type TaskStateEvent = {
|
||||
type?: 'task_state'
|
||||
generateAssetsRunning?: boolean
|
||||
regenerateAssetsRunning?: boolean
|
||||
checkVideosRunning?: boolean
|
||||
cleanupRunning?: boolean
|
||||
anyRunning?: boolean
|
||||
ts?: number
|
||||
}
|
||||
|
||||
export type AnalysisProgressEvent = {
|
||||
type?: 'analysis_progress'
|
||||
scope?: string
|
||||
requestId?: string
|
||||
analysisRequestId?: string
|
||||
running?: boolean
|
||||
phase?: 'starting' | 'running' | 'done' | 'error' | string
|
||||
progress?: number
|
||||
current?: number
|
||||
total?: number
|
||||
file?: string
|
||||
sourceFile?: string
|
||||
message?: string
|
||||
error?: string
|
||||
startedAtMs?: number
|
||||
finishedAtMs?: number
|
||||
durationMs?: number
|
||||
ts?: number
|
||||
}
|
||||
|
||||
export type BackgroundSplitProgress = {
|
||||
phase: 'preparing' | 'splitting' | 'done' | 'error'
|
||||
total: number
|
||||
current: number
|
||||
completed: number
|
||||
segmentProgress?: number
|
||||
overallProgress?: number
|
||||
message?: string
|
||||
segment?: {
|
||||
index: number
|
||||
label: string
|
||||
start: number
|
||||
end: number
|
||||
duration: number
|
||||
}
|
||||
startedAtMs: number
|
||||
sourceFile: string
|
||||
}
|
||||
|
||||
export type StoredModel = {
|
||||
id: string
|
||||
input: string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user