Skip to content

Commit

Permalink
implement copy/paste segment tags
Browse files Browse the repository at this point in the history
closes #1964
  • Loading branch information
mifi committed Apr 21, 2024
1 parent 8217be4 commit 3f4c214
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 29 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@
"semver": "^7.5.2",
"string-to-stream": "^3.0.1",
"winston": "^3.8.1",
"yargs-parser": "^21.1.1"
"yargs-parser": "^21.1.1",
"zod": "^3.22.5"
},
"build": {
"directories": {
Expand Down
8 changes: 4 additions & 4 deletions src/renderer/src/SegmentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,11 @@ const SegmentList = memo(({
);
}

const [editingTag, setEditingTag] = useState();
const [editingTag, setEditingTag] = useState<string>();

const onTagChange = useCallback((tag: string, value: string) => setEditingSegmentTags((existingTags) => ({
const onTagsChange = useCallback((keyValues: Record<string, string>) => setEditingSegmentTags((existingTags) => ({
...existingTags,
[tag]: value,
...keyValues,
})), [setEditingSegmentTags]);

const onTagReset = useCallback((tag: string) => setEditingSegmentTags((tags) => {
Expand Down Expand Up @@ -437,7 +437,7 @@ const SegmentList = memo(({
onCloseComplete={onSegmentTagsCloseComplete}
>
<div style={{ color: 'black' }}>
<TagEditor customTags={editingSegmentTags} editingTag={editingTag} setEditingTag={setEditingTag} onTagChange={onTagChange} onTagReset={onTagReset} addTagTitle={t('Add segment tag')} addTagText={t('Enter tag key')} />
<TagEditor customTags={editingSegmentTags} editingTag={editingTag} setEditingTag={setEditingTag} onTagsChange={onTagsChange} onTagReset={onTagReset} addTagTitle={t('Add segment tag')} addTagText={t('Enter tag key')} />
</div>
</Dialog>

Expand Down
1 change: 0 additions & 1 deletion src/renderer/src/components/CopyClipboardButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const CopyClipboardButton = memo(({ text, style }: { text: string, style?: Motio
<motion.span animate={animation} style={{ display: 'inline-block', cursor: 'pointer', ...style }}>
<FaClipboard title={t('Copy to clipboard')} onClick={onClick} />
</motion.span>

);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,70 @@
import { memo, useRef, useState, useMemo, useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { TextInput, TrashIcon, TickIcon, EditIcon, PlusIcon, Button, IconButton } from 'evergreen-ui';
import invariant from 'tiny-invariant';

import { askForMetadataKey } from '../dialogs';
import { SegmentTags, segmentTagsSchema } from '../types';
import CopyClipboardButton from './CopyClipboardButton';
import { errorToast } from '../swal';


const { clipboard } = window.require('electron');

const activeColor = '#429777';

const emptyObject = {};

function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editingTag, setEditingTag, onTagChange, onTagReset, addTagTitle, addTagText }) {
function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editingTag, setEditingTag, onTagsChange, onTagReset, addTagTitle, addTagText }: {
existingTags?: SegmentTags, customTags?: SegmentTags | undefined, editingTag: string | undefined, setEditingTag: (v: string | undefined) => void, onTagsChange: (keyValues: Record<string, string>) => void, onTagReset: (tag: string) => void, addTagTitle: string, addTagText: string,
}) {
const { t } = useTranslation();
const ref = useRef();
const ref = useRef<HTMLInputElement>(null);

const [editingTagVal, setEditingTagVal] = useState();
const [newTag, setNewTag] = useState();
const [editingTagVal, setEditingTagVal] = useState<string>();
const [newTag, setNewTag] = useState<string>();

const mergedTags = useMemo(() => ({ ...existingTags, ...customTags, ...(newTag ? { [newTag]: '' } : {}) }), [customTags, existingTags, newTag]);
const mergedTags = useMemo(() => ({ ...existingTags, ...customTags, ...(newTag ? { [newTag]: '' } : undefined) }), [customTags, existingTags, newTag]);

const onResetClick = useCallback(() => {
invariant(editingTag != null);
onTagReset(editingTag);
setEditingTag();
setNewTag();
setEditingTag(undefined);
setNewTag(undefined);
}, [editingTag, onTagReset, setEditingTag]);

const onEditClick = useCallback((tag) => {
const onPasteClick = useCallback(async () => {
const text = clipboard.readText();
try {
const json = JSON.parse(text);
const newTags = segmentTagsSchema.parse(json);
onTagsChange(newTags);
} catch (e) {
if (e instanceof Error) errorToast(e.message);
}
}, [onTagsChange]);

const onEditClick = useCallback((tag?: string) => {
if (newTag) {
onTagChange(editingTag, editingTagVal);
setEditingTag();
setNewTag();
invariant(editingTag != null);
invariant(editingTagVal != null);
onTagsChange({ [editingTag]: editingTagVal });
setEditingTag(undefined);
setNewTag(undefined);
} else if (editingTag != null) {
if (editingTagVal !== existingTags[editingTag]) {
onTagChange(editingTag, editingTagVal);
setEditingTag();
invariant(editingTag != null);
invariant(editingTagVal != null);
onTagsChange({ [editingTag]: editingTagVal });
setEditingTag(undefined);
} else { // If not actually changed, no need to update
onResetClick();
}
} else {
setEditingTag(tag);
setEditingTagVal(mergedTags[tag]);
setEditingTagVal(tag && String(mergedTags[tag]));
}
}, [editingTag, editingTagVal, existingTags, mergedTags, newTag, onResetClick, onTagChange, setEditingTag]);
}, [editingTag, editingTagVal, existingTags, mergedTags, newTag, onResetClick, onTagsChange, setEditingTag]);

function onSubmit(e) {
e.preventDefault();
Expand Down Expand Up @@ -69,7 +93,7 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi

return (
<>
<table style={{ color: 'black' }}>
<table style={{ color: 'black', marginBottom: 10 }}>
<tbody>
{Object.keys(mergedTags).map((tag) => {
const editingThis = tag === editingTag;
Expand All @@ -87,7 +111,7 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
<TextInput ref={ref} placeholder={t('Enter value')} value={editingTagVal || ''} onChange={(e) => setEditingTagVal(e.target.value)} />
</form>
) : (
<span style={{ padding: '.5em 0', color: thisTagCustom ? activeColor : undefined, fontWeight: thisTagCustom ? 'bold' : undefined }}>{mergedTags[tag] || `<${t('empty')}>`}</span>
<span style={{ padding: '.5em 0', color: thisTagCustom ? activeColor : undefined, fontWeight: thisTagCustom ? 'bold' : undefined }}>{mergedTags[tag] ? String(mergedTags[tag]) : `<${t('empty')}>`}</span>
)}
{(editingTag == null || editingThis) && <IconButton icon={Icon} title={t('Edit')} appearance="minimal" style={{ marginLeft: '.4em' }} onClick={() => onEditClick(tag)} intent={editingThis ? 'success' : 'none'} />}
{editingThis && <IconButton icon={TrashIcon} title={thisTagCustom ? t('Delete') : t('Reset')} appearance="minimal" onClick={onResetClick} intent="danger" />}
Expand All @@ -98,7 +122,14 @@ function TagEditor({ existingTags = emptyObject, customTags = emptyObject, editi
</tbody>
</table>

<Button style={{ marginTop: 10 }} iconBefore={PlusIcon} onClick={onAddPress}>{addTagTitle}</Button>
<Button iconBefore={PlusIcon} onClick={onAddPress}>{addTagTitle}</Button>

<div style={{ marginTop: '1em' }}>
<span style={{ marginRight: '1em' }}>{t('Batch')}:</span>
<CopyClipboardButton text={JSON.stringify(mergedTags)} style={{ marginRight: '.3em', verticalAlign: 'middle' }} />

<Button appearance="minimal" onClick={onPasteClick}>{t('Paste')}</Button>
</div>
</>
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/src/dialogs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,8 @@ export async function askForAlignSegments() {
};
}

export async function askForMetadataKey({ title, text }) {
const { value } = await Swal.fire({
export async function askForMetadataKey({ title, text }: { title: string, text: string }) {
const { value } = await Swal.fire<string>({
title,
text,
input: 'text',
Expand All @@ -352,7 +352,7 @@ export async function askForMetadataKey({ title, text }) {
}

export async function confirmExtractAllStreamsDialog() {
const { value } = await Swal.fire({
const { value } = await Swal.fire<string>({
text: i18n.t('Please confirm that you want to extract all tracks as separate files'),
showCancelButton: true,
confirmButtonText: i18n.t('Extract all tracks'),
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/swal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const swalToastOptions: SweetAlertOptions = {

export const toast = Swal.mixin(swalToastOptions);

export const errorToast = (text) => toast.fire({
export const errorToast = (text: string) => toast.fire({
icon: 'error',
text,
});
4 changes: 3 additions & 1 deletion src/renderer/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { MenuItem, MenuItemConstructorOptions } from 'electron';
import { z } from 'zod';


export interface ChromiumHTMLVideoElement extends HTMLVideoElement {
Expand All @@ -23,8 +24,9 @@ export interface ApparentSegmentBase extends SegmentColorIndex {
end: number,
}

export const segmentTagsSchema = z.record(z.string(), z.string());

export type SegmentTags = Record<string, unknown>;
export type SegmentTags = z.infer<typeof segmentTagsSchema>

export type EditingSegmentTags = Record<string, SegmentTags>

Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7996,6 +7996,7 @@ __metadata:
vitest: "npm:^1.2.2"
winston: "npm:^3.8.1"
yargs-parser: "npm:^21.1.1"
zod: "npm:^3.22.5"
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -12397,3 +12398,10 @@ __metadata:
checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801
languageName: node
linkType: hard

"zod@npm:^3.22.5":
version: 3.22.5
resolution: "zod@npm:3.22.5"
checksum: a60c1b55c4cc824a5d0432ee29d93b087b5d8a1bd2d0f4cd6e7ffe5b602da9cab2f2c27b1ae6c96d88d9f778cc933cead70e08b7944a98893576c61dca5e0c74
languageName: node
linkType: hard

0 comments on commit 3f4c214

Please sign in to comment.