Promise resolving to a detailed manual vs. automatic skip analysis object
// Analyze manual vs. automatic skip behavior
const skipTypeAnalysis = await analyzeManualVsAutoSkipPatterns();
console.log(`Manual skips: ${skipTypeAnalysis.manualSkipPercentage.toFixed(1)}%`);
console.log(`Auto skips: ${skipTypeAnalysis.autoSkipPercentage.toFixed(1)}%`);
renderSkipTypeChart(skipTypeAnalysis);
export async function analyzeManualVsAutoSkipPatterns(): Promise<{
totalSkips: number;
manualSkips: number;
autoSkips: number;
manualSkipPercentage: number;
autoSkipPercentage: number;
manualByHour: number[];
autoByHour: number[];
mostFrequentManualSkipHour: number;
mostFrequentAutoSkipHour: number;
}> {
try {
// Import the store module for getSkippedTracks
const store = await import("../../helpers/storage/store");
const skippedTracks = await store.getSkippedTracks();
// Initialize result structure
const result = {
totalSkips: 0,
manualSkips: 0,
autoSkips: 0,
manualSkipPercentage: 0,
autoSkipPercentage: 0,
manualByHour: Array(24).fill(0),
autoByHour: Array(24).fill(0),
mostFrequentManualSkipHour: 0,
mostFrequentAutoSkipHour: 0,
};
// Aggregate data from skipped tracks
skippedTracks.forEach((track: SkippedTrack) => {
const manualCount = track.manualSkipCount || 0;
const autoCount = track.autoSkipCount || 0;
result.totalSkips += track.skipCount || 0;
result.manualSkips += manualCount;
result.autoSkips += autoCount;
// Analyze time-of-day patterns if available - use timeOfDay instead of timeOfDayData
if (track.timeOfDay && typeof track.timeOfDay === "object") {
// Convert timeOfDay object to array format
const hourlyData = Array(24).fill(0);
// Process the timeOfDay object which contains string hour keys
Object.entries(track.timeOfDay).forEach(([hourKey, count]) => {
const hour = parseInt(hourKey, 10);
if (!isNaN(hour) && hour >= 0 && hour < 24) {
hourlyData[hour] = count;
}
});
// We need to estimate how many skips at each hour were manual vs. auto
// using the overall ratio for this track as an approximation
const totalTrackSkips = manualCount + autoCount;
if (totalTrackSkips > 0) {
const manualRatio = manualCount / totalTrackSkips;
hourlyData.forEach((hourCount: number, hour: number) => {
const estimatedManualForHour = Math.round(hourCount * manualRatio);
const estimatedAutoForHour = hourCount - estimatedManualForHour;
result.manualByHour[hour] += estimatedManualForHour;
result.autoByHour[hour] += estimatedAutoForHour;
});
}
}
});
// Calculate percentages
if (result.totalSkips > 0) {
result.manualSkipPercentage =
(result.manualSkips / result.totalSkips) * 100;
result.autoSkipPercentage = (result.autoSkips / result.totalSkips) * 100;
}
// Find peak hours
let maxManual = 0;
let maxAuto = 0;
result.manualByHour.forEach((count, hour) => {
if (count > maxManual) {
maxManual = count;
result.mostFrequentManualSkipHour = hour;
}
});
result.autoByHour.forEach((count, hour) => {
if (count > maxAuto) {
maxAuto = count;
result.mostFrequentAutoSkipHour = hour;
}
});
return result;
} catch (error) {
console.error("Error analyzing manual vs. automatic skip patterns:", error);
// Return a default result on error
return {
totalSkips: 0,
manualSkips: 0,
autoSkips: 0,
manualSkipPercentage: 0,
autoSkipPercentage: 0,
manualByHour: Array(24).fill(0),
autoByHour: Array(24).fill(0),
mostFrequentManualSkipHour: 0,
mostFrequentAutoSkipHour: 0,
};
}
}
Analyzes the manual vs. automatic skip patterns in the user's listening history
Compares and contrasts user-initiated skips with automatic skips (timeout or end-of-preview) to identify patterns in explicit user rejection versus passive non-engagement. This function processes the entire skip history to build a comprehensive picture of user intent.
The analysis includes:
This analysis helps distinguish between active content rejection (manual skips) and passive disengagement (automatic skips), providing insights into user intent and attention patterns throughout the day.