add full screen video support

closes #543
stores
Mikael Finstad 2023-12-22 14:38:54 +08:00
rodzic eda009274e
commit 899e6e2960
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 25AB36E3E81CBC26
6 zmienionych plików z 40 dodań i 1 usunięć

Wyświetl plik

@ -82,6 +82,7 @@
"react-sortablejs": "^6.1.4",
"react-syntax-highlighter": "^15.4.3",
"react-use": "^17.4.0",
"screenfull": "^6.0.2",
"scroll-into-view-if-needed": "^2.2.28",
"sharp": "^0.32.6",
"smpte-timecode": "^1.2.3",

Wyświetl plik

@ -65,6 +65,8 @@ const defaultKeyBindings = [
{ keys: 'ctrl+c', action: 'copySegmentsToClipboard' },
{ keys: 'command+c', action: 'copySegmentsToClipboard' },
{ key: 'f', action: 'toggleFullscreenVideo' },
{ keys: 'enter', action: 'labelCurrentSegment' },
{ keys: 'e', action: 'export' },

Wyświetl plik

@ -8,6 +8,7 @@ import { useDebounce } from 'use-debounce';
import i18n from 'i18next';
import { useTranslation } from 'react-i18next';
import { produce } from 'immer';
import screenfull from 'screenfull';
import fromPairs from 'lodash/fromPairs';
import sortBy from 'lodash/sortBy';
@ -1909,6 +1910,21 @@ const App = memo(() => {
}
}, [addStreamSourceFile]);
const toggleFullscreenVideo = useCallback(async () => {
if (!screenfull.isEnabled) {
console.warn('Fullscreen not allowed');
return;
}
try {
if (videoRef.current == null) {
console.warn('No video tag to full screen');
return;
}
await screenfull.toggle(videoRef.current, { navigationUI: 'hide' });
} catch (err) {
console.error('Failed to toggle fullscreen', err);
}
}, []);
const mainActions = useMemo(() => {
async function exportYouTube() {
@ -2039,8 +2055,9 @@ const App = memo(() => {
toggleShowThumbnails,
toggleShowKeyframes,
showIncludeExternalStreamsDialog,
toggleFullscreenVideo,
};
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
}, [addSegment, alignSegmentTimesToKeyframes, apparentCutSegments, askStartTimeOffset, batchFileJump, batchOpenSelectedFile, captureSnapshot, captureSnapshotAsCoverArt, changePlaybackRate, checkFileOpened, cleanupFilesDialog, clearSegments, closeBatch, closeFileWithConfirm, combineOverlappingSegments, combineSelectedSegments, concatBatch, convertFormatBatch, copySegmentsToClipboard, createFixedDurationSegments, createNumSegments, createRandomSegments, createSegmentsFromKeyframes, currentSegIndexSafe, cutSegmentsHistory, deselectAllSegments, detectBlackScenes, detectSceneChanges, detectSilentScenes, duplicateCurrentSegment, extractAllStreams, extractCurrentSegmentFramesAsImages, extractSelectedSegmentsFramesAsImages, fillSegmentsGaps, goToTimecode, handleShowStreamsSelectorClick, increaseRotation, invertAllSegments, invertSelectedSegments, jumpCutEnd, jumpCutStart, jumpSeg, jumpTimelineEnd, jumpTimelineStart, keyboardNormalSeekSpeed, keyboardSeekAccFactor, onExportPress, onLabelSegment, openFilesDialog, openSendReportDialogWithState, pause, play, removeCutSegment, removeSelectedSegments, reorderSegsByStartTime, seekClosestKeyframe, seekRel, seekRelPercent, selectAllSegments, selectOnlyCurrentSegment, setCutEnd, setCutStart, setPlaybackVolume, shiftAllSegmentTimes, shortStep, showIncludeExternalStreamsDialog, shuffleSegments, splitCurrentSegment, timelineToggleComfortZoom, toggleCaptureFormat, toggleCurrentSegmentSelected, toggleFullscreenVideo, toggleKeyboardShortcuts, toggleKeyframeCut, toggleLastCommands, toggleLoopSelectedSegments, togglePlay, toggleSegmentsList, toggleSettings, toggleShowKeyframes, toggleShowThumbnails, toggleStreamsSelector, toggleStripAudio, toggleWaveformMode, tryFixInvalidDuration, userHtml5ifyCurrentFile, zoomRel]);
const getKeyboardAction = useCallback((action) => mainActions[action], [mainActions]);
@ -2342,6 +2359,7 @@ const App = memo(() => {
<div className="no-user-select" style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, visibility: !isFileOpened || !hasVideo || bigWaveformEnabled ? 'hidden' : undefined }} onWheel={onTimelineWheel}>
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
<video
className="main-player"
muted={playbackVolume === 0}
ref={videoRef}
style={videoStyle}
@ -2352,6 +2370,7 @@ const App = memo(() => {
onDurationChange={onDurationChange}
onTimeUpdate={onTimeUpdate}
onError={onVideoError}
onDoubleClick={toggleFullscreenVideo}
>
{renderSubtitles()}
</video>

Wyświetl plik

@ -540,6 +540,10 @@ const KeyboardShortcuts = memo(({
name: t('Show keyframes'),
category: otherCategory,
},
toggleFullscreenVideo: {
name: 'Toggle full screen video',
category: otherCategory,
},
toggleSettings: {
name: t('Settings'),
category: otherCategory,

Wyświetl plik

@ -83,3 +83,8 @@ code.highlighted {
.button-unstyled:focus {
outline: revert;
}
/* https://stackoverflow.com/questions/18270894/html5-video-does-not-hide-controls-in-fullscreen-mode-in-chrome */
video.main-player::-webkit-media-controls {
display:none !important;
}

Wyświetl plik

@ -6622,6 +6622,7 @@ __metadata:
react-sortablejs: "npm:^6.1.4"
react-syntax-highlighter: "npm:^15.4.3"
react-use: "npm:^17.4.0"
screenfull: "npm:^6.0.2"
scroll-into-view-if-needed: "npm:^2.2.28"
semver: "npm:^7.5.2"
sharp: "npm:^0.32.6"
@ -8705,6 +8706,13 @@ __metadata:
languageName: node
linkType: hard
"screenfull@npm:^6.0.2":
version: 6.0.2
resolution: "screenfull@npm:6.0.2"
checksum: 13ad07683538a94a0dac99533ddf54755c9c10890850f726872a9dace69ad09457451b2e467efcbb270f19f201bbb9b6911ab7b12618222648a093f369be6fd2
languageName: node
linkType: hard
"scroll-into-view-if-needed@npm:^2.2.28":
version: 2.2.28
resolution: "scroll-into-view-if-needed@npm:2.2.28"