197 lines
5.2 KiB
JavaScript
197 lines
5.2 KiB
JavaScript
const { _electron: electron } = require('playwright');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const APPDATA_DIR = path.join(process.env.PROGRAMDATA || 'C:\\ProgramData', 'Twitch_VOD_Manager');
|
|
const CONFIG_FILE = path.join(APPDATA_DIR, 'config.json');
|
|
|
|
const DEFAULT_CONFIG = {
|
|
client_id: '',
|
|
client_secret: '',
|
|
download_path: path.join(process.env.USERPROFILE || 'C:\\Users\\ploet', 'Desktop', 'Twitch_VODs'),
|
|
streamers: [],
|
|
theme: 'twitch',
|
|
download_mode: 'full',
|
|
part_minutes: 120,
|
|
language: 'en',
|
|
filename_template_vod: '{title}.mp4',
|
|
filename_template_parts: '{date}_Part{part_padded}.mp4',
|
|
filename_template_clip: '{date}_{part}.mp4',
|
|
smart_queue_scheduler: true,
|
|
performance_mode: 'balanced',
|
|
prevent_duplicate_downloads: true,
|
|
metadata_cache_minutes: 10
|
|
};
|
|
|
|
function backupFile(filePath) {
|
|
if (!fs.existsSync(filePath)) return null;
|
|
return fs.readFileSync(filePath);
|
|
}
|
|
|
|
function restoreFile(filePath, backup) {
|
|
if (backup === null) {
|
|
if (fs.existsSync(filePath)) {
|
|
fs.rmSync(filePath, { force: true });
|
|
}
|
|
return;
|
|
}
|
|
|
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
fs.writeFileSync(filePath, backup);
|
|
}
|
|
|
|
function writeConfig(config) {
|
|
fs.mkdirSync(path.dirname(CONFIG_FILE), { recursive: true });
|
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
}
|
|
|
|
function readConfig() {
|
|
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
}
|
|
|
|
async function launchApp() {
|
|
const electronPath = require('electron');
|
|
return electron.launch({
|
|
executablePath: electronPath,
|
|
args: ['.'],
|
|
cwd: process.cwd()
|
|
});
|
|
}
|
|
|
|
async function setSettingsAndBlur(win, mode, partMinutes) {
|
|
await win.evaluate(async ({ mode, partMinutes }) => {
|
|
window.showTab('settings');
|
|
const modeField = document.getElementById('downloadMode');
|
|
const partField = document.getElementById('partMinutes');
|
|
|
|
modeField.value = mode;
|
|
modeField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
|
|
partField.focus();
|
|
partField.value = String(partMinutes);
|
|
partField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
partField.blur();
|
|
|
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
}, { mode, partMinutes });
|
|
}
|
|
|
|
async function setSettingsAndCloseImmediately(win, mode, partMinutes) {
|
|
await win.evaluate(({ mode, partMinutes }) => {
|
|
window.showTab('settings');
|
|
const modeField = document.getElementById('downloadMode');
|
|
const partField = document.getElementById('partMinutes');
|
|
|
|
modeField.value = mode;
|
|
modeField.dispatchEvent(new Event('change', { bubbles: true }));
|
|
|
|
partField.focus();
|
|
partField.value = String(partMinutes);
|
|
partField.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}, { mode, partMinutes });
|
|
}
|
|
|
|
async function readSettingsFromUi(win) {
|
|
return win.evaluate(() => {
|
|
window.showTab('settings');
|
|
return {
|
|
downloadMode: document.getElementById('downloadMode')?.value || '',
|
|
partMinutes: document.getElementById('partMinutes')?.value || ''
|
|
};
|
|
});
|
|
}
|
|
|
|
async function run() {
|
|
const configBackup = backupFile(CONFIG_FILE);
|
|
const baseConfig = configBackup ? { ...DEFAULT_CONFIG, ...JSON.parse(String(configBackup)) } : { ...DEFAULT_CONFIG };
|
|
|
|
let app = null;
|
|
try {
|
|
writeConfig({
|
|
...baseConfig,
|
|
client_id: '',
|
|
client_secret: '',
|
|
download_mode: 'full',
|
|
part_minutes: 120
|
|
});
|
|
|
|
app = await launchApp();
|
|
let win = await app.firstWindow();
|
|
await win.waitForTimeout(2200);
|
|
await setSettingsAndBlur(win, 'parts', 60);
|
|
await app.close();
|
|
app = null;
|
|
|
|
const afterBlurClose = readConfig();
|
|
|
|
app = await launchApp();
|
|
win = await app.firstWindow();
|
|
await win.waitForTimeout(2200);
|
|
const reopenedAfterBlur = await readSettingsFromUi(win);
|
|
await app.close();
|
|
app = null;
|
|
|
|
writeConfig({
|
|
...baseConfig,
|
|
client_id: '',
|
|
client_secret: '',
|
|
download_mode: 'full',
|
|
part_minutes: 120
|
|
});
|
|
|
|
app = await launchApp();
|
|
win = await app.firstWindow();
|
|
await win.waitForTimeout(2200);
|
|
await setSettingsAndCloseImmediately(win, 'parts', 75);
|
|
await app.close();
|
|
app = null;
|
|
|
|
const afterDirectClose = readConfig();
|
|
|
|
const result = {
|
|
afterBlurClose: {
|
|
config: {
|
|
download_mode: afterBlurClose.download_mode,
|
|
part_minutes: afterBlurClose.part_minutes
|
|
},
|
|
ui: reopenedAfterBlur
|
|
},
|
|
afterDirectClose: {
|
|
config: {
|
|
download_mode: afterDirectClose.download_mode,
|
|
part_minutes: afterDirectClose.part_minutes
|
|
}
|
|
}
|
|
};
|
|
|
|
console.log(JSON.stringify(result, null, 2));
|
|
|
|
const blurCaseOk =
|
|
afterBlurClose.download_mode === 'parts' &&
|
|
afterBlurClose.part_minutes === 60 &&
|
|
reopenedAfterBlur.downloadMode === 'parts' &&
|
|
reopenedAfterBlur.partMinutes === '60';
|
|
|
|
const directCloseOk =
|
|
afterDirectClose.download_mode === 'parts' &&
|
|
afterDirectClose.part_minutes === 75;
|
|
|
|
process.exit(blurCaseOk && directCloseOk ? 0 : 1);
|
|
} finally {
|
|
if (app) {
|
|
try {
|
|
await app.close();
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
restoreFile(CONFIG_FILE, configBackup);
|
|
}
|
|
}
|
|
|
|
run().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|