PDF file: include meeting and room name
This commit is contained in:
parent
717c692468
commit
7851d54484
@ -35,6 +35,14 @@ class StoreExportJobInRedisPresAnnEvent extends AbstractPresentationWithAnnotati
|
||||
eventMap.put(JOB_TYPE, jobType)
|
||||
}
|
||||
|
||||
def setMeetingName(meetingName: String) {
|
||||
eventMap.put(MEETING_NAME, meetingName)
|
||||
}
|
||||
|
||||
def setPresName(presName: String) {
|
||||
eventMap.put(PRES_NAME, presName)
|
||||
}
|
||||
|
||||
def setPresId(presId: String) {
|
||||
eventMap.put(PRES_ID, presId)
|
||||
}
|
||||
@ -63,6 +71,8 @@ class StoreExportJobInRedisPresAnnEvent extends AbstractPresentationWithAnnotati
|
||||
object StoreExportJobInRedisPresAnnEvent {
|
||||
protected final val JOB_ID = "jobId"
|
||||
protected final val JOB_TYPE = "jobType"
|
||||
protected final val MEETING_NAME = "meetingName"
|
||||
protected final val PRES_NAME = "presName"
|
||||
protected final val PRES_ID = "presId"
|
||||
protected final val PRES_LOCATION = "presLocation"
|
||||
protected final val ALL_PAGES = "allPages"
|
||||
|
@ -753,6 +753,7 @@ class MeetingActor(
|
||||
def handleMakePresentationWithAnnotationDownloadReqMsg(m: MakePresentationWithAnnotationDownloadReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val meetingName: String = liveMeeting.props.meetingProp.name
|
||||
|
||||
// Whiteboard ID
|
||||
val presId: String = m.body.presId match {
|
||||
@ -765,18 +766,31 @@ class MeetingActor(
|
||||
|
||||
// Determine page amount
|
||||
val presentationPods: Vector[PresentationPod] = state.presentationPodManager.getAllPresentationPodsInMeeting()
|
||||
val currentPres = presentationPods.flatMap(_.getCurrentPresentation()).head
|
||||
|
||||
val pageCount = currentPres.pages.size
|
||||
val currentPres = presentationPods.flatMap(_.getCurrentPresentation()).headOption
|
||||
|
||||
currentPres match {
|
||||
case None =>
|
||||
log.error(s"No presentation set in meeting ${meetingId}")
|
||||
return
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
val pageCount = currentPres.get.pages.size
|
||||
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else pages
|
||||
|
||||
var storeAnnotationPages = new Array[PresentationPageForExport](pagesRange.size)
|
||||
var resultingPage = 0
|
||||
|
||||
for (pageNumber <- pagesRange) {
|
||||
if (pageNumber < 1 || pageNumber > pageCount) {
|
||||
println(pagesRange.length)
|
||||
log.error(s"Page ${pageNumber} requested for export out of range, aborting")
|
||||
return
|
||||
}
|
||||
|
||||
var whiteboardId = s"${presId}/${pageNumber.toString}"
|
||||
val presentationPage: PresentationPage = currentPres.pages(whiteboardId)
|
||||
val presentationPage: PresentationPage = currentPres.get.pages(whiteboardId)
|
||||
val xOffset: Double = presentationPage.xOffset
|
||||
val yOffset: Double = presentationPage.yOffset
|
||||
val widthRatio: Double = presentationPage.widthRatio
|
||||
@ -796,7 +810,7 @@ class MeetingActor(
|
||||
// 2) Insert Export Job in Redis
|
||||
val jobType = "PresentationWithAnnotationDownloadJob"
|
||||
val presLocation = s"/var/bigbluebutton/${meetingId}/${meetingId}/${presId}"
|
||||
val exportJob = new ExportJob(jobId, jobType, presId, presLocation, allPages, pagesRange, meetingId, "")
|
||||
val exportJob = new ExportJob(jobId, jobType, meetingName, currentPres.get.name, presId, presLocation, allPages, pagesRange, meetingId, "")
|
||||
var job = buildStoreExportJobInRedisSysMsg(exportJob)
|
||||
outGW.send(job)
|
||||
}
|
||||
@ -804,25 +818,33 @@ class MeetingActor(
|
||||
def handleExportPresentationWithAnnotationReqMsg(m: ExportPresentationWithAnnotationReqMsg, state: MeetingState2x, liveMeeting: LiveMeeting): Unit = {
|
||||
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val meetingName: String = liveMeeting.props.meetingProp.name
|
||||
val userId = m.header.userId
|
||||
val presId: String = getMeetingInfoPresentationDetails.id
|
||||
val parentMeetingId: String = m.body.parentMeetingId
|
||||
val allPages: Boolean = m.body.allPages
|
||||
|
||||
val presentationPods: Vector[PresentationPod] = state.presentationPodManager.getAllPresentationPodsInMeeting()
|
||||
val currentPres = presentationPods.flatMap(_.getCurrentPresentation()).head
|
||||
val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres).get
|
||||
val currentPres = presentationPods.flatMap(_.getCurrentPresentation()).headOption
|
||||
|
||||
val pageCount = currentPres.pages.size
|
||||
currentPres match {
|
||||
case None =>
|
||||
log.error(s"No presentation set in meeting ${meetingId}")
|
||||
return
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
val currentPage: PresentationPage = PresentationInPod.getCurrentPage(currentPres.get).get
|
||||
|
||||
val pageCount = currentPres.get.pages.size
|
||||
val pagesRange: List[Int] = if (allPages) (1 to pageCount).toList else List(currentPage.num)
|
||||
|
||||
var storeAnnotationPages = new Array[PresentationPageForExport](pagesRange.size)
|
||||
var resultingPage = 0
|
||||
|
||||
for (pageNumber <- pagesRange) {
|
||||
|
||||
var whiteboardId = s"${presId}/${pageNumber.toString}"
|
||||
val presentationPage: PresentationPage = currentPres.pages(whiteboardId)
|
||||
val presentationPage: PresentationPage = currentPres.get.pages(whiteboardId)
|
||||
val xOffset: Double = presentationPage.xOffset
|
||||
val yOffset: Double = presentationPage.yOffset
|
||||
val widthRatio: Double = presentationPage.widthRatio
|
||||
@ -837,7 +859,7 @@ class MeetingActor(
|
||||
val jobId = RandomStringGenerator.randomAlphanumericString(16)
|
||||
|
||||
// Informs bbb-web about the token so that when we use it to upload the presentation, it is able to look it up in the list of tokens
|
||||
outGW.send(buildPresentationUploadTokenSysPubMsg(parentMeetingId, userId, presentationUploadToken, currentPres.name))
|
||||
outGW.send(buildPresentationUploadTokenSysPubMsg(parentMeetingId, userId, presentationUploadToken, currentPres.get.name))
|
||||
|
||||
// 1) Send Annotations to Redis
|
||||
var annotations = new StoredAnnotations(jobId, presId, storeAnnotationPages)
|
||||
@ -846,7 +868,7 @@ class MeetingActor(
|
||||
// 2) Insert Export Job in Redis
|
||||
val jobType: String = "PresentationWithAnnotationExportJob"
|
||||
val presLocation = s"/var/bigbluebutton/${meetingId}/${meetingId}/${presId}"
|
||||
val exportJob = new ExportJob(jobId, jobType, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
|
||||
val exportJob = new ExportJob(jobId, jobType, meetingName, currentPres.get.name, presId, presLocation, allPages, pagesRange, parentMeetingId, presentationUploadToken)
|
||||
var job = buildStoreExportJobInRedisSysMsg(exportJob)
|
||||
outGW.send(job)
|
||||
}
|
||||
|
@ -75,6 +75,8 @@ class ExportAnnotationsActor(
|
||||
|
||||
ev.setJobId(msg.body.exportJob.jobId)
|
||||
ev.setJobType(msg.body.exportJob.jobType)
|
||||
ev.setMeetingName(msg.body.exportJob.meetingName)
|
||||
ev.setPresName(msg.body.exportJob.presName)
|
||||
ev.setPresId(msg.body.exportJob.presId)
|
||||
ev.setPresLocation(msg.body.exportJob.presLocation)
|
||||
ev.setAllPages(msg.body.exportJob.allPages.toString)
|
||||
|
@ -142,7 +142,7 @@ class RedisRecorderActor(
|
||||
ev.setSenderId(msg.body.msg.sender.id)
|
||||
ev.setMessage(msg.body.msg.message)
|
||||
ev.setSenderRole(msg.body.msg.sender.role)
|
||||
|
||||
|
||||
val isModerator = msg.body.msg.sender.role == "MODERATOR"
|
||||
ev.setChatEmphasizedText(msg.body.msg.chatEmphasizedText && isModerator)
|
||||
|
||||
|
@ -21,6 +21,8 @@ case class StoredAnnotations(
|
||||
case class ExportJob(
|
||||
jobId: String,
|
||||
jobType: String,
|
||||
meetingName: String,
|
||||
presName: String,
|
||||
presId: String,
|
||||
presLocation: String,
|
||||
allPages: Boolean,
|
||||
|
@ -27,9 +27,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
location ~^\/bigbluebutton\/presentation\/(?<meeting_id_1>[A-Za-z0-9\-]+)\/(?<meeting_id_2>[A-Za-z0-9\-]+)\/(?<pres_id>[A-Za-z0-9\-]+)\/pdf\/(?<job_id>[A-Za-z0-9]+)$ {
|
||||
location ~^\/bigbluebutton\/presentation\/(?<meeting_id_1>[A-Za-z0-9\-]+)\/(?<meeting_id_2>[A-Za-z0-9\-]+)\/(?<pres_id>[A-Za-z0-9\-]+)\/pdf\/(?<job_id>[A-Za-z0-9]+)/(?<filename>.*)$ {
|
||||
default_type application/pdf;
|
||||
alias /var/bigbluebutton/$meeting_id_2/$meeting_id_2/$pres_id/pdfs/annotated_slides_$job_id.pdf;
|
||||
alias /var/bigbluebutton/$meeting_id_2/$meeting_id_2/$pres_id/pdfs/$job_id/annotated_$filename.pdf;
|
||||
if ($bbb_loadbalancer_node) {
|
||||
add_header 'Access-Control-Allow-Origin' $bbb_loadbalancer_node always;
|
||||
}
|
||||
|
@ -4,13 +4,14 @@ const fs = require('fs');
|
||||
const redis = require('redis');
|
||||
const { commandOptions } = require('redis');
|
||||
const { Worker } = require('worker_threads');
|
||||
const path = require('path');
|
||||
|
||||
const logger = new Logger('presAnn Master');
|
||||
logger.info("Running export-annotations");
|
||||
|
||||
const kickOffCollectorWorker = (jobId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker('./workers/collector.js', { workerData: jobId });
|
||||
const worker = new Worker(path.join(__dirname, 'workers', 'collector.js'), { workerData: jobId });
|
||||
worker.on('message', resolve);
|
||||
worker.on('error', reject);
|
||||
worker.on('exit', (code) => {
|
||||
@ -44,11 +45,11 @@ const kickOffCollectorWorker = (jobId) => {
|
||||
const exportJob = JSON.parse(job.element);
|
||||
|
||||
// Create folder in dropbox
|
||||
let dropbox = `${config.shared.presAnnDropboxDir}/${exportJob.jobId}`
|
||||
let dropbox = path.join(config.shared.presAnnDropboxDir, exportJob.jobId);
|
||||
fs.mkdirSync(dropbox, { recursive: true })
|
||||
|
||||
// Drop job into dropbox as JSON
|
||||
fs.writeFile(`${dropbox}/job`, job.element, function(err) {
|
||||
fs.writeFile(path.join(dropbox, 'job'), job.element, function(err) {
|
||||
if(err) { return logger.error(err); }
|
||||
});
|
||||
|
||||
|
43
export-annotations/package-lock.json
generated
43
export-annotations/package-lock.json
generated
@ -12,6 +12,7 @@
|
||||
"form-data": "^4.0.0",
|
||||
"image-size": "^1.0.1",
|
||||
"redis": "^4.0.3",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"xmlbuilder2": "^3.0.2"
|
||||
}
|
||||
},
|
||||
@ -288,11 +289,32 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/sanitize-filename": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
|
||||
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
|
||||
"dependencies": {
|
||||
"truncate-utf8-bytes": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"node_modules/truncate-utf8-bytes": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
||||
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
|
||||
"dependencies": {
|
||||
"utf8-byte-length": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/utf8-byte-length": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
|
||||
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
|
||||
},
|
||||
"node_modules/xmlbuilder2": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-3.0.2.tgz",
|
||||
@ -529,11 +551,32 @@
|
||||
"redis-errors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sanitize-filename": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
|
||||
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
|
||||
"requires": {
|
||||
"truncate-utf8-bytes": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"truncate-utf8-bytes": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
||||
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
|
||||
"requires": {
|
||||
"utf8-byte-length": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"utf8-byte-length": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
|
||||
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
|
||||
},
|
||||
"xmlbuilder2": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-3.0.2.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"form-data": "^4.0.0",
|
||||
"image-size": "^1.0.1",
|
||||
"redis": "^4.0.3",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"xmlbuilder2": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ const config = require('../config');
|
||||
const fs = require('fs');
|
||||
const redis = require('redis');
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
const { Worker, workerData, parentPort } = require('worker_threads')
|
||||
const path = require('path');
|
||||
|
||||
const jobId = workerData;
|
||||
|
||||
@ -23,10 +23,10 @@ const kickOffProcessWorker = (jobId) => {
|
||||
})
|
||||
}
|
||||
|
||||
let dropbox = `${config.shared.presAnnDropboxDir}/${jobId}`
|
||||
let dropbox = path.join(config.shared.presAnnDropboxDir, jobId);
|
||||
|
||||
// Takes the Job from the dropbox
|
||||
let job = fs.readFileSync(`${dropbox}/job`);
|
||||
let job = fs.readFileSync(path.join(dropbox, 'job'));
|
||||
let exportJob = JSON.parse(job);
|
||||
|
||||
// Collect the annotations from Redis
|
||||
@ -51,17 +51,17 @@ let exportJob = JSON.parse(job);
|
||||
let whiteboard = JSON.parse(annotations);
|
||||
let pages = JSON.parse(whiteboard.pages);
|
||||
|
||||
fs.writeFile(`${dropbox}/whiteboard`, annotations, function(err) {
|
||||
fs.writeFile(path.join(dropbox, 'whiteboard'), annotations, function(err) {
|
||||
if(err) { return logger.error(err); }
|
||||
});
|
||||
|
||||
// Collect the Presentation Page files from the presentation directory
|
||||
let path = `${exportJob.presLocation}/${exportJob.presId}`;
|
||||
let pdfFileExists = fs.existsSync(`${path}.pdf`);
|
||||
let presentationFile = path.join(exportJob.presLocation, exportJob.presId);
|
||||
let pdfFileExists = fs.existsSync(`${presentationFile}.pdf`);
|
||||
|
||||
for (let p of pages) {
|
||||
let pageNumber = p.page;
|
||||
let file = `${dropbox}/slide${pageNumber}`;
|
||||
let outputFile = path.join(dropbox, `slide${pageNumber}`);
|
||||
|
||||
if(pdfFileExists) {
|
||||
let extactSlideAsPDFCommands = [
|
||||
@ -70,8 +70,8 @@ let exportJob = JSON.parse(job);
|
||||
'-f', pageNumber,
|
||||
'-l', pageNumber,
|
||||
'-singlefile',
|
||||
`${path}.pdf`,
|
||||
file
|
||||
`${presentationFile}.pdf`,
|
||||
outputFile
|
||||
].join(' ');
|
||||
|
||||
execSync(extactSlideAsPDFCommands, (error, stderr) => {
|
||||
@ -85,19 +85,19 @@ let exportJob = JSON.parse(job);
|
||||
})
|
||||
}
|
||||
|
||||
else if (fs.existsSync(`${path}.png`)) {
|
||||
fs.copyFileSync(`${path}.png`, `${file}.png`);
|
||||
else if (fs.existsSync(`${presentationFile}.png`)) {
|
||||
fs.copyFileSync(`${presentationFile}.png`, `${outputFile}.png`);
|
||||
}
|
||||
|
||||
else if (fs.existsSync(`${path}.jpeg`)) {
|
||||
else if (fs.existsSync(`${presentationFile}.jpeg`)) {
|
||||
let convertImageToPngCommands = [
|
||||
'convert',
|
||||
`${path}.jpeg`,
|
||||
`${presentationFile}.jpeg`,
|
||||
'-background', 'white',
|
||||
'-resize', '1600x1600',
|
||||
'-auto-orient',
|
||||
'-flatten',
|
||||
`${file}.png`
|
||||
`${outputFile}.png`
|
||||
].join(' ');
|
||||
|
||||
execSync(convertImageToPngCommands, (error, stderr) => {
|
||||
|
@ -4,15 +4,16 @@ const fs = require('fs');
|
||||
const FormData = require('form-data');
|
||||
const redis = require('redis');
|
||||
const axios = require('axios').default;
|
||||
const path = require('path');
|
||||
|
||||
const { workerData, parentPort } = require('worker_threads')
|
||||
|
||||
const [jobType, jobId] = workerData;
|
||||
const [jobType, jobId, filename] = workerData;
|
||||
|
||||
const logger = new Logger('presAnn Notifier Worker');
|
||||
|
||||
const dropbox = `${config.shared.presAnnDropboxDir}/${jobId}`
|
||||
let job = fs.readFileSync(`${dropbox}/job`);
|
||||
let job = fs.readFileSync(path.join(dropbox, 'job'));
|
||||
let exportJob = JSON.parse(job);
|
||||
|
||||
async function notifyMeetingActor() {
|
||||
@ -25,7 +26,7 @@ async function notifyMeetingActor() {
|
||||
await client.connect();
|
||||
client.on('error', (err) => logger.info('Redis Client Error', err));
|
||||
|
||||
let link = `${config.notifier.protocol}://${config.notifier.host}/bigbluebutton/presentation/${exportJob.parentMeetingId}/${exportJob.parentMeetingId}/${exportJob.presId}/pdf/${jobId}`;
|
||||
let link = `${config.notifier.protocol}://${config.notifier.host}/bigbluebutton/presentation/${exportJob.parentMeetingId}/${exportJob.parentMeetingId}/${exportJob.presId}/pdf/${jobId}/${filename}`;
|
||||
// Notify Meeting Actor of file availability by sending a message through Redis PubSub
|
||||
const notification = {
|
||||
envelope: {
|
||||
@ -56,13 +57,10 @@ async function upload(exportJob) {
|
||||
let callbackUrl = `http://${config.bbbWeb.host}:${config.bbbWeb.port}/bigbluebutton/presentation/${exportJob.presentationUploadToken}/upload`
|
||||
let formData = new FormData();
|
||||
|
||||
formData.append('presentation_name', 'annotated_slides.pdf');
|
||||
formData.append('Filename', 'annotated_slides');
|
||||
formData.append('conference', exportJob.parentMeetingId);
|
||||
formData.append('room', exportJob.parentMeetingId);
|
||||
formData.append('pod_id', config.notifier.pod_id);
|
||||
formData.append('is_downloadable', config.notifier.is_downloadable);
|
||||
formData.append('fileUpload', fs.createReadStream(`${exportJob.presLocation}/pdfs/annotated_slides_${jobId}.pdf`));
|
||||
formData.append('fileUpload', fs.createReadStream(`${exportJob.presLocation}/pdfs/${jobId}/${filename}.pdf`));
|
||||
|
||||
let res = await axios.post(callbackUrl, formData, { headers: formData.getHeaders() });
|
||||
logger.info(`Upload of job ${exportJob.jobId} returned ${res.data}`);
|
||||
|
@ -5,6 +5,8 @@ const sizeOf = require('image-size');
|
||||
const { create } = require('xmlbuilder2', { encoding: 'utf-8' });
|
||||
const { execSync } = require("child_process");
|
||||
const { Worker, workerData, parentPort } = require('worker_threads');
|
||||
const path = require('path');
|
||||
const sanitize = require("sanitize-filename");
|
||||
|
||||
const jobId = workerData;
|
||||
const MAGIC_MYSTERY_NUMBER = 2;
|
||||
@ -12,9 +14,9 @@ const MAGIC_MYSTERY_NUMBER = 2;
|
||||
const logger = new Logger('presAnn Process Worker');
|
||||
logger.info("Processing PDF for job " + jobId);
|
||||
|
||||
const kickOffNotifierWorker = (jobType) => {
|
||||
const kickOffNotifierWorker = (jobType, sanitizedFilename) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const worker = new Worker('./workers/notifier.js', { workerData: [jobType, jobId] });
|
||||
const worker = new Worker('./workers/notifier.js', { workerData: [jobType, jobId, sanitizedFilename] });
|
||||
worker.on('message', resolve);
|
||||
worker.on('error', reject);
|
||||
worker.on('exit', (code) => {
|
||||
@ -43,7 +45,7 @@ function render_HTMLTextBox(htmlFilePath, id, width, height) {
|
||||
'--crop-h', height,
|
||||
'--log-level', 'none',
|
||||
'--quality', '100',
|
||||
htmlFilePath, `${dropbox}/text${id}.png`
|
||||
htmlFilePath, path.join(dropbox, `text${id}.png`)
|
||||
]
|
||||
|
||||
execSync(commands.join(' '), (error, stderr) => {
|
||||
@ -176,8 +178,8 @@ function overlay_poll(svg, annotation, w, h) {
|
||||
let poll_width = Math.round(scale_shape(w, annotation.points[2]));
|
||||
let poll_height = Math.round(scale_shape(h, annotation.points[3]));
|
||||
let pollId = annotation.id.replace(/\//g, '');
|
||||
let pollSVG = `${dropbox}/poll-${pollId}.svg`
|
||||
let pollJSON = `${dropbox}/poll-${pollId}.json`
|
||||
let pollSVG = path.join(dropbox, `poll-${pollId}.svg`);
|
||||
let pollJSON = path.join(dropbox, `poll-${pollId}.json`);
|
||||
|
||||
// Rename 'numVotes' key to 'num_votes'
|
||||
let pollJSONContent = annotation.result.map(result => {
|
||||
@ -281,7 +283,7 @@ function overlay_text(svg, annotation, w, h) {
|
||||
</p>
|
||||
</html>`;
|
||||
|
||||
var htmlFilePath = `${dropbox}/text${annotation.id}.html`
|
||||
var htmlFilePath = path.join(dropbox, `text${annotation.id}.html`)
|
||||
|
||||
fs.writeFileSync(htmlFilePath, html, function (err) {
|
||||
if (err) logger.error(err)
|
||||
@ -331,19 +333,19 @@ function overlay_annotations(svg, currentSlideAnnotations, w, h) {
|
||||
// Process the presentation pages and annotations into a PDF file
|
||||
|
||||
// 1. Get the job
|
||||
const dropbox = `${config.shared.presAnnDropboxDir}/${jobId}`
|
||||
let job = fs.readFileSync(`${dropbox}/job`);
|
||||
const dropbox = path.join(config.shared.presAnnDropboxDir, jobId);
|
||||
let job = fs.readFileSync(path.join(dropbox, 'job'));
|
||||
let exportJob = JSON.parse(job);
|
||||
|
||||
// 2. Get the annotations
|
||||
let annotations = fs.readFileSync(`${dropbox}/whiteboard`);
|
||||
let annotations = fs.readFileSync(path.join(dropbox, 'whiteboard'));
|
||||
let whiteboard = JSON.parse(annotations);
|
||||
let pages = JSON.parse(whiteboard.pages);
|
||||
let ghostScriptInput = ""
|
||||
|
||||
// 3. Convert annotations to SVG
|
||||
for (let currentSlide of pages) {
|
||||
var dimensions = sizeOf(`${dropbox}/slide${currentSlide.page}.png`);
|
||||
var dimensions = sizeOf(path.join(dropbox, `slide${currentSlide.page}.png`));
|
||||
var slideWidth = dimensions.width;
|
||||
var slideHeight = dimensions.height;
|
||||
|
||||
@ -381,8 +383,8 @@ for (let currentSlide of pages) {
|
||||
|
||||
svg = svg.end({ prettyPrint: true });
|
||||
// Write annotated SVG file
|
||||
let SVGfile = `${dropbox}/annotated-slide${currentSlide.page}.svg`
|
||||
let PDFfile = `${dropbox}/annotated-slide${currentSlide.page}.pdf`
|
||||
let SVGfile = path.join(dropbox, `annotated-slide${currentSlide.page}.svg`)
|
||||
let PDFfile = path.join(dropbox, `annotated-slide${currentSlide.page}.pdf`)
|
||||
|
||||
fs.writeFileSync(SVGfile, svg, function(err) {
|
||||
if(err) { return logger.error(err); }
|
||||
@ -408,14 +410,16 @@ for (let currentSlide of pages) {
|
||||
}
|
||||
|
||||
// Create PDF output directory if it doesn't exist
|
||||
let output_dir = `${exportJob.presLocation}/pdfs`;
|
||||
if (!fs.existsSync(output_dir)) { fs.mkdirSync(output_dir); }
|
||||
let output_dir = path.join(exportJob.presLocation, 'pdfs', jobId);
|
||||
let filename = sanitize(`annotated_${exportJob.meetingName}_${path.parse(exportJob.presName).name}`).replace(/\s/g, '_');
|
||||
|
||||
if (!fs.existsSync(output_dir)) { fs.mkdirSync(output_dir, { recursive: true }); }
|
||||
|
||||
let mergePDFs = [
|
||||
'gs',
|
||||
'-dNOPAUSE',
|
||||
'-sDEVICE=pdfwrite',
|
||||
`-sOUTPUTFILE=${output_dir}/annotated_slides_${jobId}.pdf`,
|
||||
`-sOUTPUTFILE="${path.join(output_dir, `${filename}.pdf`)}"`,
|
||||
`-dBATCH`,
|
||||
ghostScriptInput,
|
||||
].join(' ');
|
||||
@ -432,8 +436,8 @@ execSync(mergePDFs, (error, stderr) => {
|
||||
});
|
||||
|
||||
// Launch Notifier Worker depending on job type
|
||||
logger.info(`Saved PDF at ${output_dir}/annotated_slides_${jobId}.pdf`);
|
||||
logger.info(`Saved PDF at ${output_dir}/${jobId}/${filename}.pdf`);
|
||||
|
||||
kickOffNotifierWorker(exportJob.jobType);
|
||||
kickOffNotifierWorker(exportJob.jobType, filename);
|
||||
|
||||
parentPort.postMessage({ message: workerData })
|
||||
|
Loading…
Reference in New Issue
Block a user