mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-07-09 03:25:09 +00:00
Initial settings, download UI, various bugfixes
This commit is contained in:
@@ -3,6 +3,10 @@ import { VersionResult, AlbumArtResult } from './interfaces/songDetails.interfac
|
||||
import SearchHandler from '../ipc/SearchHandler.ipc'
|
||||
import SongDetailsHandler from '../ipc/SongDetailsHandler.ipc'
|
||||
import AlbumArtHandler from '../ipc/AlbumArtHandler.ipc'
|
||||
import { Download, NewDownload } from './interfaces/download.interface'
|
||||
import { AddDownloadHandler } from '../ipc/download/AddDownloadHandler'
|
||||
import { Settings } from './Settings'
|
||||
import InitSettingsHandler from '../ipc/InitSettingsHandler.ipc'
|
||||
|
||||
/**
|
||||
* To add a new IPC listener:
|
||||
@@ -12,30 +16,51 @@ import AlbumArtHandler from '../ipc/AlbumArtHandler.ipc'
|
||||
* 4.) Add the class to getIPCHandlers
|
||||
*/
|
||||
|
||||
export function getIPCHandlers(): IPCHandler<keyof IPCEvents>[] {
|
||||
export function getIPCInvokeHandlers(): IPCInvokeHandler<keyof IPCInvokeEvents>[] {
|
||||
return [
|
||||
new InitSettingsHandler(),
|
||||
new SearchHandler(),
|
||||
new SongDetailsHandler(),
|
||||
new AlbumArtHandler()
|
||||
]
|
||||
}
|
||||
|
||||
export type IPCEvents = {
|
||||
['song-search']: {
|
||||
export type IPCInvokeEvents = {
|
||||
'init-settings': {
|
||||
input: undefined
|
||||
output: Settings
|
||||
}
|
||||
'song-search': {
|
||||
input: SongSearch
|
||||
output: SongResult[]
|
||||
}
|
||||
['album-art']: {
|
||||
'album-art': {
|
||||
input: SongResult['id']
|
||||
output: AlbumArtResult
|
||||
}
|
||||
['song-details']: {
|
||||
'song-details': {
|
||||
input: SongResult['id']
|
||||
output: VersionResult[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface IPCHandler<E extends keyof IPCEvents> {
|
||||
export interface IPCInvokeHandler<E extends keyof IPCInvokeEvents> {
|
||||
event: E
|
||||
handler(data: IPCEvents[E]['input']): Promise<IPCEvents[E]['output']> | IPCEvents[E]['output']
|
||||
handler(data: IPCInvokeEvents[E]['input']): Promise<IPCInvokeEvents[E]['output']> | IPCInvokeEvents[E]['output']
|
||||
}
|
||||
|
||||
export function getIPCEmitHandlers(): IPCEmitHandler<keyof IPCEmitEvents>[]{
|
||||
return [
|
||||
new AddDownloadHandler()
|
||||
]
|
||||
}
|
||||
|
||||
export type IPCEmitEvents = {
|
||||
'add-download': NewDownload
|
||||
'download-updated': Download
|
||||
}
|
||||
|
||||
export interface IPCEmitHandler<E extends keyof IPCEmitEvents> {
|
||||
event: E
|
||||
handler(data: IPCEmitEvents[E]): void
|
||||
}
|
||||
9
src/electron/shared/Paths.ts
Normal file
9
src/electron/shared/Paths.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import * as path from 'path'
|
||||
import { app } from 'electron'
|
||||
|
||||
// Data paths
|
||||
export const dataPath = path.join(app.getPath('userData'), 'bridge_data')
|
||||
export const libraryPath = path.join(dataPath, 'library.db')
|
||||
export const settingsPath = path.join(dataPath, 'settings.json')
|
||||
export const tempPath = path.join(dataPath, 'temp')
|
||||
export const themesPath = path.join(dataPath, 'themes')
|
||||
@@ -1,19 +1,11 @@
|
||||
export class Settings {
|
||||
export interface Settings {
|
||||
rateLimitDelay: number // Number of seconds to wait between each file download from Google servers
|
||||
theme: string // The name of the currently enabled UI theme
|
||||
libraryPath: string // The path to the user's library
|
||||
}
|
||||
|
||||
// Singleton
|
||||
private constructor() { }
|
||||
private static settings: Settings
|
||||
static async getInstance() {
|
||||
if (this.settings == undefined) {
|
||||
this.settings = new Settings()
|
||||
}
|
||||
await this.settings.initSettings()
|
||||
return this.settings
|
||||
}
|
||||
|
||||
songsFolderPath: string
|
||||
|
||||
private async initSettings() {
|
||||
// TODO: load settings from settings file or set defaults
|
||||
}
|
||||
export const defaultSettings: Settings = {
|
||||
rateLimitDelay: 31,
|
||||
theme: 'Default',
|
||||
libraryPath: 'C:/Users/bouviejs/Desktop/Bridge Notes/TestLibrary'
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
import { basename } from 'path'
|
||||
import { Settings } from './Settings'
|
||||
|
||||
const settings = Settings.getInstance()
|
||||
let sanitize = require('sanitize-filename')
|
||||
|
||||
/**
|
||||
* @param absoluteFilepath The absolute filepath to a folder
|
||||
@@ -12,4 +9,48 @@ export function getRelativeFilepath(absoluteFilepath: string) {
|
||||
// loads everything and connects to the database, etc...)
|
||||
// return basename(scanSettings.songsFolderPath) + absoluteFilepath.substring(scanSettings.songsFolderPath.length)
|
||||
return absoluteFilepath
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns A random UUID
|
||||
*/
|
||||
export function generateUUID() { // Public Domain/MIT
|
||||
var d = new Date().getTime()//Timestamp
|
||||
var d2 = Date.now() // Time in microseconds since page-load or 0 if unsupported
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
var r = Math.random() * 16//random number between 0 and 16
|
||||
if (d > 0) {//Use timestamp until depleted
|
||||
r = (d + r) % 16 | 0
|
||||
d = Math.floor(d / 16)
|
||||
} else {//Use microseconds since page-load if supported
|
||||
r = (d2 + r) % 16 | 0
|
||||
d2 = Math.floor(d2 / 16)
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a filename of any characters that cannot be part of a windows filename.
|
||||
* @param filename The name of the file to sanitize.
|
||||
*/
|
||||
export function sanitizeFilename(filename: string): string {
|
||||
const newName = sanitize(filename, {
|
||||
replacement: ((invalidChar: string) => {
|
||||
switch (invalidChar) {
|
||||
case '/': return '-'
|
||||
case '\\': return '-'
|
||||
case '"': return "'"
|
||||
default: return '_' //TODO: add more cases for replacing invalid characters
|
||||
}
|
||||
})
|
||||
})
|
||||
return newName
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts <val> from the range (<fromA>, <fromB>) to the range (<toA>, <toB>).
|
||||
*/
|
||||
export function interpolate(val: number, fromA: number, fromB: number, toA: number, toB: number) {
|
||||
return ((val - fromA) / (fromB - fromA)) * (toB - toA) + toA
|
||||
}
|
||||
33
src/electron/shared/interfaces/download.interface.ts
Normal file
33
src/electron/shared/interfaces/download.interface.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Represents the download of a single chart
|
||||
*/
|
||||
export interface Download {
|
||||
versionID: number
|
||||
title: string
|
||||
header: string
|
||||
description: string
|
||||
percent: number
|
||||
|
||||
//TODO: figure out how to handle user clicking "retry"
|
||||
}
|
||||
|
||||
export interface NewDownload {
|
||||
versionID: number
|
||||
avTagName: string
|
||||
artist: string
|
||||
charter: string
|
||||
links: { [type: string]: string }
|
||||
}
|
||||
|
||||
|
||||
export enum DownloadState {
|
||||
wait, // Waiting for Google rate limit...
|
||||
request, // [song.ini] Sending request...
|
||||
warning, // Warning! [song.ini] has been modified recently and may not match how it was displayed in search results. Download anyway?
|
||||
download, // [song.ini] Downloading: 25%
|
||||
extract, // [archive.zip] Extracting: 44%
|
||||
transfer, // Copying files to library...
|
||||
complete // Complete
|
||||
}
|
||||
|
||||
// Try again button appears after an error: restarts the stage that failed
|
||||
1
src/electron/shared/typeDefinitions/node-7z.d.ts
vendored
Normal file
1
src/electron/shared/typeDefinitions/node-7z.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'node-7z'
|
||||
Reference in New Issue
Block a user