mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 06:09:39 +00:00
Fixed maximize drag and nested .rar extraction
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component, ViewChild } from '@angular/core'
|
||||
import { Component, ViewChild, AfterViewInit } from '@angular/core'
|
||||
import { ChartSidebarComponent } from './chart-sidebar/chart-sidebar.component'
|
||||
import { StatusBarComponent } from './status-bar/status-bar.component'
|
||||
import { SongResult } from 'src/electron/shared/interfaces/search.interface'
|
||||
@@ -9,7 +9,7 @@ import { ResultTableComponent } from './result-table/result-table.component'
|
||||
templateUrl: './browse.component.html',
|
||||
styleUrls: ['./browse.component.scss']
|
||||
})
|
||||
export class BrowseComponent {
|
||||
export class BrowseComponent implements AfterViewInit {
|
||||
|
||||
@ViewChild('resultTable', { static: true }) resultTable: ResultTableComponent
|
||||
@ViewChild('chartSidebar', { static: true }) chartSidebar: ChartSidebarComponent
|
||||
@@ -17,6 +17,24 @@ export class BrowseComponent {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngAfterViewInit() {
|
||||
const $tableColumn = $('#table-column')
|
||||
$tableColumn.visibility({
|
||||
once: false,
|
||||
continuous: true,
|
||||
context: $tableColumn,
|
||||
observeChanges: true,
|
||||
onUpdate: () => {
|
||||
let pos = $tableColumn[0].scrollTop + $tableColumn[0].offsetHeight
|
||||
let max = $tableColumn[0].scrollHeight
|
||||
if (pos >= max - 5) {
|
||||
// TODO: load more results (should be debounced or something; wait until results have loaded before sending the request for more)
|
||||
console.log('UPDATE SCROLL')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onResultsUpdated(results: SongResult[]) {
|
||||
this.resultTable.results = results
|
||||
this.resultTable.onNewSearch()
|
||||
@@ -25,4 +43,8 @@ export class BrowseComponent {
|
||||
this.statusBar.resultCount = results.length
|
||||
this.statusBar.selectedResults = []
|
||||
}
|
||||
|
||||
loadMoreResults() {
|
||||
// TODO: use the same query as the current search, but append more results if there are any more to be viewed
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,7 @@ export class ChartSidebarComponent {
|
||||
this.selectedVersion.versionID, {
|
||||
avTagName: this.selectedVersion.avTagName,
|
||||
artist: this.songResult.artist,
|
||||
charter: this.selectedVersion.charters,
|
||||
charter: this.selectedVersion.charters, //TODO: get the charter name associated with this particular version
|
||||
links: JSON.parse(this.selectedVersion.downloadLink)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<div class="right menu">
|
||||
<a class="item traffic-light" (click)="minimize()"><i class="minus icon"></i></a>
|
||||
<a class="item traffic-light" (click)="maximize()"><i class="icon window" [ngClass]="isMaximized ? 'restore' : 'maximize'"></i></a>
|
||||
<a class="item traffic-light" (click)="toggleMaximized()"><i class="icon window" [ngClass]="isMaximized ? 'restore' : 'maximize'"></i></a>
|
||||
<a class="item traffic-light" (click)="close()"><i class="x icon"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { Component, OnInit, ChangeDetectorRef } from '@angular/core'
|
||||
import { ElectronService } from '../../core/services/electron.service'
|
||||
|
||||
@Component({
|
||||
@@ -10,17 +10,25 @@ export class ToolbarComponent implements OnInit {
|
||||
|
||||
isMaximized: boolean
|
||||
|
||||
constructor(private electronService: ElectronService) { }
|
||||
constructor(private electronService: ElectronService, private ref: ChangeDetectorRef) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.isMaximized = this.electronService.currentWindow.isMaximized()
|
||||
this.electronService.currentWindow.on('unmaximize', () => {
|
||||
this.isMaximized = false
|
||||
this.ref.detectChanges()
|
||||
})
|
||||
this.electronService.currentWindow.on('maximize', () => {
|
||||
this.isMaximized = true
|
||||
this.ref.detectChanges()
|
||||
})
|
||||
}
|
||||
|
||||
minimize() {
|
||||
this.electronService.currentWindow.minimize()
|
||||
}
|
||||
|
||||
maximize() {
|
||||
toggleMaximized() {
|
||||
if (this.isMaximized) {
|
||||
this.electronService.currentWindow.restore()
|
||||
} else {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
39
src/electron/ipc/download/RarExtractor.ts
Normal file
39
src/electron/ipc/download/RarExtractor.ts
Normal 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}`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user