Skip to content

Commit

Permalink
Support 'toggle recording' command in local video player
Browse files Browse the repository at this point in the history
  • Loading branch information
killergerbah committed Jan 4, 2025
1 parent f81f71e commit 97b93ab
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 7 deletions.
51 changes: 47 additions & 4 deletions common/app/components/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import {
PauseOnHoverMode,
allTextSubtitleSettings,
} from '@project/common/settings';
import { surroundingSubtitles, mockSurroundingSubtitles, seekWithNudge } from '@project/common/util';
import {
surroundingSubtitles,
mockSurroundingSubtitles,
seekWithNudge,
surroundingSubtitlesAroundInterval,
} from '@project/common/util';
import { SubtitleCollection } from '@project/common/subtitle-collection';
import SubtitleTextImage from '@project/common/components/SubtitleTextImage';
import Clock from '../services/clock';
Expand Down Expand Up @@ -1097,16 +1102,33 @@ export default function VideoPlayer({
const endTimestamp = clock.time(length);

if (endTimestamp > mineIntervalStartTimestamp) {
const currentSubtitle = {
let currentSubtitle: SubtitleModel = {
text: '',
start: mineIntervalStartTimestamp,
originalStart: mineIntervalStartTimestamp,
end: endTimestamp,
originalEnd: endTimestamp,
track: 0,
};
let surroundingSubtitles: SubtitleModel[];

if (subtitles.length === 0) {
surroundingSubtitles = mockSurroundingSubtitles(currentSubtitle, length, 5000);
} else {
const calculated = surroundingSubtitlesAroundInterval(
subtitles,
mineIntervalStartTimestamp,
endTimestamp,
settings.surroundingSubtitlesCountRadius,
settings.surroundingSubtitlesTimeRadius
);
currentSubtitle = {
...currentSubtitle,
text: calculated.subtitle?.text ?? '',
};
surroundingSubtitles = calculated.surroundingSubtitles ?? [];
}

const surroundingSubtitles = mockSurroundingSubtitles(currentSubtitle, length, 5000);
mineSubtitle(
postMineAction,
videoFile,
Expand All @@ -1133,6 +1155,9 @@ export default function VideoPlayer({
selectedAudioTrack,
videoFile,
videoFileName,
subtitles,
settings.surroundingSubtitlesCountRadius,
settings.surroundingSubtitlesTimeRadius,
]
);

Expand All @@ -1146,10 +1171,18 @@ export default function VideoPlayer({
if (!subtitle && !surroundingSubtitles && subtitles.length === 0) {
toggleSelectMiningInterval(postMineAction, cardTextFieldValues);
} else {
if (mineIntervalStartTimestamp !== undefined) {
// Edge case: user started manually recording but are now using an "automatic" mining shortcut
// Cancel the "recording" operation
setAlertDisableAutoHide(false);
setAlertOpen(false);
setMineIntervalStartTimestamp(undefined);
}

mineCurrentSubtitle(postMineAction, subtitle, surroundingSubtitles, cardTextFieldValues);
}
},
[mineCurrentSubtitle, toggleSelectMiningInterval, subtitles]
[mineCurrentSubtitle, toggleSelectMiningInterval, mineIntervalStartTimestamp, subtitles]
);

useEffect(() => {
Expand Down Expand Up @@ -1222,6 +1255,16 @@ export default function VideoPlayer({
);
}, [clock, length, keyBinder, lastMinedRecord, mineSubtitle, popOut, ankiDialogOpen, onAnkiDialogRewind]);

useEffect(() => {
return keyBinder.bindToggleRecording(
(event) => {
event.preventDefault();
toggleSelectMiningInterval(PostMineAction.showAnkiDialog);
},
() => false
);
}, [keyBinder, toggleSelectMiningInterval]);

useEffect(() => {
return keyBinder.bindCopy(
(event, subtitle) => {
Expand Down
19 changes: 19 additions & 0 deletions common/app/services/app-key-binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default class AppKeyBinder implements KeyBinder {
private readonly ankiExportHandlers: ((event: KeyboardEvent) => void)[] = [];
private readonly updateLastCardHandlers: ((event: KeyboardEvent) => void)[] = [];
private readonly takeScreenshotHandlers: ((event: KeyboardEvent) => void)[] = [];
private readonly toggleRecordingHandlers: ((event: KeyboardEvent) => void)[] = [];
private _unsubscribeExtension?: () => void;

constructor(keyBinder: DefaultKeyBinder, extension: ChromeExtension) {
Expand Down Expand Up @@ -36,6 +37,8 @@ export default class AppKeyBinder implements KeyBinder {
}
} else if (message.data.command === 'take-screenshot') {
handlers = this.takeScreenshotHandlers;
} else if (message.data.command === 'toggle-recording') {
handlers = this.toggleRecordingHandlers;
}

if (handlers !== undefined) {
Expand Down Expand Up @@ -113,6 +116,22 @@ export default class AppKeyBinder implements KeyBinder {
return this.defaultKeyBinder.bindTakeScreenshot(onTakeScreenshot, disabledGetter, useCapture);
}

bindToggleRecording(
onToggleRecording: (event: KeyboardEvent) => void,
disabledGetter: () => boolean,
useCapture?: boolean | undefined
): () => void {
if (this.extension.installed) {
const handler = this.defaultKeyBinder.toggleRecordingHandler(onToggleRecording, disabledGetter);
this.toggleRecordingHandlers.push(handler);
return () => {
this._remove(handler, this.toggleRecordingHandlers);
};
}

return this.defaultKeyBinder.bindToggleRecording(onToggleRecording, disabledGetter, useCapture);
}

private _remove(callback: (event: KeyboardEvent) => void, list: ((event: KeyboardEvent) => void)[]) {
for (let i = list.length - 1; i >= 0; --i) {
if (callback === list[i]) {
Expand Down
3 changes: 1 addition & 2 deletions common/components/SettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ function SelectableSetting({
);
}

type AllKeyNames = KeyBindName | 'toggleRecording' | 'selectSubtitleTrack';
type AllKeyNames = KeyBindName | 'selectSubtitleTrack';

interface KeyBindProperties {
label: string;
Expand Down Expand Up @@ -709,7 +709,6 @@ export default function SettingsForm({
toggleRecording: {
label: t('binds.extensionToggleRecording')!,
boundViaChrome: true,
hide: !extensionInstalled,
},
selectSubtitleTrack: {
label: t('binds.extensionSelectSubtitleTrack')!,
Expand Down
31 changes: 31 additions & 0 deletions common/key-binder/key-binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ export interface KeyBinder {
disabledGetter: () => boolean,
capture?: boolean
): () => void;
bindToggleRecording(
onToggleRecording: (event: KeyboardEvent) => void,
disabledGetter: () => boolean,
capture?: boolean
): () => void;
}

export class DefaultKeyBinder implements KeyBinder {
Expand Down Expand Up @@ -260,6 +265,32 @@ export class DefaultKeyBinder implements KeyBinder {
};
}

bindToggleRecording(
onToggleRecording: (event: KeyboardEvent) => void,
disabledGetter: () => boolean,
capture = false
) {
const shortcut = this.keyBindSet.toggleRecording.keys;

if (!shortcut) {
return () => {};
}

const handler = this.takeScreenshotHandler(onToggleRecording, disabledGetter);
return this._bind(shortcut, capture, handler);
}

toggleRecordingHandler(onToggleRecording: (event: KeyboardEvent) => void, disabledGetter: () => boolean) {
return (event: KeyboardEvent) => {
if (disabledGetter()) {
return false;
}

onToggleRecording(event);
return true;
};
}

bindSeekToSubtitle(
onSeekToSubtitle: (event: KeyboardEvent, subtitle: SubtitleModel) => void,
disabledGetter: () => boolean,
Expand Down
2 changes: 1 addition & 1 deletion common/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
"error": "Error: {{message}}",
"errorNoMessage": "Error",
"toggleSubtitlesShortcut": "Press \"{{keys}}\" to toggle subtitle display",
"manualMiningIntervalPrompt": "Use mining shortcut again to select time range"
"manualMiningIntervalPrompt": "Use mining shortcut again"
},
"landing": {
"cta": "Drag and drop subtitle and media files, or <1>browse</1>.",
Expand Down
1 change: 1 addition & 0 deletions common/settings/settings-import-export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ it('validates exported settings', () => {
seekToNextSubtitle: { keys: 'right' },
seekToPreviousSubtitle: { keys: 'left' },
takeScreenshot: { keys: '⇧+⌃+V' },
toggleRecording: { keys: '⇧+⌃+R' },
toggleAsbplayerSubtitleTrack1: { keys: 'W+1' },
toggleAsbplayerSubtitleTrack2: { keys: 'W+2' },
unblurAsbplayerTrack1: { keys: 'B+1' },
Expand Down
1 change: 1 addition & 0 deletions common/settings/settings-import-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ const settingsSchema = {
ankiExport: { $ref: '/KeyBind' },
updateLastCard: { $ref: '/KeyBind' },
takeScreenshot: { $ref: '/KeyBind' },
toggleRecording: { $ref: '/KeyBind' },
decreasePlaybackRate: { $ref: '/KeyBind' },
increasePlaybackRate: { $ref: '/KeyBind' },
toggleSidePanel: { $ref: '/KeyBind' },
Expand Down
1 change: 1 addition & 0 deletions common/settings/settings-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export const defaultSettings: AsbplayerSettings = {
ankiExport: { keys: isMacOs ? '⇧+⌃+X' : 'ctrl+shift+X' },
updateLastCard: { keys: isMacOs ? '⇧+⌃+U' : 'ctrl+shift+U' },
takeScreenshot: { keys: isMacOs ? '⇧+⌃+V' : 'ctrl+shift+V' },
toggleRecording: { keys: isMacOs ? '⇧+⌃+R' : 'ctrl+shift+R' },
decreasePlaybackRate: { keys: isMacOs ? '⇧+⌃+[' : 'ctrl+shift+[' },
increasePlaybackRate: { keys: isMacOs ? '⇧+⌃+]' : 'ctrl+shift+]' },
toggleSidePanel: { keys: '`' },
Expand Down
1 change: 1 addition & 0 deletions common/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ export interface KeyBindSet {
readonly ankiExport: KeyBind;
readonly updateLastCard: KeyBind;
readonly takeScreenshot: KeyBind;
readonly toggleRecording: KeyBind;
}

export interface WebSocketClientSettings {
Expand Down
16 changes: 16 additions & 0 deletions extension/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,22 @@ chrome.commands?.onCommand.addListener((command) => {
};
return extensionToVideoCommand;
});
tabRegistry.publishCommandToAsbplayers({
commandFactory: (asbplayer) => {
if (!validAsbplayer(asbplayer)) {
return undefined;
}

const extensionToPlayerCommand: ExtensionToAsbPlayerCommand<ToggleRecordingMessage> = {
sender: 'asbplayer-extension-to-player',
message: {
command: 'toggle-recording',
},
asbplayerId: asbplayer.id,
};
return extensionToPlayerCommand;
},
});
break;
default:
throw new Error('Unknown command ' + command);
Expand Down

0 comments on commit 97b93ab

Please sign in to comment.