mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-11 14:19:38 +00:00
Add download location settings
This commit is contained in:
@@ -1,20 +1,11 @@
|
||||
import { randomBytes } from 'crypto'
|
||||
import { basename, parse } from 'path'
|
||||
import { parse } from 'path'
|
||||
import sanitize from 'sanitize-filename'
|
||||
import { inspect } from 'util'
|
||||
|
||||
import { lower } from '../src-shared/UtilFunctions.js'
|
||||
import { settings } from './ipc/SettingsHandler.ipc.js'
|
||||
import { emitIpcEvent } from './main.js'
|
||||
|
||||
/**
|
||||
* @returns The relative filepath from the library folder to `absoluteFilepath`.
|
||||
*/
|
||||
export async function getRelativeFilepath(absoluteFilepath: string) {
|
||||
if (!settings.libraryPath) { throw 'getRelativeFilepath() failed; libraryPath is undefined' }
|
||||
return basename(settings.libraryPath) + absoluteFilepath.substring(settings.libraryPath.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `true` if `name` has a valid video file extension.
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@ const downloadQueue: DownloadQueue = new DownloadQueue()
|
||||
|
||||
export async function download(data: Download) {
|
||||
switch (data.action) {
|
||||
case 'add': downloadQueue.add(data.md5, data.chartName!); break
|
||||
case 'add': downloadQueue.add(data.md5, data.chart!); break
|
||||
case 'retry': downloadQueue.retry(data.md5); break
|
||||
case 'remove': downloadQueue.remove(data.md5); break
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ReadableStream } from 'stream/web'
|
||||
import { inspect } from 'util'
|
||||
|
||||
import { tempPath } from '../../../src-shared/Paths.js'
|
||||
import { sanitizeFilename } from '../../ElectronUtilFunctions.js'
|
||||
import { resolveChartFolderName } from '../../../src-shared/UtilFunctions.js'
|
||||
import { getSettings } from '../SettingsHandler.ipc.js'
|
||||
|
||||
export interface DownloadMessage {
|
||||
@@ -58,14 +58,17 @@ export class ChartDownload {
|
||||
private stepCompletedCount = 0
|
||||
private tempPath: string
|
||||
|
||||
private destinationName: string
|
||||
private chartFolderPath: string
|
||||
private isSng: boolean
|
||||
|
||||
private showProgress = _.throttle((description: string, percent: number | null = null) => {
|
||||
this.eventEmitter.emit('progress', { header: description, body: '' }, percent)
|
||||
}, 10, { leading: true, trailing: true })
|
||||
|
||||
constructor(public readonly md5: string, private chartName: string) { }
|
||||
constructor(
|
||||
public readonly md5: string,
|
||||
private chart: { name: string; artist: string; album: string; genre: string; year: string; charter: string },
|
||||
) { }
|
||||
|
||||
on<T extends keyof ChartDownloadEvents>(event: T, listener: ChartDownloadEvents[T]) {
|
||||
this.eventEmitter.on(event, listener)
|
||||
@@ -125,23 +128,16 @@ export class ChartDownload {
|
||||
}
|
||||
|
||||
this.isSng = settings.isSng
|
||||
this.destinationName = sanitizeFilename(this.isSng ? `${this.chartName}.sng` : this.chartName)
|
||||
this.chartFolderPath = resolveChartFolderName(settings.chartFolderName, this.chart) + (this.isSng ? '.sng' : '')
|
||||
this.showProgress('Checking for any duplicate charts...')
|
||||
const destinationPath = join(settings.libraryPath, this.destinationName)
|
||||
const destinationPath = join(settings.libraryPath, this.chartFolderPath)
|
||||
const isDuplicate = await access(destinationPath, constants.F_OK).then(() => true).catch(() => false)
|
||||
if (this._canceled) { return }
|
||||
if (isDuplicate) {
|
||||
throw { header: 'This chart already exists in your library folder', body: destinationPath, isPath: true }
|
||||
}
|
||||
|
||||
this.tempPath = join(tempPath, randomUUID())
|
||||
try {
|
||||
this.showProgress('Creating temporary download folder...')
|
||||
await ensureDir(this.tempPath)
|
||||
if (this._canceled) { return }
|
||||
} catch (err) {
|
||||
throw { header: 'Failed to create temporary download folder', body: inspect(err) }
|
||||
}
|
||||
this.tempPath = join(tempPath, randomUUID()) + (this.isSng ? '.sng' : '')
|
||||
}
|
||||
|
||||
private async downloadChart() {
|
||||
@@ -149,7 +145,7 @@ export class ChartDownload {
|
||||
const fileSize = BigInt(response.headers['content-length']!)
|
||||
|
||||
if (this.isSng) {
|
||||
response.pipe(createWriteStream(join(this.tempPath, this.destinationName), { highWaterMark: 2e+9 }))
|
||||
response.pipe(createWriteStream(this.tempPath, { highWaterMark: 2e+9 }))
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
let downloadedByteCount = BigInt(0)
|
||||
@@ -169,12 +165,12 @@ export class ChartDownload {
|
||||
const sngStream = new SngStream(Readable.toWeb(response) as any, { generateSongIni: true })
|
||||
let downloadedByteCount = BigInt(0)
|
||||
|
||||
await ensureDir(join(this.tempPath, this.destinationName))
|
||||
await ensureDir(this.tempPath)
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
sngStream.on('file', async (fileName, fileStream, nextFile) => {
|
||||
const nodeFileStream = Readable.fromWeb(fileStream as ReadableStream<Uint8Array>, { highWaterMark: 2e+9 })
|
||||
nodeFileStream.pipe(createWriteStream(join(this.tempPath, this.destinationName, fileName), { highWaterMark: 2e+9 }))
|
||||
nodeFileStream.pipe(createWriteStream(join(this.tempPath, fileName), { highWaterMark: 2e+9 }))
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
nodeFileStream.on('end', resolve)
|
||||
@@ -220,8 +216,8 @@ export class ChartDownload {
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 200)) // Delay for OS file processing
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
if (settings.libraryPath) {
|
||||
const destinationPath = join(settings.libraryPath, this.destinationName)
|
||||
move(join(this.tempPath, this.destinationName), destinationPath, { overwrite: true }, err => {
|
||||
const destinationPath = join(settings.libraryPath, this.chartFolderPath)
|
||||
move(this.tempPath, destinationPath, { overwrite: true }, err => {
|
||||
if (err) {
|
||||
reject({ header: 'Failed to move chart to library folder', body: inspect(err) })
|
||||
} else {
|
||||
@@ -240,9 +236,8 @@ export class ChartDownload {
|
||||
throw { header: 'Failed to delete temporary folder', body: inspect(err) }
|
||||
}
|
||||
|
||||
const destinationPath = join(settings.libraryPath!, this.destinationName)
|
||||
this.showProgress.cancel()
|
||||
this.eventEmitter.emit('end', destinationPath)
|
||||
this.eventEmitter.emit('end', join(settings.libraryPath!, this.chartFolderPath))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ export class DownloadQueue {
|
||||
return false
|
||||
}
|
||||
|
||||
add(md5: string, chartName: string) {
|
||||
add(md5: string, chart: { name: string; artist: string; album: string; genre: string; year: string; charter: string }) {
|
||||
if (!this.isChartInQueue(md5)) {
|
||||
const chartDownload = new ChartDownload(md5, chartName)
|
||||
const chartDownload = new ChartDownload(md5, chart)
|
||||
this.downloadQueue.push(chartDownload)
|
||||
|
||||
chartDownload.on('progress', (message, percent) => emitIpcEvent('downloadQueueUpdate', {
|
||||
md5,
|
||||
chartName,
|
||||
chart,
|
||||
header: message.header,
|
||||
body: message.body,
|
||||
percent,
|
||||
@@ -33,7 +33,7 @@ export class DownloadQueue {
|
||||
chartDownload.on('error', err => {
|
||||
emitIpcEvent('downloadQueueUpdate', {
|
||||
md5,
|
||||
chartName,
|
||||
chart,
|
||||
header: err.header,
|
||||
body: err.body,
|
||||
percent: null,
|
||||
@@ -49,7 +49,7 @@ export class DownloadQueue {
|
||||
chartDownload.on('end', destinationPath => {
|
||||
emitIpcEvent('downloadQueueUpdate', {
|
||||
md5,
|
||||
chartName,
|
||||
chart,
|
||||
header: 'Download complete',
|
||||
body: destinationPath,
|
||||
percent: 100,
|
||||
@@ -81,7 +81,7 @@ export class DownloadQueue {
|
||||
|
||||
emitIpcEvent('downloadQueueUpdate', {
|
||||
md5,
|
||||
chartName: 'Canceled',
|
||||
chart: { name: '', artist: '', album: '', genre: '', year: '', charter: '' },
|
||||
header: '',
|
||||
body: '',
|
||||
percent: null,
|
||||
|
||||
Reference in New Issue
Block a user