fix: use git commit SHA for versioning, fix audio playback resume, remove all streak localStorage code

This commit is contained in:
2026-01-25 01:22:54 +00:00
committed by GitHub
parent 0f719ab3d5
commit 995f5406e2
7 changed files with 5 additions and 1086 deletions

View File

@@ -115,8 +115,9 @@ export const AudioPlayerProvider: React.FC<{ children: React.ReactNode }> = ({ c
if (savedCurrentTrack) {
try {
const track = JSON.parse(savedCurrentTrack);
// Clear autoPlay flag when loading from localStorage to prevent auto-play on refresh
track.autoPlay = false;
// Check if there's a saved playback position - if so, user was likely playing
const savedTime = localStorage.getItem('navidrome-current-track-time');
track.autoPlay = savedTime !== null && parseFloat(savedTime) > 0;
setCurrentTrack(track);
} catch (error) {
console.error('Failed to parse saved current track:', error);
@@ -230,40 +231,6 @@ export const AudioPlayerProvider: React.FC<{ children: React.ReactNode }> = ({ c
if (currentTrack) {
setPlayedTracks((prev) => [...prev, currentTrack]);
// Record the play for listening streak
// This will store timestamp with the track play
try {
const today = new Date().toISOString().split('T')[0];
const streakData = localStorage.getItem('navidrome-streak-data');
if (streakData) {
const parsedData = JSON.parse(streakData);
const todayData = parsedData[today] || {
date: today,
tracks: 0,
uniqueArtists: [],
uniqueAlbums: [],
totalListeningTime: 0
};
// Update today's listening data
todayData.tracks += 1;
if (!todayData.uniqueArtists.includes(currentTrack.artistId)) {
todayData.uniqueArtists.push(currentTrack.artistId);
}
if (!todayData.uniqueAlbums.includes(currentTrack.albumId)) {
todayData.uniqueAlbums.push(currentTrack.albumId);
}
todayData.totalListeningTime += currentTrack.duration;
// Save updated data
parsedData[today] = todayData;
localStorage.setItem('navidrome-streak-data', JSON.stringify(parsedData));
}
} catch (error) {
console.error('Failed to update listening streak data:', error);
}
}
// Set autoPlay flag on the track

View File

@@ -1,71 +0,0 @@
'use client';
import { useEffect, useState } from 'react';
import { useListeningStreak } from '@/hooks/use-listening-streak';
import { Card, CardContent } from '@/components/ui/card';
import { Flame } from 'lucide-react';
import { cn } from '@/lib/utils';
import { AnimatePresence, motion } from 'framer-motion';
export default function CompactListeningStreak() {
const { stats, hasListenedToday, getStreakEmoji } = useListeningStreak();
const [animate, setAnimate] = useState(false);
// Trigger animation when streak increases
useEffect(() => {
if (stats.currentStreak > 0) {
setAnimate(true);
const timer = setTimeout(() => setAnimate(false), 1000);
return () => clearTimeout(timer);
}
}, [stats.currentStreak]);
const hasCompletedToday = hasListenedToday();
const streakEmoji = getStreakEmoji();
// Only show if the streak is 3 days or more
if (stats.currentStreak < 3) {
return null;
}
return (
<Card className="mb-4">
<CardContent className="p-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Flame className={cn(
"w-5 h-5",
hasCompletedToday ? "text-amber-500" : "text-muted-foreground"
)} />
<AnimatePresence>
<motion.div
key={stats.currentStreak}
initial={{ scale: animate ? 0.8 : 1 }}
animate={{ scale: 1 }}
className="flex items-center"
>
<span className="text-xl font-bold">
{stats.currentStreak}
</span>
<span className="ml-1 text-sm text-muted-foreground">
day streak
</span>
{streakEmoji && (
<motion.span
className="ml-1 text-xl"
animate={{ rotate: animate ? [0, 15, -15, 0] : 0 }}
>
{streakEmoji}
</motion.span>
)}
</motion.div>
</AnimatePresence>
</div>
<div className="text-sm text-muted-foreground">
{hasCompletedToday ? "Today's goal complete!" : "Keep listening!"}
</div>
</div>
</CardContent>
</Card>
);
}

View File

@@ -1,153 +0,0 @@
'use client';
import { useEffect, useState } from 'react';
import { useListeningStreak } from '@/hooks/use-listening-streak';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Progress } from '@/components/ui/progress';
import { Flame, Calendar, Clock, Music, Disc, User2 } from 'lucide-react';
import { AnimatePresence, motion } from 'framer-motion';
import { cn } from '@/lib/utils';
export default function ListeningStreakCard() {
const { stats, hasListenedToday, getStreakEmoji, getTodaySummary, streakThresholds } = useListeningStreak();
const [animate, setAnimate] = useState(false);
// Trigger animation when streak increases
useEffect(() => {
if (stats.currentStreak > 0) {
setAnimate(true);
const timer = setTimeout(() => setAnimate(false), 1000);
return () => clearTimeout(timer);
}
}, [stats.currentStreak]);
const todaySummary = getTodaySummary();
const hasCompletedToday = hasListenedToday();
// Calculate progress towards today's goal
const trackProgress = Math.min(100, (todaySummary.tracks / streakThresholds.tracks) * 100);
const timeInMinutes = parseInt(todaySummary.time.replace('m', ''), 10) || 0;
const timeThresholdMinutes = Math.floor(streakThresholds.time / 60);
const timeProgress = Math.min(100, (timeInMinutes / timeThresholdMinutes) * 100);
// Overall progress (highest of the two metrics)
const overallProgress = Math.max(trackProgress, timeProgress);
return (
<Card className="mb-6 break-inside-avoid py-5">
<CardHeader className="pb-2">
<CardTitle className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Flame className={cn(
"w-5 h-5 transition-all",
hasCompletedToday ? "text-amber-500" : "text-muted-foreground"
)} />
<span>Listening Streak</span>
</div>
<div className="flex items-center gap-2">
<Calendar className="w-4 h-4 text-muted-foreground" />
<span className="text-sm font-normal text-muted-foreground">
{stats.totalDaysListened} days
</span>
</div>
</CardTitle>
</CardHeader>
<CardContent>
<div className="flex flex-col items-center py-2">
<AnimatePresence>
<motion.div
key={stats.currentStreak}
initial={{ scale: animate ? 0.5 : 1 }}
animate={{ scale: 1 }}
exit={{ scale: 0.5 }}
className="relative mb-2"
>
<div className="text-5xl font-bold text-center">
{stats.currentStreak}
</div>
<div className="text-sm text-center text-muted-foreground">
day{stats.currentStreak !== 1 ? 's' : ''} streak
</div>
{getStreakEmoji() && (
<motion.div
className="absolute -top-2 -right-4 text-2xl"
animate={{ rotate: animate ? [0, 15, -15, 0] : 0 }}
transition={{ duration: 0.5 }}
>
{getStreakEmoji()}
</motion.div>
)}
</motion.div>
</AnimatePresence>
<div className="w-full mt-4">
<div className="flex justify-between items-center text-sm mb-1">
<span className="text-muted-foreground">Today&apos;s Progress</span>
<span className={cn(
hasCompletedToday ? "text-green-500 font-medium" : "text-muted-foreground"
)}>
{hasCompletedToday ? "Complete!" : "In progress..."}
</span>
</div>
<Progress
value={overallProgress}
className={cn(
"h-2",
hasCompletedToday ? "bg-green-500/20" : "",
hasCompletedToday ? "[&>div]:bg-green-500" : ""
)}
/>
</div>
<div className="grid grid-cols-2 gap-4 w-full mt-6">
<div className="flex flex-col items-center p-3 rounded-md bg-accent/30">
<div className="flex items-center gap-2 mb-1">
<Music className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">Tracks</span>
</div>
<span className="text-xl font-semibold">{todaySummary.tracks}</span>
<span className="text-xs text-muted-foreground">
Goal: {streakThresholds.tracks}
</span>
</div>
<div className="flex flex-col items-center p-3 rounded-md bg-accent/30">
<div className="flex items-center gap-2 mb-1">
<Clock className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">Time</span>
</div>
<span className="text-xl font-semibold">{todaySummary.time}</span>
<span className="text-xs text-muted-foreground">
Goal: {timeThresholdMinutes}m
</span>
</div>
</div>
<div className="grid grid-cols-2 gap-4 w-full mt-4">
<div className="flex flex-col items-center p-3 rounded-md bg-accent/20">
<div className="flex items-center gap-2 mb-1">
<User2 className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">Artists</span>
</div>
<span className="text-xl font-semibold">{todaySummary.artists}</span>
</div>
<div className="flex flex-col items-center p-3 rounded-md bg-accent/20">
<div className="flex items-center gap-2 mb-1">
<Disc className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground">Albums</span>
</div>
<span className="text-xl font-semibold">{todaySummary.albums}</span>
</div>
</div>
<div className="mt-4 text-xs text-center text-muted-foreground">
{hasCompletedToday ? (
<span>You&#39;ve met your daily listening goal! 🎵</span>
) : (
<span>Listen to {streakThresholds.tracks} tracks or {timeThresholdMinutes} minutes to continue your streak!</span>
)}
</div>
</div>
</CardContent>
</Card>
);
}