Previous playback state before track change
User-defined skip threshold as decimal (0.0-1.0)
Object containing skip detection results:
// Analyze if the previous track was skipped
const skipResult = analyzePositionBasedSkip(previousState, 0.7);
if (skipResult.isSkip) {
console.log(`Track skipped (${skipResult.skipType}): ${skipResult.reason}`);
} else {
console.log('Track completed normally');
}
export function analyzePositionBasedSkip(
previousState: PlaybackState,
skipThreshold: number,
): {
isSkip: boolean;
skipType: SkipType;
confidence: number;
reason: string;
} {
// Default result
const result = {
isSkip: false,
skipType: SkipType.NONE,
confidence: 0,
reason: "No skip detected",
};
// Need basic information to analyze
if (
!previousState ||
!previousState.currentTrackDuration ||
!previousState.lastProgress
) {
return result;
}
const duration = previousState.currentTrackDuration;
const progress = previousState.lastProgress;
const progressPercent = progress / duration;
// 1. Quick Skip Detection (played very briefly)
if (progress < VERY_SHORT_PLAY_MS) {
return {
isSkip: true,
skipType: SkipType.QUICK_PREVIEW,
confidence: 0.9,
reason: `Track played for only ${progress}ms, likely a quick preview skip`,
};
}
// 2. Standard Skip Detection (below threshold)
if (progressPercent < skipThreshold) {
// Calculate confidence based on how far from threshold
const confidenceValue = 1 - progressPercent / skipThreshold;
return {
isSkip: true,
skipType: SkipType.STANDARD,
confidence: Math.min(0.95, confidenceValue),
reason: `Track skipped at ${(progressPercent * 100).toFixed(1)}%, below threshold of ${skipThreshold * 100}%`,
};
}
// 3. Near-Completion (close to end but not quite finished)
if (progressPercent > 0.9 && progressPercent < 0.98) {
// Only count as a skip if it's below the user's threshold
if (progressPercent < skipThreshold) {
return {
isSkip: true,
skipType: SkipType.NEAR_COMPLETION,
confidence: 0.7,
reason: `Track nearly finished (${(progressPercent * 100).toFixed(1)}%) but skipped before end`,
};
} else {
// Track has passed user's threshold, so don't count as a skip
return {
isSkip: false,
skipType: SkipType.NONE,
confidence: 0.9,
reason: `Track played beyond threshold (${(progressPercent * 100).toFixed(1)}% > ${skipThreshold * 100}%), considered completed`,
};
}
}
// 4. Normal completion or very close to end
if (progressPercent >= 0.98) {
return {
isSkip: false,
skipType: SkipType.NONE,
confidence: 0.95,
reason: `Track completed (${(progressPercent * 100).toFixed(1)}%)`,
};
}
// If we get here, the track wasn't skipped by our thresholds
return result;
}
Analyzes position data to determine if a track change was a skip
Evaluates track progress information to determine if a track change should be classified as a skip, and if so, what type of skip it was. This algorithm considers factors like:
Each classification includes a confidence rating indicating the algorithm's certainty in its determination.