added boobjob position
This commit is contained in:
parent
d55c6b5854
commit
98e7bc70f2
@ -195,7 +195,16 @@ func ensureAnalyzeAllGoalsForVideoCtxForce(
|
||||
return false, err
|
||||
}
|
||||
|
||||
return hasAIAnalysisForAllOutputGoals(videoPath, requiredAnalyzeGoals()), nil
|
||||
analysisReady := hasAIAnalysisForAllOutputGoals(videoPath, requiredAnalyzeGoals())
|
||||
if !analysisReady {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Direkt nach erfolgreicher Analyse löschen.
|
||||
// Wichtig: hier rating übergeben, nicht nil.
|
||||
autoDeleteLowRatedDownloadAfterAnalysis(actx, videoPath, rating)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func assetsTruthForVideo(videoPath string) finishedPhaseTruth {
|
||||
@ -897,10 +906,18 @@ func ensureAnalyzeForVideoCtx(
|
||||
return false, perr
|
||||
}
|
||||
|
||||
if _, err := ensureAnalyzeAllGoalsForVideoCtx(ctx, videoPath, sourceURL); err != nil {
|
||||
analyzed, err := ensureAnalyzeAllGoalsForVideoCtx(ctx, videoPath, sourceURL)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if analyzed {
|
||||
if _, statErr := os.Stat(videoPath); os.IsNotExist(statErr) {
|
||||
// Analyse war erfolgreich, Datei wurde danach absichtlich durch AutoDelete gelöscht.
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return hasAIAnalysisForOutputGoal(videoPath, goal), nil
|
||||
}
|
||||
|
||||
@ -926,10 +943,18 @@ func ensureDeferredAssetsAndAI(ctx context.Context, videoPath, sourceURL string,
|
||||
}
|
||||
|
||||
// Analyse genau einmal für alle Standard-Ziele.
|
||||
if _, err := ensureAnalyzeAllGoalsForVideoCtx(ctx, videoPath, sourceURL); err != nil {
|
||||
analyzed, err := ensureAnalyzeAllGoalsForVideoCtx(ctx, videoPath, sourceURL)
|
||||
if err != nil {
|
||||
return appErrorf("deferred analyze failed for %s: %w", videoPath, err)
|
||||
}
|
||||
|
||||
if analyzed {
|
||||
if _, statErr := os.Stat(videoPath); os.IsNotExist(statErr) {
|
||||
// Analyse war erfolgreich, Datei wurde danach absichtlich durch AutoDelete gelöscht.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
goal = "highlights"
|
||||
|
||||
if !hasAIAnalysisForOutputGoal(videoPath, goal) {
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
"facesitting",
|
||||
"handjob",
|
||||
"blowjob",
|
||||
"boobjob",
|
||||
"toy_play",
|
||||
"fingering",
|
||||
"69"
|
||||
|
||||
@ -125,6 +125,7 @@ func isKnownPositionLabel(label string) bool {
|
||||
"facesitting",
|
||||
"handjob",
|
||||
"blowjob",
|
||||
"boobjob",
|
||||
"toy_play",
|
||||
"fingering",
|
||||
"69":
|
||||
@ -144,7 +145,7 @@ func positionSeverityWeight(label string) float64 {
|
||||
return 0.98
|
||||
case "missionary", "prone_bone":
|
||||
return 0.95
|
||||
case "blowjob", "cunnilingus", "69", "facesitting":
|
||||
case "blowjob", "cunnilingus", "69", "facesitting", "boobjob":
|
||||
return 0.94
|
||||
case "toy_play":
|
||||
return 0.88
|
||||
|
||||
@ -942,9 +942,6 @@ func runGenerateMissingAssetsJob(jobID string, ctx context.Context) {
|
||||
publishAssetsTaskPhase(it.name, "enrich", "analyze", "error", "Analyse fehlgeschlagen")
|
||||
} else if assetsTaskTruthForVideo(id, it.path).AnalyzeReady {
|
||||
publishAssetsTaskPhase(it.name, "enrich", "analyze", "done", "Analyse")
|
||||
|
||||
// Nach erfolgreicher Hintergrund-Analyse optional nach Rating löschen.
|
||||
autoDeleteLowRatedDownloadAfterAnalysis(fileCtx, it.path, nil)
|
||||
} else {
|
||||
publishAssetsTaskPhase(it.name, "enrich", "analyze", "error", "Analyse fehlgeschlagen")
|
||||
}
|
||||
|
||||
@ -739,6 +739,11 @@ func autoDeleteLowRatedDownloadAfterAnalysis(ctx context.Context, videoPath stri
|
||||
default:
|
||||
}
|
||||
|
||||
videoPath = strings.TrimSpace(videoPath)
|
||||
if videoPath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
s := getSettings()
|
||||
if !s.AutoDeleteLowRatedDownloads {
|
||||
return
|
||||
@ -747,6 +752,7 @@ func autoDeleteLowRatedDownloadAfterAnalysis(ctx context.Context, videoPath stri
|
||||
maxStars := clampAutoDeleteRatingStars(s.AutoDeleteLowRatedDownloadsMaxStars)
|
||||
|
||||
stars := 0
|
||||
|
||||
if rating != nil {
|
||||
stars = rating.Stars
|
||||
if stars <= 0 && rating.Score > 0 {
|
||||
@ -754,21 +760,34 @@ func autoDeleteLowRatedDownloadAfterAnalysis(ctx context.Context, videoPath stri
|
||||
}
|
||||
}
|
||||
|
||||
// Falls kein Rating direkt übergeben wurde, aus der gespeicherten meta.json lesen.
|
||||
// Das brauchen wir für Asset-/Regenerate-Jobs, weil dort die Analyse erst geprüft
|
||||
// und danach gelöscht werden soll.
|
||||
if stars < 1 || stars > 5 {
|
||||
metaStars, ok, err := ratingStarsForVideoPath(videoPath)
|
||||
if err != nil {
|
||||
appLogln("⚠️ [rating-delete] rating aus meta konnte nicht gelesen werden:", filepath.Base(videoPath), err)
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
// Wichtig für Background-/Regenerate-Analyse:
|
||||
// Dort wird rating teilweise als nil übergeben, obwohl es kurz vorher
|
||||
// in meta.json gespeichert wurde. Dann lesen wir die Sterne aus der Meta.
|
||||
if stars <= 0 {
|
||||
if metaStars, ok, err := ratingStarsForVideoPath(videoPath); err != nil {
|
||||
appLogln("⚠️ [rating-delete] rating lookup failed:", filepath.Base(videoPath), err)
|
||||
} else if ok {
|
||||
stars = metaStars
|
||||
}
|
||||
}
|
||||
|
||||
if stars < 1 || stars > 5 || stars > maxStars {
|
||||
if stars < 1 || stars > 5 {
|
||||
appLogf(
|
||||
"ℹ️ [rating-delete] übersprungen, kein gültiges Rating: %s stars=%d threshold<=%d",
|
||||
filepath.Base(videoPath),
|
||||
stars,
|
||||
maxStars,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if stars > maxStars {
|
||||
appLogf(
|
||||
"ℹ️ [rating-delete] behalten: %s stars=%d threshold<=%d",
|
||||
filepath.Base(videoPath),
|
||||
stars,
|
||||
maxStars,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
// frontend\src\aiLabels.ts
|
||||
|
||||
export type AiLabelGroup =
|
||||
| 'people'
|
||||
| 'position'
|
||||
@ -22,6 +24,7 @@ export const AI_POSITION_LABELS = [
|
||||
'facesitting',
|
||||
'handjob',
|
||||
'blowjob',
|
||||
'boobjob',
|
||||
'toy_play',
|
||||
'fingering',
|
||||
'69',
|
||||
@ -122,6 +125,7 @@ export const AI_LABEL_FALLBACKS: Record<string, string> = {
|
||||
facesitting: 'Facesitting',
|
||||
handjob: 'Handjob',
|
||||
blowjob: 'Blowjob',
|
||||
boobjob: 'Boobjob',
|
||||
toy_play: 'Toy Play',
|
||||
fingering: 'Fingering',
|
||||
'69': '69',
|
||||
|
||||
@ -63,6 +63,42 @@ export function FemaleBreastIcon(props: IconProps) {
|
||||
)
|
||||
}
|
||||
|
||||
export function BoobjobIcon(props: IconProps) {
|
||||
const { title, className, ...rest } = props
|
||||
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 100 100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={iconClassName(className, 'origin-center scale-[1.12]')}
|
||||
aria-hidden={title ? undefined : true}
|
||||
role={title ? 'img' : undefined}
|
||||
{...rest}
|
||||
>
|
||||
{title ? <title>{title}</title> : null}
|
||||
|
||||
<FemaleBreastIcon
|
||||
x="3"
|
||||
y="20"
|
||||
width="94"
|
||||
height="58"
|
||||
aria-hidden="true"
|
||||
className="opacity-100"
|
||||
/>
|
||||
|
||||
<MaleGenitaliaIcon
|
||||
x="35"
|
||||
y="25"
|
||||
width="30"
|
||||
height="54"
|
||||
aria-hidden="true"
|
||||
className="opacity-100"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function ButtocksIcon(props: IconProps) {
|
||||
return (
|
||||
<IconBase
|
||||
@ -1010,6 +1046,24 @@ const SEGMENT_LABEL_META: SegmentLabelMeta[] = [
|
||||
text: 'Blowjob',
|
||||
icon: BlowjobIcon,
|
||||
},
|
||||
{
|
||||
match: [
|
||||
'boobjob',
|
||||
'boob_job',
|
||||
'boob-job',
|
||||
'boob job',
|
||||
'titjob',
|
||||
'tit_job',
|
||||
'tit-job',
|
||||
'tit job',
|
||||
'titfuck',
|
||||
'tit_fuck',
|
||||
'tit-fuck',
|
||||
'tit fuck',
|
||||
],
|
||||
text: 'Boobjob',
|
||||
icon: BoobjobIcon,
|
||||
},
|
||||
{
|
||||
match: ['cunnilingus'],
|
||||
text: 'Cunnilingus',
|
||||
|
||||
@ -1076,6 +1076,12 @@ function segmentKindFromText(value: unknown): SegmentVisualKind {
|
||||
clean.includes('facesitting') ||
|
||||
clean.includes('handjob') ||
|
||||
clean.includes('blowjob') ||
|
||||
clean.includes('boobjob') ||
|
||||
clean.includes('boob job') ||
|
||||
clean.includes('boob_job') ||
|
||||
clean.includes('titjob') ||
|
||||
clean.includes('tit job') ||
|
||||
clean.includes('tit_job') ||
|
||||
clean.includes('fingering') ||
|
||||
clean.includes('toy play') ||
|
||||
clean.includes('toy_play') ||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user