add download buttons to tv
This commit is contained in:
@@ -325,6 +325,7 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item
|
||||
🏷
|
||||
</button>
|
||||
)}
|
||||
{!showTags && (
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={smallBtn}
|
||||
@@ -336,6 +337,7 @@ export default function ImageLightbox({ url, name, onClose, onPrev, onNext, item
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Text display button — bottom-right, hidden when panel open */}
|
||||
|
||||
@@ -100,6 +100,7 @@ export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, i
|
||||
🏷
|
||||
</button>
|
||||
)}
|
||||
{!showTags && (
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={smallBtn}
|
||||
@@ -111,6 +112,7 @@ export default function VideoPlayerModal({ url, name, onClose, onPrev, onNext, i
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ interface Props {
|
||||
onTag?: () => void
|
||||
onDelete?: () => void
|
||||
onRename?: (newName: string) => Promise<boolean>
|
||||
downloadUrl?: string
|
||||
}
|
||||
|
||||
export default function EpisodeCard({ episode, onClick, onTag, onDelete, onRename }: Props) {
|
||||
export default function EpisodeCard({ episode, onClick, onTag, onDelete, onRename, downloadUrl }: Props) {
|
||||
const epLabel = episode.episodeNumber !== null ? `E${String(episode.episodeNumber).padStart(2, '0')}` : null
|
||||
const menuRef = useRef<HTMLDivElement>(null)
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
@@ -79,7 +80,7 @@ export default function EpisodeCard({ episode, onClick, onTag, onDelete, onRenam
|
||||
</button>
|
||||
)}
|
||||
{/* Kebab menu */}
|
||||
{onDelete && (
|
||||
{(onDelete || downloadUrl) && (
|
||||
<div className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity hidden group-hover:block" ref={menuRef}>
|
||||
<button
|
||||
onClick={(e) => { e.stopPropagation(); setMenuOpen((o) => !o); setConfirming(false) }}
|
||||
@@ -94,6 +95,19 @@ export default function EpisodeCard({ episode, onClick, onTag, onDelete, onRenam
|
||||
className="absolute right-0 top-full mt-1 rounded-lg shadow-lg overflow-hidden z-20 min-w-max"
|
||||
style={{ backgroundColor: 'var(--surface)', border: '1px solid var(--border)' }}
|
||||
>
|
||||
{downloadUrl && (
|
||||
<a
|
||||
href={downloadUrl}
|
||||
download
|
||||
onClick={(e) => { e.stopPropagation(); setMenuOpen(false) }}
|
||||
className="flex items-center gap-2 w-full px-4 py-2 text-sm text-left transition-colors"
|
||||
style={{ color: 'var(--text-primary)' }}
|
||||
onMouseEnter={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'var(--border)')}
|
||||
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'transparent')}
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
)}
|
||||
{onRename && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -931,6 +931,7 @@ export default function TvView({ libraryId }: Props) {
|
||||
episode={ep}
|
||||
onClick={() => setPlayingEpisodeIndex(episodes.indexOf(ep))}
|
||||
onTag={() => { setTagPanelItemKey(ep.item_key!); setTagPanelDisabled(false); setShowTagPanel(true) }}
|
||||
downloadUrl={`/api/file?libraryId=${encodeURIComponent(libraryId)}&path=${encodeURIComponent(ep.videoPath)}`}
|
||||
onDelete={() => {
|
||||
fetch(
|
||||
`/api/tv?libraryId=${encodeURIComponent(libraryId)}&seriesId=${encodeURIComponent(selectedSeries!.id)}&episodeKey=${encodeURIComponent(ep.item_key!)}`,
|
||||
|
||||
Reference in New Issue
Block a user