Add GUI States
This adds states for the GUI that get saved to a file, notably this means that queue's of services are no longer lost when changing services, or closing and reopening the program. Also changed was a few spelling fixes
This commit is contained in:
parent
f7ddaf1176
commit
c3dab33f6b
12 changed files with 93 additions and 53 deletions
15
@types/messageHandler.d.ts
vendored
15
@types/messageHandler.d.ts
vendored
|
|
@ -4,6 +4,7 @@ import type { AvailableMuxer } from '../modules/module.args';
|
||||||
import { LanguageItem } from '../modules/module.langsData';
|
import { LanguageItem } from '../modules/module.langsData';
|
||||||
|
|
||||||
export interface MessageHandler {
|
export interface MessageHandler {
|
||||||
|
name: string
|
||||||
auth: (data: AuthData) => Promise<AuthResponse>;
|
auth: (data: AuthData) => Promise<AuthResponse>;
|
||||||
checkToken: () => Promise<CheckTokenResponse>;
|
checkToken: () => Promise<CheckTokenResponse>;
|
||||||
search: (data: SearchData) => Promise<SearchResponse>,
|
search: (data: SearchData) => Promise<SearchResponse>,
|
||||||
|
|
@ -21,8 +22,7 @@ export interface MessageHandler {
|
||||||
removeFromQueue: (index: number) => void,
|
removeFromQueue: (index: number) => void,
|
||||||
clearQueue: () => void,
|
clearQueue: () => void,
|
||||||
setDownloadQueue: (data: boolean) => void,
|
setDownloadQueue: (data: boolean) => void,
|
||||||
getDownloadQueue: () => Promise<boolean>,
|
getDownloadQueue: () => Promise<boolean>
|
||||||
name: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FolderTypes = 'content' | 'config';
|
export type FolderTypes = 'content' | 'config';
|
||||||
|
|
@ -131,7 +131,7 @@ export type ProgressData = {
|
||||||
bytes: number
|
bytes: number
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PossibleMessanges = keyof ServiceHandler;
|
export type PossibleMessages = keyof ServiceHandler;
|
||||||
|
|
||||||
export type DownloadInfo = {
|
export type DownloadInfo = {
|
||||||
image: string,
|
image: string,
|
||||||
|
|
@ -146,4 +146,13 @@ export type DownloadInfo = {
|
||||||
export type ExtendedProgress = {
|
export type ExtendedProgress = {
|
||||||
progress: ProgressData,
|
progress: ProgressData,
|
||||||
downloadInfo: DownloadInfo
|
downloadInfo: DownloadInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GuiState = {
|
||||||
|
setup: Boolean,
|
||||||
|
services: Record<string, GuiStateService>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GuiStateService = {
|
||||||
|
queue: QueueItem[]
|
||||||
}
|
}
|
||||||
2
@types/ws.d.ts
vendored
2
@types/ws.d.ts
vendored
|
|
@ -33,7 +33,7 @@ export type MessageTypes = {
|
||||||
'setup': ['funi'|'crunchy'|'hidive'|undefined, undefined],
|
'setup': ['funi'|'crunchy'|'hidive'|undefined, undefined],
|
||||||
'openFile': [[FolderTypes, string], undefined],
|
'openFile': [[FolderTypes, string], undefined],
|
||||||
'openURL': [string, undefined],
|
'openURL': [string, undefined],
|
||||||
'setuped': [undefined, boolean],
|
'isSetup': [undefined, boolean],
|
||||||
'setupServer': [GUIConfig, boolean],
|
'setupServer': [GUIConfig, boolean],
|
||||||
'requirePassword': [undefined, boolean],
|
'requirePassword': [undefined, boolean],
|
||||||
'getQueue': [undefined, QueueItem[]],
|
'getQueue': [undefined, QueueItem[]],
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"setuped": true
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { useSnackbar } from 'notistack';
|
||||||
import { LockOutlined, PowerSettingsNew } from '@mui/icons-material';
|
import { LockOutlined, PowerSettingsNew } from '@mui/icons-material';
|
||||||
import { GUIConfig } from '../../../../modules/module.cfg-loader';
|
import { GUIConfig } from '../../../../modules/module.cfg-loader';
|
||||||
|
|
||||||
export type FrontEndMessanges = (MessageHandler & { randomEvents: RandomEventHandler, logout: () => Promise<boolean> });
|
export type FrontEndMessages = (MessageHandler & { randomEvents: RandomEventHandler, logout: () => Promise<boolean> });
|
||||||
|
|
||||||
export class RandomEventHandler {
|
export class RandomEventHandler {
|
||||||
private handler: {
|
private handler: {
|
||||||
|
|
@ -38,7 +38,7 @@ export class RandomEventHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const messageChannelContext = React.createContext<FrontEndMessanges|undefined>(undefined);
|
export const messageChannelContext = React.createContext<FrontEndMessages|undefined>(undefined);
|
||||||
|
|
||||||
async function messageAndResponse<T extends keyof MessageTypes>(socket: WebSocket, msg: WSMessage<T>): Promise<WSMessage<T, 1>> {
|
async function messageAndResponse<T extends keyof MessageTypes>(socket: WebSocket, msg: WSMessage<T>): Promise<WSMessage<T, 1>> {
|
||||||
const id = v4();
|
const id = v4();
|
||||||
|
|
@ -65,7 +65,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
||||||
const [socket, setSocket] = React.useState<undefined|WebSocket>();
|
const [socket, setSocket] = React.useState<undefined|WebSocket>();
|
||||||
const [publicWS, setPublicWS] = React.useState<undefined|WebSocket>();
|
const [publicWS, setPublicWS] = React.useState<undefined|WebSocket>();
|
||||||
const [usePassword, setUsePassword] = React.useState<'waiting'|'yes'|'no'>('waiting');
|
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();
|
const { enqueueSnackbar } = useSnackbar();
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
||||||
if (!publicWS)
|
if (!publicWS)
|
||||||
return;
|
return;
|
||||||
setUsePassword((await messageAndResponse(publicWS, { name: 'requirePassword', data: undefined })).data ? 'yes' : 'no');
|
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]);
|
}, [publicWS]);
|
||||||
|
|
||||||
|
|
@ -190,7 +190,7 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
||||||
</Box>;
|
</Box>;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSetuped === 'no') {
|
if (isSetup === 'no') {
|
||||||
return <Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
return <Box sx={{ mt: 3, display: 'flex', flexDirection: 'column', justifyItems: 'center', alignItems: 'center' }}>
|
||||||
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
||||||
<PowerSettingsNew />
|
<PowerSettingsNew />
|
||||||
|
|
@ -211,7 +211,8 @@ const MessageChannelProvider: FCWithChildren = ({ children }) => {
|
||||||
</Box>;
|
</Box>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messageHandler: FrontEndMessanges = {
|
const messageHandler: FrontEndMessages = {
|
||||||
|
name: "default",
|
||||||
auth: async (data) => (await messageAndResponse(socket, { name: 'auth', data })).data,
|
auth: async (data) => (await messageAndResponse(socket, { name: 'auth', data })).data,
|
||||||
checkToken: async () => (await messageAndResponse(socket, { name: 'checkToken', data: undefined })).data,
|
checkToken: async () => (await messageAndResponse(socket, { name: 'checkToken', data: undefined })).data,
|
||||||
search: async (data) => (await messageAndResponse(socket, { name: 'search', data })).data,
|
search: async (data) => (await messageAndResponse(socket, { name: 'search', data })).data,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { ServerResponse } from 'http';
|
import { ServerResponse } from 'http';
|
||||||
import { Server } from 'http';
|
import { Server } from 'http';
|
||||||
import { IncomingMessage } from 'http';
|
import { IncomingMessage } from 'http';
|
||||||
import { MessageHandler } from '../../@types/messageHandler';
|
import { MessageHandler, GuiState } from '../../@types/messageHandler';
|
||||||
import { setSetuped, writeYamlCfgFile } from '../../modules/module.cfg-loader';
|
import { setState, getState, writeYamlCfgFile } from '../../modules/module.cfg-loader';
|
||||||
import CrunchyHandler from './services/crunchyroll';
|
import CrunchyHandler from './services/crunchyroll';
|
||||||
import FunimationHandler from './services/funimation';
|
import FunimationHandler from './services/funimation';
|
||||||
import HidiveHandler from './services/hidive';
|
import HidiveHandler from './services/hidive';
|
||||||
|
|
@ -12,16 +12,19 @@ export default class ServiceHandler {
|
||||||
|
|
||||||
private service: MessageHandler|undefined = undefined;
|
private service: MessageHandler|undefined = undefined;
|
||||||
private ws: WebSocketHandler;
|
private ws: WebSocketHandler;
|
||||||
|
private state: GuiState;
|
||||||
|
|
||||||
constructor(server: Server<typeof IncomingMessage, typeof ServerResponse>) {
|
constructor(server: Server<typeof IncomingMessage, typeof ServerResponse>) {
|
||||||
this.ws = new WebSocketHandler(server);
|
this.ws = new WebSocketHandler(server);
|
||||||
this.handleMessanges();
|
this.handleMessages();
|
||||||
|
this.state = getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleMessanges() {
|
private handleMessages() {
|
||||||
this.ws.events.on('setupServer', ({ data }, respond) => {
|
this.ws.events.on('setupServer', ({ data }, respond) => {
|
||||||
writeYamlCfgFile('gui', data);
|
writeYamlCfgFile('gui', data);
|
||||||
setSetuped(true);
|
this.state.setup = true;
|
||||||
|
setState(this.state);
|
||||||
respond(true);
|
respond(true);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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 { RandomEvent, RandomEvents } from '../../../@types/randomEvents';
|
||||||
import WebSocketHandler from '../websocket';
|
import WebSocketHandler from '../websocket';
|
||||||
import open from 'open';
|
import open from 'open';
|
||||||
import { cfg } from '..';
|
import { cfg } from '..';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { console } from '../../../modules/log';
|
import { console } from '../../../modules/log';
|
||||||
|
import { getState, setState } from '../../../modules/module.cfg-loader';
|
||||||
|
|
||||||
export default class Base {
|
export default class Base {
|
||||||
|
private state: GuiState;
|
||||||
constructor(private ws: WebSocketHandler) {}
|
public name = 'default';
|
||||||
|
constructor(private ws: WebSocketHandler) {
|
||||||
|
this.state = getState();
|
||||||
|
}
|
||||||
|
|
||||||
private downloading = false;
|
private downloading = false;
|
||||||
|
|
||||||
private queue: QueueItem[] = [];
|
private queue: QueueItem[] = [];
|
||||||
private workOnQueue = false;
|
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) {
|
setDownloading(downloading: boolean) {
|
||||||
this.downloading = downloading;
|
this.downloading = downloading;
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +124,8 @@ export default class Base {
|
||||||
this.queue = this.queue.slice(1);
|
this.queue = this.queue.slice(1);
|
||||||
this.queueChange();
|
this.queueChange();
|
||||||
}
|
}
|
||||||
|
this.state.services[this.name].queue = this.queue;
|
||||||
|
setState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onFinish() {
|
public async onFinish() {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class CrunchyHandler extends Base implements MessageHandler {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.crunchy = new Crunchy();
|
this.crunchy = new Crunchy();
|
||||||
this.crunchy.refreshToken();
|
this.crunchy.refreshToken();
|
||||||
|
this.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes (id: string): Promise<EpisodeListResponse> {
|
public async listEpisodes (id: string): Promise<EpisodeListResponse> {
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ class FunimationHandler extends Base implements MessageHandler {
|
||||||
constructor(ws: WebSocketHandler) {
|
constructor(ws: WebSocketHandler) {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.funi = new Funimation();
|
this.funi = new Funimation();
|
||||||
|
this.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listEpisodes (id: string) : Promise<EpisodeListResponse> {
|
public async listEpisodes (id: string) : Promise<EpisodeListResponse> {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ class HidiveHandler extends Base implements MessageHandler {
|
||||||
super(ws);
|
super(ws);
|
||||||
this.hidive = new Hidive();
|
this.hidive = new Hidive();
|
||||||
this.hidive.doInit();
|
this.hidive.doInit();
|
||||||
|
this.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public auth(data: AuthData) {
|
public auth(data: AuthData) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { RandomEvent, RandomEvents } from '../../@types/randomEvents';
|
||||||
import { MessageTypes, UnknownWSMessage, WSMessage } from '../../@types/ws';
|
import { MessageTypes, UnknownWSMessage, WSMessage } from '../../@types/ws';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { cfg } from '.';
|
import { cfg } from '.';
|
||||||
import { isSetuped } from '../../modules/module.cfg-loader';
|
import { getState } from '../../modules/module.cfg-loader';
|
||||||
import { console } from '../../modules/log';
|
import { console } from '../../modules/log';
|
||||||
|
|
||||||
declare interface ExternalEvent {
|
declare interface ExternalEvent {
|
||||||
|
|
@ -81,6 +81,7 @@ export default class WebSocketHandler {
|
||||||
export class PublicWebSocket {
|
export class PublicWebSocket {
|
||||||
private wsServer: ws.Server;
|
private wsServer: ws.Server;
|
||||||
|
|
||||||
|
private state = getState();
|
||||||
constructor(server: Server) {
|
constructor(server: Server) {
|
||||||
this.wsServer = new ws.WebSocketServer({ noServer: true, path: '/public' });
|
this.wsServer = new ws.WebSocketServer({ noServer: true, path: '/public' });
|
||||||
|
|
||||||
|
|
@ -90,8 +91,8 @@ export class PublicWebSocket {
|
||||||
socket.on('message', (msg) => {
|
socket.on('message', (msg) => {
|
||||||
const data = JSON.parse(msg.toString()) as UnknownWSMessage;
|
const data = JSON.parse(msg.toString()) as UnknownWSMessage;
|
||||||
switch (data.name) {
|
switch (data.name) {
|
||||||
case 'setuped':
|
case 'isSetup':
|
||||||
this.send(socket, data.id, data.name, isSetuped());
|
this.send(socket, data.id, data.name, this.state.setup);
|
||||||
break;
|
break;
|
||||||
case 'requirePassword':
|
case 'requirePassword':
|
||||||
this.send(socket, data.id, data.name, cfg.gui.password !== undefined);
|
this.send(socket, data.id, data.name, cfg.gui.password !== undefined);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import yaml from 'yaml';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { lookpath } from 'lookpath';
|
import { lookpath } from 'lookpath';
|
||||||
import { console } from './log';
|
import { console } from './log';
|
||||||
|
import { GuiState } from '../@types/messageHandler';
|
||||||
|
|
||||||
// new-cfg
|
// new-cfg
|
||||||
const workingDir = (process as NodeJS.Process & {
|
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 dirCfgFile = path.join(workingDir, 'config', 'dir-path');
|
||||||
const guiCfgFile = path.join(workingDir, 'config', 'gui');
|
const guiCfgFile = path.join(workingDir, 'config', 'gui');
|
||||||
const cliCfgFile = path.join(workingDir, 'config', 'cli-defaults');
|
const cliCfgFile = path.join(workingDir, 'config', 'cli-defaults');
|
||||||
const hdProfileCfgFile = path.join(workingDir, 'config', 'hd_profile');
|
const hdPflCfgFile = path.join(workingDir, 'config', 'hd_profile');
|
||||||
const sessCfgFile = {
|
const sessCfgFile = {
|
||||||
funi: path.join(workingDir, 'config', 'funi_sess'),
|
funi: path.join(workingDir, 'config', 'funi_sess'),
|
||||||
cr: path.join(workingDir, 'config', 'cr_sess'),
|
cr: path.join(workingDir, 'config', 'cr_sess'),
|
||||||
hd: path.join(workingDir, 'config', 'hd_sess')
|
hd: path.join(workingDir, 'config', 'hd_sess')
|
||||||
};
|
};
|
||||||
const setupFile = path.join(workingDir, 'config', 'setup');
|
const stateFile = path.join(workingDir, 'config', 'guistate');
|
||||||
const tokenFile = {
|
const tokenFile = {
|
||||||
funi: path.join(workingDir, 'config', 'funi_token'),
|
funi: path.join(workingDir, 'config', 'funi_token'),
|
||||||
cr: path.join(workingDir, 'config', 'cr_token'),
|
cr: path.join(workingDir, 'config', 'cr_token'),
|
||||||
hd: path.join(workingDir, 'config', 'hd_token')
|
hd: path.join(workingDir, 'config', 'hd_token')
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ensureConfig = () => {
|
export const ensureConfig = () => {
|
||||||
|
|
@ -256,10 +257,10 @@ const saveHDToken = (data: Record<string, unknown>) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveHDProfile = (data: Record<string, unknown>) => {
|
const saveHDProfile = (data: Record<string, unknown>) => {
|
||||||
const cfgFolder = path.dirname(hdProfileCfgFile);
|
const cfgFolder = path.dirname(hdPflCfgFile);
|
||||||
try{
|
try{
|
||||||
fs.ensureDirSync(cfgFolder);
|
fs.ensureDirSync(cfgFolder);
|
||||||
fs.writeFileSync(`${hdProfileCfgFile}.yml`, yaml.stringify(data));
|
fs.writeFileSync(`${hdPflCfgFile}.yml`, yaml.stringify(data));
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
console.error('Can\'t save profile file to disk!');
|
console.error('Can\'t save profile file to disk!');
|
||||||
|
|
@ -267,7 +268,7 @@ const saveHDProfile = (data: Record<string, unknown>) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadHDProfile = () => {
|
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){
|
if(typeof profile !== 'object' || profile === null || Array.isArray(profile) || Object.keys(profile).length === 0){
|
||||||
profile = {
|
profile = {
|
||||||
// base
|
// base
|
||||||
|
|
@ -316,23 +317,31 @@ const saveFuniToken = (data: {
|
||||||
|
|
||||||
const cfgDir = path.join(workingDir, 'config');
|
const cfgDir = path.join(workingDir, 'config');
|
||||||
|
|
||||||
const isSetuped = (): boolean => {
|
const getState = (): GuiState => {
|
||||||
const fn = `${setupFile}.json`;
|
const fn = `${stateFile}.json`;
|
||||||
if (!fs.existsSync(fn))
|
if (!fs.existsSync(fn)) {
|
||||||
return false;
|
return {
|
||||||
return JSON.parse(fs.readFileSync(fn).toString()).setuped;
|
"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 setState = (state: GuiState) => {
|
||||||
const fn = `${setupFile}.json`;
|
const fn = `${stateFile}.json`;
|
||||||
if (bool) {
|
try {
|
||||||
fs.writeFileSync(fn, JSON.stringify({
|
fs.writeFileSync(fn, JSON.stringify(state, null, 2));
|
||||||
setuped: true
|
} catch(e) {
|
||||||
}, null, 2));
|
console.error('Failed to write state file.');
|
||||||
} else {
|
|
||||||
if (fs.existsSync(fn)) {
|
|
||||||
fs.removeSync(fn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -352,10 +361,10 @@ export {
|
||||||
loadHDToken,
|
loadHDToken,
|
||||||
saveHDProfile,
|
saveHDProfile,
|
||||||
loadHDProfile,
|
loadHDProfile,
|
||||||
isSetuped,
|
getState,
|
||||||
setSetuped,
|
setState,
|
||||||
writeYamlCfgFile,
|
writeYamlCfgFile,
|
||||||
sessCfgFile,
|
sessCfgFile,
|
||||||
hdProfileCfgFile,
|
hdPflCfgFile,
|
||||||
cfgDir
|
cfgDir
|
||||||
};
|
};
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "multi-downloader-nx",
|
"name": "multi-downloader-nx",
|
||||||
"short_name": "aniDL",
|
"short_name": "aniDL",
|
||||||
"version": "4.2.1b1",
|
"version": "4.3.0b1",
|
||||||
"description": "Download videos from Funimation, Crunchyroll, or Hidive via cli",
|
"description": "Download videos from Funimation, Crunchyroll, or Hidive via cli",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"download",
|
"download",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue