1import React, { useRef, useEffect, useState } from 'react';
2import WebViewer from '@pdftron/webviewer';
3import { initializeVideoViewer } from '@pdftron/webviewer-video';
4import './App.css';
5import {
6 initializeAudioViewer
7} from '@pdftron/webviewer-audio';
8import {
9 demoPeaks,
10 demoXFDFString,
11} from './constants/demo-vars';
12
13const App = () => {
14 const viewer = useRef(null);
15 const inputFile = useRef(null);
16 const [state, setState] = useState({ instance: null, videoInstance: null, audioInstance: null });
17
18 useEffect(() => {
19 WebViewer.Iframe(
20 {
21 path: '/webviewer/lib',
22 enableRedaction: process.env.DEMO ? true : false,
23 },
24 viewer.current,
25 ).then(async instance => {
26 const license = `---- Insert commercial license key here after purchase ----`;
27 const videoUrl = 'https://pdftron.s3.amazonaws.com/downloads/pl/video/video.mp4';
28
29 const audioInstance = await initializeAudioViewer(
30 instance,
31 { license },
32 );
33
34 const videoInstance = await initializeVideoViewer(
35 instance,
36 {
37 license,
38 AudioComponent: audioInstance.Waveform,
39 isDemoMode: process.env.DEMO,
40 generatedPeaks: !process.env.DEMO ? null : demoPeaks, // waves can be pre-generated as seen here for fast loading: https://github.com/bbc/audiowaveform
41 enableRedaction: process.env.DEMO ? true : false,
42 }
43 );
44
45 instance.UI.setTheme('dark');
46
47 setState({ instance, videoInstance, audioInstance });
48
49 // Load a video at a specific url. Can be a local or public link
50 // If local it needs to be relative to lib/ui/index.html.
51 // Or at the root. (eg '/video.mp4')
52 videoInstance.loadVideo(videoUrl);
53 initializeHeader(instance);
54
55 if (process.env.DEMO) {
56 const { documentViewer } = instance.Core;
57 const annotManager = documentViewer.getAnnotationManager();
58 // Load saved annotations
59 documentViewer.addEventListener(
60 'videoElementReady',
61 async () => {
62 const video = videoInstance.getVideo();
63 const xfdfString = demoXFDFString;
64 await annotManager.importAnnotations(xfdfString);
65 video.updateAnnotationsToTime(0);
66 },
67 { once: true },
68 );
69 }
70 });
71 }, []);
72
73 const onFileChange = async event => {
74 const file = event.target.files[0];
75 const url = URL.createObjectURL(file);
76 const { instance, videoInstance, audioInstance } = state;
77
78 // Seamlessly switch between PDFs and videos.
79 // Can also detect by specific video file types (ie. mp4, ogg, etc.)
80 if (file.type.includes('video') ||
81 (file.name.includes('.mpd') && file.type === '')
82 ) {
83 videoInstance.loadVideo(url, { fileName: file.name });
84 // TODO: Notespanel needs to be delayed when opening. Not sure why.
85 setTimeout(() => {
86 instance.openElements('notesPanel');
87 });
88 } else if (file.type.includes('audio')) {
89 audioInstance.loadAudio(url, { fileName: file.name });
90
91 setTimeout(() => {
92 instance.UI.openElements('notesPanel');
93 });
94 } else {
95 instance.UI.setToolMode('AnnotationEdit');
96 instance.UI.loadDocument(url);
97 }
98 };
99
100 function initializeHeader(instance) {
101 const { setHeaderItems } = instance.UI;
102
103 setHeaderItems(header => {
104 // Add upload file button
105 header.push({
106 type: 'actionButton',
107 img: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
108 <path d="M11 15H13V9H16L12 4L8 9H11V15Z" fill="currentColor"/>
109 <path d="M20 18H4V11H2V18C2 19.103 2.897 20 4 20H20C21.103 20 22 19.103 22 18V11H20V18Z" fill="currentColor"/>
110 </svg>`,
111 title: 'Load file',
112 dataElement: 'audio-loadFileButton',
113 onClick: () => {
114 inputFile.current.click();
115 }
116 });
117 });
118 }
119
120 return (
121 <div className="App">
122 <input type="file" hidden ref={inputFile} onChange={onFileChange} value=""/>
123 <div className="webviewer" ref={viewer}/>
124 </div>
125 );
126};
127
128export default App;
129