Migrate configStore to ts
This commit is contained in:
parent
bd695e7067
commit
b37d614e27
9 changed files with 247 additions and 150 deletions
5
.github/workflows/main.yml
vendored
5
.github/workflows/main.yml
vendored
|
|
@ -131,17 +131,20 @@ jobs:
|
|||
VERSION="${GITHUB_REF##*/}"
|
||||
SHA=$(git rev-parse HEAD)
|
||||
DATE=$(date -u +"%Y%m%d")
|
||||
BRANCH=$(echo "${GITHUB_REF#refs/heads/}" | sed 's/\//-/g')
|
||||
|
||||
echo "Current version: ${VERSION}, SHA: ${SHA}, Date: ${DATE}"
|
||||
echo "Current version: ${VERSION}, Branch: ${BRANCH}, SHA: ${SHA}, Date: ${DATE}"
|
||||
|
||||
echo "APP_VERSION=${VERSION}" >> $"$GITHUB_ENV"
|
||||
echo "APP_SHA=${SHA}" >> "$GITHUB_ENV"
|
||||
echo "APP_DATE=${DATE}" >> "$GITHUB_ENV"
|
||||
echo "APP_BRANCH=${BRANCH}" >> "$GITHUB_ENV"
|
||||
|
||||
sed -i \
|
||||
-e "s/^APP_VERSION = \".*\"/APP_VERSION = \"${VERSION}\"/" \
|
||||
-e "s/^APP_COMMIT_SHA = \".*\"/APP_COMMIT_SHA = \"${SHA}\"/" \
|
||||
-e "s/^APP_BUILD_DATE = \".*\"/APP_BUILD_DATE = \"${DATE}\"/" \
|
||||
-e "s/^APP_BRANCH = \".*\"/APP_BRANCH = \"${BRANCH}\"/" \
|
||||
app/library/version.py
|
||||
|
||||
- name: Set up QEMU
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import coloredlogs
|
|||
from dotenv import load_dotenv
|
||||
|
||||
from .Utils import FileLogFormatter, arg_converter
|
||||
from .version import APP_BUILD_DATE, APP_COMMIT_SHA, APP_VERSION
|
||||
from .version import APP_BRANCH, APP_BUILD_DATE, APP_COMMIT_SHA, APP_VERSION
|
||||
|
||||
|
||||
class Config:
|
||||
|
|
@ -122,6 +122,9 @@ class Config:
|
|||
app_build_date: str = APP_BUILD_DATE
|
||||
"The build date of the application."
|
||||
|
||||
app_branch: str = APP_BRANCH
|
||||
"The branch of the application."
|
||||
|
||||
__instance = None
|
||||
"The instance of the class."
|
||||
|
||||
|
|
@ -201,6 +204,7 @@ class Config:
|
|||
"app_version",
|
||||
"app_commit_sha",
|
||||
"app_build_date",
|
||||
"app_branch",
|
||||
)
|
||||
"The variables that are immutable."
|
||||
|
||||
|
|
@ -257,6 +261,7 @@ class Config:
|
|||
"app_version",
|
||||
"app_commit_sha",
|
||||
"app_build_date",
|
||||
"app_branch",
|
||||
)
|
||||
"The variables that are relevant to the frontend."
|
||||
|
||||
|
|
|
|||
|
|
@ -11,3 +11,6 @@ APP_COMMIT_SHA = "unknown"
|
|||
|
||||
APP_BUILD_DATE = "unknown"
|
||||
"Build date of the application"
|
||||
|
||||
APP_BRANCH = "unknown"
|
||||
"Branch of the application"
|
||||
|
|
|
|||
18
ui/@types/changelogs.d.ts
vendored
Normal file
18
ui/@types/changelogs.d.ts
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
type changelogs = changeset[]
|
||||
|
||||
type changeset = {
|
||||
tag: string
|
||||
full_sha: string
|
||||
date: string
|
||||
commits: Commit[]
|
||||
}
|
||||
|
||||
type Commit = {
|
||||
sha: string
|
||||
full_sha: string
|
||||
message: string
|
||||
author: string
|
||||
date: string
|
||||
}
|
||||
|
||||
export type {changelogs, changeset, Commit}
|
||||
79
ui/@types/config.d.ts
vendored
Normal file
79
ui/@types/config.d.ts
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
|
||||
type AppConfig = {
|
||||
/** Path where downloaded files will be saved */
|
||||
download_path: string
|
||||
/** Indicates if the app should keep an archive of downloaded files */
|
||||
keep_archive: boolean
|
||||
/** Indicates if files should be removed after download */
|
||||
remove_files: boolean
|
||||
/** Indicates if the UI should update the title with the current download status */
|
||||
ui_update_title: boolean
|
||||
/** Output template for yt-dlp, e.g. "%(title)s.%(ext)s" */
|
||||
output_template: string
|
||||
/** yt-dlp version, e.g. "2023.10.01" */
|
||||
ytdlp_version: string
|
||||
/** Maximum number of concurrent download workers */
|
||||
max_workers: number
|
||||
/** Indicates if the app is in basic mode, which may limit some features */
|
||||
basic_mode: boolean
|
||||
/** Default preset name, e.g. "default" */
|
||||
default_preset: string
|
||||
/** Instance title for the app, null if not set */
|
||||
instance_title: string | null
|
||||
/** Sentry DSN for error tracking, null if not configured */
|
||||
sentry_dsn: string | null
|
||||
/** Indicates if the console is enabled */
|
||||
console_enabled: boolean
|
||||
/** Indicates if the file browser is enabled */
|
||||
browser_enabled: boolean
|
||||
/** Command options for yt-dlp */
|
||||
ytdlp_cli: string
|
||||
/** Indicates if file logging is enabled */
|
||||
file_logging: boolean
|
||||
/** Indicates if the app is running in a native environment (e.g., Electron) */
|
||||
is_native: boolean
|
||||
/** App version in format "1.0.0" */
|
||||
app_version: string
|
||||
/** App version in semantic versioning format, e.g. "1.0.0" */
|
||||
app_commit_sha: string
|
||||
/** App build date in ISO format, e.g. "2023-10-01T12:00:00Z" */
|
||||
app_build_date: string
|
||||
/** App branch name, e.g. "main" or "develop" */
|
||||
app_branch: string
|
||||
}
|
||||
|
||||
type Preset = {
|
||||
/** Unique identifier for the preset */
|
||||
id?: string
|
||||
/** Preset name, e.g. "default" */
|
||||
name: string
|
||||
/** Optional description for the preset */
|
||||
description: string
|
||||
/** Folder where files will be saved, e.g. "/downloads" */
|
||||
folder: string
|
||||
/** Output template for the preset, e.g. "%(title)s.%(ext)s" */
|
||||
template: string
|
||||
/** Cookies for the preset, e.g. "cookies.txt" */
|
||||
cookies: string
|
||||
/** Additional command line options for yt-dlp */
|
||||
cli: string
|
||||
/** Indicates if this is the default preset */
|
||||
default: boolean
|
||||
}
|
||||
|
||||
type ConfigState = {
|
||||
/** Show or hide the download form */
|
||||
showForm: RemovableRef<boolean>
|
||||
/** Application configuration */
|
||||
app: AppConfig
|
||||
/** List of presets */
|
||||
presets: Preset[]
|
||||
/** List of folders where files can be saved */
|
||||
folders: string[]
|
||||
/** Indicates if downloads are currently paused */
|
||||
paused: boolean
|
||||
/** Indicates if the configuration has been loaded */
|
||||
is_loaded: boolean
|
||||
}
|
||||
|
||||
export type { AppConfig, Preset, ConfigState }
|
||||
|
|
@ -113,14 +113,14 @@
|
|||
|
||||
<div class="columns mt-3 is-mobile">
|
||||
<div class="column is-8-mobile">
|
||||
<div class="has-text-left" v-if="config.app?.version">
|
||||
<div class="has-text-left" v-if="config.app?.app_version">
|
||||
© {{ Year }} - <NuxtLink href="https://github.com/ArabCoders/ytptube" target="_blank">YTPTube</NuxtLink>
|
||||
<span class="is-hidden-mobile"
|
||||
v-tooltip="`Build Date: ${config.app?.app_build_date}, commit: ${config.app?.app_commit_sha}`">
|
||||
({{ config?.app?.version || 'unknown' }})</span>
|
||||
v-tooltip="`Build Date: ${config.app?.app_build_date}, Branch: ${config.app?.app_branch}, commit: ${config.app?.app_commit_sha}`">
|
||||
({{ config?.app?.app_version || 'unknown' }})</span>
|
||||
- <NuxtLink target="_blank" href="https://github.com/yt-dlp/yt-dlp">yt-dlp</NuxtLink>
|
||||
<span class="is-hidden-mobile"> ({{ config?.app?.ytdlp_version || 'unknown' }})</span>
|
||||
- <NuxtLink :to="`/changelog?version=${config?.app?.version || 'unknown'}`">CHANGELOG</NuxtLink>
|
||||
- <NuxtLink to="/changelog">CHANGELOG</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column is-4-mobile" v-if="config.app?.started">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,18 @@
|
|||
<style scoped>
|
||||
.logs-container {
|
||||
padding: 1rem;
|
||||
min-width: 100%;
|
||||
max-height: 73vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: unset;
|
||||
border-bottom: 1px solid var(--bulma-grey-light) !important
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<main>
|
||||
<div class="mt-1 columns is-multiline">
|
||||
|
|
@ -51,8 +66,9 @@
|
|||
</main>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import moment from 'moment'
|
||||
import type { changelogs, changeset } from '~/@types/changelogs'
|
||||
|
||||
const toast = useNotification()
|
||||
const config = useConfigStore()
|
||||
|
|
@ -63,63 +79,38 @@ const PROJECT = 'ytptube'
|
|||
const REPO = `https://github.com/arabcoders/${PROJECT}`
|
||||
const REPO_URL = `https://arabcoders.github.io/${PROJECT}/CHANGELOG.json?version={version}`
|
||||
|
||||
const logs = ref([])
|
||||
const logs = ref<changelogs>([])
|
||||
const api_version = ref('')
|
||||
const isLoading = ref(false)
|
||||
const hashLength = ref(7)
|
||||
|
||||
const branch = computed(() => {
|
||||
const branch = String(api_version.value).split('-')[0] ?? 'master'
|
||||
return ['master', 'dev'].includes(branch) ? branch : 'master'
|
||||
})
|
||||
|
||||
watch(() => config.app.version, async value => {
|
||||
if (!value) {
|
||||
return
|
||||
}
|
||||
|
||||
api_version.value = value
|
||||
hashLength.value = value.split('-').pop().length
|
||||
|
||||
await nextTick()
|
||||
await loadContent()
|
||||
}, { immediate: true })
|
||||
const api_branch = ref('')
|
||||
const api_sha = ref('')
|
||||
const isLoading = ref(true)
|
||||
|
||||
const loadContent = async () => {
|
||||
if ('' === api_version.value) {
|
||||
if ('' === api_version.value || logs.value.length > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
try {
|
||||
try{
|
||||
logs.value = await (await request(uri('/CHANGELOG.json'), { method: 'GET' })).json()
|
||||
}catch(e){
|
||||
console.error(e)
|
||||
const changes = await fetch(REPO_URL.replace('{branch}', branch.value).replace('{version}', api_version.value))
|
||||
try {
|
||||
const changes = await fetch(REPO_URL.replace('{branch}', api_branch.value).replace('{version}', api_version.value))
|
||||
logs.value = await changes.json()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
logs.value = await (await request(uri('/CHANGELOG.json'), { method: 'GET' })).json()
|
||||
}
|
||||
|
||||
await nextTick()
|
||||
|
||||
logs.value = logs.value.slice(0, 10).map(log => {
|
||||
log.commits = log.commits.map(commit => {
|
||||
commit.full_sha = commit.sha.padEnd(hashLength.value, '0')
|
||||
return commit
|
||||
})
|
||||
log.full_sha = log.tag.padEnd(hashLength.value, '0')
|
||||
return log
|
||||
})
|
||||
|
||||
} catch (e) {
|
||||
logs.value = logs.value.slice(0, 10)
|
||||
} catch (e: any) {
|
||||
console.error(e)
|
||||
toast.error('error', 'Error', `Failed to fetch changelog. ${e.message}`)
|
||||
toast.error(`Failed to fetch changelog. ${e.message}`)
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const isInstalled = log => {
|
||||
const installed = String(api_version.value).split('-').pop()
|
||||
const isInstalled = (log: changeset) => {
|
||||
const installed = String(api_sha.value)
|
||||
|
||||
if (log.full_sha.startsWith(installed)) {
|
||||
return true
|
||||
|
|
@ -134,20 +125,11 @@ const isInstalled = log => {
|
|||
return false
|
||||
}
|
||||
|
||||
onMounted(() => loadContent())
|
||||
onMounted(async () => {
|
||||
await awaiter(config.isLoaded)
|
||||
api_branch.value = config.app.app_branch
|
||||
api_version.value = config.app.app_version
|
||||
api_sha.value = config.app.app_commit_sha
|
||||
loadContent()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.logs-container {
|
||||
padding: 1rem;
|
||||
min-width: 100%;
|
||||
max-height: 73vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: unset;
|
||||
border-bottom: 1px solid var(--bulma-grey-light) !important
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
import { useStorage } from '@vueuse/core'
|
||||
|
||||
const CONFIG_KEYS = {
|
||||
showForm: useStorage('showForm', false),
|
||||
app: {
|
||||
download_path: '/downloads',
|
||||
keep_archive: false,
|
||||
remove_files: false,
|
||||
ui_update_title: true,
|
||||
output_template: '',
|
||||
ytdlp_version: '',
|
||||
max_workers: 1,
|
||||
version: '',
|
||||
basic_mode: true,
|
||||
default_preset: 'default',
|
||||
instance_title: null,
|
||||
sentry_dsn: null,
|
||||
console_enabled: false,
|
||||
browser_enabled: false,
|
||||
ytdlp_cli: '',
|
||||
file_logging: false,
|
||||
is_native: false,
|
||||
app_version: '',
|
||||
app_commit_sha: '',
|
||||
app_build_date: '',
|
||||
},
|
||||
presets: [
|
||||
{
|
||||
'name': 'default',
|
||||
'format': 'default',
|
||||
'folder': '',
|
||||
'template': '',
|
||||
'cookies': '',
|
||||
'cli': '',
|
||||
'default': true
|
||||
}
|
||||
],
|
||||
folders: [],
|
||||
tasks: [],
|
||||
paused: false,
|
||||
};
|
||||
|
||||
export const useConfigStore = defineStore('config', () => {
|
||||
const state = reactive(CONFIG_KEYS);
|
||||
|
||||
const actions = {
|
||||
add(key, value) {
|
||||
if (key.includes('.')) {
|
||||
const [parentKey, subKey] = key.split('.');
|
||||
state[parentKey][subKey] = value;
|
||||
return;
|
||||
}
|
||||
state[key] = value;
|
||||
},
|
||||
get(key, defaultValue = null) {
|
||||
if (key.includes('.')) {
|
||||
const [parentKey, subKey] = key.split('.');
|
||||
return state[parentKey][subKey] || defaultValue;
|
||||
}
|
||||
return state[key] || defaultValue;
|
||||
},
|
||||
update(key, value) {
|
||||
if (key.includes('.')) {
|
||||
const [parentKey, subKey] = key.split('.');
|
||||
state[parentKey][subKey] = value;
|
||||
return;
|
||||
}
|
||||
state[key] = value;
|
||||
},
|
||||
getAll() {
|
||||
return state;
|
||||
},
|
||||
setAll(data) {
|
||||
Object.keys(data).forEach((key) => {
|
||||
if (key.includes('.')) {
|
||||
const [parentKey, subKey] = key.split('.');
|
||||
state[parentKey][subKey] = data[key];
|
||||
return;
|
||||
}
|
||||
state[key] = data[key];
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
return { ...toRefs(state), ...actions };
|
||||
});
|
||||
93
ui/stores/ConfigStore.ts
Normal file
93
ui/stores/ConfigStore.ts
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import { useStorage } from '@vueuse/core'
|
||||
import type { ConfigState } from '~/@types/config';
|
||||
|
||||
export const useConfigStore = defineStore('config', () => {
|
||||
const state = reactive<ConfigState>({
|
||||
showForm: useStorage('showForm', false),
|
||||
app: {
|
||||
download_path: '/downloads',
|
||||
keep_archive: false,
|
||||
remove_files: false,
|
||||
ui_update_title: true,
|
||||
output_template: '',
|
||||
ytdlp_version: '',
|
||||
max_workers: 1,
|
||||
basic_mode: true,
|
||||
default_preset: 'default',
|
||||
instance_title: null,
|
||||
sentry_dsn: null,
|
||||
console_enabled: false,
|
||||
browser_enabled: false,
|
||||
ytdlp_cli: '',
|
||||
file_logging: false,
|
||||
is_native: false,
|
||||
app_version: '',
|
||||
app_commit_sha: '',
|
||||
app_build_date: '',
|
||||
app_branch: '',
|
||||
},
|
||||
presets: [
|
||||
{
|
||||
'name': 'default',
|
||||
'description': 'Default preset for downloads',
|
||||
'folder': '',
|
||||
'template': '',
|
||||
'cookies': '',
|
||||
'cli': '',
|
||||
'default': true
|
||||
}
|
||||
],
|
||||
folders: [],
|
||||
paused: false,
|
||||
is_loaded: 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 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 isLoaded = () => state.is_loaded
|
||||
|
||||
return {
|
||||
...toRefs(state), add, get, update, getAll, setAll, isLoaded,
|
||||
} as { [K in keyof ConfigState]: Ref<ConfigState[K]> } & {
|
||||
add: typeof add
|
||||
get: typeof get
|
||||
update: typeof update
|
||||
getAll: typeof getAll
|
||||
setAll: typeof setAll
|
||||
isLoaded: typeof isLoaded
|
||||
}
|
||||
});
|
||||
Loading…
Reference in a new issue