Improve scanner

This commit is contained in:
viktorstrate
2019-08-21 18:20:43 +02:00
parent 108f6c2d0c
commit e5688bdee8
10 changed files with 135 additions and 101 deletions

View File

@@ -2,21 +2,13 @@ import { EVENT_SCANNER_PROGRESS } from '../scanner/Scanner'
const Mutation = {
async scanAll(root, args, ctx, info) {
if (ctx.scanner.isRunning) {
return {
finished: false,
success: false,
errorMessage: 'Scanner already running',
}
}
ctx.scanner.scanAll()
return {
finished: false,
success: true,
progress: 0,
errorMessage: null,
message: 'Starting scanner',
}
},
}

View File

@@ -7,6 +7,66 @@ import _scanAll from './scanAll'
export const EVENT_SCANNER_PROGRESS = 'SCANNER_PROGRESS'
async function _execScan(scanner, scanFunction) {
try {
if (scanner.isRunning) throw new Error('Scanner already running')
scanner.isRunning = true
scanner.imageProgress = {}
const session = scanner.driver.session()
const photoResult = await session.run(
'MATCH (photo:Photo) RETURN photo.id as photoId'
)
session.close()
photoResult.records
.map(x => x.get('photoId'))
.forEach(id => {
scanner.markImageToProgress(id)
})
scanner.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 0,
finished: false,
success: true,
message: 'Scan started',
},
})
console.log('Calling scan function')
await scanFunction()
console.log('Scan function ended')
console.log(
`Done scanning ${Object.keys(scanner.imageProgress).length} photos`
)
scanner.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 100,
finished: true,
success: true,
message: `Done scanning ${
Object.keys(scanner.imageProgress).length
} photos`,
},
})
} catch (e) {
console.error(`SCANNER ERROR: ${e.message}\n${e.stack}`)
scanner.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 0,
finished: true,
success: false,
message: `Scanner error: ${e.message}`,
},
})
} finally {
scanner.isRunning = false
}
}
class PhotoScanner {
constructor(driver) {
this.driver = driver
@@ -18,97 +78,67 @@ class PhotoScanner {
this.scanUser = this.scanUser.bind(this)
this.scanAll = this.scanAll.bind(this)
this.imagesToProgress = 0
this.finishedImages = 0
this.imageProgress = {}
this.markImageToProgress = () => {
this.imagesToProgress++
this.markImageToProgress = imageId => {
if (!this.imageProgress[imageId]) this.imageProgress[imageId] = false
}
this.markFinishedImage = () => {
this.finishedImages++
this.markFinishedImage = imageId => {
this.imageProgress[imageId] = true
this.broadcastProgress()
}
this.finishedImages = () =>
Object.values(this.imageProgress).reduce((prev, x) => {
x ? prev++ : prev
return prev
}, 0)
this.broadcastProgress = _.debounce(() => {
if (this.imagesToProgress == 0) return
if (!this.isRunning) return
if (Object.keys(this.imageProgress).length == 0) return
console.log(
`Progress: ${(this.finishedImages / this.imagesToProgress) * 100}`
)
let progress =
(this.finishedImages() / Object.keys(this.imageProgress).length) * 100
console.log(`Progress: ${progress}`)
this.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: (this.finishedImages / this.imagesToProgress) * 100,
progress,
finished: false,
success: true,
errorMessage: '',
message: `${this.finishedImages()} photos scanned`,
},
})
}, 250)
this.markImageToProgress = this.markImageToProgress.bind(this)
this.markFinishedImage = this.markFinishedImage.bind(this)
this.finishedImages = this.finishedImages.bind(this)
}
async scanUser(user) {
await _scanUser({ driver: this.driver, scanAlbum: this.scanAlbum }, user)
await _execScan(this, async () => {
await _scanUser({ driver: this.driver, scanAlbum: this.scanAlbum }, user)
})
}
async scanAlbum(album) {
await _scanAlbum(
{
driver: this.driver,
markImageToProgress: this.markImageToProgress,
markFinishedImage: this.markFinishedImage,
processImage: this.processImage,
},
album
)
await _execScan(this, async () => {
await _scanAlbum(this, album)
})
}
async processImage(id) {
await _processImage(
{
driver: this.driver,
markFinishedImage: this.markFinishedImage,
},
id
)
this.broadcastProgress()
await _execScan(this, async () => {
await _processImage(this, id)
})
}
async scanAll() {
this.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 0,
finished: false,
success: true,
errorMessage: '',
},
})
try {
await _scanAll({ driver: this.driver, scanUser: this.scanUser })
} catch (error) {
this.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 0,
finished: false,
success: false,
errorMessage: error.message,
},
})
throw error
}
console.log(
`Done scanning ${this.finishedImages} of ${this.imagesToProgress}`
)
this.pubsub.publish(EVENT_SCANNER_PROGRESS, {
scannerStatusUpdate: {
progress: 100,
finished: true,
success: true,
errorMessage: '',
},
await _execScan(this, async () => {
await _scanAll(this)
})
}
}

View File

@@ -54,7 +54,8 @@ async function addExifTags({ session, photo }) {
console.log('Added exif tags to photo', photo.path)
}
export default async function processImage({ driver, markFinishedImage }, id) {
export default async function processImage(scanner, id) {
const { driver, markFinishedImage } = scanner
const session = driver.session()
const result = await session.run(
@@ -77,7 +78,7 @@ export default async function processImage({ driver, markFinishedImage }, id) {
)
if (urlResult.records.length == 2) {
markFinishedImage()
markFinishedImage(id)
session.close()
@@ -196,5 +197,5 @@ export default async function processImage({ driver, markFinishedImage }, id) {
session.close()
markFinishedImage()
markFinishedImage(id)
}

View File

@@ -2,12 +2,12 @@ import fs from 'fs-extra'
import path from 'path'
import generateID from '../id-generator'
import { isImage, getImageCachePath } from './utils'
import _processImage from './processImage'
export default async function scanAlbum(
{ driver, markImageToProgress, markFinishedImage, processImage },
album
) {
export default async function scanAlbum(scanner, album) {
const { driver, markImageToProgress } = scanner
const { title, path: albumPath, id } = album
console.log('Scanning album', title)
let processedImages = []
@@ -22,8 +22,6 @@ export default async function scanAlbum(
if (await isImage(itemPath)) {
const session = driver.session()
markImageToProgress()
const photoResult = await session.run(
`MATCH (p:Photo {path: {imgPath} })<--(a:Album {id: {albumId}}) RETURN p`,
{
@@ -36,29 +34,33 @@ export default async function scanAlbum(
// console.log(`Photo already exists ${item}`)
const photoId = photoResult.records[0].get('p').properties.id
markImageToProgress(photoId)
const thumbnailPath = path.resolve(
getImageCachePath(photoId, id),
'thumbnail.jpg'
)
processingImagePromises.push(processImage(photoId))
processingImagePromises.push(_processImage(scanner, photoId))
} else {
console.log(`Found new image at ${itemPath}`)
const imageId = generateID()
const photoId = generateID()
markImageToProgress(photoId)
await session.run(
`MATCH (a:Album { id: {albumId} })
CREATE (p:Photo {id: {id}, path: {path}, title: {title} })
CREATE (a)-[:CONTAINS]->(p)`,
{
id: imageId,
id: photoId,
path: itemPath,
title: item,
albumId: id,
}
)
processingImagePromises.push(processImage(imageId))
processingImagePromises.push(_processImage(scanner, photoId))
}
}
}
@@ -91,4 +93,6 @@ export default async function scanAlbum(
await Promise.all(processingImagePromises)
console.log('Done processing album', album.title)
scanner.broadcastProgress()
}

View File

@@ -1,4 +1,7 @@
export default function scanAll({ driver, scanUser }) {
import _scanUser from './scanUser'
export default function scanAll(scanner) {
const { driver } = scanner
return new Promise((resolve, reject) => {
let session = driver.session()
@@ -20,7 +23,7 @@ export default function scanAll({ driver, scanUser }) {
for (let user of usersToScan) {
try {
await scanUser(user)
await _scanUser(scanner, user)
} catch (reason) {
console.log(
`User scan exception for user ${user.username} ${reason}`
@@ -28,6 +31,8 @@ export default function scanAll({ driver, scanUser }) {
reject(reason)
}
}
resolve()
},
onError: error => {
session.close()

View File

@@ -2,9 +2,12 @@ import fs from 'fs-extra'
import { resolve as pathResolve } from 'path'
import generateID from '../id-generator'
import { isImage, getAlbumCachePath } from './utils'
import _scanAlbum from './scanAlbum'
export default async function scanUser({ driver, scanAlbum }, user) {
console.log('Scanning user', user.username, 'at', user.path)
export default async function scanUser(scanner, user) {
const { driver } = scanner
console.log('Scanning user', user.username, 'at', user.rootPath)
let foundAlbumIds = []
@@ -50,7 +53,7 @@ export default async function scanUser({ driver, scanAlbum }, user) {
foundImageOrAlbum = true
nextParentAlbum = album.id
foundAlbumIds.push(album.id)
await scanAlbum(album)
await _scanAlbum(scanner, album)
continue
}
@@ -106,7 +109,7 @@ export default async function scanUser({ driver, scanAlbum }, user) {
}
foundAlbumIds.push(album.id)
await scanAlbum(album)
await _scanAlbum(scanner, album)
session.close()
}

View File

@@ -95,8 +95,8 @@ type AuthorizeResult {
type ScannerResult {
finished: Boolean!
success: Boolean!
errorMessage: String
progress: Float
message: String
}
type Result {

View File

@@ -10,7 +10,7 @@ const syncSubscription = gql`
scannerStatusUpdate {
finished
success
errorMessage
message
progress
}
}
@@ -49,7 +49,7 @@ const MessageProgress = ({ header, content, percent = 0, ...props }) => {
MessageProgress.propTypes = {
header: PropTypes.string,
content: PropTypes.element,
content: PropTypes.any,
percent: PropTypes.number,
}
@@ -90,9 +90,7 @@ class Messages extends Component {
this.setState({ showSyncMessage: false })
}}
header={update.finished ? 'Synced' : 'Syncing'}
content={
update.finished ? 'Finished syncing' : 'Syncing in progress'
}
content={update.message}
percent={update.progress}
/>
)

View File

@@ -10,7 +10,7 @@ const scanMutation = gql`
mutation scanAllMutation {
scanAll {
success
errorMessage
message
}
}
`

View File

@@ -57,7 +57,8 @@ export const AlbumBox = ({ album, customLink, ...props }) => {
thumbnail =
thumbnail ||
(album.subAlbums[0] &&
(album.subAlbums &&
album.subAlbums[0] &&
album.subAlbums[0].photos[0] &&
album.subAlbums[0].photos[0].thumbnail.url)