Skip to content

Commit e3f7291

Browse files
Fix the issue where files could become corrupted during retries after DL failures
- Add `jpyTax` and `dlsitePriceTable` to `configReadOnly.ts` for pricing calculations - Enhance default exclude regex pattern in `configUser.ts` to cover more non-SE variations
1 parent e2dd033 commit e3f7291

File tree

8 files changed

+107
-16
lines changed

8 files changed

+107
-16
lines changed

build-rel.bat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@echo off&cd /d %~dp0
22

33
set "ISCC_PATH=C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
4-
set VERSION_NUM=1.2.1
4+
set VERSION_NUM=1.2.2
55

66
mkdir build\asmr-dl-ng
77
xcopy bin build\asmr-dl-ng\bin /E /I /Q

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "asmr-dl-ng",
3-
"version": "1.2.1",
3+
"version": "1.2.2",
44
"description": "ASMR Direct Downloader (New Generation)",
55
"author": "daydreamer-json <[email protected]> (https://github.com/daydreamer-json)",
66
"license": "AGPL-3.0-or-later",

setup/main.iss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#define MyAppName "asmr-dl-ng"
2-
#define MyAppVersion "1.2.1"
2+
#define MyAppVersion "1.2.2"
33
#define MyAppPublisher "daydreamer-json"
44
#define MyAppURL "https://github.com/daydreamer-json/asmr-dl-ng"
55
#define MyAppExeName "asmr-dl-ng.exe"

src/utils/configEmbed.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ import semver from 'semver';
22

33
export default {
44
APPLICATION_NAME: 'asmr-dl-ng',
5-
VERSION_NUMBER: semver.valid('1.2.1'),
5+
VERSION_NUMBER: semver.valid('1.2.2'),
66
};

src/utils/configReadOnly.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,49 @@ export default {
77
'If the program terminates abnormally, delete the folder containing this text file.\n',
88
].join('\n'),
99
},
10+
jpyTax: 10, // %
11+
dlsitePriceTable: [
12+
// input: creator's desired wholesale price (creator's net earnings)
13+
// output: actual selling price (including fees)
14+
{ input: 50, output: 100 },
15+
{ input: 100, output: 200 },
16+
{ input: 150, output: 300 },
17+
{ input: 200, output: 400 },
18+
{ input: 250, output: 500 },
19+
{ input: 300, output: 600 },
20+
{ input: 400, output: 700 },
21+
{ input: 450, output: 800 },
22+
{ input: 500, output: 900 },
23+
{ input: 600, output: 1000 },
24+
{ input: 700, output: 1100 },
25+
{ input: 800, output: 1200 },
26+
{ input: 900, output: 1300 },
27+
{ input: 950, output: 1400 },
28+
{ input: 1000, output: 1500 },
29+
{ input: 1100, output: 1600 },
30+
{ input: 1200, output: 1700 },
31+
{ input: 1300, output: 1800 },
32+
{ input: 1400, output: 1900 },
33+
{ input: 1450, output: 2000 },
34+
{ input: 1500, output: 2100 },
35+
{ input: 1600, output: 2200 },
36+
{ input: 1700, output: 2300 },
37+
{ input: 1800, output: 2400 },
38+
{ input: 1900, output: 2500 },
39+
{ input: 1950, output: 2600 },
40+
{ input: 2000, output: 2700 },
41+
{ input: 2100, output: 2800 },
42+
{ input: 2200, output: 2900 },
43+
{ input: 2300, output: 3000 },
44+
{ input: 2400, output: 3100 },
45+
{ input: 2450, output: 3200 },
46+
{ input: 2500, output: 3300 },
47+
{ input: 2600, output: 3400 },
48+
{ input: 2700, output: 3500 },
49+
{ input: 2800, output: 3600 },
50+
{ input: 2900, output: 3700 },
51+
{ input: 3000, output: 3800 },
52+
{ input: 3100, output: 3900 },
53+
{ input: 3200, output: 4000 },
54+
] as const,
1055
};

src/utils/configUser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const initialConfig: ConfigType = {
5454
useAutoFilterRegex: false,
5555
filterRegex: {
5656
include: ['^.*$'],
57-
exclude: ['^.*\\.mp3$', '^.*(SE|SE|効果音)(な|無)し.*$'],
57+
exclude: ['^.*\\.mp3$', '^.*((SE|SE|se|se|効果音)(な|無)し|noSE).*$'],
5858
},
5959
},
6060
media: {

src/utils/download.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ async function downloadWork(
286286
};
287287

288288
while (retriedCount <= appConfig.network.retryCount) {
289+
// Ensure the file is deleted before attempting to download
290+
try {
291+
await fs.promises.unlink(outFilePath);
292+
} catch (e: any) {
293+
// if (e.code !== 'ENOENT') logger.warn(`Could not delete incomplete file: ${outFilePath}`);
294+
}
289295
const abortController = new AbortController();
290296
let timeoutTimer: NodeJS.Timeout | null = null;
291297
let lastNonZeroRateTime = Date.now();
@@ -320,7 +326,7 @@ async function downloadWork(
320326
await stream.promises.pipeline(
321327
stream.Readable.fromWeb(response.body as any),
322328
progressStream,
323-
fs.createWriteStream(outFilePath, { flags: 'wx' }),
329+
fs.createWriteStream(outFilePath),
324330
{ signal: abortController.signal },
325331
);
326332
progBarUpdateFunc(fileEntry.size);
@@ -332,9 +338,12 @@ async function downloadWork(
332338
if (timeoutTimer) clearInterval(timeoutTimer);
333339
timeoutTimer = null;
334340

341+
// Attempt to clean up the partially downloaded file
335342
try {
336343
await fs.promises.unlink(outFilePath);
337-
} catch (_e) {}
344+
} catch (e: any) {
345+
// if (e.code !== 'ENOENT') logger.warn(`Could not delete incomplete file on error: ${outFilePath}`);
346+
}
338347

339348
retriedCount++;
340349
if (retriedCount > appConfig.network.retryCount) {

src/utils/termPretty.ts

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as wakachigaki from 'wakachigaki';
88
import * as TypesApiEndpoint from '../types/ApiEndpoint.js';
99
import * as TypesApiFiles from '../types/ApiFiles.js';
1010
import appConfig from './config.js';
11+
import configReadOnly from './configReadOnly.js';
1112
import mathUtils from './math.js';
1213
import stringUtils from './string.js';
1314

@@ -158,15 +159,43 @@ function printWorkInfo(workApiRsp: {
158159
const availableMaxTextWidth = Math.min(54, process.stdout.columns - 20);
159160

160161
const tmpObj = {
161-
dlCount: workApiRsp.info.dl_count.toLocaleString(),
162-
price: workApiRsp.info.price.toLocaleString(),
163-
totalSales: (workApiRsp.info.price * workApiRsp.info.dl_count).toLocaleString(),
162+
dlCount: workApiRsp.infoOrig.dl_count.toLocaleString(),
163+
price: workApiRsp.infoOrig.price.toLocaleString(),
164+
...(() => {
165+
const outPrice: number = (workApiRsp.infoOrig.price * 100) / (100 + configReadOnly.jpyTax);
166+
const inputPrice: number =
167+
outPrice > configReadOnly.dlsitePriceTable.at(-1)?.output!
168+
? outPrice * 0.8
169+
: configReadOnly.dlsitePriceTable.find((e) => e.output === outPrice)!.input;
170+
const dlsiteFeePrice: number = outPrice - inputPrice;
171+
return {
172+
creatorEarn: (inputPrice * workApiRsp.infoOrig.dl_count).toLocaleString(),
173+
bizEarn: (dlsiteFeePrice * workApiRsp.infoOrig.dl_count).toLocaleString(),
174+
feePcnt: mathUtils.rounder('round', (dlsiteFeePrice / inputPrice) * 100, 1).orig.toString() + '%',
175+
};
176+
})(),
164177
totalSize: mathUtils.formatFileSize(
165178
mathUtils.arrayTotal(workApiRsp.fileEntry.transformed.map((e) => e.size)),
166179
fmtFileSizeDefaultCfg,
167180
),
168181
};
169182

183+
// (() => {
184+
// const table2 = new CliTable3(cliTableConfig.rounded);
185+
// table2.push(
186+
// ['Input', 'Output', 'Fee', 'Fee%'].map((e) => chalk.dim(e)),
187+
// ...configReadOnly.dlsitePriceTable.map((e) =>
188+
// [
189+
// e.input.toLocaleString(),
190+
// e.output.toLocaleString(),
191+
// (e.output - e.input).toLocaleString(),
192+
// mathUtils.rounder('round', ((e.output - e.input) / e.input) * 100, 1).padded + '%',
193+
// ].map((f) => ({ hAlign: 'right' as const, content: f })),
194+
// ),
195+
// );
196+
// console.log(table2.toString());
197+
// })();
198+
170199
table.push(
171200
...[
172201
['ID', workApiRsp.info.source_id],
@@ -200,8 +229,6 @@ function printWorkInfo(workApiRsp: {
200229
availableMaxTextWidth,
201230
).join('\n'),
202231
],
203-
['Release Date', DateTime.fromISO(workApiRsp.info.release).toFormat('yyyy/MM/dd')],
204-
['Created Date', DateTime.fromISO(workApiRsp.info.create_date).toFormat('yyyy/MM/dd')],
205232
[
206233
'Age Category',
207234
stringUtils.replaceMultiPatterns(
@@ -213,11 +240,20 @@ function printWorkInfo(workApiRsp: {
213240
workApiRsp.info.age_category_string,
214241
),
215242
],
243+
['Release Date', DateTime.fromISO(workApiRsp.info.release).toFormat('yyyy/MM/dd')],
244+
['Created Date', DateTime.fromISO(workApiRsp.info.create_date).toFormat('yyyy/MM/dd')],
216245
['DL Count', tmpObj.dlCount.padStart(mathUtils.arrayMax(Object.values(tmpObj).map((e) => e.length)), ' ')],
217246
['Price', tmpObj.price.padStart(mathUtils.arrayMax(Object.values(tmpObj).map((e) => e.length)), ' ') + ' JPY'],
218247
[
219-
'Total Sales',
220-
tmpObj.totalSales.padStart(mathUtils.arrayMax(Object.values(tmpObj).map((e) => e.length)), ' ') + ' JPY',
248+
'Creator Earn',
249+
tmpObj.creatorEarn.padStart(mathUtils.arrayMax(Object.values(tmpObj).map((e) => e.length)), ' ') + ' JPY',
250+
],
251+
[
252+
'DLsite Earn',
253+
tmpObj.bizEarn.padStart(mathUtils.arrayMax(Object.values(tmpObj).map((e) => e.length)), ' ') +
254+
' JPY (' +
255+
tmpObj.feePcnt +
256+
' fee)',
221257
],
222258
[
223259
'Total Size',
@@ -276,10 +312,11 @@ function generateProgBarBox(current: number, total: number, width: number, useSh
276312
const remainingChars = width - usedChars;
277313

278314
// generate empty area (LIGHT SHADE or space)
279-
const emptyChar = useShade ? '\u2591' : ' ';
315+
// const emptyChar = useShade ? '\u2591' : ' ';
316+
const emptyChar = ' ';
280317
bar += emptyChar.repeat(remainingChars);
281318

282-
return bar;
319+
return useShade ? chalk.bgHex('#404040')(bar) : bar;
283320
}
284321

285322
function detectUseFancyProgBarBox(): Record<'fancy' | 'shade', boolean> {

0 commit comments

Comments
 (0)