import type { Torrent } from '../shared'; import { useEffect, useState } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { useTorrentMutations } from '../useTransmissionData'; // Transmission 4 replaced the old trackerAdd/trackerRemove/trackerReplace triple with `trackerList`: the // whole announce list as text, one URL per line, a blank line between tiers. Editing text is also the only // honest way to express tiers, which a list of rows with buttons cannot. type TrackersDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; torrent: Torrent | null }; /** Rebuild the tier-separated text from trackerStats when the daemon didn't send trackerList. */ function fromStats(torrent: Torrent): string { const tiers = new Map(); for (const t of torrent.trackerStats ?? []) { const list = tiers.get(t.tier) ?? []; list.push(t.announce); tiers.set(t.tier, list); } return [...tiers.entries()] .sort((a, b) => a[0] - b[0]) .map(([, urls]) => urls.join('\n')) .join('\n\n'); } export const TrackersDialog = ({ open, onOpenChange, torrent }: TrackersDialogProps) => { const { set } = useTorrentMutations(); const [text, setText] = useState(''); useEffect(() => { if (!open || !torrent) return; setText(torrent.trackerList ?? fromStats(torrent)); }, [open, torrent]); const submit = async () => { if (!torrent) return; // Trailing whitespace on a line makes Transmission reject the whole list, and pasting from a website // reliably brings some along. const normalised = text .split('\n') .map((line) => line.trim()) .join('\n'); await set.mutateAsync({ ids: [torrent.id], trackerList: normalised }); onOpenChange(false); }; return ( Trackers {torrent?.name}