Skip to content

Commit

Permalink
Find DM Only maps, more efficient marker search
Browse files Browse the repository at this point in the history
  • Loading branch information
rrgeorge committed Sep 26, 2021
1 parent 938d666 commit 32170d4
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 37 deletions.
96 changes: 60 additions & 36 deletions ddb.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const path = require('path')
const url = require('url')
const vision = require('@google-cloud/vision');
const jsdom = require('jsdom');
const cv = require('opencv4nodejs-prebuilt');

function slugify(str) {
return Slugify(str,{ lower: true, strict: true })
Expand Down Expand Up @@ -1723,7 +1724,8 @@ function displayModal(path,id) {
zip.addFile('assets/js/custom.js',customjs)
if (this.maps && this.maps != "nomaps") {
const getGrid = require('./getgrid')
prog.detail = "Searching for Maps"
prog.text = "Searching for Maps..."
prog.detail = "Scanning pages..."
var mapJobs = []
const mapgroup = uuid5(`https://www.dndbeyond.com/${book.sourceURL}/maps`,uuid5.URL)
if (this.mapsloc != "parent") {
Expand Down Expand Up @@ -1759,10 +1761,17 @@ function displayModal(path,id) {
if (figures.length<1) {
figures = dom.window.document.querySelectorAll(".compendium-image-view-player")
}
if (figures.length<1) {
figures = dom.window.document.querySelectorAll(".compendium-image-with-subtitle-center")
}
if (figures) {
for (let figure of figures) {
let mapTitle,mapUrl,dmMap
if (figure.tagName == "P") {
if (figure.classList.contains("compendium-image-with-subtitle-center")) {
mapTitle = figure.textContent.trim()
mapUrl = figure.querySelector("img")?.getAttribute('src')
dmMap = mapUrl
} else if (figure.tagName == "P") {
const caption = figure.previousElementSibling
if (!figure.querySelector("A")?.textContent?.match(/[Pp]layer/s))
{
Expand All @@ -1773,7 +1782,7 @@ function displayModal(path,id) {
if (!figure.id) figure.id = caption.id
mapTitle = caption.textContent.trim()
mapUrl = figure.querySelector("A").getAttribute('href')
dmMap = caption.querySelector("img").getAttribute('src')
dmMap = caption.querySelector("img")?.getAttribute('src')
} else {
const caption = figure.querySelector("figcaption")
if (!caption) continue
Expand All @@ -1798,8 +1807,7 @@ function displayModal(path,id) {
}
}
mapsort ++
prog.detail = `Found Map - ${mapTitle}`
prog.detail = `Found Map - ${mapTitle} - Analyzing grid`
prog.detail = `Found: ${mapTitle}`
let { data: mapfile, info } = await sharp(zip.readFile(mapUrl)).toBuffer({resolveWithObject: true})
if (book.remotePrefix) {
let remoteData = await this.getImage(`${book.remotePrefix}${mapUrl}`).catch(e=>console.log(`Could not load remote map: ${e}`))
Expand Down Expand Up @@ -1831,25 +1839,54 @@ function displayModal(path,id) {
]
}
if (grid.freq > 0) {
prog.detail = `Found Map - ${mapTitle} - Analyzing grid: ${grid.size}px`
prog.detail = `${mapTitle} - Analyzing grid: ${grid.size}px`
playerMap._content.push( { gridSize: grid.size } )
playerMap._content.push( { gridOffsetX: grid.x } )
playerMap._content.push( { gridOffsetY: grid.y } )
playerMap._content.push( { scale: grid.scale } )
}
if (this.maps == "markers") {
if (dmMap) {
const dmMapImg = await sharp(zip.readFile(dmMap)).toBuffer()
let {data:dmMapImg,info:dmMapInfo} = await sharp(zip.readFile(dmMap)).toBuffer({resolveWithObject: true})
let markerOffset = {x:0,y:0}
if (dmMapInfo.width!=info.width||dmMapInfo.height!=info.height) {
let dmImage = cv.imdecode(dmMapImg)
let pcImage = cv.imdecode(mapfile)
if (dmMapInfo.width>info.width||dmMapInfo.height>info.height) {
let res = dmImage.matchTemplate(pcImage,cv.TM_CCOEFF)
let loc = res.minMaxLoc()
markerOffset.x -= loc.maxLoc.x
markerOffset.y -= loc.maxLoc.y
} else {
let res = pcImage.matchTemplate(dmImage,cv.TM_CCOEFF)
let loc = res.minMaxLoc()
markerOffset.x += loc.maxLoc.x
markerOffset.y += loc.maxLoc.y
}
console.log(`${mapTitle} DM Map differs, offsetting markers by ${markerOffset.x},${markerOffset.y}`)
}
if (dmMapImg.length > 10485760) dmMapImg = await sharp(dmMapImg).webp().toBuffer()
//(book.remotePrefix)?`${book.remotePrefix}${dmMap}`:await sharp(zip.readFile(dmMap)).toBuffer()
let tasks = []
const headings = dom.window.document.querySelectorAll("h1, h2, h3, h4, h5, h6")
prog.detail = `Found Map - ${mapTitle} - Scanning for markers with Google Vision`
const headings = Array.from(dom.window.document.querySelectorAll("h1, h2, h3, h4, h5, h6"))
let siblingHeadings = []
if (page.page._attrs.parent) {
for (let nextpage of mod._content.filter(p=>p.page&&p.page._attrs.parent==page.page._attrs.parent)) {
let nxtDom = new jsdom.JSDOM(nextpage.page.content)
let nxtHeadings = Array.from(nxtDom.window.document.querySelectorAll("h1, h2, h3, h4, h5, h6"))
siblingHeadings.push({slug:nextpage.page.slug,headings:nxtHeadings})
}
}
prog.detail = `${mapTitle} - Scanning for markers with Google Vision`
const gVisionClient = new vision.ImageAnnotatorClient({
keyFile: path.join(__dirname,'.gkey.json')
});
const [ocrResult] = await gVisionClient.textDetection(dmMapImg).catch(e=>console.log(`Error submitting ${dmMap} (${typeof(dmMap)}) to Google Vision: ${e}`))
const [ocrResult] = await gVisionClient.textDetection(dmMapImg).catch(e=>console.log(`Error submitting ${dmMap} to Google Vision: ${e}`)) || [null]
gVisionClient.close()
console.log(`Processing markers for ${mapTitle}...`)
ocrResult?.textAnnotations?.forEach((word,i)=>{
if (i === 0) {
prog.detail = `${mapTitle} - Matching markers (0%)`
const mapScale = /(1 square)? = ([0-9]+) (.+)/mi.exec(word.description)
if (mapScale) {
let unit = mapScale[3]
Expand All @@ -1862,7 +1899,9 @@ function displayModal(path,id) {
}
return
}
prog.detail = `${mapTitle} - Matching markers (${(100*(i+1)/(ocrResult.textAnnotations.length)).toFixed(0)}%) ${prog.detail.substr(prog.detail.indexOf(')')+1)}`
let txt = word.description.replaceAll(/[\W_]+/g,'').trim();
if (!txt) return
let box = word.boundingPoly.vertices
let x = box[0].x, y = box[0].y
let x2=x, y2=y
Expand All @@ -1875,34 +1914,20 @@ function displayModal(path,id) {
let w = x2-x, h = y2-y
let marker = null
let pageslug = page.page.slug
for (const heading of headings) {
if (heading.textContent.match(new RegExp(`^${txt.toLowerCase()}\\. `,'i'))) {
marker = heading
break
}
}
if (!marker && page.page._attrs.parent) {
//console.log("Marker not found on this page. Looking on siblings")
for (const nextpage of mod._content) {
if (!nextpage.page) continue
if (nextpage.page._attrs.parent!=page.page._attrs.parent) continue

let nxtDom = new jsdom.JSDOM(nextpage.page.content)
let nxtHeadings = nxtDom.window.document.querySelectorAll("h1, h2, h3, h4, h5, h6")

for (const heading of nxtHeadings) {
if (heading.textContent.match(new RegExp(`^${txt.toLowerCase()}\\. `,'i'))) {
pageslug = nextpage.page.slug
marker = heading
break
}
const markerRegex = new RegExp(`^${txt.toLowerCase()}\\. `,'i')
marker = headings.find(h=>h.textContent.match(markerRegex))
if (!marker && siblingHeadings) {
for(let sibling of siblingHeadings) {
marker = sibling.headings.find(h=>h.textContent.match(markerRegex))
if (marker) {
pageslug = sibling.slug
break
}
if (marker) break
}
}
if (marker) {
console.log(`Adding marker for ${marker.textContent} to ${mapTitle}`)
prog.detail = `Found Map - ${mapTitle} - Placing Marker for ${marker.textContent.substr(0,marker.textContent.indexOf('.'))}`
prog.detail = `${prog.detail.substr(0,prog.detail.indexOf(')')+1)} ${marker.textContent.substr(0,marker.textContent.indexOf('.'))}`
playerMap._content.push({
marker: {
name: "",
Expand All @@ -1912,16 +1937,15 @@ function displayModal(path,id) {
size: "medium",
hidden: "YES",
locked: "YES",
x: Math.round(x+(w/2)),
y: Math.round(y+(h/2)),
x: Math.round(x+(w/2)+markerOffset.x),
y: Math.round(y+(h/2)+markerOffset.y),
content: {_attrs: { ref: `/page/${pageslug}#${marker.id}` }}
}
})
} else {
console.log(`No matching heading found for "${txt}"`)
}
})
gVisionClient.close()
}
}
prog.detail = `Adding Map: ${mapTitle}`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "encounterlog",
"productName": "EncounterLog",
"version": "2.1.9",
"version": "2.1.10",
"description": "Connect D&D Beyond to EncounterPlus",
"repository": {
"type": "git",
Expand Down

0 comments on commit 32170d4

Please sign in to comment.