diff --git a/@types/messageHandler.d.ts b/@types/messageHandler.d.ts index eaec70c..1a7dab1 100644 --- a/@types/messageHandler.d.ts +++ b/@types/messageHandler.d.ts @@ -4,6 +4,7 @@ import type { AvailableMuxer } from '../modules/module.args'; import { LanguageItem } from '../modules/module.langsData'; export interface MessageHandler { + name: string auth: (data: AuthData) => Promise; checkToken: () => Promise; search: (data: SearchData) => Promise, @@ -21,8 +22,7 @@ export interface MessageHandler { removeFromQueue: (index: number) => void, clearQueue: () => void, setDownloadQueue: (data: boolean) => void, - getDownloadQueue: () => Promise, - name: string + getDownloadQueue: () => Promise } export type FolderTypes = 'content' | 'config'; @@ -131,7 +131,7 @@ export type ProgressData = { bytes: number }; -export type PossibleMessanges = keyof ServiceHandler; +export type PossibleMessages = keyof ServiceHandler; export type DownloadInfo = { image: string, @@ -146,4 +146,13 @@ export type DownloadInfo = { export type ExtendedProgress = { progress: ProgressData, downloadInfo: DownloadInfo +} + +export type GuiState = { + setup: Boolean, + services: Record +} + +export type GuiStateService = { + queue: QueueItem[] } \ No newline at end of file diff --git a/@types/ws.d.ts b/@types/ws.d.ts index 68fe557..01887fa 100644 --- a/@types/ws.d.ts +++ b/@types/ws.d.ts @@ -33,7 +33,7 @@ export type MessageTypes = { 'setup': ['funi'|'crunchy'|'hidive'|undefined, undefined], 'openFile': [[FolderTypes, string], undefined], 'openURL': [string, undefined], - 'setuped': [undefined, boolean], + 'isSetup': [undefined, boolean], 'setupServer': [GUIConfig, boolean], 'requirePassword': [undefined, boolean], 'getQueue': [undefined, QueueItem[]], diff --git a/config/setup.json b/config/setup.json deleted file mode 100644 index 4ffe8a0..0000000 --- a/config/setup.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "setuped": true -} \ No newline at end of file diff --git a/gui/react/src/provider/MessageChannel.tsx b/gui/react/src/provider/MessageChannel.tsx index 3626f26..aa6da47 100644 --- a/gui/react/src/provider/MessageChannel.tsx +++ b/gui/react/src/provider/MessageChannel.tsx @@ -9,7 +9,7 @@ import { useSnackbar } from 'notistack'; import { LockOutlined, PowerSettingsNew } from '@mui/icons-material'; import { GUIConfig } from '../../../../modules/module.cfg-loader'; -export type FrontEndMessanges = (MessageHandler & { randomEvents: RandomEventHandler, logout: () => Promise }); +export type FrontEndMessages = (MessageHandler & { randomEvents: RandomEventHandler, logout: () => Promise }); export class RandomEventHandler { private handler: { @@ -38,7 +38,7 @@ export class RandomEventHandler { } } -export const messageChannelContext = React.createContext(undefined); +export const messageChannelContext = React.createContext(undefined); async function messageAndResponse(socket: WebSocket, msg: WSMessage): Promise> { const id = v4(); @@ -65,7 +65,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => { const [socket, setSocket] = React.useState(); const [publicWS, setPublicWS] = React.useState(); const [usePassword, setUsePassword] = React.useState<'waiting'|'yes'|'no'>('waiting'); - const [isSetuped, setIsSetuped] = React.useState<'waiting'|'yes'|'no'>('waiting'); + const [isSetup, setIsSetup] = React.useState<'waiting'|'yes'|'no'>('waiting'); const { enqueueSnackbar } = useSnackbar(); @@ -84,7 +84,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => { if (!publicWS) return; setUsePassword((await messageAndResponse(publicWS, { name: 'requirePassword', data: undefined })).data ? 'yes' : 'no'); - setIsSetuped((await messageAndResponse(publicWS, { name: 'setuped', data: undefined })).data ? 'yes' : 'no'); + setIsSetup((await messageAndResponse(publicWS, { name: 'isSetup', data: undefined })).data ? 'yes' : 'no'); })(); }, [publicWS]); @@ -190,7 +190,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => { ; } - if (isSetuped === 'no') { + if (isSetup === 'no') { return @@ -211,7 +211,8 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => { ; } - const messageHandler: FrontEndMessanges = { + const messageHandler: FrontEndMessages = { + name: "default", auth: async (data) => (await messageAndResponse(socket, { name: 'auth', data })).data, checkToken: async () => (await messageAndResponse(socket, { name: 'checkToken', data: undefined })).data, search: async (data) => (await messageAndResponse(socket, { name: 'search', data })).data, diff --git a/gui/server/serviceHandler.ts b/gui/server/serviceHandler.ts index 9f4722e..22a96e8 100644 --- a/gui/server/serviceHandler.ts +++ b/gui/server/serviceHandler.ts @@ -1,8 +1,8 @@ import { ServerResponse } from 'http'; import { Server } from 'http'; import { IncomingMessage } from 'http'; -import { MessageHandler } from '../../@types/messageHandler'; -import { setSetuped, writeYamlCfgFile } from '../../modules/module.cfg-loader'; +import { MessageHandler, GuiState } from '../../@types/messageHandler'; +import { setState, getState, writeYamlCfgFile } from '../../modules/module.cfg-loader'; import CrunchyHandler from './services/crunchyroll'; import FunimationHandler from './services/funimation'; import HidiveHandler from './services/hidive'; @@ -12,16 +12,19 @@ export default class ServiceHandler { private service: MessageHandler|undefined = undefined; private ws: WebSocketHandler; + private state: GuiState; constructor(server: Server) { this.ws = new WebSocketHandler(server); - this.handleMessanges(); + this.handleMessages(); + this.state = getState(); } - private handleMessanges() { + private handleMessages() { this.ws.events.on('setupServer', ({ data }, respond) => { writeYamlCfgFile('gui', data); - setSetuped(true); + this.state.setup = true; + setState(this.state); respond(true); process.exit(0); }); diff --git a/gui/server/services/base.ts b/gui/server/services/base.ts index b75b7c8..733dbca 100644 --- a/gui/server/services/base.ts +++ b/gui/server/services/base.ts @@ -1,20 +1,35 @@ -import { DownloadInfo, FolderTypes, ProgressData, QueueItem } from '../../../@types/messageHandler'; +import { DownloadInfo, FolderTypes, GuiState, ProgressData, QueueItem } from '../../../@types/messageHandler'; import { RandomEvent, RandomEvents } from '../../../@types/randomEvents'; import WebSocketHandler from '../websocket'; import open from 'open'; import { cfg } from '..'; import path from 'path'; import { console } from '../../../modules/log'; +import { getState, setState } from '../../../modules/module.cfg-loader'; export default class Base { - - constructor(private ws: WebSocketHandler) {} + private state: GuiState; + public name = 'default'; + constructor(private ws: WebSocketHandler) { + this.state = getState(); + } private downloading = false; private queue: QueueItem[] = []; private workOnQueue = false; + initState() { + if (this.state.services[this.name]) { + this.queue = this.state.services[this.name].queue; + this.queueChange(); + } else { + this.state.services[this.name] = { + 'queue': [] + } + } + } + setDownloading(downloading: boolean) { this.downloading = downloading; } @@ -109,6 +124,8 @@ export default class Base { this.queue = this.queue.slice(1); this.queueChange(); } + this.state.services[this.name].queue = this.queue; + setState(this.state); } public async onFinish() { diff --git a/gui/server/services/crunchyroll.ts b/gui/server/services/crunchyroll.ts index 679d92e..9bc2777 100644 --- a/gui/server/services/crunchyroll.ts +++ b/gui/server/services/crunchyroll.ts @@ -14,6 +14,7 @@ class CrunchyHandler extends Base implements MessageHandler { super(ws); this.crunchy = new Crunchy(); this.crunchy.refreshToken(); + this.initState(); } public async listEpisodes (id: string): Promise { diff --git a/gui/server/services/funimation.ts b/gui/server/services/funimation.ts index 39390f1..bee900e 100644 --- a/gui/server/services/funimation.ts +++ b/gui/server/services/funimation.ts @@ -13,6 +13,7 @@ class FunimationHandler extends Base implements MessageHandler { constructor(ws: WebSocketHandler) { super(ws); this.funi = new Funimation(); + this.initState(); } public async listEpisodes (id: string) : Promise { diff --git a/gui/server/services/hidive.ts b/gui/server/services/hidive.ts index 8fc648a..1c7b238 100644 --- a/gui/server/services/hidive.ts +++ b/gui/server/services/hidive.ts @@ -14,6 +14,7 @@ class HidiveHandler extends Base implements MessageHandler { super(ws); this.hidive = new Hidive(); this.hidive.doInit(); + this.initState(); } public auth(data: AuthData) { diff --git a/gui/server/websocket.ts b/gui/server/websocket.ts index 061c5d3..27ff7f3 100644 --- a/gui/server/websocket.ts +++ b/gui/server/websocket.ts @@ -4,7 +4,7 @@ import { RandomEvent, RandomEvents } from '../../@types/randomEvents'; import { MessageTypes, UnknownWSMessage, WSMessage } from '../../@types/ws'; import { EventEmitter } from 'events'; import { cfg } from '.'; -import { isSetuped } from '../../modules/module.cfg-loader'; +import { getState } from '../../modules/module.cfg-loader'; import { console } from '../../modules/log'; declare interface ExternalEvent { @@ -81,6 +81,7 @@ export default class WebSocketHandler { export class PublicWebSocket { private wsServer: ws.Server; + private state = getState(); constructor(server: Server) { this.wsServer = new ws.WebSocketServer({ noServer: true, path: '/public' }); @@ -90,8 +91,8 @@ export class PublicWebSocket { socket.on('message', (msg) => { const data = JSON.parse(msg.toString()) as UnknownWSMessage; switch (data.name) { - case 'setuped': - this.send(socket, data.id, data.name, isSetuped()); + case 'isSetup': + this.send(socket, data.id, data.name, this.state.setup); break; case 'requirePassword': this.send(socket, data.id, data.name, cfg.gui.password !== undefined); diff --git a/modules/module.cfg-loader.ts b/modules/module.cfg-loader.ts index d4adb88..9f2fad6 100644 --- a/modules/module.cfg-loader.ts +++ b/modules/module.cfg-loader.ts @@ -3,6 +3,7 @@ import yaml from 'yaml'; import fs from 'fs-extra'; import { lookpath } from 'lookpath'; import { console } from './log'; +import { GuiState } from '../@types/messageHandler'; // new-cfg const workingDir = (process as NodeJS.Process & { @@ -15,17 +16,17 @@ const binCfgFile = path.join(workingDir, 'config', 'bin-path'); const dirCfgFile = path.join(workingDir, 'config', 'dir-path'); const guiCfgFile = path.join(workingDir, 'config', 'gui'); const cliCfgFile = path.join(workingDir, 'config', 'cli-defaults'); -const hdProfileCfgFile = path.join(workingDir, 'config', 'hd_profile'); -const sessCfgFile = { +const hdPflCfgFile = path.join(workingDir, 'config', 'hd_profile'); +const sessCfgFile = { funi: path.join(workingDir, 'config', 'funi_sess'), - cr: path.join(workingDir, 'config', 'cr_sess'), - hd: path.join(workingDir, 'config', 'hd_sess') + cr: path.join(workingDir, 'config', 'cr_sess'), + hd: path.join(workingDir, 'config', 'hd_sess') }; -const setupFile = path.join(workingDir, 'config', 'setup'); +const stateFile = path.join(workingDir, 'config', 'guistate'); const tokenFile = { funi: path.join(workingDir, 'config', 'funi_token'), - cr: path.join(workingDir, 'config', 'cr_token'), - hd: path.join(workingDir, 'config', 'hd_token') + cr: path.join(workingDir, 'config', 'cr_token'), + hd: path.join(workingDir, 'config', 'hd_token') }; export const ensureConfig = () => { @@ -256,10 +257,10 @@ const saveHDToken = (data: Record) => { }; const saveHDProfile = (data: Record) => { - const cfgFolder = path.dirname(hdProfileCfgFile); + const cfgFolder = path.dirname(hdPflCfgFile); try{ fs.ensureDirSync(cfgFolder); - fs.writeFileSync(`${hdProfileCfgFile}.yml`, yaml.stringify(data)); + fs.writeFileSync(`${hdPflCfgFile}.yml`, yaml.stringify(data)); } catch(e){ console.error('Can\'t save profile file to disk!'); @@ -267,7 +268,7 @@ const saveHDProfile = (data: Record) => { }; const loadHDProfile = () => { - let profile = loadYamlCfgFile(hdProfileCfgFile, true); + let profile = loadYamlCfgFile(hdPflCfgFile, true); if(typeof profile !== 'object' || profile === null || Array.isArray(profile) || Object.keys(profile).length === 0){ profile = { // base @@ -316,23 +317,31 @@ const saveFuniToken = (data: { const cfgDir = path.join(workingDir, 'config'); -const isSetuped = (): boolean => { - const fn = `${setupFile}.json`; - if (!fs.existsSync(fn)) - return false; - return JSON.parse(fs.readFileSync(fn).toString()).setuped; +const getState = (): GuiState => { + const fn = `${stateFile}.json`; + if (!fs.existsSync(fn)) { + return { + "setup": false, + "services": {} + } + } + try { + return JSON.parse(fs.readFileSync(fn).toString()); + } catch(e) { + console.error('Invalid state file, regenerating'); + return { + "setup": false, + "services": {} + } + } }; -const setSetuped = (bool: boolean) => { - const fn = `${setupFile}.json`; - if (bool) { - fs.writeFileSync(fn, JSON.stringify({ - setuped: true - }, null, 2)); - } else { - if (fs.existsSync(fn)) { - fs.removeSync(fn); - } +const setState = (state: GuiState) => { + const fn = `${stateFile}.json`; + try { + fs.writeFileSync(fn, JSON.stringify(state, null, 2)); + } catch(e) { + console.error('Failed to write state file.'); } }; @@ -352,10 +361,10 @@ export { loadHDToken, saveHDProfile, loadHDProfile, - isSetuped, - setSetuped, + getState, + setState, writeYamlCfgFile, sessCfgFile, - hdProfileCfgFile, + hdPflCfgFile, cfgDir }; \ No newline at end of file diff --git a/package.json b/package.json index f419626..3d08470 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "multi-downloader-nx", "short_name": "aniDL", - "version": "4.2.1b1", + "version": "4.3.0b1", "description": "Download videos from Funimation, Crunchyroll, or Hidive via cli", "keywords": [ "download",