From b37d614e2701cd656f566268e6c59df285ae7e98 Mon Sep 17 00:00:00 2001 From: arabcoders Date: Sun, 22 Jun 2025 21:49:07 +0300 Subject: [PATCH] Migrate configStore to ts --- .github/workflows/main.yml | 5 +- app/library/config.py | 7 ++- app/library/version.py | 3 ++ ui/@types/changelogs.d.ts | 18 +++++++ ui/@types/config.d.ts | 79 ++++++++++++++++++++++++++++++ ui/layouts/default.vue | 8 ++-- ui/pages/changelog.vue | 98 ++++++++++++++++---------------------- ui/stores/ConfigStore.js | 86 --------------------------------- ui/stores/ConfigStore.ts | 93 ++++++++++++++++++++++++++++++++++++ 9 files changed, 247 insertions(+), 150 deletions(-) create mode 100644 ui/@types/changelogs.d.ts create mode 100644 ui/@types/config.d.ts delete mode 100644 ui/stores/ConfigStore.js create mode 100644 ui/stores/ConfigStore.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1e01a61b..c4fd07cb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 diff --git a/app/library/config.py b/app/library/config.py index ce2986be..f3009903 100644 --- a/app/library/config.py +++ b/app/library/config.py @@ -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." diff --git a/app/library/version.py b/app/library/version.py index e10ec5de..4902396f 100644 --- a/app/library/version.py +++ b/app/library/version.py @@ -11,3 +11,6 @@ APP_COMMIT_SHA = "unknown" APP_BUILD_DATE = "unknown" "Build date of the application" + +APP_BRANCH = "unknown" +"Branch of the application" diff --git a/ui/@types/changelogs.d.ts b/ui/@types/changelogs.d.ts new file mode 100644 index 00000000..976ffaf8 --- /dev/null +++ b/ui/@types/changelogs.d.ts @@ -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} diff --git a/ui/@types/config.d.ts b/ui/@types/config.d.ts new file mode 100644 index 00000000..5f33c982 --- /dev/null +++ b/ui/@types/config.d.ts @@ -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 + /** 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 } diff --git a/ui/layouts/default.vue b/ui/layouts/default.vue index c034a18d..f8a296bd 100644 --- a/ui/layouts/default.vue +++ b/ui/layouts/default.vue @@ -113,14 +113,14 @@
-
+
© {{ Year }} - YTPTube -  ({{ config?.app?.version || 'unknown' }}) + 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' }}) - yt-dlp  ({{ config?.app?.ytdlp_version || 'unknown' }}) - - CHANGELOG + - CHANGELOG
diff --git a/ui/pages/changelog.vue b/ui/pages/changelog.vue index 7c2e5dd6..523a23a3 100644 --- a/ui/pages/changelog.vue +++ b/ui/pages/changelog.vue @@ -1,3 +1,18 @@ + + - - - diff --git a/ui/stores/ConfigStore.js b/ui/stores/ConfigStore.js deleted file mode 100644 index 0ab2ae68..00000000 --- a/ui/stores/ConfigStore.js +++ /dev/null @@ -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 }; -}); diff --git a/ui/stores/ConfigStore.ts b/ui/stores/ConfigStore.ts new file mode 100644 index 00000000..7d9848bf --- /dev/null +++ b/ui/stores/ConfigStore.ts @@ -0,0 +1,93 @@ +import { useStorage } from '@vueuse/core' +import type { ConfigState } from '~/@types/config'; + +export const useConfigStore = defineStore('config', () => { + const state = reactive({ + 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) => { + 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 } & { + add: typeof add + get: typeof get + update: typeof update + getAll: typeof getAll + setAll: typeof setAll + isLoaded: typeof isLoaded + } +});