v1.0.2: Mood mix optimizations and media player improvements

- Fixed player seek flicker on podcasts (30s skip buttons)
- Added dual-layer seek lock mechanism to prevent stale time updates
- Optimized cached podcast seeking (direct seek before reload fallback)
- Large skips now execute immediately for responsive feel
- Mood mix performance optimizations
This commit is contained in:
Kevin O'Neill
2025-12-26 13:06:17 -06:00
parent d8c608cf70
commit f8b464feec
28 changed files with 5328 additions and 1615 deletions

View File

@@ -1,6 +1,6 @@
const AUTH_TOKEN_KEY = "auth_token";
// Mood Mix Types
// Mood Mix Types (Legacy - for old presets endpoint)
export interface MoodPreset {
id: string;
name: string;
@@ -29,6 +29,43 @@ export interface MoodMixParams {
limit?: number;
}
// New Mood Bucket Types (simplified mood system)
export type MoodType =
| "happy"
| "sad"
| "chill"
| "energetic"
| "party"
| "focus"
| "melancholy"
| "aggressive"
| "acoustic";
export interface MoodBucketPreset {
id: MoodType;
name: string;
color: string;
icon: string;
trackCount: number;
}
export interface MoodBucketMix {
id: string;
mood: MoodType;
name: string;
description: string;
trackIds: string[];
coverUrls: string[];
trackCount: number;
color: string;
tracks?: any[];
}
export interface SavedMoodMixResponse {
success: boolean;
mix: MoodBucketMix & { generatedAt: string };
}
// Dynamically determine API URL based on configuration
const getApiBaseUrl = () => {
// Server-side rendering
@@ -1225,7 +1262,7 @@ class ApiClient {
);
}
// Mood on Demand
// Mood on Demand (Legacy)
async getMoodPresets() {
return this.request<MoodPreset[]>("/mixes/mood/presets");
}
@@ -1237,6 +1274,30 @@ class ApiClient {
});
}
// New Mood Bucket System (simplified, pre-computed)
async getMoodBucketPresets() {
return this.request<MoodBucketPreset[]>("/mixes/mood/buckets/presets");
}
async getMoodBucketMix(mood: MoodType) {
return this.request<MoodBucketMix>(`/mixes/mood/buckets/${mood}`);
}
async saveMoodBucketMix(mood: MoodType) {
return this.request<SavedMoodMixResponse>(
`/mixes/mood/buckets/${mood}/save`,
{ method: "POST" }
);
}
async backfillMoodBuckets() {
return this.request<{
success: boolean;
processed: number;
assigned: number;
}>("/mixes/mood/buckets/backfill", { method: "POST" });
}
// Enrichment
async getEnrichmentSettings() {
return this.request<any>("/enrichment/settings");