219 lines
5 KiB
TypeScript
219 lines
5 KiB
TypeScript
import { proxyRefs, reactive, toRefs } from 'vue';
|
|
import { useStorage } from '@vueuse/core';
|
|
import type { ConfigState } from '~/types/config';
|
|
import type { DLField } from '~/types/dl_fields';
|
|
import type { Preset } from '~/types/presets';
|
|
import type { ConfigFeature, ConfigUpdateAction } from '~/types/sockets';
|
|
import { useQueueState } from '~/composables/useQueueState';
|
|
import { request } from '~/utils';
|
|
|
|
let last_reload = 0;
|
|
const CONFIG_TTL = 10;
|
|
|
|
const state = reactive<ConfigState>({
|
|
showForm: useStorage('showForm', true),
|
|
app: {
|
|
download_path: '/downloads',
|
|
remove_files: false,
|
|
output_template: '',
|
|
ytdlp_version: '',
|
|
max_workers: 20,
|
|
max_workers_per_extractor: 2,
|
|
default_preset: 'default',
|
|
instance_title: null,
|
|
console_enabled: false,
|
|
browser_control_enabled: false,
|
|
file_logging: false,
|
|
is_native: false,
|
|
app_version: '',
|
|
app_commit_sha: '',
|
|
app_build_date: '',
|
|
app_branch: '',
|
|
started: 0,
|
|
app_env: 'production',
|
|
simple_mode: false,
|
|
default_pagination: 50,
|
|
log_level: '',
|
|
runtime_log_level: '',
|
|
check_for_updates: true,
|
|
new_version: '',
|
|
yt_new_version: '',
|
|
},
|
|
presets: [
|
|
{
|
|
name: 'default',
|
|
description: 'Default preset',
|
|
folder: '',
|
|
template: '',
|
|
cookies: '',
|
|
cli: '',
|
|
default: true,
|
|
priority: 0,
|
|
},
|
|
],
|
|
dl_fields: [],
|
|
ytdlp_options: [],
|
|
paused: false,
|
|
is_loaded: false,
|
|
is_loading: false,
|
|
});
|
|
|
|
const loadConfig = async (force: boolean = false) => {
|
|
if (state.is_loading) {
|
|
return;
|
|
}
|
|
const now = Date.now();
|
|
|
|
if (state.is_loaded && !force && last_reload > 0) {
|
|
const age = (now - last_reload) / 1000;
|
|
if (age < CONFIG_TTL) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
state.is_loaded = false;
|
|
state.is_loading = true;
|
|
try {
|
|
const resp = await request('/api/system/configuration', { timeout: 10 });
|
|
if (!resp.ok) {
|
|
return;
|
|
}
|
|
const data = await resp.json();
|
|
const queueState = useQueueState();
|
|
|
|
if ('number' === typeof data.history_count) {
|
|
delete data.history_count;
|
|
}
|
|
|
|
if (data.queue) {
|
|
queueState.addAll(data.queue);
|
|
delete data.queue;
|
|
}
|
|
|
|
setAll(data);
|
|
state.is_loaded = true;
|
|
last_reload = now;
|
|
} catch (e: any) {
|
|
console.error(`Failed to load configuration: ${e}`);
|
|
} finally {
|
|
state.is_loading = false;
|
|
}
|
|
};
|
|
|
|
const add = (key: string, value: any) => {
|
|
if (key.includes('.')) {
|
|
const [parentKey, subKey] = key.split('.') as [keyof ConfigState, string];
|
|
state[parentKey][subKey] = value;
|
|
return;
|
|
}
|
|
(state as any)[key] = value;
|
|
};
|
|
|
|
const get = (key: string, defaultValue: any = null): any => {
|
|
if (key.includes('.')) {
|
|
const [parentKey, subKey] = key.split('.') as [keyof ConfigState, string];
|
|
const parent = state[parentKey] as any;
|
|
return parent?.[subKey] ?? defaultValue;
|
|
}
|
|
return (state as any)[key] ?? defaultValue;
|
|
};
|
|
|
|
const isLoaded = () => state.is_loaded;
|
|
|
|
const update = add;
|
|
|
|
const getAll = (): ConfigState => state;
|
|
|
|
const setAll = (data: Record<string, any>) => {
|
|
Object.keys(data).forEach((key) => {
|
|
if (key.includes('.')) {
|
|
const [parentKey, subKey] = key.split('.') as [keyof ConfigState, string];
|
|
const parent = state[parentKey] as any;
|
|
parent[subKey] = data[key];
|
|
return;
|
|
}
|
|
(state as any)[key] = data[key];
|
|
});
|
|
|
|
state.is_loaded = true;
|
|
};
|
|
|
|
const patch = (feature: ConfigFeature, action: ConfigUpdateAction, data: unknown): void => {
|
|
const supportedFeatures: ConfigFeature[] = ['dl_fields', 'presets'];
|
|
|
|
if (!supportedFeatures.includes(feature)) {
|
|
return;
|
|
}
|
|
|
|
if ('presets' === feature) {
|
|
const item = data as Preset;
|
|
const current = get(feature, []) as Array<Preset>;
|
|
|
|
if ('create' === action) {
|
|
current.push(item);
|
|
return;
|
|
}
|
|
|
|
if ('delete' === action) {
|
|
const index = current.findIndex((i) => i.id === item.id);
|
|
if (-1 !== index) {
|
|
current.splice(index, 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ('update' === action) {
|
|
const target = current.find((i) => i.id === item.id);
|
|
if (target) {
|
|
Object.assign(target, item);
|
|
}
|
|
return;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ('dl_fields' === feature) {
|
|
const item = data as DLField;
|
|
const current = get(feature, []) as Array<DLField>;
|
|
|
|
if ('create' === action) {
|
|
current.push(item);
|
|
return;
|
|
}
|
|
|
|
if ('delete' === action) {
|
|
const index = current.findIndex((i) => i.id === item.id);
|
|
if (-1 !== index) {
|
|
current.splice(index, 1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ('update' === action) {
|
|
const target = current.find((i) => i.id === item.id);
|
|
if (target) {
|
|
Object.assign(target, item);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ('replace' === action) {
|
|
state.dl_fields = data as Array<DLField>;
|
|
}
|
|
}
|
|
};
|
|
|
|
const ytpConfigApi = proxyRefs({
|
|
...toRefs(state),
|
|
add,
|
|
get,
|
|
update,
|
|
getAll,
|
|
setAll,
|
|
isLoaded,
|
|
patch,
|
|
loadConfig,
|
|
});
|
|
|
|
export const useYtpConfig = () => ytpConfigApi;
|