• Not Exported

    Detects patterns related to specific listening contexts (playlists, albums, etc.)

    Analyzes skip events to identify correlations between skip behavior and the context in which tracks are played. This reveals important insights about how content organization and presentation affects user engagement.

    The detection algorithm:

    1. Aggregates skip events by their context (playlist, album, etc.)
    2. Calculates skip statistics for each unique context
    3. Identifies contexts with statistically significant skip rates
    4. Generates appropriate descriptions based on context type

    Context-specific patterns can reveal:

    • Ineffective playlist curation or sequencing
    • Mismatch between context theme and user expectations
    • Content organization issues affecting listening experience
    • Specific contexts that consistently trigger skip behavior

    Parameters

    • skippedTracks: SkippedTrack[]

      Array of tracks with skip event data

    Returns DetectedPattern[]

    Array of detected context-specific patterns meeting confidence thresholds

    // Detect context-specific skip patterns
    const tracks = await getSkippedTracks();
    const contextPatterns = detectContextSpecificPatterns(tracks);

    // Example results:
    // [
    // {
    // type: "context_specific",
    // description: "Frequently skips tracks in playlist \"Workout Mix\"",
    // confidence: 0.82,
    // ...
    // },
    // {
    // type: "context_specific",
    // description: "Frequently skips tracks when listening to album \"Greatest Hits\"",
    // confidence: 0.75,
    // ...
    // }
    // ]
    function detectContextSpecificPatterns(
    skippedTracks: SkippedTrack[],
    ): DetectedPattern[] {
    const patterns: DetectedPattern[] = [];

    // Collect skip counts by context
    const contextSkips: Record<
    string,
    {
    type: string;
    name: string;
    uri?: string;
    skipCount: number;
    tracks: Set<string>;
    }
    > = {};

    // Process all tracks with context data
    skippedTracks.forEach((track) => {
    if (!track.skipEvents) return;

    track.skipEvents.forEach((event) => {
    if (!event.context) return;

    const contextKey =
    (event.context.name as string) ||
    event.context.uri ||
    event.context.type;

    if (!contextSkips[contextKey]) {
    contextSkips[contextKey] = {
    type: event.context.type,
    name: event.context.name || "(Unknown)",
    uri: event.context.uri,
    skipCount: 0,
    tracks: new Set<string>(),
    };
    }

    contextSkips[contextKey].skipCount++;
    contextSkips[contextKey].tracks.add(track.id);
    });
    });

    // Find contexts with significant skip counts
    Object.values(contextSkips).forEach((context) => {
    if (
    context.skipCount >= PATTERN_THRESHOLDS.MIN_OCCURRENCES &&
    context.tracks.size >= 3
    ) {
    const confidence = calculateConfidence(
    0.7, // Base confidence
    context.tracks.size,
    context.skipCount,
    );

    if (confidence >= PATTERN_THRESHOLDS.CONFIDENCE_THRESHOLD) {
    patterns.push({
    type: PatternType.CONTEXT_SPECIFIC,
    confidence,
    description:
    context.type === "playlist"
    ? `Frequently skips tracks in playlist "${context.name}"`
    : `Frequently skips tracks when listening to ${context.type} "${context.name}"`,
    occurrences: context.skipCount,
    relatedItems: [context.name],
    details: {
    contextType: context.type,
    contextName: context.name,
    contextUri: context.uri,
    uniqueTracksSkipped: context.tracks.size,
    },
    firstDetected: new Date().toISOString(),
    lastDetected: new Date().toISOString(),
    });
    }
    }
    });

    return patterns;
    }