Add inline YouTube player on recommendation cards, fetch real video IDs via ytmusicapi
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Heart, ExternalLink, Music, ThumbsDown, Repeat, Share2, Check, Calendar, MapPin, Ticket, ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { Heart, ExternalLink, Music, ThumbsDown, Repeat, Share2, Check, Calendar, MapPin, Ticket, ChevronUp, Play, X } from 'lucide-react'
|
||||
import type { RecommendationItem, ConcertEvent } from '../lib/api'
|
||||
import { shareRecommendation, findConcerts } from '../lib/api'
|
||||
|
||||
@@ -19,6 +19,16 @@ export default function RecommendationCard({ recommendation, onToggleSave, onDis
|
||||
const [concertsOpen, setConcertsOpen] = useState(false)
|
||||
const [concerts, setConcerts] = useState<ConcertEvent[] | null>(null)
|
||||
const [concertsLoading, setConcertsLoading] = useState(false)
|
||||
const [playerOpen, setPlayerOpen] = useState(false)
|
||||
|
||||
// Extract YouTube video ID from URL if it's a direct link
|
||||
const getYouTubeVideoId = (url: string | null): string | null => {
|
||||
if (!url) return null
|
||||
const match = url.match(/[?&]v=([a-zA-Z0-9_-]{11})/)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
const videoId = getYouTubeVideoId(recommendation.youtube_url)
|
||||
|
||||
const handleMoreLikeThis = () => {
|
||||
const q = `find songs similar to ${recommendation.artist} - ${recommendation.title}`
|
||||
@@ -191,19 +201,49 @@ export default function RecommendationCard({ recommendation, onToggleSave, onDis
|
||||
</button>
|
||||
|
||||
{recommendation.youtube_url && (
|
||||
<a
|
||||
href={recommendation.youtube_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="p-2 rounded-full bg-red-50 text-red-600 hover:bg-red-100 transition-colors"
|
||||
title="Watch on YouTube"
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
</a>
|
||||
videoId ? (
|
||||
<button
|
||||
onClick={() => setPlayerOpen(!playerOpen)}
|
||||
className={`p-2 rounded-full transition-colors cursor-pointer border-none ${
|
||||
playerOpen
|
||||
? 'bg-red-100 text-red-700'
|
||||
: 'bg-red-50 text-red-600 hover:bg-red-100'
|
||||
}`}
|
||||
title={playerOpen ? 'Close player' : 'Play'}
|
||||
>
|
||||
{playerOpen ? <X className="w-4 h-4" /> : <Play className="w-4 h-4" />}
|
||||
</button>
|
||||
) : (
|
||||
<a
|
||||
href={recommendation.youtube_url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="p-2 rounded-full bg-red-50 text-red-600 hover:bg-red-100 transition-colors"
|
||||
title="Search on YouTube Music"
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
</a>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* YouTube Player */}
|
||||
{playerOpen && videoId && (
|
||||
<div className="border-t border-purple-50 bg-charcoal">
|
||||
<iframe
|
||||
width="100%"
|
||||
height="152"
|
||||
src={`https://www.youtube.com/embed/${videoId}?autoplay=1`}
|
||||
title={`${recommendation.artist} - ${recommendation.title}`}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
className="block"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Concert section */}
|
||||
{concertsOpen && (
|
||||
<div className="border-t border-purple-50 px-5 py-3 bg-orange-50/30">
|
||||
|
||||
Reference in New Issue
Block a user