From 444e1458bea065e479dd81929baa2a72169f475d Mon Sep 17 00:00:00 2001 From: arabcoders Date: Tue, 19 Aug 2025 19:27:45 +0300 Subject: [PATCH 1/2] minor ui updates/ --- app/routes/api/yt_dlp.py | 4 +- ui/app/composables/useMediaQuery.ts | 61 +++++++++++++++++++++++++++++ ui/app/layouts/default.vue | 19 ++++----- ui/app/pages/index.vue | 22 ++++++----- 4 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 ui/app/composables/useMediaQuery.ts diff --git a/app/routes/api/yt_dlp.py b/app/routes/api/yt_dlp.py index 6a669bcb..ca7c2677 100644 --- a/app/routes/api/yt_dlp.py +++ b/app/routes/api/yt_dlp.py @@ -144,7 +144,7 @@ async def get_info(request: Request, cache: Cache, config: Config) -> Response: "ttl_left": data.get("_cached", {}).get("expires", time.time() + 300) - time.time(), "expires": data.get("_cached", {}).get("expires", time.time() + 300), } - return web.Response(body=json.dumps(data, indent=4, default=str), status=web.HTTPOk.status_code) + return web.json_response(body=json.dumps(data, indent=4, default=str), status=web.HTTPOk.status_code) if ytdlp_proxy := config.get_ytdlp_args().get("proxy", None): opts = opts.add({"proxy": ytdlp_proxy}) @@ -203,7 +203,7 @@ async def get_info(request: Request, cache: Cache, config: Config) -> Response: cache.set(key=key, value=data, ttl=300) - return web.Response(body=json.dumps(data, indent=4, default=str), status=web.HTTPOk.status_code) + return web.json_response(body=json.dumps(data, indent=4, default=str), status=web.HTTPOk.status_code) except Exception as e: LOG.exception(e) LOG.error(f"Error encountered while getting video info for '{url}'. '{e!s}'.") diff --git a/ui/app/composables/useMediaQuery.ts b/ui/app/composables/useMediaQuery.ts new file mode 100644 index 00000000..1d322494 --- /dev/null +++ b/ui/app/composables/useMediaQuery.ts @@ -0,0 +1,61 @@ +import { ref, onMounted, onBeforeUnmount, shallowReadonly, type Ref } from 'vue' + +export interface MediaQueryOptions { + /** + * A custom media query string. + * Example: "(max-width: 640px) or (hover: none)" + * If provided, takes precedence over maxWidth. + */ + query?: string + + /** + * Max width in px considered true. + * Ignored if `query` is provided. Default: 768. + */ + maxWidth?: number +} + +/** + * Reactive state of a CSS media query. + */ +export function useMediaQuery(options: MediaQueryOptions = {}): Readonly> { + const query = options.query ?? `(max-width: ${options.maxWidth ?? 1024}px)` + const matches = ref(false) + + let mql: MediaQueryList | null = null + let onChange: ((ev: MediaQueryListEvent) => void) | null = null + + const setup = () => { + if ('undefined' === typeof window || !window.matchMedia) { + return + } + mql = window.matchMedia(query) + matches.value = mql.matches + + onChange = ev => { matches.value = ev.matches } + if ('addEventListener' in mql) { + mql.addEventListener('change', onChange as EventListener) + return + } + + // @ts-expect-error legacy Safari + mql.addListener(onChange) + } + + const teardown = () => { + if (!mql || !onChange) return + if ('removeEventListener' in mql) { + mql.removeEventListener('change', onChange as EventListener) + } else { + // @ts-expect-error legacy Safari + mql.removeListener(onChange) + } + mql = null + onChange = null + } + + onMounted(setup) + onBeforeUnmount(teardown) + + return shallowReadonly(matches) +} diff --git a/ui/app/layouts/default.vue b/ui/app/layouts/default.vue index 22456d01..4b162ffa 100644 --- a/ui/app/layouts/default.vue +++ b/ui/app/layouts/default.vue @@ -75,27 +75,22 @@ -