Convert socketStore and stateStore to ts
This commit is contained in:
parent
1580388b96
commit
84f623f2e4
6 changed files with 305 additions and 206 deletions
|
|
@ -1,163 +0,0 @@
|
|||
import { io } from "socket.io-client";
|
||||
import { ag } from "~/utils/index"
|
||||
|
||||
export const useSocketStore = defineStore('socket', () => {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const config = useConfigStore()
|
||||
const stateStore = useStateStore()
|
||||
const toast = useNotification()
|
||||
|
||||
const socket = ref(null)
|
||||
const isConnected = ref(false)
|
||||
|
||||
const connect = () => {
|
||||
let opts = {
|
||||
transports: ['websocket', 'polling'],
|
||||
withCredentials: true,
|
||||
}
|
||||
|
||||
let url = runtimeConfig.public.wss
|
||||
|
||||
if ('development' !== runtimeConfig.public?.APP_ENV) {
|
||||
url = window.origin;
|
||||
opts.path = `${runtimeConfig.app.baseURL.replace(/\/$/, '')}/socket.io`;
|
||||
}
|
||||
|
||||
socket.value = io(url, opts)
|
||||
|
||||
socket.value.on('connect', () => isConnected.value = true);
|
||||
socket.value.on('disconnect', () => isConnected.value = false);
|
||||
|
||||
socket.value.on('initial_data', stream => {
|
||||
const initialData = JSON.parse(stream)
|
||||
|
||||
config.setAll({
|
||||
app: initialData['config'],
|
||||
tasks: initialData['tasks'],
|
||||
folders: initialData['folders'],
|
||||
presets: initialData['presets'],
|
||||
paused: Boolean(initialData['paused'])
|
||||
})
|
||||
|
||||
stateStore.addAll('queue', initialData['queue'] ?? {})
|
||||
stateStore.addAll('history', initialData['done'] ?? {})
|
||||
})
|
||||
|
||||
socket.value.on('added', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
stateStore.add('queue', item._id, item);
|
||||
toast.success(`Item queued: ${ag(stateStore.get('queue', item._id, {}), 'title')}`);
|
||||
});
|
||||
|
||||
socket.value.on('error', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.error(`${json.data?.id ?? json?.type}: ${json?.message}`, json.data || {});
|
||||
});
|
||||
|
||||
socket.value.on('log_info', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.info(json?.message, json.data || {});
|
||||
});
|
||||
|
||||
socket.value.on('log_success', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.success(json?.message, json.data || {});
|
||||
});
|
||||
|
||||
socket.value.on('log_warning', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.warning(json?.message, json.data || {});
|
||||
});
|
||||
|
||||
socket.value.on('log_error', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.error(json?.message, json.data || {});
|
||||
});
|
||||
|
||||
socket.value.on('completed', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
|
||||
if (true === stateStore.has('queue', item._id)) {
|
||||
stateStore.remove('queue', item._id);
|
||||
}
|
||||
|
||||
stateStore.add('history', item._id, item);
|
||||
});
|
||||
|
||||
socket.value.on('cancelled', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item._id
|
||||
|
||||
if (true !== stateStore.has('queue', id)) {
|
||||
return
|
||||
}
|
||||
|
||||
toast.warning(`Download cancelled: ${ag(stateStore.get('queue', id, {}), 'title')}`);
|
||||
|
||||
if (true === stateStore.has('queue', id)) {
|
||||
stateStore.remove('queue', id);
|
||||
}
|
||||
});
|
||||
|
||||
socket.value.on('cleared', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item._id
|
||||
|
||||
if (true !== stateStore.has('history', id)) {
|
||||
return
|
||||
}
|
||||
|
||||
stateStore.remove('history', id);
|
||||
});
|
||||
|
||||
socket.value.on("updated", stream => {
|
||||
const data = JSON.parse(stream);
|
||||
|
||||
if (true === stateStore.has('history', data._id)) {
|
||||
stateStore.update('history', data._id, data);
|
||||
return;
|
||||
}
|
||||
|
||||
let dl = stateStore.get('queue', data._id, {});
|
||||
data.deleting = dl?.deleting;
|
||||
stateStore.update('queue', data._id, data);
|
||||
});
|
||||
|
||||
socket.value.on("update", stream => {
|
||||
const data = JSON.parse(stream);
|
||||
if (true === stateStore.has('history', data._id)) {
|
||||
stateStore.update('history', data._id, data);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
socket.value.on('paused', data => {
|
||||
const json = JSON.parse(data);
|
||||
const pausedState = Boolean(json.paused);
|
||||
config.update('paused', pausedState);
|
||||
|
||||
if (false === pausedState) {
|
||||
toast.success('Download queue resumed.');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.warning('Download queue paused.', {
|
||||
timeout: 10000,
|
||||
});
|
||||
});
|
||||
|
||||
socket.value.on('presets_update', data => config.update('presets', JSON.parse(data)));
|
||||
}
|
||||
|
||||
const on = (event, callback) => socket.value.on(event, callback);
|
||||
const off = (event, callback) => socket.value.off(event, callback);
|
||||
const emit = (event, data) => socket.value.emit(event, data);
|
||||
|
||||
if (false === isConnected.value) {
|
||||
connect();
|
||||
}
|
||||
|
||||
window.ws = socket.value;
|
||||
|
||||
return { connect, on, off, emit, socket, isConnected };
|
||||
});
|
||||
162
ui/stores/SocketStore.ts
Normal file
162
ui/stores/SocketStore.ts
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import { io } from "socket.io-client";
|
||||
import { ag } from "~/utils/index"
|
||||
import type { Socket as IOSocket, SocketOptions } from "socket.io-client"
|
||||
import type { ManagerOptions } from "socket.io-client";
|
||||
|
||||
export const useSocketStore = defineStore('socket', () => {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const config = useConfigStore()
|
||||
const stateStore = useStateStore()
|
||||
const toast = useNotification()
|
||||
|
||||
const socket = ref<IOSocket | null>(null)
|
||||
const isConnected = ref<boolean>(false)
|
||||
|
||||
const connect = () => {
|
||||
let opts = {
|
||||
transports: ['websocket', 'polling'],
|
||||
withCredentials: true,
|
||||
} as Partial<ManagerOptions & SocketOptions>
|
||||
|
||||
let url = runtimeConfig.public.wss
|
||||
|
||||
if ('development' !== runtimeConfig.public?.APP_ENV) {
|
||||
url = window.origin;
|
||||
opts.path = `${runtimeConfig.app.baseURL.replace(/\/$/, '')}/socket.io`;
|
||||
}
|
||||
|
||||
socket.value = io(url, opts)
|
||||
|
||||
socket.value.on('connect', () => isConnected.value = true);
|
||||
socket.value.on('disconnect', () => isConnected.value = false);
|
||||
|
||||
socket.value.on('initial_data', stream => {
|
||||
const json = JSON.parse(stream)
|
||||
|
||||
config.setAll({
|
||||
app: json.data.config,
|
||||
tasks: json.data.tasks,
|
||||
folders: json.data.folders,
|
||||
presets: json.data.presets,
|
||||
paused: Boolean(json.data.paused)
|
||||
})
|
||||
|
||||
stateStore.addAll('queue', json.data.queue || {})
|
||||
stateStore.addAll('history', json.data.done || {})
|
||||
})
|
||||
|
||||
socket.value.on('added', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
stateStore.add('queue', json.data._id, json.data);
|
||||
toast.success(`Item queued: ${ag(stateStore.get('queue', json.data._id, {}), 'title')}`);
|
||||
});
|
||||
|
||||
socket.value.on('error', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
toast.error(`${json.data?.id}: ${json?.message || json?.data?.message}`, json.data || {});
|
||||
});
|
||||
|
||||
['log_info', 'log_success', 'log_warning', 'log_error'].forEach(event => socket.value?.on(event, stream => {
|
||||
const json = JSON.parse(stream);
|
||||
const message = json?.message || json?.data?.message;
|
||||
const data = json.data?.data || json.data || {};
|
||||
switch (event) {
|
||||
case 'log_info':
|
||||
toast.info(message, data);
|
||||
break;
|
||||
case 'log_success':
|
||||
toast.success(message, data);
|
||||
break;
|
||||
case 'log_warning':
|
||||
toast.warning(message, data);
|
||||
break;
|
||||
case 'log_error':
|
||||
toast.error(message, data);
|
||||
break;
|
||||
}
|
||||
}));
|
||||
|
||||
socket.value.on('completed', stream => {
|
||||
const json = JSON.parse(stream);
|
||||
|
||||
if (true === stateStore.has('queue', json.data._id)) {
|
||||
stateStore.remove('queue', json.data._id);
|
||||
}
|
||||
|
||||
stateStore.add('history', json.data._id, json.data);
|
||||
});
|
||||
|
||||
socket.value.on('cancelled', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item.data._id
|
||||
|
||||
if (true !== stateStore.has('queue', id)) {
|
||||
return
|
||||
}
|
||||
|
||||
toast.warning(`Download cancelled: ${ag(stateStore.get('queue', id, {}), 'title')}`);
|
||||
|
||||
if (true === stateStore.has('queue', id)) {
|
||||
stateStore.remove('queue', id);
|
||||
}
|
||||
});
|
||||
|
||||
socket.value.on('cleared', stream => {
|
||||
const item = JSON.parse(stream);
|
||||
const id = item.data._id
|
||||
|
||||
if (true !== stateStore.has('history', id)) {
|
||||
return
|
||||
}
|
||||
|
||||
stateStore.remove('history', id);
|
||||
});
|
||||
|
||||
socket.value.on("updated", stream => {
|
||||
const json = JSON.parse(stream);
|
||||
const id = json.data._id;
|
||||
|
||||
if (true === stateStore.has('history', id)) {
|
||||
stateStore.update('history', id, json.data);
|
||||
return;
|
||||
}
|
||||
|
||||
stateStore.update('queue', id, json.data);
|
||||
});
|
||||
|
||||
socket.value.on("update", stream => {
|
||||
const json = JSON.parse(stream);
|
||||
if (true === stateStore.has('history', json.data._id)) {
|
||||
stateStore.update('history', json.data._id, json.data);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
socket.value.on('paused', data => {
|
||||
const json = JSON.parse(data);
|
||||
const pausedState = Boolean(json.data.paused);
|
||||
config.update('paused', pausedState);
|
||||
|
||||
if (false === pausedState) {
|
||||
toast.success('Download queue resumed.');
|
||||
return;
|
||||
}
|
||||
|
||||
toast.warning('Download queue paused.', { timeout: 10000 });
|
||||
});
|
||||
|
||||
socket.value.on('presets_update', (data: string) => config.update('presets', JSON.parse(data).data || []));
|
||||
}
|
||||
|
||||
const emit = (event: string, data?: any): any => socket.value?.emit(event, data)
|
||||
const on = (event: string, callback: (...args: any[]) => void): any => socket.value?.on(event, callback)
|
||||
const off = (event: string, callback: (...args: any[]) => void): any => socket.value?.off(event, callback)
|
||||
|
||||
if (false === isConnected.value) {
|
||||
connect();
|
||||
}
|
||||
|
||||
window.ws = socket.value;
|
||||
|
||||
return { connect, on, off, emit, socket, isConnected };
|
||||
});
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
export const useStateStore = defineStore('state', () => {
|
||||
const state = reactive({
|
||||
queue: {},
|
||||
history: {}
|
||||
});
|
||||
|
||||
const actions = {
|
||||
add(type, key, value) {
|
||||
state[type][key] = value;
|
||||
},
|
||||
update(type, key, value) {
|
||||
state[type][key] = value;
|
||||
},
|
||||
remove(type, key) {
|
||||
if (state[type][key]) {
|
||||
delete state[type][key];
|
||||
}
|
||||
},
|
||||
get(type, key, defaultValue = null) {
|
||||
return state[type][key] || defaultValue;
|
||||
},
|
||||
has(type, key) {
|
||||
return !!state[type][key];
|
||||
},
|
||||
clearAll(type) {
|
||||
state[type] = {};
|
||||
},
|
||||
addAll(type, data) {
|
||||
state[type] = data;
|
||||
},
|
||||
move(fromType, toType, key) {
|
||||
if (state[fromType][key]) {
|
||||
state[toType][key] = state[fromType][key];
|
||||
delete state[fromType][key];
|
||||
}
|
||||
},
|
||||
count(type) {
|
||||
return Object.keys(state[type]).length;
|
||||
}
|
||||
}
|
||||
|
||||
return { ...toRefs(state), ...actions };
|
||||
});
|
||||
59
ui/stores/StateStore.ts
Normal file
59
ui/stores/StateStore.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { reactive, toRefs } from 'vue'
|
||||
import type { StoreItem } from '~/types/store'
|
||||
|
||||
type StateType = 'queue' | 'history'
|
||||
type KeyType = string
|
||||
type ValueType = StoreItem
|
||||
|
||||
interface State {
|
||||
queue: Record<KeyType, ValueType>
|
||||
history: Record<KeyType, ValueType>
|
||||
}
|
||||
|
||||
export const useStateStore = defineStore('state', () => {
|
||||
const state = reactive<State>({ queue: {}, history: {} })
|
||||
|
||||
const add = (type: StateType, key: KeyType, value: ValueType): void => {
|
||||
state[type][key] = value
|
||||
}
|
||||
|
||||
const update = (type: StateType, key: KeyType, value: ValueType): void => {
|
||||
state[type][key] = value
|
||||
}
|
||||
|
||||
const remove = (type: StateType, key: KeyType): void => {
|
||||
if (state[type][key]) {
|
||||
delete state[type][key]
|
||||
}
|
||||
}
|
||||
|
||||
const get = (type: StateType, key: KeyType, defaultValue: ValueType | null | object = null): ValueType | null => {
|
||||
return state[type][key] || defaultValue
|
||||
}
|
||||
|
||||
const has = (type: StateType, key: KeyType): boolean => {
|
||||
return !!state[type][key]
|
||||
}
|
||||
|
||||
const clearAll = (type: StateType): void => {
|
||||
state[type] = {}
|
||||
}
|
||||
|
||||
const addAll = (type: StateType, data: Record<KeyType, ValueType>): void => {
|
||||
state[type] = data
|
||||
}
|
||||
|
||||
const move = (fromType: StateType, toType: StateType, key: KeyType): void => {
|
||||
if (state[fromType][key]) {
|
||||
state[toType][key] = state[fromType][key]
|
||||
delete state[fromType][key]
|
||||
}
|
||||
}
|
||||
|
||||
const count = (type: StateType): number => {
|
||||
return Object.keys(state[type]).length
|
||||
}
|
||||
|
||||
return { ...toRefs(state), add, update, remove, get, has, clearAll, addAll, move, count }
|
||||
})
|
||||
8
ui/types/sockets.d.ts
vendored
Normal file
8
ui/types/sockets.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
export type Event = {
|
||||
id: str
|
||||
created_at: str
|
||||
event: str
|
||||
title: str | null = null
|
||||
message: str | null = null
|
||||
data: Any = { }
|
||||
}
|
||||
76
ui/types/store.d.ts
vendored
Normal file
76
ui/types/store.d.ts
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
export type ItemStatus = 'finished' | 'preparing' | 'error' | 'cancelled' | 'downloading' | 'postprocessing' | 'not_live' | null;
|
||||
export type StoreItem = {
|
||||
/** Unique identifier for the item */
|
||||
_id: string
|
||||
/** Error message if available */
|
||||
error: string | null
|
||||
/** Item source id */
|
||||
id: string
|
||||
/** Title of the item */
|
||||
title: string
|
||||
/** URL of the item */
|
||||
url: string
|
||||
/** Preset used for the item */
|
||||
preset: string
|
||||
/** Folder where the item is saved */
|
||||
folder: string
|
||||
/** Download directory */
|
||||
download_dir: string
|
||||
/** Temporary directory for the item */
|
||||
temp_dir: string
|
||||
/** Status of the item */
|
||||
status: ItemStatus
|
||||
/** If the item has cookies */
|
||||
cookies: string
|
||||
/** If the item has custom output_template */
|
||||
template: string
|
||||
/** If the item has custom output_template for chapters */
|
||||
template_chapter: string
|
||||
/** When the item was created */
|
||||
timestamp: number
|
||||
/** If the item is a live stream */
|
||||
is_live: boolean
|
||||
/** ISO 8601 formatted start time of the item */
|
||||
datetime: string
|
||||
/** Live stream start time if available */
|
||||
live_in: string | null
|
||||
/** File size of the item if available */
|
||||
file_size: number | null
|
||||
/** Custom yt-dlp command line arguments */
|
||||
cli: string
|
||||
/** If the item is auto-started */
|
||||
auto_start: boolean
|
||||
/** Options for the item */
|
||||
options: Record<string, unknown>
|
||||
/** Extras for the item */
|
||||
extras: {
|
||||
/** Which channel the item belongs to */
|
||||
channel?: string
|
||||
/** The video duration if available */
|
||||
duration?: number | null
|
||||
/** The video release date if available */
|
||||
release_in?: string
|
||||
/** The video thumbnail URL if available */
|
||||
thumbnail?: string
|
||||
/** The uploader of the item if available */
|
||||
uploader?: string
|
||||
}
|
||||
/** The item temporary filename */
|
||||
tmpfilename?: string | null
|
||||
/** The item filename */
|
||||
filename?: string | null
|
||||
/** Actual file size of the item if available */
|
||||
total_bytes?: number | null
|
||||
/** Estimated total bytes for the item if available */
|
||||
total_bytes_estimate?: number | null
|
||||
/** Downloaded bytes of the item if available */
|
||||
downloaded_bytes?: number | null
|
||||
/** Message attached with the item if available */
|
||||
msg?: string | null
|
||||
/** Progress percentage of the item if available */
|
||||
percent?: number | null
|
||||
/** Speed of the item download if available */
|
||||
speed?: number | null
|
||||
/** Time remaining for the item download if available */
|
||||
eta?: number | null
|
||||
}
|
||||
Loading…
Reference in a new issue