rename TaskRunnerModal's track bindings off t, before keying it
No behaviour change. Separated from the conversion because a 40-site rename hiding inside a string diff is unreviewable. Read first rather than renamed blindly, and it earned it twice. `\bt\b` matches 93 times in this file and only some are tracks: `const t = ctx.currentTime` is an audio timestamp in the beep helper, and `border-t` inside classNames matches too — a blanket rename would have silently corrupted five CSS classes and the typecheck would not have said a word about them. So this renames the track bindings only, by property (`t.id`, `t.lang`, `t.codec`, `t.channels`, `t.bitrate`, `t.title`) and by parameter, leaving the timestamp and the class names alone.
This commit is contained in:
+58
-49
@@ -291,14 +291,16 @@ type TaskInputFormProps = {
|
||||
hideTrackPickers?: boolean;
|
||||
};
|
||||
|
||||
const trackLabel = (t: { title: string; lang: string; id: number }) =>
|
||||
t.title || (t.lang && t.lang !== 'und' && t.lang !== 'unknown' ? t.lang.toUpperCase() : '') || `Track ${t.id + 1}`;
|
||||
const trackLabel = (track: { title: string; lang: string; id: number }) =>
|
||||
track.title ||
|
||||
(track.lang && track.lang !== 'und' && track.lang !== 'unknown' ? track.lang.toUpperCase() : '') ||
|
||||
`Track ${track.id + 1}`;
|
||||
|
||||
// Channel count → friendly layout name; audio meta → "stereo · aac 193k"-style detail for a track row.
|
||||
const chLabel = (n: number) =>
|
||||
n === 1 ? 'mono' : n === 2 ? 'stereo' : n === 6 ? '5.1' : n === 8 ? '7.1' : n ? `${n}ch` : '';
|
||||
const audioMeta = (t: AudioTrack) =>
|
||||
[chLabel(t.channels), t.codec].filter(Boolean).join(' ') + (t.bitrate ? ` ${t.bitrate}k` : '');
|
||||
const audioMeta = (track: AudioTrack) =>
|
||||
[chLabel(track.channels), track.codec].filter(Boolean).join(' ') + (track.bitrate ? ` ${track.bitrate}k` : '');
|
||||
|
||||
// subtitle_edit input: per-subtitle keep flag + editable label, serialized to JSON in the form value.
|
||||
type SubtitleEditEntry = { id: number; keep: boolean; label: string };
|
||||
@@ -333,14 +335,16 @@ export const TaskInputForm = ({
|
||||
if (def.type === 'subtitle_edit') {
|
||||
const tracks = subtitleTracks ?? [];
|
||||
const byId = new Map(parseSubtitleSpec(values[key]).map((e) => [e.id, e]));
|
||||
const entryFor = (t: SubtitleTrack): SubtitleEditEntry =>
|
||||
byId.get(t.id) ?? { id: t.id, keep: true, label: trackLabel(t) };
|
||||
const entryFor = (track: SubtitleTrack): SubtitleEditEntry =>
|
||||
byId.get(track.id) ?? { id: track.id, keep: true, label: trackLabel(track) };
|
||||
const update = (id: number, patch: Partial<SubtitleEditEntry>) =>
|
||||
onChange(
|
||||
key,
|
||||
JSON.stringify(tracks.map((t) => (t.id === id ? { ...entryFor(t), ...patch } : entryFor(t)))),
|
||||
JSON.stringify(
|
||||
tracks.map((track) => (track.id === id ? { ...entryFor(track), ...patch } : entryFor(track))),
|
||||
),
|
||||
);
|
||||
const keptCount = tracks.filter((t) => entryFor(t).keep).length;
|
||||
const keptCount = tracks.filter((track) => entryFor(track).keep).length;
|
||||
return (
|
||||
<div key={key} className="flex flex-col gap-1.5">
|
||||
<span className="text-sm font-medium text-duck-dark dark:text-foreground">{def.description ?? key}</span>
|
||||
@@ -354,26 +358,26 @@ export const TaskInputForm = ({
|
||||
) : (
|
||||
<>
|
||||
<div className="flex flex-col gap-1 max-h-72 overflow-y-auto pr-1">
|
||||
{tracks.map((t) => {
|
||||
const e = entryFor(t);
|
||||
{tracks.map((track) => {
|
||||
const e = entryFor(track);
|
||||
return (
|
||||
<div key={t.id} className="flex items-center gap-2">
|
||||
<div key={track.id} className="flex items-center gap-2">
|
||||
<label className="flex items-center gap-2 cursor-pointer shrink-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={e.keep}
|
||||
onChange={() => update(t.id, { keep: !e.keep })}
|
||||
onChange={() => update(track.id, { keep: !e.keep })}
|
||||
className="accent-duck-teal cursor-pointer"
|
||||
/>
|
||||
<span className="text-[10px] font-mono uppercase w-9 text-duck-dark/40 dark:text-foreground/40">
|
||||
{t.lang || 'und'}
|
||||
{track.lang || 'und'}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={e.label}
|
||||
disabled={!e.keep}
|
||||
onChange={(ev) => update(t.id, { label: ev.target.value })}
|
||||
onChange={(ev) => update(track.id, { label: ev.target.value })}
|
||||
className="flex-1 min-w-0 px-2 py-1 text-sm rounded-md border border-duck-dark/15 dark:border-foreground/15 bg-background focus:outline-none focus:ring-1 focus:ring-duck-teal disabled:opacity-40"
|
||||
/>
|
||||
</div>
|
||||
@@ -419,23 +423,23 @@ export const TaskInputForm = ({
|
||||
<span className="text-xs text-duck-dark/50 dark:text-foreground/50">None</span>
|
||||
) : (
|
||||
<div className="flex flex-wrap gap-x-3 gap-y-1.5">
|
||||
{tracks.map((t) => (
|
||||
{tracks.map((track) => (
|
||||
<label
|
||||
key={t.id}
|
||||
key={track.id}
|
||||
className="flex items-center gap-1.5 text-sm cursor-pointer text-duck-dark dark:text-foreground"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selected.has(t.id)}
|
||||
onChange={() => toggle(t.id)}
|
||||
checked={selected.has(track.id)}
|
||||
onChange={() => toggle(track.id)}
|
||||
className="accent-duck-teal cursor-pointer"
|
||||
/>
|
||||
<span className="whitespace-nowrap">
|
||||
{trackLabel(t)}
|
||||
{trackLabel(track)}
|
||||
{isAudio && (
|
||||
<span className="text-duck-dark/40 dark:text-foreground/40">
|
||||
{' '}
|
||||
· {(t as AudioTrack).channels}ch
|
||||
· {(track as AudioTrack).channels}ch
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
@@ -691,9 +695,9 @@ const pickerKinds = (defs: Record<string, TaskInputDef> | null): PickerKinds =>
|
||||
});
|
||||
|
||||
const defaultGroupSel = (g: FolderTrackGroup): GroupSel => ({
|
||||
audio: g.audioTracks.map((t) => t.id).join(','), // audio: keep all
|
||||
audio: g.audioTracks.map((track) => track.id).join(','), // audio: keep all
|
||||
subs: 'none', // subtitles: keep none by default — you usually want only a few of many
|
||||
subEdit: g.subtitleTracks.map((t) => ({ id: t.id, keep: false, label: trackLabel(t) })),
|
||||
subEdit: g.subtitleTracks.map((track) => ({ id: track.id, keep: false, label: trackLabel(track) })),
|
||||
});
|
||||
|
||||
// Does a group's selection change anything vs keep-all + original labels?
|
||||
@@ -703,9 +707,9 @@ const groupChanges = (g: FolderTrackGroup, s: GroupSel, has: PickerKinds): boole
|
||||
if (has.subs && (s.subs === 'none' ? g.subtitleTracks.length > 0 : parseCsv(s.subs).size < g.subtitleTracks.length))
|
||||
return true;
|
||||
if (has.subEdit) {
|
||||
for (const t of g.subtitleTracks) {
|
||||
const e = s.subEdit.find((x) => x.id === t.id);
|
||||
if (!e || !e.keep || e.label !== trackLabel(t)) return true;
|
||||
for (const track of g.subtitleTracks) {
|
||||
const e = s.subEdit.find((x) => x.id === track.id);
|
||||
if (!e || !e.keep || e.label !== trackLabel(track)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -726,7 +730,8 @@ const buildGroupConfig = (groups: FolderTrackGroup[], sel: GroupSel[], has: Pick
|
||||
...(has.subEdit
|
||||
? {
|
||||
subEdit: g.subtitleTracks.map(
|
||||
(t) => s.subEdit.find((x) => x.id === t.id) ?? { id: t.id, keep: true, label: trackLabel(t) },
|
||||
(track) =>
|
||||
s.subEdit.find((x) => x.id === track.id) ?? { id: track.id, keep: true, label: trackLabel(track) },
|
||||
),
|
||||
}
|
||||
: {}),
|
||||
@@ -780,11 +785,13 @@ const PerGroupTrackConfig = ({ groups, has, sel, onChange, probing }: PerGroupTr
|
||||
n.has(id) ? n.delete(id) : n.add(id);
|
||||
onChange(gi, { subs: n.size ? [...n].sort((a, b) => a - b).join(',') : 'none' });
|
||||
};
|
||||
const entryFor = (t: SubtitleTrack): SubtitleEditEntry =>
|
||||
s.subEdit.find((x) => x.id === t.id) ?? { id: t.id, keep: true, label: trackLabel(t) };
|
||||
const entryFor = (track: SubtitleTrack): SubtitleEditEntry =>
|
||||
s.subEdit.find((x) => x.id === track.id) ?? { id: track.id, keep: true, label: trackLabel(track) };
|
||||
const updateEdit = (id: number, patch: Partial<SubtitleEditEntry>) =>
|
||||
onChange(gi, {
|
||||
subEdit: g.subtitleTracks.map((t) => (t.id === id ? { ...entryFor(t), ...patch } : entryFor(t))),
|
||||
subEdit: g.subtitleTracks.map((track) =>
|
||||
track.id === id ? { ...entryFor(track), ...patch } : entryFor(track),
|
||||
),
|
||||
});
|
||||
return (
|
||||
<div
|
||||
@@ -805,20 +812,20 @@ const PerGroupTrackConfig = ({ groups, has, sel, onChange, probing }: PerGroupTr
|
||||
{g.audioTracks.length === 0 ? (
|
||||
<span className="text-xs text-duck-dark/40 dark:text-foreground/40">none</span>
|
||||
) : (
|
||||
g.audioTracks.map((t) => (
|
||||
g.audioTracks.map((track) => (
|
||||
<label
|
||||
key={t.id}
|
||||
key={track.id}
|
||||
className="flex items-center gap-2 text-sm cursor-pointer text-duck-dark dark:text-foreground"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={aSel.has(t.id)}
|
||||
onChange={() => toggleA(t.id)}
|
||||
checked={aSel.has(track.id)}
|
||||
onChange={() => toggleA(track.id)}
|
||||
className="accent-duck-teal cursor-pointer shrink-0"
|
||||
/>
|
||||
<span className="whitespace-nowrap">
|
||||
{trackLabel(t)}
|
||||
<span className="text-duck-dark/40 dark:text-foreground/40"> · {audioMeta(t)}</span>
|
||||
{trackLabel(track)}
|
||||
<span className="text-duck-dark/40 dark:text-foreground/40"> · {audioMeta(track)}</span>
|
||||
</span>
|
||||
</label>
|
||||
))
|
||||
@@ -832,20 +839,20 @@ const PerGroupTrackConfig = ({ groups, has, sel, onChange, probing }: PerGroupTr
|
||||
{g.subtitleTracks.length === 0 ? (
|
||||
<span className="text-xs text-duck-dark/40 dark:text-foreground/40">none</span>
|
||||
) : (
|
||||
g.subtitleTracks.map((t) => (
|
||||
g.subtitleTracks.map((track) => (
|
||||
<label
|
||||
key={t.id}
|
||||
key={track.id}
|
||||
className="flex items-center gap-2 text-sm cursor-pointer text-duck-dark dark:text-foreground"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={sSel.has(t.id)}
|
||||
onChange={() => toggleS(t.id)}
|
||||
checked={sSel.has(track.id)}
|
||||
onChange={() => toggleS(track.id)}
|
||||
className="accent-duck-teal cursor-pointer shrink-0"
|
||||
/>
|
||||
<span className="whitespace-nowrap">
|
||||
{trackLabel(t)}
|
||||
<span className="text-duck-dark/40 dark:text-foreground/40"> · {t.codec}</span>
|
||||
{trackLabel(track)}
|
||||
<span className="text-duck-dark/40 dark:text-foreground/40"> · {track.codec}</span>
|
||||
</span>
|
||||
</label>
|
||||
))
|
||||
@@ -859,26 +866,26 @@ const PerGroupTrackConfig = ({ groups, has, sel, onChange, probing }: PerGroupTr
|
||||
{g.subtitleTracks.length === 0 ? (
|
||||
<span className="text-xs text-duck-dark/40 dark:text-foreground/40">none</span>
|
||||
) : (
|
||||
g.subtitleTracks.map((t) => {
|
||||
const e = entryFor(t);
|
||||
g.subtitleTracks.map((track) => {
|
||||
const e = entryFor(track);
|
||||
return (
|
||||
<div key={t.id} className="flex items-center gap-2">
|
||||
<div key={track.id} className="flex items-center gap-2">
|
||||
<label className="flex items-center gap-2 cursor-pointer shrink-0">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={e.keep}
|
||||
onChange={() => updateEdit(t.id, { keep: !e.keep })}
|
||||
onChange={() => updateEdit(track.id, { keep: !e.keep })}
|
||||
className="accent-duck-teal cursor-pointer"
|
||||
/>
|
||||
<span className="text-[10px] font-mono uppercase w-9 text-duck-dark/40 dark:text-foreground/40">
|
||||
{t.lang || 'und'}
|
||||
{track.lang || 'und'}
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={e.label}
|
||||
disabled={!e.keep}
|
||||
onChange={(ev) => updateEdit(t.id, { label: ev.target.value })}
|
||||
onChange={(ev) => updateEdit(track.id, { label: ev.target.value })}
|
||||
className="flex-1 min-w-0 px-2 py-1 text-sm rounded-md border border-duck-dark/15 dark:border-foreground/15 bg-background focus:outline-none focus:ring-1 focus:ring-duck-teal disabled:opacity-40"
|
||||
/>
|
||||
</div>
|
||||
@@ -1015,10 +1022,12 @@ const ScriptRunner = ({
|
||||
setFormValues((prev) => {
|
||||
const next = { ...prev };
|
||||
for (const [key, def] of Object.entries(defs)) {
|
||||
if (def.type === 'audio_tracks') next[key] = aud.map((t) => t.id).join(',') || 'none';
|
||||
if (def.type === 'audio_tracks') next[key] = aud.map((track) => track.id).join(',') || 'none';
|
||||
if (def.type === 'subtitle_tracks') next[key] = 'none';
|
||||
if (def.type === 'subtitle_edit')
|
||||
next[key] = JSON.stringify(sub.map((t) => ({ id: t.id, keep: false, label: trackLabel(t) })));
|
||||
next[key] = JSON.stringify(
|
||||
sub.map((track) => ({ id: track.id, keep: false, label: trackLabel(track) })),
|
||||
);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user