bugfixes
This commit is contained in:
parent
1a559fe76d
commit
6b333ee78a
@ -2462,6 +2462,7 @@ type analyzeLabelSegmentPoint struct {
|
|||||||
Label string
|
Label string
|
||||||
Start float64
|
Start float64
|
||||||
End float64
|
End float64
|
||||||
|
Time float64
|
||||||
Score float64
|
Score float64
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2550,10 +2551,19 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
score = 1
|
score = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markerTime := hit.Time
|
||||||
|
if markerTime < 0 {
|
||||||
|
markerTime = (start + end) / 2
|
||||||
|
}
|
||||||
|
if duration > 0 {
|
||||||
|
markerTime = math.Max(0, math.Min(markerTime, duration))
|
||||||
|
}
|
||||||
|
|
||||||
byLabel[key] = append(byLabel[key], analyzeLabelSegmentPoint{
|
byLabel[key] = append(byLabel[key], analyzeLabelSegmentPoint{
|
||||||
Label: label,
|
Label: label,
|
||||||
Start: start,
|
Start: start,
|
||||||
End: end,
|
End: end,
|
||||||
|
Time: markerTime,
|
||||||
Score: score,
|
Score: score,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2580,6 +2590,8 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curEndMarker := points[0].End
|
curEndMarker := points[0].End
|
||||||
curScoreSum := points[0].Score
|
curScoreSum := points[0].Score
|
||||||
curScoreCount := 1
|
curScoreCount := 1
|
||||||
|
curMarkerTime := points[0].Time
|
||||||
|
curBestScore := points[0].Score
|
||||||
|
|
||||||
for i := 1; i < len(points); i++ {
|
for i := 1; i < len(points); i++ {
|
||||||
n := points[i]
|
n := points[i]
|
||||||
@ -2598,6 +2610,10 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
|
|
||||||
curScoreSum += n.Score
|
curScoreSum += n.Score
|
||||||
curScoreCount++
|
curScoreCount++
|
||||||
|
if n.Score > curBestScore {
|
||||||
|
curBestScore = n.Score
|
||||||
|
curMarkerTime = n.Time
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2605,6 +2621,7 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curLabel,
|
curLabel,
|
||||||
curStartMarker,
|
curStartMarker,
|
||||||
curEndMarker,
|
curEndMarker,
|
||||||
|
curMarkerTime,
|
||||||
curScoreSum,
|
curScoreSum,
|
||||||
curScoreCount,
|
curScoreCount,
|
||||||
halfSample,
|
halfSample,
|
||||||
@ -2620,12 +2637,15 @@ func buildLabelContinuitySegmentsFromAnalyzeHits(
|
|||||||
curEndMarker = n.End
|
curEndMarker = n.End
|
||||||
curScoreSum = n.Score
|
curScoreSum = n.Score
|
||||||
curScoreCount = 1
|
curScoreCount = 1
|
||||||
|
curMarkerTime = n.Time
|
||||||
|
curBestScore = n.Score
|
||||||
}
|
}
|
||||||
|
|
||||||
segment := makeLabelContinuitySegment(
|
segment := makeLabelContinuitySegment(
|
||||||
curLabel,
|
curLabel,
|
||||||
curStartMarker,
|
curStartMarker,
|
||||||
curEndMarker,
|
curEndMarker,
|
||||||
|
curMarkerTime,
|
||||||
curScoreSum,
|
curScoreSum,
|
||||||
curScoreCount,
|
curScoreCount,
|
||||||
halfSample,
|
halfSample,
|
||||||
@ -2654,6 +2674,7 @@ func makeLabelContinuitySegment(
|
|||||||
label string,
|
label string,
|
||||||
startMarker float64,
|
startMarker float64,
|
||||||
endMarker float64,
|
endMarker float64,
|
||||||
|
markerTime float64,
|
||||||
scoreSum float64,
|
scoreSum float64,
|
||||||
scoreCount int,
|
scoreCount int,
|
||||||
halfSample float64,
|
halfSample float64,
|
||||||
@ -2680,6 +2701,13 @@ func makeLabelContinuitySegment(
|
|||||||
score = scoreSum / float64(scoreCount)
|
score = scoreSum / float64(scoreCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if markerTime < 0 {
|
||||||
|
markerTime = (start + end) / 2
|
||||||
|
}
|
||||||
|
if duration > 0 {
|
||||||
|
markerTime = math.Max(0, math.Min(markerTime, duration))
|
||||||
|
}
|
||||||
|
|
||||||
return aiSegmentMeta{
|
return aiSegmentMeta{
|
||||||
Label: label,
|
Label: label,
|
||||||
StartSeconds: start,
|
StartSeconds: start,
|
||||||
@ -2689,6 +2717,8 @@ func makeLabelContinuitySegment(
|
|||||||
AutoSelected: true,
|
AutoSelected: true,
|
||||||
Position: segmentPositionFromAnalyzeLabel(label),
|
Position: segmentPositionFromAnalyzeLabel(label),
|
||||||
Tags: segmentTagsFromAnalyzeLabel(label),
|
Tags: segmentTagsFromAnalyzeLabel(label),
|
||||||
|
MarkerSeconds: markerTime,
|
||||||
|
PreviewSeconds: markerTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -104,6 +104,8 @@ type aiSegmentMeta struct {
|
|||||||
AutoSelected bool `json:"autoSelected,omitempty"`
|
AutoSelected bool `json:"autoSelected,omitempty"`
|
||||||
Position string `json:"position,omitempty"`
|
Position string `json:"position,omitempty"`
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
MarkerSeconds float64 `json:"markerSeconds,omitempty"`
|
||||||
|
PreviewSeconds float64 `json:"previewSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type aiAnalysisMeta struct {
|
type aiAnalysisMeta struct {
|
||||||
|
|||||||
@ -535,85 +535,6 @@ func refreshMyFreeCamsSnapshotNow(ctx context.Context, store *ModelStore) (time.
|
|||||||
return fetchedAt, okCount, nil
|
return fetchedAt, okCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startMyFreeCamsOnlinePoller(store *ModelStore) {
|
|
||||||
const interval = mfcOnlinePollInterval
|
|
||||||
|
|
||||||
if store != nil {
|
|
||||||
setMyFreeCamsOnlineModelStore(store)
|
|
||||||
}
|
|
||||||
|
|
||||||
lastLoggedErr := ""
|
|
||||||
|
|
||||||
refreshOnce := func(trigger string) {
|
|
||||||
if !myFreeCamsProviderAPIEnabled() {
|
|
||||||
if verboseLogs() {
|
|
||||||
appLogln("ℹ️ [myfreecams] online refresh skipped: provider API disabled")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mfcOnlineRefreshMu.Lock()
|
|
||||||
if mfcOnlineRefreshInFlight {
|
|
||||||
mfcOnlineRefreshMu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mfcOnlineRefreshInFlight = true
|
|
||||||
mfcOnlineRefreshMu.Unlock()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
mfcOnlineRefreshMu.Lock()
|
|
||||||
mfcOnlineRefreshInFlight = false
|
|
||||||
mfcOnlineRefreshMu.Unlock()
|
|
||||||
}()
|
|
||||||
|
|
||||||
fetchedAt, count, err := refreshMyFreeCamsSnapshotNow(context.Background(), store)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
msg := err.Error()
|
|
||||||
|
|
||||||
if strings.Contains(msg, "usernameLookup pausiert") {
|
|
||||||
if verboseLogs() && msg != lastLoggedErr {
|
|
||||||
appLogln("⏸️ [myfreecams] online refresh skipped:", msg)
|
|
||||||
lastLoggedErr = msg
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg != lastLoggedErr {
|
|
||||||
appLogln("⚠️ [myfreecams] online refresh failed:", msg)
|
|
||||||
lastLoggedErr = msg
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if lastLoggedErr != "" {
|
|
||||||
appLogln("✅ [myfreecams] online refresh recovered")
|
|
||||||
lastLoggedErr = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if verboseLogs() {
|
|
||||||
appLogln(
|
|
||||||
"✅ [myfreecams] checked models:",
|
|
||||||
count,
|
|
||||||
"snapshot",
|
|
||||||
fetchedAt.Format(time.RFC3339),
|
|
||||||
"trigger="+trigger,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshOnce("startup")
|
|
||||||
|
|
||||||
ticker := time.NewTicker(interval)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for range ticker.C {
|
|
||||||
refreshOnce("ticker")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type mfcOnlineResponse struct {
|
type mfcOnlineResponse struct {
|
||||||
Enabled bool `json:"enabled"`
|
Enabled bool `json:"enabled"`
|
||||||
FetchedAt time.Time `json:"fetchedAt"`
|
FetchedAt time.Time `json:"fetchedAt"`
|
||||||
@ -630,107 +551,16 @@ func myfreecamsOnlineHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wantRefresh := false
|
|
||||||
var users []string
|
|
||||||
|
|
||||||
if r.Method == http.MethodPost {
|
|
||||||
r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
|
|
||||||
var req struct {
|
|
||||||
Q []string `json:"q"`
|
|
||||||
Refresh bool `json:"refresh"`
|
|
||||||
}
|
|
||||||
_ = json.NewDecoder(r.Body).Decode(&req)
|
|
||||||
wantRefresh = req.Refresh
|
|
||||||
for _, u := range req.Q {
|
|
||||||
u = strings.ToLower(strings.TrimSpace(u))
|
|
||||||
if u != "" {
|
|
||||||
users = append(users, u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qRefresh := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("refresh")))
|
|
||||||
wantRefresh = qRefresh == "1" || qRefresh == "true" || qRefresh == "yes"
|
|
||||||
|
|
||||||
qUsers := strings.TrimSpace(r.URL.Query().Get("q"))
|
|
||||||
if qUsers != "" {
|
|
||||||
for _, u := range strings.Split(qUsers, ",") {
|
|
||||||
u = strings.ToLower(strings.TrimSpace(u))
|
|
||||||
if u != "" {
|
|
||||||
users = append(users, u)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
store := mfcOnlineModelStore
|
|
||||||
if store == nil {
|
|
||||||
store = getModelStore()
|
|
||||||
}
|
|
||||||
|
|
||||||
if wantRefresh && store != nil {
|
|
||||||
if !myFreeCamsProviderAPIEnabled() {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.Header().Set("Cache-Control", "no-store")
|
w.Header().Set("Cache-Control", "no-store")
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(mfcOnlineResponse{
|
_ = json.NewEncoder(w).Encode(mfcOnlineResponse{
|
||||||
Enabled: false,
|
Enabled: false,
|
||||||
LastError: "MyFreeCams API ist in den Einstellungen deaktiviert",
|
FetchedAt: time.Time{},
|
||||||
|
LastAttempt: time.Time{},
|
||||||
|
Count: 0,
|
||||||
|
Total: 0,
|
||||||
|
LastError: "MyFreeCams Online-Prüfung deaktiviert; usernameLookup nur über biocontext bei Bedarf.",
|
||||||
Rooms: []MyFreeCamsOnlineRoomLite{},
|
Rooms: []MyFreeCamsOnlineRoomLite{},
|
||||||
})
|
})
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
mfcOnlineRefreshMu.Lock()
|
|
||||||
if !mfcOnlineRefreshInFlight {
|
|
||||||
mfcOnlineRefreshInFlight = true
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
mfcOnlineRefreshMu.Lock()
|
|
||||||
mfcOnlineRefreshInFlight = false
|
|
||||||
mfcOnlineRefreshMu.Unlock()
|
|
||||||
}()
|
|
||||||
|
|
||||||
_, _, _ = refreshMyFreeCamsSnapshotNow(context.Background(), store)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
mfcOnlineRefreshMu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
mfcOnlineMu.RLock()
|
|
||||||
fetchedAt := mfcOnline.FetchedAt
|
|
||||||
lastAttempt := mfcOnline.LastAttempt
|
|
||||||
lastErr := mfcOnline.LastErr
|
|
||||||
liteByUser := mfcOnline.LiteByUser
|
|
||||||
mfcOnlineMu.RUnlock()
|
|
||||||
|
|
||||||
total := 0
|
|
||||||
if liteByUser != nil {
|
|
||||||
total = len(liteByUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
rooms := make([]MyFreeCamsOnlineRoomLite, 0)
|
|
||||||
|
|
||||||
if len(users) > 0 {
|
|
||||||
for _, u := range users {
|
|
||||||
if rm, ok := liteByUser[u]; ok {
|
|
||||||
rooms = append(rooms, rm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if fetchedAt.IsZero() && lastErr == "" {
|
|
||||||
lastErr = "warming up"
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Header().Set("Cache-Control", "no-store")
|
|
||||||
|
|
||||||
_ = json.NewEncoder(w).Encode(mfcOnlineResponse{
|
|
||||||
Enabled: true,
|
|
||||||
FetchedAt: fetchedAt,
|
|
||||||
LastAttempt: lastAttempt,
|
|
||||||
Count: len(rooms),
|
|
||||||
Total: total,
|
|
||||||
LastError: lastErr,
|
|
||||||
Rooms: rooms,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,11 +23,11 @@ type aiRatingMeta struct {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Normales Zusammenziehen sehr kurzer Pausen.
|
// Normales Zusammenziehen sehr kurzer Pausen.
|
||||||
ratingMaxSilentGapSec = 6.5
|
ratingMaxSilentGapSec = 4.5
|
||||||
|
|
||||||
// Größere Lücken dürfen überbrückt werden,
|
// Größere Lücken dürfen überbrückt werden,
|
||||||
// wenn beide Seiten stark genug / thematisch ähnlich sind.
|
// wenn beide Seiten stark genug / thematisch ähnlich sind.
|
||||||
ratingBridgeStrongGapSec = 35.0
|
ratingBridgeStrongGapSec = 12.0
|
||||||
|
|
||||||
ratingMinSegmentDurationSec = 2.5
|
ratingMinSegmentDurationSec = 2.5
|
||||||
)
|
)
|
||||||
@ -743,7 +743,41 @@ func ratingBridgeStrengthFromSet(set ratingSignalSet) float64 {
|
|||||||
return strength
|
return strength
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ratingPositionSetFromLabels(labels map[string]bool) map[string]bool {
|
||||||
|
out := map[string]bool{}
|
||||||
|
|
||||||
|
for label := range labels {
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
out[normalized] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func ratingPositionSetsConflict(a map[string]bool, b map[string]bool) bool {
|
||||||
|
ap := ratingPositionSetFromLabels(a)
|
||||||
|
bp := ratingPositionSetFromLabels(b)
|
||||||
|
|
||||||
|
if len(ap) == 0 || len(bp) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for label := range ap {
|
||||||
|
if bp[label] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
||||||
|
if ratingPositionSetsConflict(a, b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
for la := range a {
|
for la := range a {
|
||||||
na := normalizeRatingSignalLabel(la)
|
na := normalizeRatingSignalLabel(la)
|
||||||
if na == "" {
|
if na == "" {
|
||||||
@ -765,9 +799,11 @@ func ratingLabelsBridgeCompatible(a map[string]bool, b map[string]bool) bool {
|
|||||||
as := ratingSignalSetFromLabels(a)
|
as := ratingSignalSetFromLabels(a)
|
||||||
bs := ratingSignalSetFromLabels(b)
|
bs := ratingSignalSetFromLabels(b)
|
||||||
|
|
||||||
if as.HasPosition && bs.HasPosition {
|
// Wichtig:
|
||||||
return true
|
// Unterschiedliche Positionen NICHT pauschal verbinden.
|
||||||
}
|
// Vorher hat "Doggy" + "Reverse Cowgirl" als kompatibel gegolten,
|
||||||
|
// nur weil beide irgendeine Position waren.
|
||||||
|
|
||||||
if as.HasBody && bs.HasBody {
|
if as.HasBody && bs.HasBody {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -845,6 +881,94 @@ func mergeRatingActivitySegments(
|
|||||||
scoreSum float64
|
scoreSum float64
|
||||||
scoreWeight float64
|
scoreWeight float64
|
||||||
labels map[string]bool
|
labels map[string]bool
|
||||||
|
positionWeights map[string]float64
|
||||||
|
marker float64
|
||||||
|
markerWeight float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var addRatingPositionWeight func(weights map[string]float64, label string, weight float64)
|
||||||
|
|
||||||
|
addRatingPositionWeight = func(weights map[string]float64, label string, weight float64) {
|
||||||
|
label = strings.ToLower(strings.TrimSpace(label))
|
||||||
|
if label == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(label, "combo:") {
|
||||||
|
raw := strings.TrimPrefix(label, "combo:")
|
||||||
|
for _, part := range strings.Split(raw, "+") {
|
||||||
|
addRatingPositionWeight(weights, part, weight)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
weights[normalized] += weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
effectiveRatingLabelsForBlock := func(labels map[string]bool, positionWeights map[string]float64) map[string]bool {
|
||||||
|
out := map[string]bool{}
|
||||||
|
|
||||||
|
bestPosition := ""
|
||||||
|
bestWeight := -1.0
|
||||||
|
|
||||||
|
for label := range labels {
|
||||||
|
normalized := normalizeRatingSignalLabel(label)
|
||||||
|
if normalized == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(normalized, "position:") {
|
||||||
|
w := positionWeights[normalized]
|
||||||
|
if w <= 0 {
|
||||||
|
w = ratingSegmentSeverity(normalized)
|
||||||
|
}
|
||||||
|
|
||||||
|
if w > bestWeight {
|
||||||
|
bestWeight = w
|
||||||
|
bestPosition = normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
out[normalized] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if bestPosition != "" {
|
||||||
|
out[bestPosition] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentMarker := func(s aiSegmentMeta) float64 {
|
||||||
|
if s.PreviewSeconds > 0 {
|
||||||
|
return s.PreviewSeconds
|
||||||
|
}
|
||||||
|
if s.MarkerSeconds > 0 {
|
||||||
|
return s.MarkerSeconds
|
||||||
|
}
|
||||||
|
if s.EndSeconds > s.StartSeconds {
|
||||||
|
return (s.StartSeconds + s.EndSeconds) / 2
|
||||||
|
}
|
||||||
|
return s.StartSeconds
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentMarkerWeight := func(s aiSegmentMeta) float64 {
|
||||||
|
conf := ratingClamp01(s.Score)
|
||||||
|
if conf <= 0 {
|
||||||
|
conf = 0.50
|
||||||
|
}
|
||||||
|
|
||||||
|
sev := ratingSegmentSeverity(s.Label)
|
||||||
|
if sev <= 0 {
|
||||||
|
sev = 0.50
|
||||||
|
}
|
||||||
|
|
||||||
|
return conf * sev
|
||||||
}
|
}
|
||||||
|
|
||||||
newBlock := func(s aiSegmentMeta) activityBlock {
|
newBlock := func(s aiSegmentMeta) activityBlock {
|
||||||
@ -857,12 +981,21 @@ func mergeRatingActivitySegments(
|
|||||||
conf = 0.50
|
conf = 0.50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
positionWeights := map[string]float64{}
|
||||||
|
addRatingPositionWeight(positionWeights, s.Label, conf*math.Max(1, dur))
|
||||||
|
|
||||||
|
marker := segmentMarker(s)
|
||||||
|
markerWeight := segmentMarkerWeight(s)
|
||||||
|
|
||||||
return activityBlock{
|
return activityBlock{
|
||||||
start: s.StartSeconds,
|
start: s.StartSeconds,
|
||||||
end: s.EndSeconds,
|
end: s.EndSeconds,
|
||||||
scoreSum: conf * dur,
|
scoreSum: conf * dur,
|
||||||
scoreWeight: dur,
|
scoreWeight: dur,
|
||||||
labels: labels,
|
labels: labels,
|
||||||
|
positionWeights: positionWeights,
|
||||||
|
marker: marker,
|
||||||
|
markerWeight: markerWeight,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,7 +1005,8 @@ func mergeRatingActivitySegments(
|
|||||||
return aiSegmentMeta{}, false
|
return aiSegmentMeta{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
label := buildRatingComboLabel(b.labels)
|
effectiveLabels := effectiveRatingLabelsForBlock(b.labels, b.positionWeights)
|
||||||
|
label := buildRatingComboLabel(effectiveLabels)
|
||||||
if label == "" {
|
if label == "" {
|
||||||
return aiSegmentMeta{}, false
|
return aiSegmentMeta{}, false
|
||||||
}
|
}
|
||||||
@ -901,6 +1035,8 @@ func mergeRatingActivitySegments(
|
|||||||
AutoSelected: true,
|
AutoSelected: true,
|
||||||
Position: segmentPositionFromAnalyzeLabel(label),
|
Position: segmentPositionFromAnalyzeLabel(label),
|
||||||
Tags: segmentTagsFromAnalyzeLabel(label),
|
Tags: segmentTagsFromAnalyzeLabel(label),
|
||||||
|
MarkerSeconds: b.marker,
|
||||||
|
PreviewSeconds: b.marker,
|
||||||
}, true
|
}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,8 +1092,17 @@ func mergeRatingActivitySegments(
|
|||||||
if conf <= 0 {
|
if conf <= 0 {
|
||||||
conf = 0.50
|
conf = 0.50
|
||||||
}
|
}
|
||||||
|
|
||||||
cur.scoreSum += conf * dur
|
cur.scoreSum += conf * dur
|
||||||
cur.scoreWeight += dur
|
cur.scoreWeight += dur
|
||||||
|
|
||||||
|
addRatingPositionWeight(cur.positionWeights, n.Label, conf*math.Max(1, dur))
|
||||||
|
}
|
||||||
|
|
||||||
|
nextMarkerWeight := segmentMarkerWeight(n)
|
||||||
|
if nextMarkerWeight > cur.markerWeight {
|
||||||
|
cur.markerWeight = nextMarkerWeight
|
||||||
|
cur.marker = segmentMarker(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
addRatingLabelsFromSegment(cur.labels, n.Label)
|
addRatingLabelsFromSegment(cur.labels, n.Label)
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"useMyFreeCamsApi": true,
|
"useMyFreeCamsApi": true,
|
||||||
"autoDeleteSmallDownloads": true,
|
"autoDeleteSmallDownloads": true,
|
||||||
"autoDeleteSmallDownloadsBelowMB": 300,
|
"autoDeleteSmallDownloadsBelowMB": 300,
|
||||||
"autoDeleteSmallDownloadsKeepFavorites": true,
|
"autoDeleteSmallDownloadsKeepFavorites": false,
|
||||||
"lowDiskPauseBelowGB": 5,
|
"lowDiskPauseBelowGB": 5,
|
||||||
"blurPreviews": false,
|
"blurPreviews": false,
|
||||||
"teaserPlayback": "all",
|
"teaserPlayback": "all",
|
||||||
|
|||||||
@ -715,7 +715,6 @@ func main() {
|
|||||||
// Hintergrund-Worker
|
// Hintergrund-Worker
|
||||||
go startDiskSpaceGuard()
|
go startDiskSpaceGuard()
|
||||||
go startChaturbateOnlinePoller(store)
|
go startChaturbateOnlinePoller(store)
|
||||||
go startMyFreeCamsOnlinePoller(store)
|
|
||||||
go startChaturbateAutoStartWorker(store)
|
go startChaturbateAutoStartWorker(store)
|
||||||
go startMyFreeCamsAutoStartWorker(store)
|
go startMyFreeCamsAutoStartWorker(store)
|
||||||
|
|
||||||
|
|||||||
@ -888,22 +888,13 @@ function segmentAnchorTime(
|
|||||||
obj: Record<string, unknown>,
|
obj: Record<string, unknown>,
|
||||||
durationSeconds: number
|
durationSeconds: number
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
const start = firstSegmentTimeNumber(obj, [
|
|
||||||
'startSec',
|
|
||||||
'startSeconds',
|
|
||||||
'start_s',
|
|
||||||
'start',
|
|
||||||
'from',
|
|
||||||
'startMs',
|
|
||||||
'startRatio',
|
|
||||||
'startPercent',
|
|
||||||
'startPct',
|
|
||||||
], durationSeconds)
|
|
||||||
|
|
||||||
const marker = firstSegmentTimeNumber(obj, [
|
const marker = firstSegmentTimeNumber(obj, [
|
||||||
'markerTime',
|
'previewSeconds',
|
||||||
'markerSec',
|
'previewSec',
|
||||||
|
'previewTime',
|
||||||
'markerSeconds',
|
'markerSeconds',
|
||||||
|
'markerSec',
|
||||||
|
'markerTime',
|
||||||
'time',
|
'time',
|
||||||
't',
|
't',
|
||||||
'timestamp',
|
'timestamp',
|
||||||
@ -918,18 +909,41 @@ function segmentAnchorTime(
|
|||||||
'timestampPct',
|
'timestampPct',
|
||||||
], durationSeconds)
|
], durationSeconds)
|
||||||
|
|
||||||
if (typeof start === 'number') return start
|
|
||||||
if (typeof marker === 'number') return marker
|
if (typeof marker === 'number') return marker
|
||||||
|
|
||||||
return undefined
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
|
'startSec',
|
||||||
|
'startSeconds',
|
||||||
|
'start_s',
|
||||||
|
'start',
|
||||||
|
'from',
|
||||||
|
'startMs',
|
||||||
|
'startRatio',
|
||||||
|
'startPercent',
|
||||||
|
'startPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
|
return typeof start === 'number' ? start : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentPreviewTime(
|
function segmentPreviewTime(
|
||||||
obj: Record<string, unknown>,
|
obj: Record<string, unknown>,
|
||||||
durationSeconds: number
|
durationSeconds: number
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
const anchor = segmentAnchorTime(obj, durationSeconds)
|
const marker = segmentAnchorTime(obj, durationSeconds)
|
||||||
if (typeof anchor === 'number') return anchor
|
if (typeof marker === 'number') return marker
|
||||||
|
|
||||||
|
const start = firstSegmentTimeNumber(obj, [
|
||||||
|
'startSec',
|
||||||
|
'startSeconds',
|
||||||
|
'start_s',
|
||||||
|
'start',
|
||||||
|
'from',
|
||||||
|
'startMs',
|
||||||
|
'startRatio',
|
||||||
|
'startPercent',
|
||||||
|
'startPct',
|
||||||
|
], durationSeconds)
|
||||||
|
|
||||||
const end = firstSegmentTimeNumber(obj, [
|
const end = firstSegmentTimeNumber(obj, [
|
||||||
'endSec',
|
'endSec',
|
||||||
@ -943,7 +957,14 @@ function segmentPreviewTime(
|
|||||||
'endPct',
|
'endPct',
|
||||||
], durationSeconds)
|
], durationSeconds)
|
||||||
|
|
||||||
return typeof end === 'number' ? end : undefined
|
if (typeof start === 'number' && typeof end === 'number') {
|
||||||
|
return Math.max(0, (start + end) / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof start === 'number') return start
|
||||||
|
if (typeof end === 'number') return end
|
||||||
|
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function segmentOpenTime(
|
function segmentOpenTime(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user