chore(electron): Use worker thread instead of separate process (#395)
This commit is contained in:
@@ -40,6 +40,7 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
extraResources
|
||||
todo
|
||||
conf.json
|
||||
src/Bot/conf.js
|
||||
|
||||
@@ -2,5 +2,4 @@ dist
|
||||
build
|
||||
node_modules
|
||||
assets
|
||||
config
|
||||
scripts
|
||||
@@ -1,58 +1,56 @@
|
||||
const path = require('path');
|
||||
const paths = require('./paths');
|
||||
const webpack = require('webpack');
|
||||
const getClientEnvironment = require('./env');
|
||||
|
||||
|
||||
module.exports = mode => {
|
||||
const env = getClientEnvironment('/');
|
||||
|
||||
return {
|
||||
target: "electron-main",
|
||||
target: 'electron-main',
|
||||
mode,
|
||||
entry: {
|
||||
main: paths.electronIndexJs,
|
||||
osuSongsScan: paths.osuSongsScan,
|
||||
osuIsRunning: paths.osuIsRunning
|
||||
osuIsRunning: paths.osuIsRunning,
|
||||
},
|
||||
output: {
|
||||
path: paths.appBuild,
|
||||
publicPath: paths.publicUrl,
|
||||
filename: '[name].bundle.js'
|
||||
filename: '[name].bundle.js',
|
||||
},
|
||||
node: {
|
||||
__dirname: false
|
||||
__dirname: false,
|
||||
},
|
||||
module: {
|
||||
rules : [{
|
||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||
include: paths.appSrc,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
sourceType: 'unambiguous',
|
||||
presets: [
|
||||
'@babel/preset-env'
|
||||
],
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /ipcMessages.js$/,
|
||||
loader: 'string-replace-loader',
|
||||
options:{
|
||||
multiple: [
|
||||
{
|
||||
search: './processes/osuSongsScan.js',
|
||||
replace: './osuSongsScan.bundle.js'
|
||||
},
|
||||
{
|
||||
search: './processes/osuIsRunning.js',
|
||||
replace: './osuIsRunning.bundle.js'
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|mjs|jsx|ts|tsx)$/,
|
||||
include: paths.appSrc,
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
sourceType: 'unambiguous',
|
||||
presets: ['@babel/preset-env'],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /threads.*\.js$/,
|
||||
loader: 'string-replace-loader',
|
||||
options: {
|
||||
multiple: [
|
||||
{
|
||||
search: './osuSongsScan.worker.js',
|
||||
replace: '../../extraResources/osuSongsScan.bundle.js',
|
||||
},
|
||||
{
|
||||
search: './osuIsRunning.worker.js',
|
||||
replace: '../../extraResources/osuIsRunning.bundle.js',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(env.stringified),
|
||||
],
|
||||
}
|
||||
};
|
||||
plugins: [new webpack.DefinePlugin(env.stringified)],
|
||||
};
|
||||
};
|
||||
|
||||
+5
-11
@@ -22,8 +22,7 @@ function ensureSlash(inputPath, needsSlash) {
|
||||
}
|
||||
}
|
||||
|
||||
const getPublicUrl = appPackageJson =>
|
||||
envPublicUrl || require(appPackageJson).homepage;
|
||||
const getPublicUrl = appPackageJson => envPublicUrl || require(appPackageJson).homepage;
|
||||
|
||||
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
|
||||
// "public path" at which the app is served.
|
||||
@@ -33,8 +32,7 @@ const getPublicUrl = appPackageJson =>
|
||||
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
|
||||
function getServedPath(appPackageJson) {
|
||||
const publicUrl = getPublicUrl(appPackageJson);
|
||||
const servedUrl =
|
||||
envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
|
||||
const servedUrl = envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
|
||||
return ensureSlash(servedUrl, true);
|
||||
}
|
||||
|
||||
@@ -54,9 +52,7 @@ const moduleFileExtensions = [
|
||||
|
||||
// Resolve file paths in the same order as webpack
|
||||
const resolveModule = (resolveFn, filePath) => {
|
||||
const extension = moduleFileExtensions.find(extension =>
|
||||
fs.existsSync(resolveFn(`${filePath}.${extension}`))
|
||||
);
|
||||
const extension = moduleFileExtensions.find(extension => fs.existsSync(resolveFn(`${filePath}.${extension}`)));
|
||||
|
||||
if (extension) {
|
||||
return resolveFn(`${filePath}.${extension}`);
|
||||
@@ -85,10 +81,8 @@ module.exports = {
|
||||
publicUrl: getPublicUrl(resolveApp('package.json')),
|
||||
servedPath: getServedPath(resolveApp('package.json')),
|
||||
rendererWebpackConfig: resolveApp('config/renderer.webpack.config.js'),
|
||||
osuSongsScan: resolveApp('./src/electron/processes/osuSongsScan.js'),
|
||||
osuIsRunning: resolveApp('./src/electron/processes/osuIsRunning.js')
|
||||
osuSongsScan: resolveApp('./src/electron/threads/osuSongsScan.worker.js'),
|
||||
osuIsRunning: resolveApp('./src/electron/threads/osuIsRunning.worker.js'),
|
||||
};
|
||||
|
||||
|
||||
|
||||
module.exports.moduleFileExtensions = moduleFileExtensions;
|
||||
|
||||
+5
-3
@@ -11,8 +11,7 @@
|
||||
"dev": "node scripts/start.js",
|
||||
"start": "electron ./build/main.bundle.js",
|
||||
"dev:win": "@powershell -NoProfile -ExecutionPolicy Unrestricted -Command ./scripts/start.ps1",
|
||||
"prebuild": "node scripts/preBuild.js",
|
||||
"build": "node scripts/build.js",
|
||||
"build": "node scripts/preBuild.js && node scripts/build.js && node scripts/postBuild.js",
|
||||
"test": "node scripts/test.js",
|
||||
"lint": "yarn lint:prettier && yarn lint:es",
|
||||
"lint:fix": "yarn lint:fix:prettier && yarn lint:fix:es",
|
||||
@@ -46,6 +45,9 @@
|
||||
},
|
||||
"build": {
|
||||
"appId": "io.beatconnect.client",
|
||||
"extraResources": [
|
||||
"./extraResources/**"
|
||||
],
|
||||
"publish": [
|
||||
{
|
||||
"provider": "github",
|
||||
@@ -232,4 +234,4 @@
|
||||
"react-app"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
const { join } = require('path')
|
||||
const { copyFileSync, emptyDirSync } = require('fs-extra')
|
||||
const paths = require('../config/paths');
|
||||
// Copy wallpaper binaries to public folder on build
|
||||
|
||||
|
||||
|
||||
const sources = [
|
||||
'../build/osuIsRunning.bundle.js',
|
||||
'../build/osuSongsScan.bundle.js',
|
||||
]
|
||||
|
||||
const destFolder = join(__dirname, '..', 'extraResources');
|
||||
emptyDirSync(destFolder);
|
||||
|
||||
sources.forEach(src => copyFileSync(join(__dirname,src), join(destFolder, src.split('/').pop())))
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable no-alert */
|
||||
/* eslint-disable no-console */
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { error } from 'electron-log';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -11,38 +13,28 @@ import { scanOsuCollection } from './scanOsuCollections';
|
||||
export const useOsuDbScan = () => {
|
||||
const osuSongsPath = useSelector(getOsuSongPath);
|
||||
const osuPath = useSelector(getOsuPath);
|
||||
const { add: addTask, update, terminate } = useTasks();
|
||||
const { add: addTask, terminate } = useTasks();
|
||||
const history = useDownloadHistory();
|
||||
const [isScanning, setIsScanning] = useState(false);
|
||||
|
||||
const scanOsuSongs = () => {
|
||||
const scanOsuSongs = async () => {
|
||||
if (isScanning) return;
|
||||
if (!osuPath && !osuSongsPath) {
|
||||
return alert('You need to select your osu! or songs folder before performing a scan');
|
||||
alert('You need to select your osu! or songs folder before performing a scan');
|
||||
return;
|
||||
}
|
||||
setIsScanning(true);
|
||||
addTask({ name: 'Scanning beatmaps', status: 'running', description: '', section: 'Settings' });
|
||||
ipcRenderer.send('osuSongsScan', { osuPath, osuSongsPath, allowLegacy: true }); // User osu folder path
|
||||
ipcRenderer.on('osuSongsScanStatus', (e, args) => {
|
||||
update({
|
||||
name: 'Scanning beatmaps',
|
||||
description: `${Math.round(args * 100)}%`,
|
||||
});
|
||||
});
|
||||
ipcRenderer.on('osuSongsScanResults', (e, args) => {
|
||||
terminate('Scanning beatmaps');
|
||||
setIsScanning(false);
|
||||
if (args.err) error(`Error while scannings song: ${args.err}`);
|
||||
else {
|
||||
history.set(args);
|
||||
setLastScan({ date: Date.now(), beatmaps: Object.keys(args.beatmaps).length });
|
||||
}
|
||||
});
|
||||
ipcRenderer.on('osuSongsScanError', (e, args) => {
|
||||
terminate('Scanning beatmaps');
|
||||
setIsScanning(false);
|
||||
alert('Failed to scan beatmaps, check your songs and osu! path in settings section');
|
||||
});
|
||||
const result = await ipcRenderer.invoke('osuSongsScan', { osuPath });
|
||||
|
||||
terminate('Scanning beatmaps');
|
||||
setIsScanning(false);
|
||||
if (result.error) {
|
||||
throw new Error(`Error while scannings song: ${result.error}`);
|
||||
} else {
|
||||
history.set(result);
|
||||
setLastScan({ date: Date.now(), beatmaps: Object.keys(result.beatmaps).length });
|
||||
}
|
||||
};
|
||||
|
||||
return scanOsuSongs;
|
||||
@@ -54,8 +46,13 @@ export const useOsuDbAutoScan = () => {
|
||||
const osuPath = useSelector(getOsuPath);
|
||||
useEffect(() => {
|
||||
if (osuPath && osuSongsPath !== '') {
|
||||
osuDbScan();
|
||||
scanOsuCollection(osuPath).then(console.log);
|
||||
osuDbScan()
|
||||
.then(() => console.log('Osu db scan success!'))
|
||||
.catch(err => {
|
||||
error(`Error while scannings song: ${err.message}`);
|
||||
alert('Failed to scan beatmaps, check your songs and osu! path in settings section');
|
||||
});
|
||||
scanOsuCollection(osuPath).then(() => console.log('Collection scan success!'));
|
||||
}
|
||||
}, []);
|
||||
};
|
||||
|
||||
+13
-23
@@ -2,27 +2,18 @@ const log = require('electron-log');
|
||||
const { error } = require('electron-log');
|
||||
const { ipcMain, dialog, shell } = require('electron');
|
||||
const { join } = require('path');
|
||||
const { fork } = require('child_process');
|
||||
const { downloadAndSetWallpaper } = require('./wallpaper');
|
||||
const { readCollectionDB } = require('./helpers/osuCollections/collections.utils');
|
||||
const startPullingOsuState = require('./threads/osuIsRunning');
|
||||
const scanOsuDb = require('./threads/osuSongsScan');
|
||||
|
||||
ipcMain.on('osuSongsScan', (event, options) => {
|
||||
// TODO Replace with osu-db-parser module
|
||||
const osuSongsScanProcess = fork(join(__dirname, './processes/osuSongsScan.js'), null, { silent: true });
|
||||
osuSongsScanProcess.stdout.pipe(process.stdout);
|
||||
osuSongsScanProcess.send(JSON.stringify({ msg: 'start', ...options }));
|
||||
osuSongsScanProcess.on('message', msg => {
|
||||
const { results, status, err, overallDuration, overallUnplayedCount } = JSON.parse(msg);
|
||||
if (results) {
|
||||
event.reply('osuSongsScanResults', { beatmaps: results, overallDuration, overallUnplayedCount });
|
||||
osuSongsScanProcess.kill('SIGTERM');
|
||||
}
|
||||
if (status) event.reply('osuSongsScanStatus', status);
|
||||
if (err) {
|
||||
event.reply('osuSongsScanError', err);
|
||||
osuSongsScanProcess.kill('SIGTERM');
|
||||
}
|
||||
});
|
||||
ipcMain.handle('osuSongsScan', async (event, { osuPath }) => {
|
||||
try {
|
||||
const [beatmaps, overallDuration, overallUnplayedCount] = await scanOsuDb(`${osuPath}/osu!.db`);
|
||||
return { beatmaps, overallDuration, overallUnplayedCount };
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('set-wallpaper', (event, bgUri) => {
|
||||
@@ -44,11 +35,10 @@ ipcMain.on('set-wallpaper', (event, bgUri) => {
|
||||
ipcMain.on('start-osu', (event, osuPath) => shell.openPath(join(osuPath, 'osu!.exe')).catch(error));
|
||||
|
||||
ipcMain.once('start-pulling-osu-state', event => {
|
||||
const osuIsRunningChecker = fork(join(__dirname, './processes/osuIsRunning.js'));
|
||||
osuIsRunningChecker.on('message', msg => {
|
||||
event.reply('osu-is-running', !!msg);
|
||||
});
|
||||
osuIsRunningChecker.send('start');
|
||||
const osuStateHandler = isRunning => {
|
||||
event.reply('osu-is-running', isRunning);
|
||||
};
|
||||
startPullingOsuState(osuStateHandler);
|
||||
});
|
||||
|
||||
ipcMain.handle('scan-osu-collections', async (event, osuPath) => {
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
type callback('a) = (Js.Nullable.t(Js.Exn.t), 'a) => unit;
|
||||
|
||||
[@bs.module "fs"]
|
||||
external readFile: (string, callback(Buffer.t)) => unit = "readFile";
|
||||
[@bs.module "fs"]
|
||||
external writeFile: (string, Buffer.t, callback(string)) => unit =
|
||||
"writeFile";
|
||||
[@bs.module "process"] external on: (string, string => unit) => unit = "on";
|
||||
[@bs.module "process"] external send: string => unit = "send";
|
||||
|
||||
let osuDb =
|
||||
readFile("/Users/yannis/Downloads/osu!.db", (err, buffer) =>
|
||||
switch (Js.Nullable.toOption(err)) {
|
||||
| Some(err) => Js.log(err)
|
||||
| None => Js.log(OsuDbParser.read(buffer))
|
||||
}
|
||||
);
|
||||
|
||||
// let handleMessage = (message) =>
|
||||
// switch (message) {
|
||||
// | "start" => "Yep"
|
||||
// | _ =>
|
||||
// };
|
||||
|
||||
// on("message")
|
||||
|
||||
// TODO Handle incoming messages from main
|
||||
// Send messages to main
|
||||
// Handle those messages in main
|
||||
// Send back datas from main to renderer
|
||||
// All of this on reason via shared channel polymorphic variants and JSON converters
|
||||
@@ -1,27 +0,0 @@
|
||||
const { lookup } = require('ps-node');
|
||||
|
||||
const osuIsRuning = () => {
|
||||
lookup(
|
||||
{
|
||||
command: 'osu!.exe',
|
||||
},
|
||||
(err, resultList) => {
|
||||
if (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
process.send(resultList.length);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
let pullIntervalId = null;
|
||||
process.on('message', msg => {
|
||||
if (msg === 'start') {
|
||||
pullIntervalId = setInterval(osuIsRuning, 15000);
|
||||
}
|
||||
});
|
||||
|
||||
process.once('SIGTERM', () => {
|
||||
process.removeAllListeners();
|
||||
if (pullIntervalId) clearInterval(pullIntervalId);
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { join } = require('path');
|
||||
const { log } = require('electron-log');
|
||||
const parser = require('../helpers/beatmapParser');
|
||||
const { readOsuDB, winTickToMs } = require('../helpers/osudb');
|
||||
|
||||
const osuSongsScan = songsDirectoryPath =>
|
||||
new Promise((resolve, reject) => {
|
||||
try {
|
||||
const output = {};
|
||||
const beatmaps = fs.readdirSync(songsDirectoryPath);
|
||||
const beatmapsCount = beatmaps.length;
|
||||
beatmaps.forEach((beatmap, i) => {
|
||||
if (i % 50 === 0) {
|
||||
const progress = (i / beatmapsCount).toFixed(2);
|
||||
process.send(JSON.stringify({ status: progress }));
|
||||
}
|
||||
const beatmapPath = path.join(songsDirectoryPath, beatmap);
|
||||
const dirStats = fs.lstatSync(beatmapPath);
|
||||
const isDirExists = fs.existsSync(beatmapPath) && dirStats.isDirectory();
|
||||
if (isDirExists) {
|
||||
const date = dirStats.mtimeMs;
|
||||
const assets = fs.readdirSync(beatmapPath);
|
||||
for (let j = 0; j < assets.length; j++) {
|
||||
if (assets[j].split('.').pop() === 'osu') {
|
||||
const data = fs.readFileSync(path.join(beatmapPath, assets[j]), 'utf8');
|
||||
const { Metadata } = parser(data);
|
||||
if (!(typeof Metadata === 'undefined')) {
|
||||
const { BeatmapSetID, Title, Artist } = Metadata;
|
||||
if (BeatmapSetID && BeatmapSetID !== '-1' && BeatmapSetID !== '0')
|
||||
output[BeatmapSetID] = { id: BeatmapSetID, name: `${Title} | ${Artist}`, date };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
resolve(output);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
|
||||
const osuDbScan = osuPath => {
|
||||
const re = readOsuDB(`${osuPath}/osu!.db`);
|
||||
const out = {};
|
||||
let overallDuration = 0;
|
||||
let overallUnplayedCount = 0;
|
||||
re.beatmaps.forEach(beatmap => {
|
||||
if (beatmap.beatmapset_id === -1) return;
|
||||
if (out[beatmap.beatmapset_id]) return;
|
||||
if (beatmap.unplayed) overallUnplayedCount += 1;
|
||||
overallDuration += beatmap.total_time;
|
||||
out[beatmap.beatmapset_id] = {
|
||||
id: beatmap.beatmapset_id,
|
||||
date: winTickToMs(beatmap.last_modification_time),
|
||||
title: beatmap.song_title,
|
||||
artist: beatmap.artist_name,
|
||||
creator: beatmap.creator_name,
|
||||
isUnplayed: beatmap.unplayed,
|
||||
md5: beatmap.md5,
|
||||
audioPath: join(beatmap.folder_name, beatmap.audio_file_name),
|
||||
previewOffset: beatmap.preview_offset,
|
||||
};
|
||||
});
|
||||
|
||||
return [out, overallDuration, overallUnplayedCount];
|
||||
};
|
||||
|
||||
process.on('message', async data => {
|
||||
const { msg, osuPath, osuSongsPath, allowLegacy } = JSON.parse(data);
|
||||
let beatmaps = [];
|
||||
let overallDuration = 0;
|
||||
let overallUnplayedCount = 0;
|
||||
switch (msg) {
|
||||
case 'start':
|
||||
try {
|
||||
if (osuPath) {
|
||||
[beatmaps, overallDuration, overallUnplayedCount] = osuDbScan(osuPath);
|
||||
}
|
||||
// Fallback to direcrory scan if failed to read osu db
|
||||
if (!Object.keys(beatmaps).length && allowLegacy) beatmaps = await osuSongsScan(osuSongsPath);
|
||||
} catch (err) {
|
||||
log.error(`OsuSongScan: ${JSON.stringify(err.message)}`);
|
||||
process.send(JSON.stringify({ err: err.message }));
|
||||
throw err;
|
||||
}
|
||||
process.send(JSON.stringify({ results: beatmaps, overallDuration, overallUnplayedCount }));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
const { Worker } = require('worker_threads');
|
||||
const { error } = require('electron-log');
|
||||
const { join } = require('path');
|
||||
|
||||
let worker;
|
||||
let pullIntervalId;
|
||||
const startPullingOsuState = handler => {
|
||||
if (worker && pullIntervalId) {
|
||||
throw new Error('startPullingOsuState was already called and is started to end it call the returned stop function');
|
||||
}
|
||||
worker = new Worker(join(__dirname, './osuIsRunning.worker.js'));
|
||||
pullIntervalId = setInterval(() => worker.postMessage('check-osu-state'), 10000);
|
||||
worker.on('message', data => {
|
||||
switch (data[0]) {
|
||||
case 'result':
|
||||
handler(data[1]);
|
||||
break;
|
||||
case 'error':
|
||||
error(`[osuIsRunning thread]: ${data[1]}`);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
const stopPullingOsuState = () => {
|
||||
clearInterval(pullIntervalId);
|
||||
worker.removeAllListeners();
|
||||
worker.terminate();
|
||||
};
|
||||
|
||||
return stopPullingOsuState;
|
||||
};
|
||||
|
||||
module.exports = startPullingOsuState;
|
||||
@@ -0,0 +1,22 @@
|
||||
const { parentPort } = require('worker_threads');
|
||||
const { lookup } = require('ps-node');
|
||||
|
||||
let isBusy = false;
|
||||
parentPort.on('message', data => {
|
||||
if (data === 'check-osu-state' && !isBusy) {
|
||||
isBusy = true;
|
||||
lookup(
|
||||
{
|
||||
command: 'osu!.exe',
|
||||
},
|
||||
(err, resultList) => {
|
||||
if (err) {
|
||||
parentPort.postMessage(['error', err.message]);
|
||||
} else {
|
||||
parentPort.postMessage(['result', !!resultList.length]);
|
||||
}
|
||||
isBusy = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
const { Worker } = require('worker_threads');
|
||||
const { join } = require('path');
|
||||
const { error } = require('electron-log');
|
||||
|
||||
const scanOsuDb = osuDbPath =>
|
||||
new Promise((resolve, reject) => {
|
||||
const worker = new Worker(join(__dirname, './osuSongsScan.worker.js'));
|
||||
const terminate = () => {
|
||||
worker.removeAllListeners();
|
||||
worker.terminate();
|
||||
};
|
||||
worker.on('message', data => {
|
||||
switch (data[0]) {
|
||||
case 'result':
|
||||
terminate();
|
||||
resolve(data[1]);
|
||||
break;
|
||||
case 'error':
|
||||
terminate();
|
||||
error(`[scanOsuDb thread]: ${data[1]}`);
|
||||
reject(data[1]);
|
||||
break;
|
||||
default:
|
||||
terminate();
|
||||
break;
|
||||
}
|
||||
});
|
||||
worker.postMessage(osuDbPath);
|
||||
});
|
||||
|
||||
module.exports = scanOsuDb;
|
||||
@@ -0,0 +1,34 @@
|
||||
const { parentPort } = require('worker_threads');
|
||||
const { join } = require('path');
|
||||
const { readOsuDB, winTickToMs } = require('../helpers/osudb');
|
||||
|
||||
parentPort.on('message', osuDbPath => {
|
||||
if (osuDbPath) {
|
||||
try {
|
||||
const re = readOsuDB(osuDbPath);
|
||||
const beatmaps = {};
|
||||
let overallDuration = 0;
|
||||
let overallUnplayedCount = 0;
|
||||
re.beatmaps.forEach(beatmap => {
|
||||
if (beatmap.beatmapset_id === -1) return;
|
||||
if (beatmaps[beatmap.beatmapset_id]) return;
|
||||
if (beatmap.unplayed) overallUnplayedCount += 1;
|
||||
overallDuration += beatmap.total_time;
|
||||
beatmaps[beatmap.beatmapset_id] = {
|
||||
id: beatmap.beatmapset_id,
|
||||
date: winTickToMs(beatmap.last_modification_time),
|
||||
title: beatmap.song_title,
|
||||
artist: beatmap.artist_name,
|
||||
creator: beatmap.creator_name,
|
||||
isUnplayed: beatmap.unplayed,
|
||||
md5: beatmap.md5,
|
||||
audioPath: join(beatmap.folder_name, beatmap.audio_file_name),
|
||||
previewOffset: beatmap.preview_offset,
|
||||
};
|
||||
});
|
||||
parentPort.postMessage(['result', [beatmaps, overallDuration, overallUnplayedCount]]);
|
||||
} catch (e) {
|
||||
parentPort.postMessage(['error', e.message]);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user