Fixed maximize drag and nested .rar extraction

This commit is contained in:
Geomitron
2020-03-09 10:52:41 -04:00
parent d7659554cc
commit 3a3c2b5476
7 changed files with 110 additions and 32 deletions

View File

@@ -1,13 +1,13 @@
import { exists as _exists, mkdir as _mkdir, readFile as _readFile, writeFile as _writeFile } from 'fs'
import * as fs from 'fs'
import { dataPath, tempPath, themesPath, settingsPath } from '../shared/Paths'
import { promisify } from 'util'
import { IPCInvokeHandler, IPCEmitHandler } from '../shared/IPCHandler'
import { defaultSettings, Settings } from '../shared/Settings'
const exists = promisify(_exists)
const mkdir = promisify(_mkdir)
const readFile = promisify(_readFile)
const writeFile = promisify(_writeFile)
const exists = promisify(fs.exists)
const mkdir = promisify(fs.mkdir)
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
let settings: Settings

View File

@@ -1,21 +1,20 @@
import { DownloadError } from './FileDownloader'
import { readdir as _readdir, unlink as _unlink, lstat as _lstat, copyFile as _copyFile,
rmdir as _rmdir, access as _access, mkdir as _mkdir, constants } from 'fs'
import * as fs from 'fs'
import { promisify } from 'util'
import { join, extname } from 'path'
import * as node7z from 'node-7z'
import * as zipBin from '7zip-bin'
import * as unrarjs from 'node-unrar-js'
import { getSettingsHandler } from '../SettingsHandler.ipc'
import { extractRar } from './RarExtractor'
const getSettings = getSettingsHandler.getSettings
const readdir = promisify(_readdir)
const unlink = promisify(_unlink)
const lstat = promisify(_lstat)
const copyFile = promisify(_copyFile)
const rmdir = promisify(_rmdir)
const access = promisify(_access)
const mkdir = promisify(_mkdir)
const readdir = promisify(fs.readdir)
const unlink = promisify(fs.unlink)
const lstat = promisify(fs.lstat)
const copyFile = promisify(fs.copyFile)
const rmdir = promisify(fs.rmdir)
const access = promisify(fs.access)
const mkdir = promisify(fs.mkdir)
type EventCallback = {
'extract': (filename: string) => void
@@ -47,7 +46,7 @@ export class FileExtractor {
this.libraryFolder = getSettings().libraryPath
const files = await readdir(this.sourceFolder)
if (this.isArchive) {
this.extract(files[0])
this.extract(files[0], extname(files[0]) == '.rar')
} else {
this.transfer()
}
@@ -56,19 +55,24 @@ export class FileExtractor {
/**
* Extracts the file at `filename` to `this.sourceFolder`.
*/
private extract(filename: string) {
private async extract(filename: string, useRarExtractor: boolean) {
await new Promise<void>(resolve => setTimeout(() => resolve(), 100)) // Wait for filesystem to process downloaded file...
if (this.wasCanceled) { return } // CANCEL POINT
this.callbacks.extract(filename)
const source = join(this.sourceFolder, filename)
if (extname(filename) == '.rar') {
if (useRarExtractor) {
// Use node-unrar-js to extract the archive
try {
let extractor = unrarjs.createExtractorFromFile(source, this.sourceFolder)
extractor.extractAll()
await extractRar(source, this.sourceFolder)
} catch (err) {
this.callbacks.error({ header: 'Extract Failed.', body: `Unable to extract [${filename}]: ${err.name}` }, () => this.extract(filename))
this.callbacks.error({
header: 'Extract Failed.',
body: `Unable to extract [${filename}]: ${err}`
},
() => this.extract(filename, extname(filename) == '.rar')
)
return
}
this.transfer(source)
@@ -82,12 +86,17 @@ export class FileExtractor {
this.callbacks.extractProgress(progress.percent, progress.fileCount)
})
stream.on('error', (err: Error) => {
this.callbacks.error({ header: 'Extract Failed.', body: `Unable to extract [${filename}]: ${err.name}` }, () => this.extract(filename))
let extractErrorOccured = false
stream.on('error', () => {
extractErrorOccured = true
console.log(`Failed to extract [${filename}], retrying with .rar extractor...`)
this.extract(filename, true)
})
stream.on('end', () => {
this.transfer(source)
if (!extractErrorOccured) {
this.transfer(source)
}
})
}
@@ -104,7 +113,7 @@ export class FileExtractor {
const destinationFolder = join(this.libraryFolder, this.destinationFolderName)
this.callbacks.transfer(destinationFolder)
try {
await access(destinationFolder, constants.F_OK)
await access(destinationFolder, fs.constants.F_OK)
} catch (e) {
await mkdir(destinationFolder)
}

View File

@@ -0,0 +1,39 @@
import * as fs from 'fs'
import { join } from 'path'
import * as unrarjs from 'node-unrar-js'
import { promisify } from 'util'
const mkdir = promisify(fs.mkdir)
/**
* Extracts the archive at `sourceFile` to a new folder in `destinationFolder`. Throws an error when this fails.
*/
export async function extractRar(sourceFile: string, destinationFolder: string) {
const extractor = unrarjs.createExtractorFromFile(sourceFile, destinationFolder)
const fileList = extractor.getFileList()
if (fileList[0].state != 'FAIL') {
// Create directories for nested archives (because unrarjs didn't feel like handling that automatically)
const headers = fileList[1].fileHeaders
for (const header of headers) {
if (header.flags.directory) {
try {
await mkdir(join(destinationFolder, header.name), { recursive: true })
} catch (e) {
throw new Error(`Failed to extract directory: ${e}`)
}
}
}
} else {
console.log('Warning: failed to read .rar files: ', fileList[0].reason, fileList[0].msg)
}
// Extract archive
const extractResult = extractor.extractAll()
if (extractResult[0].state == 'FAIL') {
throw new Error(`${extractResult[0].reason}: ${extractResult[0].msg}`)
}
}