diff --git a/package.json b/package.json index 800ab87..bbb6bf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "streamyx", - "version": "3.6.31", + "version": "3.6.32", "author": "Vitaly Gashkov ", "description": "Command-line video downloader", "main": "dist/streamyx.js", diff --git a/packages/wive b/packages/wive index be9d5cf..46ee48b 160000 --- a/packages/wive +++ b/packages/wive @@ -1 +1 @@ -Subproject commit be9d5cf7dffca6e38dcb29cde3a08a67e499fd18 +Subproject commit 46ee48bb8c6876cb9ae0780fbef74d00c5649758 diff --git a/packages/wivenative b/packages/wivenative index 2d78612..0267163 160000 --- a/packages/wivenative +++ b/packages/wivenative @@ -1 +1 @@ -Subproject commit 2d786121b93ba0b19cb67e4cad31c0f950a82b30 +Subproject commit 02671632985e6170bc95a78809216b0ba76d099e diff --git a/src/browser.ts b/src/browser.ts index ead50cc..09b40e6 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -27,7 +27,7 @@ export const launchBrowser = async (options: BrowserLaunchArgumentOptions = {}) page = (await browser?.newPage()) ?? null; } catch (e) { logger.error((e as Error).message); - executablePath = await prompt('Enter valid Chrome executable path'); + executablePath = await prompt.waitForInput('Enter valid Chrome executable path'); } } if (executablePath !== chromePath) saveSettings({ chromePath: executablePath }); diff --git a/src/providers b/src/providers index 04a8598..18b6911 160000 --- a/src/providers +++ b/src/providers @@ -1 +1 @@ -Subproject commit 04a8598a4339cd4addc81584121b1c3d247ab8b0 +Subproject commit 18b6911222d44c73595feb488679da581c3085d0 diff --git a/src/utils.ts b/src/utils.ts index a03f964..3244e89 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,17 +2,54 @@ import { createInterface } from 'node:readline/promises'; import { stdin, stdout } from 'node:process'; import { delimiter, join } from 'node:path'; import { stat } from 'node:fs/promises'; +import EventEmitter from 'node:events'; -const prompt = async (message: string, type = 'input') => { - const readline = createInterface({ input: stdin, output: stdout }); - const question = { message, type }; - const isBooleanQuestion = question.type === 'confirm'; - const formattedMessage = question.message + (isBooleanQuestion ? ' (y/n)' : '') + ': '; - const answer = await readline.question(formattedMessage); - const result = isBooleanQuestion ? answer === 'y' : answer.trim(); - readline.close(); - return result as T; -}; +type PromptType = 'input' | 'confirm'; +type PromptAnswer = T extends 'input' ? string : T extends 'confirm' ? boolean : never; + +class Prompt extends EventEmitter { + constructor() { + super(); + } + + async waitForInput( + message: string, + type?: T + ): Promise> { + const hasPromptListener = !!this.listeners('prompt').length; + const answer = hasPromptListener + ? await this.waitForListenerResponse(message, type) + : await this.waitForCliResponse(message, type); + if (type === 'confirm') { + if (typeof answer === 'string') + return (answer?.toLowerCase() === 'y') as PromptAnswer; + else return !!answer as PromptAnswer; + } else { + return String(answer).trim() as PromptAnswer; + } + } + + private async waitForCliResponse(message: string, type: PromptType = 'input') { + const readline = createInterface({ input: stdin, output: stdout }); + const question = { message, type }; + const isBooleanQuestion = question.type === 'confirm'; + const formattedMessage = question.message + (isBooleanQuestion ? ' (y/n)' : '') + ': '; + const answer = await readline.question(formattedMessage); + readline.close(); + return answer; + } + + private async waitForListenerResponse(message: string, type: PromptType = 'input') { + return new Promise((resolve) => { + this.emit('prompt', message, type); + this.addListener('prompt:response', (response) => { + resolve(response); + }); + }); + } +} + +export const prompt = new Prompt(); const sleep = async (seconds: number) => new Promise((resolve) => setTimeout(resolve, seconds * 1000)); @@ -94,10 +131,10 @@ const validateUrl = async (url: string) => { const urlObject = new URL(currentUrl); isValid = !!urlObject; } else { - currentUrl = await prompt('URL'); + currentUrl = await prompt.waitForInput('URL'); } } catch (e) { - currentUrl = await prompt('URL'); + currentUrl = await prompt.waitForInput('URL'); } } while (!isValid); return currentUrl; @@ -106,7 +143,6 @@ const validateUrl = async (url: string) => { const parseMainDomain = (url: string) => new URL(url).host.split('.').at(-2) || null; export { - prompt, sleep, bold, parseNumberRange,