Compare commits

..

297 commits
dev ... master

Author SHA1 Message Date
Abdulmohsen
c68646e266
Merge pull request #621 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: setting simple_mode cookie was crashing http layer
2026-06-19 19:59:35 +03:00
Abdulmohsen
0ba52fa38e
Merge pull request #620 from arabcoders/dev
Refactor: re-design simple mode
2026-06-19 18:50:15 +03:00
Abdulmohsen
44f5f2eee0
Merge pull request #618 from arabcoders/dev
chore: use ty as type checker.
2026-06-14 19:35:40 +03:00
Abdulmohsen
aedeaf9a0a
Merge pull request #617 from arabcoders/dev
Feat: paginate queue
2026-06-14 18:29:27 +03:00
Abdulmohsen
a614a48108
Merge pull request #615 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: breaking change between yt-dlp 2026.03.17 -> 2026.06.09
2026-06-11 18:03:12 +03:00
Abdulmohsen
9ada8b5a91
Merge pull request #613 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: video progress bar on iOS would fail
2026-06-10 16:53:16 +03:00
Abdulmohsen
a194b9bf28
Merge pull request #610 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Refactor: minor improvements to the WebUI
2026-06-08 10:08:19 +03:00
Abdulmohsen
6df1250a43
Merge pull request #609 from arabcoders/dev
feat: make log level runtime configurable
2026-05-31 21:07:00 +03:00
Abdulmohsen
ef8642ace7
Merge pull request #608 from arabcoders/dev
feat: add system diagnostics endpoint.
2026-05-26 19:49:47 +03:00
Abdulmohsen
8e14258c7a
Merge pull request #607 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Fix: recent change made fetch_info unpicklable
2026-05-24 22:07:41 +03:00
Abdulmohsen
f65cdddbfe
Merge pull request #604 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Refactor: use item guid as thumbnail name for easier cleanup
2026-05-15 19:40:35 +03:00
Abdulmohsen
cee3bcf48d
Merge pull request #603 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
feat: thumbnail generation
2026-05-14 23:34:00 +03:00
Abdulmohsen
e7772b361e
Merge pull request #602 from arabcoders/dev
Refactor: do not log httpx related as exceptions but errors.
2026-05-13 11:37:28 +03:00
Abdulmohsen
d3a3b5d95f
Merge pull request #601 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
feat: add generic browser extractor
2026-05-08 01:15:59 +03:00
Abdulmohsen
522e6a75ef
Merge pull request #600 from arabcoders/dev
fix: Handle TimeoutError in fetch_info to prevent double wait
2026-05-07 21:54:47 +03:00
Abdulmohsen
6cf2eb053c
Merge pull request #599 from arabcoders/dev
refactor: improve video player rendering
2026-05-05 23:42:24 +03:00
Abdulmohsen
b35ac1831a
Merge pull request #598 from arabcoders/dev
feat: extra placeholders for output template
2026-05-05 10:53:05 +03:00
Abdulmohsen
cf4386e1a5
Merge pull request #594 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
feat: add support for ignoring conditions in downloads and UI
2026-04-28 01:21:27 +03:00
Abdulmohsen
cb1c355e58
Merge pull request #593 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
refactor: re-add the automatic history update after download
2026-04-26 20:26:51 +03:00
Abdulmohsen
4ee7537733
Merge pull request #592 from arabcoders/dev
fix: Slowness in deleting big number of items
2026-04-25 01:42:01 +03:00
Abdulmohsen
fdc08989ae
Merge pull request #591 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Fix pagination UI and refactor presets layout
2026-04-22 20:01:40 +03:00
Abdulmohsen
ed77ea508c
Merge pull request #590 from arabcoders/dev
Refactor: Seperate history items from queue
2026-04-21 23:24:42 +03:00
Abdulmohsen
8729f030c7
Merge pull request #589 from arabcoders/dev
feat(console): make terminal window more durable
2026-04-14 17:32:17 +03:00
Abdulmohsen
0eabc2197b
Merge pull request #588 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: better partial live download handling
2026-04-11 19:27:44 +03:00
Abdulmohsen
28ec496430
Merge pull request #587 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: improve the native build
2026-04-10 20:11:51 +03:00
Abdulmohsen
2139e20332
Merge pull request #586 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
minor bug fixes and overall ui improvements
2026-04-10 18:33:29 +03:00
Abdulmohsen
1087596486
Merge pull request #584 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: video player responsiveness
2026-04-09 00:42:56 +03:00
Abdulmohsen
dbf1f59efb
Merge pull request #583 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Improve MiniFilter tokenization
2026-03-31 19:15:34 +03:00
Abdulmohsen
235438af51
Merge pull request #581 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
refactor: minor fixes for better mobile view.
2026-03-27 00:20:49 +03:00
Abdulmohsen
4bea8a315a
Merge pull request #579 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Feat: Rebase the UI on top of nuxt/ui
2026-03-25 23:48:31 +03:00
Abdulmohsen
932f51c583
Merge pull request #576 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
chore: update external packages.
2026-03-18 21:46:27 +03:00
Abdulmohsen
2f435a3a64
Merge pull request #574 from arabcoders/dev
chore: update external packages
2026-03-09 21:19:22 +03:00
Abdulmohsen
b462048679
Merge pull request #573 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
chore: update dependancies
2026-03-03 22:39:05 +03:00
Abdulmohsen
ffbd82096c
Merge pull request #572 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
chore: update external packages
2026-02-22 22:38:43 +03:00
Abdulmohsen
705973219c
Merge pull request #570 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
refactor: move frontend to bun
2026-02-20 23:38:49 +03:00
Abdulmohsen
d9c9a85939
Merge pull request #569 from arabcoders/dev
feat: improve task creation to support multiple URLs.
2026-02-17 21:02:09 +03:00
Abdulmohsen
0c7ebb66ed
Merge pull request #567 from arabcoders/dev
fix: forcibly register the NFOMaker PP
2026-02-14 20:32:56 +03:00
Abdulmohsen
c36295d76f
Merge pull request #566 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: improve exception handling in status tracker
2026-02-13 22:07:05 +03:00
Abdulmohsen
ee0942b37a
Merge pull request #562 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: update import path for fetch_info in HandleTask class. Closes #561
2026-02-11 18:58:15 +03:00
Abdulmohsen
1cc6172862
Merge pull request #560 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
2026-02-08 11:11:05 +03:00
Abdulmohsen
0473c86fd6
Merge pull request #557 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix: use yt-dlp[default] for upgrading logic
2026-02-05 18:08:35 +03:00
Abdulmohsen
d17aa6c29e
Merge pull request #553 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Fix: sidecar loading for history items
2026-01-28 18:07:57 +03:00
Abdulmohsen
8659f74a3b
Merge pull request #552 from arabcoders/dev
Fix: offload info extraction to ProcessPoolExecutor
2026-01-27 11:53:15 +03:00
Abdulmohsen
412ad9565d
Merge pull request #549 from arabcoders/dev
Refactor: migrate from file-based config to db model
2026-01-25 21:42:20 +03:00
Abdulmohsen
be6b68efdd
Merge pull request #542 from arabcoders/dev 2026-01-14 23:16:23 +03:00
Abdulmohsen
3b49678272
Merge pull request #541 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Fix: preset export was exporting cookies due to inverted check.
2026-01-11 21:36:42 +03:00
Abdulmohsen
2435144cb1
Merge pull request #540 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
feat: support using output template for metadata generation.
2026-01-08 20:05:47 +03:00
Abdulmohsen
1189d31f5c
Merge pull request #538 from arabcoders/dev
Feat: add flag to ignore already archived items from showing in download history.
2026-01-07 18:03:29 +03:00
Abdulmohsen
163be08803
Merge pull request #537 from arabcoders/dev
Refactor: more UX consistency changes
2026-01-06 18:02:40 +03:00
Abdulmohsen
0a70c02b3e
Merge pull request #536 from arabcoders/dev
Refactor: add priority to presets
2026-01-05 19:02:10 +03:00
Abdulmohsen
d5ae882df0
Merge pull request #535 from arabcoders/dev
Refactor: add enabled field to notifications.
2026-01-04 23:37:50 +03:00
Abdulmohsen
9eb78ecdc0
Merge pull request #534 from arabcoders/dev
Refactor: add priority and description fields to conditions
2026-01-04 19:18:10 +03:00
Abdulmohsen
a924ddb718
Merge pull request #533 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Refactor: add enabled field to conditions
2026-01-04 17:30:15 +03:00
Abdulmohsen
67f3a24580
Merge pull request #531 from arabcoders/dev
Refactor: integrate cf solver for both yt-dlp and httpx
2026-01-02 20:34:48 +03:00
Abdulmohsen
b9421f442a
Merge pull request #530 from arabcoders/dev
Refactor: reduce cf_solver priority  to allow impersonate to work
2026-01-01 22:37:44 +03:00
Abdulmohsen
3b55c4d677
Merge pull request #529 from arabcoders/dev
Feat: CF Solver handler
2026-01-01 21:03:22 +03:00
Abdulmohsen
b8934d40eb
Merge pull request #528 from arabcoders/dev
Refactor: improve filtering capabilities in downloads page
2025-12-31 21:37:28 +03:00
Abdulmohsen
2f6dcbb4d4
Merge pull request #527 from arabcoders/dev
Refactor: playlists sometimes return different ID what we got
2025-12-30 23:28:41 +03:00
Abdulmohsen
18673f0a55
Merge pull request #526 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Refactor: stagger tasks creation for playlist processing
2025-12-30 20:50:44 +03:00
Abdulmohsen
714b6d95ba
Merge pull request #525 from arabcoders/dev 2025-12-29 23:07:07 +03:00
Abdulmohsen
c9ba2b0f4c
Merge pull request #524 from arabcoders/dev
Fix: prevent sending only space as download path
2025-12-28 23:20:34 +03:00
Abdulmohsen
3d14a50f07
Merge pull request #523 from arabcoders/dev
Feat: Introduce random delays to task handlers
2025-12-28 17:52:38 +03:00
Abdulmohsen
b5276feba0
Merge pull request #522 from arabcoders/dev
Fix: Dont Crash on download_path being set to root path
2025-12-28 00:15:30 +03:00
Abdulmohsen
54dedb6696
Merge pull request #521 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Refactor: switch native builds to onedir
2025-12-27 22:06:00 +03:00
Abdulmohsen
20e6c129ba
Merge pull request #517 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Some extractors dont work with --flat-playlist
2025-12-26 20:08:38 +03:00
Abdulmohsen
47ca5461f1
Merge pull request #515 from arabcoders/dev
Refactor: swap sqlite to aiosqlite and add queued db updates
2025-12-19 22:11:36 +03:00
Abdulmohsen
93ce7a730b
Merge pull request #514 from arabcoders/dev
Fix: performance regression while loading items.
2025-12-16 15:33:06 +03:00
Abdulmohsen
2214bc66de
Merge pull request #512 from arabcoders/dev
Feat: set_preset key for condition to switch preset based on yt-dlp data
2025-12-08 20:47:37 +03:00
Abdulmohsen
3ece619834
Merge pull request #507 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Drop download_archive for generic extractors
2025-12-04 20:21:28 +03:00
Abdulmohsen
af84a03ad1
Merge pull request #504 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
QoL: Support newlines as seperator for URLs.
2025-11-29 19:13:25 +03:00
Abdulmohsen
7e6b6f0544
Merge pull request #502 from arabcoders/dev
Feat: Add task handler for tver.jp
2025-11-25 21:10:05 +03:00
Abdulmohsen
91f527887c
Merge pull request #501 from arabcoders/dev
Refactor: Improve display of notifications to indicate severity
2025-11-22 21:07:43 +03:00
Abdulmohsen
69dc19ad4f
Merge pull request #500 from arabcoders/dev
Refactor: move static serving to our internal implementation
2025-11-19 21:24:17 +03:00
Abdulmohsen
9272e0b173
Merge pull request #498 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Fix: regrassion in tasks due change in how we handle event loop
2025-11-19 02:57:16 +03:00
Abdulmohsen
c6d89dde9c
Merge pull request #497 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
2025-11-19 01:42:59 +03:00
Abdulmohsen
89a92028e0
Merge pull request #496 from arabcoders/dev
Fix: Not being able to download subtitles.
2025-11-18 22:56:14 +03:00
Abdulmohsen
70d015a2a5
Merge pull request #495 from arabcoders/dev
Feat: Make it possible to enable/disable task
2025-11-18 19:39:33 +03:00
Abdulmohsen
d13ac83425
Merge pull request #492 from arabcoders/dev
Refactor: change how clear in/completed buttons behave
2025-11-16 20:07:50 +03:00
Abdulmohsen
83a416ec4c
Merge pull request #491 from arabcoders/dev
Refactor: Use tab design for index page
2025-11-15 22:12:25 +03:00
Abdulmohsen
477dc41bb6
Merge pull request #489 from arabcoders/dev
Feat: File browser controls improvements
2025-11-14 20:17:14 +03:00
Abdulmohsen
59fe171a9d
Merge pull request #488 from arabcoders/dev
Add app manifest to allow the app to be installed
2025-11-13 23:36:14 +03:00
Abdulmohsen
46a3abebde
Merge pull request #487 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
revert: Revert changes to video player, it was causing issue with sid…
2025-11-13 00:21:35 +03:00
Abdulmohsen
b94d62accd
Merge pull request #486 from arabcoders/dev
Fix: add yt-dlp-ejs
2025-11-12 23:55:47 +03:00
Abdulmohsen
d4c14c7991
Merge pull request #485 from arabcoders/dev
Refactor: refactor postprocessor into correct directory
2025-11-12 22:06:20 +03:00
Abdulmohsen
c1b9034ef8
Merge pull request #483 from arabcoders/dev
Feat: add drop file support for cookies field.
2025-11-12 18:59:49 +03:00
Abdulmohsen
8ff6582316
Merge pull request #482 from arabcoders/dev
Fix: handle errors when fetching remote thumbnails
2025-11-11 23:45:47 +03:00
Abdulmohsen
d1a20b3972
Merge pull request #481 from arabcoders/dev
Strip out comment lines when creating yt-dlp command
2025-11-10 18:29:25 +03:00
Abdulmohsen
f0b5e20af8
Merge pull request #480 from arabcoders/dev
[FIX] implement --max-downloads arg. Ref #479
2025-11-10 00:35:48 +03:00
Abdulmohsen
8273847d46
Merge pull request #478 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
[FIX] Chromium browser does not render subtitles after HLS attach
2025-11-08 23:19:41 +03:00
Abdulmohsen
f4e5dfb2f6
Merge pull request #477 from arabcoders/dev
Minor fixes
2025-11-08 21:40:21 +03:00
Abdulmohsen
03e8166afe
Merge pull request #476 from arabcoders/dev
hide keyboard shortcuts on mobile
2025-11-07 00:26:30 +03:00
Abdulmohsen
1db5e26843
Merge pull request #473 from arabcoders/dev
[FEAT] Add keyboard shortcuts to built-in video player
2025-11-03 01:46:07 +03:00
Abdulmohsen
ee9e2a1d0b
Merge pull request #470 from arabcoders/dev
[FEAT] Add yt-dlp cli wrapper
2025-11-01 18:12:31 +03:00
Abdulmohsen
71153d6fb4
Merge pull request #468 from arabcoders/dev
[FEAT] Support running commands from newDownload into console.
2025-10-27 20:04:13 +03:00
Abdulmohsen
a81c73a469
Merge pull request #467 from arabcoders/dev
minor fixes to file listing, and unify how we present tips
2025-10-26 16:15:44 +03:00
Abdulmohsen
70c42252a6
Merge pull request #466 from arabcoders/dev
[FEAT] add grid display style for files
2025-10-24 20:06:28 +03:00
Abdulmohsen
477c7e7c98
Merge pull request #464 from arabcoders/dev
[FIX] Cancelling live streams. Closes #463
2025-10-24 00:47:11 +03:00
Abdulmohsen
b95b6eb6be
Merge pull request #460 from arabcoders/dev
Some checks failed
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
v1.0.2
2025-10-22 19:02:44 +03:00
Abdulmohsen
238deddb9d
Merge pull request #455 from arabcoders/dev
UI/UX improvements
2025-10-19 22:22:52 +03:00
Abdulmohsen
618ce4d387
Merge pull request #451 from arabcoders/dev
[FEAT] add custom download fields to simple mode.
2025-10-16 17:23:02 +03:00
Abdulmohsen
5bf97047af
Merge pull request #450 from arabcoders/dev
create new branch for testing ground
2025-10-16 15:58:57 +03:00
Abdulmohsen
2a13c47bb6
Merge pull request #444 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
v1.0.1
2025-10-15 19:22:47 +03:00
Abdulmohsen
f91811ad50
Merge pull request #440 from arabcoders/dev
Update bookmarklet URL and add note on mixed content
2025-10-13 19:24:28 +03:00
Abdulmohsen
f51b11c421
Merge pull request #438 from arabcoders/dev
Clarify standalone builds limitations
2025-10-12 21:17:55 +03:00
Abdulmohsen
fa4da50403
Merge pull request #436 from arabcoders/dev
Some checks failed
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
Fixes issue with simple view and background toggle
2025-10-11 21:21:48 +03:00
Abdulmohsen
851124a047
Merge pull request #434 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Prepare for v1.0 release.
2025-10-02 19:25:25 +03:00
Abdulmohsen
1103b93f00
Merge pull request #431 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Add experimental simple view mode
2025-09-27 21:05:58 +03:00
Abdulmohsen
8a852bcd24
Merge pull request #427 from arabcoders/dev
Bundles deno runtime
2025-09-24 22:39:50 +03:00
Abdulmohsen
b105749121
Merge pull request #424 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Added Web UI for task definitions & inspect handler
2025-09-23 19:49:09 +03:00
Abdulmohsen
dd3059d01e
Merge pull request #423 from arabcoders/dev
Use local downloaded thumbnail if available
2025-09-22 00:38:51 +03:00
Abdulmohsen
5c862eb613
Merge pull request #422 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
[FEAT] Add per extractor limits
2025-09-14 22:23:42 +03:00
Abdulmohsen
871f9e803e
Merge pull request #420 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
Support using GPU encoding for playback
2025-09-14 01:46:49 +03:00
Abdulmohsen
0de61566fb
Merge pull request #418 from arabcoders/dev
Some checks failed
native-build / build (amd64, ubuntu-latest) (push) Has been cancelled
native-build / build (amd64, windows-latest) (push) Has been cancelled
native-build / build (arm64, macos-latest) (push) Has been cancelled
native-build / build (arm64, ubuntu-latest) (push) Has been cancelled
native-build / build (arm64, windows-latest) (push) Has been cancelled
fix version tagging
2025-09-12 23:41:14 +03:00
Abdulmohsen
2323739c49
Merge pull request #417 from arabcoders/dev
Remove deprecated features and flags
2025-09-12 22:59:26 +03:00
Abdulmohsen
049b9a4e38
Merge pull request #416 from arabcoders/dev
Mostly CI improvements to include tests and linting
2025-09-12 03:02:03 +03:00
Abdulmohsen
c968ce3ed2
Merge pull request #415 from arabcoders/dev
updated external packages
2025-09-09 00:26:27 +03:00
Abdulmohsen
125a1a81a0
Merge pull request #414 from arabcoders/dev
Make it possible to ignore item download via conditions
2025-09-08 19:20:05 +03:00
Abdulmohsen
71ba8ea7f7
Merge pull request #411 from arabcoders/dev
renamed screenshot
2025-09-04 17:30:20 +03:00
Abdulmohsen
bb37f7b6ba
Merge pull request #410 from arabcoders/dev
Minor FAQ/README update
2025-09-04 17:28:57 +03:00
Abdulmohsen
2c7ba8e184
Merge pull request #409 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
FEAT: new TwitchHandler
2025-09-04 00:02:29 +03:00
Abdulmohsen
ab8545392e
Merge pull request #408 from arabcoders/dev
Expose archiver as an API endpoint.
2025-09-03 19:37:59 +03:00
Abdulmohsen
c528e2b557
Merge pull request #405 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
FEAT: Make it possible to limit notify target to specific presets.
2025-09-02 22:59:22 +03:00
Abdulmohsen
a5d91e58fa
Merge pull request #404 from arabcoders/dev
Cleanup user python packages dir after each version change.
2025-09-02 19:54:34 +03:00
Abdulmohsen
984d47e946
Merge pull request #402 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
Enhance file browser API
2025-09-01 19:56:16 +03:00
Abdulmohsen
2a1cd0a632
Merge pull request #400 from arabcoders/dev
allow updating github release notes
2025-08-31 02:14:55 +03:00
Abdulmohsen
7185bae58d
Merge pull request #399 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
test new build system
2025-08-31 01:52:57 +03:00
Abdulmohsen
c5e3899c26
Merge pull request #398 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
Re-implemented Archive feature
2025-08-30 20:57:55 +03:00
Abdulmohsen
aaab5a72e8
Merge pull request #397 from arabcoders/dev
Major refactor
2025-08-30 02:29:02 +03:00
Abdulmohsen
3de3471bd5
Merge pull request #395 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
Implement a workaround for slowness in status update
2025-08-27 01:02:17 +03:00
Abdulmohsen
8b9077d476
Merge pull request #393 from arabcoders/dev
Fix windows multiprocessing threads
2025-08-26 01:07:37 +03:00
Abdulmohsen
963fa5870c
Merge pull request #392 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
restore pycryptodome
2025-08-26 00:31:42 +03:00
Abdulmohsen
b48daf11c8
Merge pull request #391 from arabcoders/dev
more fixes.
2025-08-26 00:22:20 +03:00
Abdulmohsen
c3d8aa8348
Merge pull request #390 from arabcoders/dev
followup fix
2025-08-25 23:41:50 +03:00
Abdulmohsen
1dd464d6cc
Merge pull request #389 from arabcoders/dev
Fix native builds.
2025-08-25 23:39:08 +03:00
Abdulmohsen
c91ca38035
Merge pull request #388 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
Remove webview in favor of using built-in browser.
2025-08-25 22:43:05 +03:00
Abdulmohsen
46725e6f8e
Merge pull request #387 from arabcoders/dev
Added support for pausing adding items from playlist.
2025-08-25 19:20:36 +03:00
Abdulmohsen
43e0128c3b
Merge pull request #383 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
upgrade curl_cffi to 0.13.x
2025-08-24 20:06:20 +03:00
Abdulmohsen
8473618726
Merge pull request #382 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Added better fallback to hls.
2025-08-23 21:44:50 +03:00
Abdulmohsen
d2ce9940e8
Merge pull request #380 from arabcoders/dev
Refactor: update basic mode watch logic to check config loading state
2025-08-22 18:22:59 +03:00
Abdulmohsen
4c9c9eab84
Merge pull request #379 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Added autocomplete for cli options
2025-08-20 19:37:34 +03:00
Abdulmohsen
b4505d2fcd
Merge pull request #378 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Added built-in reference for yt-dlp options.
2025-08-19 22:33:42 +03:00
Abdulmohsen
f6d1618c91
Merge pull request #377 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
bump playlist_items_concurrency to 4 by default
2025-08-16 20:29:11 +03:00
Abdulmohsen
650ba810a8
Merge pull request #376 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
fix breaking change to playlist handling.
2025-08-15 04:47:20 +03:00
Abdulmohsen
286d8ce818
Merge pull request #374 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Make playlist_index works
2025-08-14 12:30:41 +03:00
Abdulmohsen
2cdfa2503b
Merge pull request #373 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Update yt-dlp to 2025.8.11
2025-08-12 03:45:45 +03:00
Abdulmohsen
6aab6fd062
Merge pull request #370 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Make it possible to pin specific yt-dlp version
2025-08-09 18:39:35 +03:00
Abdulmohsen
3447ac8032
Merge pull request #368 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Disable opacity whenever an overlay is showing
2025-08-08 22:37:33 +03:00
Abdulmohsen
3f11262afb
Merge pull request #366 from arabcoders/dev
Custom Fields Feature
2025-08-08 00:02:45 +03:00
Abdulmohsen
ffd99e7c09
Merge pull request #365 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fixed a bug in DownloadQueue
2025-08-05 18:15:45 +03:00
Abdulmohsen
4c54f80b87
Merge pull request #364 from arabcoders/dev
Implement a way to mark items from task as already downloaded.
2025-08-05 17:59:17 +03:00
Abdulmohsen
c310ae9abc
Merge pull request #361 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Add force download switch
2025-08-02 16:45:06 +03:00
Abdulmohsen
4c5ebf2f39
Merge pull request #359 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
fix windows build
2025-08-01 18:32:02 +03:00
Abdulmohsen
cc3057f432
Merge pull request #358 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Update the pyinstaller build to include version number.
2025-08-01 18:11:58 +03:00
Abdulmohsen
517d4e7528
Merge pull request #357 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fix threading issue on windows exe
2025-08-01 17:13:12 +03:00
Abdulmohsen
a939654715
Merge pull request #356 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Respect auto_start when re-queuing item
2025-07-31 23:56:36 +03:00
Abdulmohsen
9b5c1d9ae7
Merge pull request #355 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fix automatic premiere re-queue.
2025-07-27 17:08:28 +03:00
Abdulmohsen
33fbf4bda8
Merge pull request #354 from arabcoders/dev
Added toggle for task handler & convert_url
2025-07-27 16:57:27 +03:00
Abdulmohsen
b4e5990b83
Merge pull request #352 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fix playlist_autonumber. Closes #351
2025-07-24 23:50:17 +03:00
Abdulmohsen
fd75d3cb8f
Merge pull request #350 from arabcoders/dev
Fixed in browser match_str to closely match yt-dlp match_str
2025-07-24 19:39:01 +03:00
Abdulmohsen
6ba83ac00b
Merge pull request #349 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fix upgrading and installing pip packages
2025-07-24 17:26:08 +03:00
Abdulmohsen
35aa158f40
Merge pull request #347 from arabcoders/dev 2025-07-23 03:32:31 +03:00
Abdulmohsen
b7cb89f656
Merge pull request #346 from arabcoders/dev
Remove duplicate notifications, and improve yt-dlp opts handling
2025-07-20 17:09:31 +03:00
Abdulmohsen
10182e1373
Merge pull request #343 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Completed the events system upgrade and expanded the notifications events with support for apprise.
2025-07-19 19:54:15 +03:00
Abdulmohsen
e398321901
Merge pull request #342 from arabcoders/dev
Cleaning up the event dispatcher system.
2025-07-18 22:06:53 +03:00
Abdulmohsen
f9b70fec5f
Merge pull request #341 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Allow the UI to bypass some checks for apprise URLs
2025-07-18 00:40:37 +03:00
Abdulmohsen
6e84b78f22
Merge pull request #340 from arabcoders/dev
Major notification update to add initial support for apprise URLs.
2025-07-18 00:17:07 +03:00
Abdulmohsen
78002ef99a
Merge pull request #339 from arabcoders/dev
add preset name to history/queue
2025-07-16 17:37:28 +03:00
Abdulmohsen
043b019bde
Merge pull request #338 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Fix color contrast on pause button in dark mode. Closes #337
2025-07-15 19:01:30 +03:00
Abdulmohsen
f66980c3bf
Merge pull request #336 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Add the ability to disable temp file handling
2025-07-14 23:06:38 +03:00
Abdulmohsen
f4ec06cef9
Merge pull request #334 from arabcoders/dev
Make it possible to cancel download and keep the downloaded tmp data
2025-07-11 19:58:33 +03:00
Abdulmohsen
4c11e178b2
Merge pull request #333 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
Added the ability to add items in paused state
2025-07-08 22:25:42 +03:00
Abdulmohsen
49cce85cfe
Merge pull request #331 from arabcoders/dev
Some checks failed
Build WebView wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build WebView wrappers / build (arm64, windows-latest) (push) Has been cancelled
support running in pywebview in windows.
2025-07-07 18:48:28 +03:00
Abdulmohsen
034ff25e76
Merge pull request #330 from arabcoders/dev
split windows and nix oses packaging.
2025-07-07 16:39:36 +03:00
Abdulmohsen
a324ed8ffd
Merge pull request #329 from arabcoders/dev
remove sha256sum generation
2025-07-07 16:28:43 +03:00
Abdulmohsen
1169eea47b
Merge pull request #328 from arabcoders/dev
fix
2025-07-07 16:23:39 +03:00
Abdulmohsen
cc4b9032b0
Merge pull request #327 from arabcoders/dev
followup fix for artifacts release
2025-07-07 16:17:53 +03:00
Abdulmohsen
0edac6c93e
Merge pull request #326 from arabcoders/dev
fix artifact version tagging
2025-07-07 15:55:45 +03:00
Abdulmohsen
27e70b6df8
Merge pull request #325 from arabcoders/dev
correctly upload artifacts
2025-07-06 20:07:31 +03:00
Abdulmohsen
eb3ac026ba
Merge pull request #324 from arabcoders/dev
fix release updater
2025-07-06 19:40:18 +03:00
Abdulmohsen
6607a233c0
Merge pull request #323 from arabcoders/dev
PR to support webview
2025-07-06 19:26:47 +03:00
Abdulmohsen
b3bd02afc8
Merge pull request #322 from arabcoders/dev
Download as zipfile when downloading multiple files
2025-07-04 19:23:33 +03:00
Abdulmohsen
26455b62bf
Merge pull request #319 from arabcoders/dev
Added file browser actions
2025-07-01 18:14:33 +03:00
Abdulmohsen
6c44c587c7
Merge pull request #317 from arabcoders/dev
sometimes yt-dlp info extract doesn't return formats.
2025-06-28 22:25:15 +03:00
Abdulmohsen
8e3e7dda80
Merge pull request #316 from arabcoders/dev
Renamed presets and added optimized preset for mobile devices
2025-06-28 20:27:52 +03:00
Abdulmohsen
3fe9188b47
Merge pull request #314 from arabcoders/dev
Implements ytdlp filter logic to our own playlist processing.
2025-06-27 20:19:26 +03:00
Abdulmohsen
b5bb2a202c
Merge pull request #313 from arabcoders/dev
Fix running in subpath again.
2025-06-27 16:36:27 +03:00
Abdulmohsen
1ce9acd316
Merge pull request #311 from arabcoders/dev
Use Asyncio.Semaphore for managing concurrency.
2025-06-24 22:26:10 +03:00
Abdulmohsen
de4b88eef3
Merge pull request #309 from arabcoders/dev
minor design update for index page.
2025-06-21 20:58:01 +03:00
Abdulmohsen
3f3f63f0e2
Merge pull request #308 from arabcoders/dev
Make it possible to view local item info
2025-06-20 21:03:13 +03:00
Abdulmohsen
8fe68f36ee
Merge pull request #306 from arabcoders/dev
Improve tasks page for mass operations.
2025-06-20 00:29:26 +03:00
Abdulmohsen
4bf65f08c4
Merge pull request #305 from arabcoders/dev
When item download fails, trigger item_error event
2025-06-19 19:11:24 +03:00
Abdulmohsen
6e05efb146
Merge pull request #304 from arabcoders/dev
Use simver starting from this pull request.
2025-06-18 22:19:43 +03:00
Abdulmohsen
c07465a676
Merge pull request #303 from arabcoders/dev 2025-06-16 22:19:11 +03:00
Abdulmohsen
4c76aa7123
Merge pull request #301 from arabcoders/dev
Fix premiere video re-queue.
2025-06-15 20:00:15 +03:00
Abdulmohsen
b65008b628
Merge pull request #300 from arabcoders/dev
Fixed bug in auth handler.
2025-06-15 16:41:24 +03:00
Abdulmohsen
2eab819e87
Merge pull request #299 from arabcoders/dev
Tag premiere video correctly.
2025-06-14 22:14:04 +03:00
Abdulmohsen
670c99510e
Merge pull request #297 from arabcoders/dev
Support running on windows
2025-06-10 13:44:17 +03:00
Abdulmohsen
f1f79afea1
Merge pull request #296 from arabcoders/dev
Add support for running YTPTube from sub-directory
2025-06-05 22:52:13 +03:00
Abdulmohsen
38d99c0e1e
Merge pull request #294 from arabcoders/dev
Make sure to build linux/arm64 for default branch
2025-06-04 22:49:13 +03:00
Abdulmohsen
4a26dc1a7f
Merge pull request #293 from arabcoders/dev
fixed bug in default URL separator selector.
2025-06-04 22:42:10 +03:00
Abdulmohsen
3bbb1509e2
Merge pull request #292 from arabcoders/dev
Add notifications center
2025-06-04 22:23:56 +03:00
Abdulmohsen
cf2fb5fac8
Merge pull request #289 from arabcoders/dev
Major WebUI improvements + minor bug fixes
2025-06-04 00:45:25 +03:00
Abdulmohsen
2a60a848d6
Merge pull request #285 from arabcoders/dev
minor UI and text update.
2025-06-03 03:15:42 +03:00
Abdulmohsen
a434e3a6aa
Merge pull request #284 from arabcoders/dev
Refactor streaming logic to be more efficient
2025-06-01 19:21:01 +03:00
Abdulmohsen
8dfdf7f615
Merge pull request #283 from arabcoders/dev
Update API documentation
2025-05-28 18:24:50 +03:00
Abdulmohsen
fd27ae924e
Merge pull request #281 from arabcoders/dev
Removed a custom monkey patch for yt-dlp that addressed live-from-start MPD issues.
2025-05-27 22:26:20 +03:00
Abdulmohsen
adb191bb6d
Merge pull request #278 from arabcoders/dev
Fix problem with processing playlist
2025-05-23 18:31:36 +03:00
Abdulmohsen
4398b30b38
Merge pull request #277 from arabcoders/dev
Minor improvements.
2025-05-23 02:08:13 +03:00
Abdulmohsen
f7f5ef0e59
Merge pull request #275 from arabcoders/dev
Fix healthcheck when user:pass are set.
2025-05-13 16:33:46 +03:00
Abdulmohsen
cbc6277dc6
Merge pull request #274 from arabcoders/dev
Fix #273
2025-05-12 18:21:51 +03:00
Abdulmohsen
853a443b88
Merge pull request #270 from arabcoders/dev
Design Update & Fold preset --format into the cli args
2025-05-10 19:54:07 +03:00
Abdulmohsen
12b4b12344
Merge pull request #269 from arabcoders/dev
Communicate more error logs to user when yt-dlp throws them.
2025-05-02 21:20:42 +03:00
Abdulmohsen
1deba05902
Merge pull request #268 from arabcoders/dev 2025-05-01 03:40:42 +03:00
Abdulmohsen
9f0d88375f
Merge pull request #265 from arabcoders/dev
Switched newDownload form to use HttpAPI for easier state management
2025-04-28 19:24:37 +03:00
Abdulmohsen
d385e41f6a
Merge pull request #264 from arabcoders/dev
upgrade external packages.
2025-04-26 19:58:34 +03:00
Abdulmohsen
1bbaf461b2
Merge pull request #263 from arabcoders/dev
More protection against stale downloads
2025-04-26 19:34:31 +03:00
Abdulmohsen
b29dc00bd8
Merge pull request #262 from arabcoders/dev
Automatically re-queue upcoming live streams in history.
2025-04-22 19:10:33 +03:00
Abdulmohsen
53d3b3c81d
Merge pull request #261 from arabcoders/dev
restore message about live stream not being live yet.
2025-04-21 20:53:59 +03:00
Abdulmohsen
a2f8cb5523
Merge pull request #260 from arabcoders/dev
Display better description  when there are no formats available.
2025-04-20 17:00:39 +03:00
Abdulmohsen
3425657dbf
Merge pull request #259 from arabcoders/dev
added some protection against staled downloads
2025-04-19 17:56:31 +03:00
Abdulmohsen
fb2aa7396b
Merge pull request #258 from arabcoders/dev
Minor refactor for is_downloaded function and updated dependencies
2025-04-12 18:49:53 +03:00
Abdulmohsen
2beb6a6b08
Merge pull request #257 from arabcoders/dev
Minor logs view update
2025-04-10 02:52:40 +03:00
Abdulmohsen
53da40b5f5
Merge pull request #256 from arabcoders/dev
When using external downloader show indicator in the WebUI
2025-04-10 01:38:01 +03:00
Abdulmohsen
31f64e67da
Merge pull request #253 from arabcoders/dev
go with blacklist approach for blocking yt-dlp options.
2025-04-07 02:31:21 +03:00
Abdulmohsen
ec1f2f448a
Merge pull request #251 from arabcoders/dev
migrate the entire app to use cli options for ytdlp. Closes #250
2025-04-06 02:31:30 +03:00
Abdulmohsen
c118522fa2
Merge pull request #249 from arabcoders/dev
Add Logs Viewer
2025-04-04 23:40:01 +03:00
Abdulmohsen
62b41bfdfa
Merge pull request #248 from arabcoders/dev
added new env variable to auto upgrade yt-dlp on container startup
2025-04-03 23:31:18 +03:00
Abdulmohsen
e79d182daa
Merge pull request #247 from arabcoders/dev
Fix re-queuing existing item.
2025-04-02 01:51:46 +03:00
Abdulmohsen
18fe5409ce
Merge pull request #246 from arabcoders/dev
Simplify the codebase and removed all backwards compatibility flags
2025-04-02 00:49:10 +03:00
Abdulmohsen
2ed0bde90a
Merge pull request #245 from arabcoders/dev
Update yt-dlp to 2025.3.31
2025-04-01 19:06:23 +03:00
Abdulmohsen
6cf0b9120e
Merge pull request #243 from arabcoders/dev
deprecate JSON yt-dlp config, and encourage cli options.
2025-03-31 23:26:01 +03:00
Abdulmohsen
8305518a01
Merge pull request #242 from arabcoders/dev
Add support for --match-filter
2025-03-30 01:47:34 +03:00
Abdulmohsen
80737f7d90
Merge pull request #240 from arabcoders/dev
Small improvements to file browser.
2025-03-28 23:35:50 +03:00
Abdulmohsen
dc3c2b41e3
Merge pull request #239 from arabcoders/dev 2025-03-28 03:29:39 +03:00
Abdulmohsen
5bac7b8d20
Merge pull request #237 from arabcoders/dev
Nested browser frontend page was not loading correctly.
2025-03-28 02:27:31 +03:00
Abdulmohsen
daad7752b3
Merge pull request #236 from arabcoders/dev
Added Simple file browser.
2025-03-28 02:12:41 +03:00
Abdulmohsen
15e4232fc8
Merge pull request #234 from arabcoders/dev
minor update to list view, and added download selected items.
2025-03-27 00:55:40 +03:00
Abdulmohsen
6d77de76cd
Merge pull request #233 from arabcoders/dev
Design update
2025-03-26 22:12:28 +03:00
Abdulmohsen
5f7bbb5eba
Merge pull request #231 from arabcoders/dev
Update yt-dlp to 2025.3.26
2025-03-26 04:00:50 +03:00
Abdulmohsen
df699dd0c5
Merge pull request #229 from arabcoders/dev
Maintain playlist keys when we are extracting a playlist/channel
2025-03-26 01:04:58 +03:00
Abdulmohsen
fd93472bd0
Merge pull request #226 from arabcoders/dev
Update yt-dlp to 2025.3.25
2025-03-25 04:03:22 +03:00
Abdulmohsen
810a63d485
Merge pull request #224 from arabcoders/dev
restore opacity if the video is playing.
2025-03-25 02:08:38 +03:00
Abdulmohsen
68473a1b0d
Merge pull request #223 from arabcoders/dev
Add random beautiful backgrounds
2025-03-25 01:56:18 +03:00
Abdulmohsen
28d902b2a9
Merge pull request #222 from arabcoders/dev
Minor README & EventBus update
2025-03-23 00:55:16 +03:00
Abdulmohsen
00f3f27b8b
Merge pull request #221 from arabcoders/dev
Switiching to EventBus & updated yt-dlp to 2025.3.21
2025-03-22 20:43:51 +03:00
Abdulmohsen
25da932d21
Merge pull request #219 from arabcoders/dev
bump curl_cffi to 0.7.1
2025-03-20 01:04:48 +03:00
Abdulmohsen
87e93a5df6
Merge pull request #218 from arabcoders/dev
potential fix for #217
2025-03-18 00:24:48 +03:00
Abdulmohsen
9445e3ef86
Merge pull request #216 from arabcoders/dev 2025-03-17 19:52:45 +03:00
Abdulmohsen
0ed8aa5a30
Merge pull request #215 from arabcoders/dev
Add changeslog page to WebUI
2025-03-17 00:12:13 +03:00
Abdulmohsen
3161fc0bb8
Merge pull request #214 from arabcoders/dev
fix params Impersonate target
2025-03-16 21:32:25 +03:00
Abdulmohsen
98970da663
Merge pull request #213 from arabcoders/dev
Fix date range conversion
2025-03-16 21:13:29 +03:00
Abdulmohsen
19bdd84dd5
Merge pull request #211 from arabcoders/dev
Added indicator in the WebUI for when post-processing are running
2025-03-15 01:33:55 +03:00
Abdulmohsen
9adb6efbc5
Merge pull request #210 from arabcoders/dev
Standardize the form design & add import/export to all functions
2025-03-14 23:18:44 +03:00
Abdulmohsen
674c53893f
Merge pull request #209 from arabcoders/dev
Preset exports are base64 encoded now
2025-03-13 23:16:12 +03:00
Abdulmohsen
d5efb994ec
Merge pull request #208 from arabcoders/dev
Made it possible to not use format in preset
2025-03-11 21:10:27 +03:00
Abdulmohsen
10aeff4bfa
Merge pull request #207 from arabcoders/dev
Added advanced iOS shortcut
2025-03-11 02:23:11 +03:00
Abdulmohsen
9427f7b2a0
Merge pull request #206 from arabcoders/dev
Improve history status display
2025-03-10 01:48:30 +03:00
Abdulmohsen
7a2dc8a452
Merge pull request #205 from arabcoders/dev
Updated worker pool to be a bit more dynamic
2025-03-09 01:20:58 +03:00
Abdulmohsen
243d4554d7
Merge pull request #204 from arabcoders/dev
Disable yt-dlp console access by default
2025-03-07 20:45:37 +03:00
Abdulmohsen
7b395d717d
Merge pull request #203 from arabcoders/dev
Make presets more powerful
2025-03-07 19:01:07 +03:00
Abdulmohsen
c944c36028
Merge pull request #202 from arabcoders/dev
remove debug statement
2025-03-07 01:27:25 +03:00
Abdulmohsen
e52bef3781
Merge pull request #201 from arabcoders/dev
Dev
2025-03-07 01:05:05 +03:00
Abdulmohsen
73f97b80f3
Merge pull request #200 from arabcoders/dev
Rely on native video player
2025-03-05 22:18:35 +03:00
Abdulmohsen
327136bf09
Merge pull request #199 from arabcoders/dev 2025-03-04 21:25:12 +03:00
Abdulmohsen
48c849da5a
Merge pull request #197 from arabcoders/dev
Manage presets via WebUI
2025-03-04 02:18:46 +03:00
Abdulmohsen
a608d02d67
Merge pull request #193 from arabcoders/dev
better fallback if file was renamed and retains the same ID
2025-03-01 20:15:40 +03:00
Abdulmohsen
65dbfc775e
Merge pull request #192 from arabcoders/dev
Try to direct play video first and fallback to HLS if src load fails
2025-02-28 01:53:32 +03:00
Abdulmohsen
ad561f7e73
Merge pull request #191 from arabcoders/dev
remove json cookies and improve extraction error messages.
2025-02-27 00:45:51 +03:00
Abdulmohsen
806b795b38
Merge pull request #190 from arabcoders/dev 2025-02-20 17:32:03 +03:00
Abdulmohsen
a1f8245086
Merge pull request #188 from arabcoders/dev
Minor frontend improvements
2025-01-30 18:23:46 +03:00
Abdulmohsen
d135de5088
Merge pull request #187 from arabcoders/dev
Changed UMASK from 022 to 0002
2025-01-29 13:29:17 +03:00
Abdulmohsen
f554871b9f
Merge pull request #186 from arabcoders/dev
Major code changes.
2025-01-28 00:18:41 +03:00
Abdulmohsen
f790257b4f
Merge pull request #184 from arabcoders/dev
Revamped the notification system
2025-01-25 22:56:30 +03:00
Abdulmohsen
f0ac16cea7
Merge pull request #183 from arabcoders/dev
Overhauled the tasks page
2025-01-24 23:29:46 +03:00
Abdulmohsen
ff540addff
Merge pull request #181 from arabcoders/dev
Handle yt-dlp CLI options
2025-01-23 18:30:03 +03:00
Abdulmohsen
82d1401c27
Merge pull request #179 from arabcoders/dev
separate PR and push workflow
2025-01-19 23:55:47 +03:00
Abdulmohsen
12e18ee745
Merge pull request #178 from arabcoders/dev
updated version tagger
2025-01-19 22:30:08 +03:00
Abdulmohsen
c54e9107b3
Merge pull request #177 from arabcoders/dev
Refactoring the code to use shared manager
2025-01-19 21:40:30 +03:00
Abdulmohsen
bcf5593523
Merge pull request #176 from arabcoders/dev 2025-01-19 18:27:31 +03:00
Abdulmohsen
9ab357983b
Merge pull request #175 from arabcoders/dev
Finalize Fix for #173
2025-01-18 21:14:06 +03:00
Abdulmohsen
501e97aabd
Merge pull request #174 from arabcoders/dev
Dev
2025-01-18 17:56:15 +03:00
Abdulmohsen
084def9346
Merge pull request #172 from arabcoders/dev
Add Basic mode for WebUI
2025-01-17 15:55:51 +03:00
Abdulmohsen
5be33c6a9a
Merge pull request #170 from arabcoders/dev 2025-01-16 19:11:13 +03:00
Abdulmohsen
5b72e45432
Merge pull request #168 from arabcoders/dev
Added view url information in history and queue
2025-01-13 18:38:38 +03:00
Abdulmohsen
0614a09231
Merge pull request #166 from arabcoders/dev
Added way to check for youtube cookies status
2025-01-11 21:10:05 +03:00
Abdulmohsen
1cc4d73051
Merge pull request #165 from arabcoders/dev
Added new option to view url info
2025-01-11 17:13:11 +03:00
Abdulmohsen
ec8cd6b88a
Merge pull request #164 from arabcoders/dev
fixed typo in README and updated dependencies
2025-01-10 19:20:41 +03:00
Abdulmohsen
2e99ff1f5e
Merge pull request #163 from arabcoders/dev
Fix and document presets.json
2025-01-10 19:05:47 +03:00
Abdulmohsen
9adf48e404
Merge pull request #162 from arabcoders/dev
updates API endpoints, fix webhooks not firing due to an error.
2025-01-03 20:41:03 +03:00
Abdulmohsen
fa2fd2970a
Merge pull request #161 from arabcoders/dev
Fix download audio only preset
2025-01-03 00:48:41 +03:00
Abdulmohsen
4094e98feb
Merge pull request #159 from arabcoders/dev
fix cancelling selected items.
2025-01-02 21:37:47 +03:00
Abdulmohsen
5301e134ce
Merge pull request #157 from arabcoders/dev
fix yt-dlp Impersonate target and webhook not firing
2025-01-02 19:16:26 +03:00
Abdulmohsen
02ba97b8ab
Merge pull request #156 from arabcoders/dev
added confirm to pause download pool
2025-01-01 16:53:33 +03:00
Abdulmohsen
e415edd761
Merge pull request #155 from arabcoders/dev
Added the ability to pause download pool
2024-12-31 18:26:28 +03:00
Abdulmohsen
0682f9d443
Merge pull request #154 from arabcoders/dev
Minor UI changes
2024-12-29 22:07:31 +03:00
Abdulmohsen
0230f00a8c
Merge pull request #152 from arabcoders/dev
Document env variables and added remove_files env option.
2024-12-25 19:56:03 +03:00
Abdulmohsen
14d598eb10
Merge pull request #151 from arabcoders/dev 2024-12-25 10:26:52 +03:00
43 changed files with 2985 additions and 3138 deletions

View file

@ -30,8 +30,5 @@
"editor.defaultFormatter": "oxc.oxc-vscode", "editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.formatOnSaveMode": "file" "editor.formatOnSaveMode": "file"
},
"files.associations": {
"*.css": "tailwindcss"
} }
} }

5
FAQ.md
View file

@ -3,9 +3,8 @@
Certain configuration values can be set via environment variables, using the `-e` parameter on the docker command line, Certain configuration values can be set via environment variables, using the `-e` parameter on the docker command line,
or the `environment:` section in `compose.yaml` file. or the `environment:` section in `compose.yaml` file.
<details> <details>
<summary>Click to expand all environment Variables</summary> <summary>Click to expand</summary>
| Environment Variable | Description | Default | | Environment Variable | Description | Default |
| ------------------------------- | ------------------------------------------------------------------- | --------------------- | | ------------------------------- | ------------------------------------------------------------------- | --------------------- |
@ -65,6 +64,7 @@ or the `environment:` section in `compose.yaml` file.
| YTP_THUMB_GENERATE | Enable ffmpeg thumbnail generation when no local thumbnail exists. | `true` | | YTP_THUMB_GENERATE | Enable ffmpeg thumbnail generation when no local thumbnail exists. | `true` |
| YTP_THUMB_SIDECAR | Save generated thumbnails next to media instead of temp cache. | `false` | | YTP_THUMB_SIDECAR | Save generated thumbnails next to media instead of temp cache. | `false` |
| YTP_DISABLE_EXEC | Strip some dangerous yt-dlp options. | `false` | | YTP_DISABLE_EXEC | Strip some dangerous yt-dlp options. | `false` |
</details>
> [!NOTE] > [!NOTE]
> To raise the worker limit for a specific extractor, set an env variable using this format: `YTP_MAX_WORKERS_FOR_<EXTRACTOR_NAME>` > To raise the worker limit for a specific extractor, set an env variable using this format: `YTP_MAX_WORKERS_FOR_<EXTRACTOR_NAME>`
@ -77,7 +77,6 @@ or the `environment:` section in `compose.yaml` file.
> `YTP_AUTO_CLEAR_HISTORY_DAYS` `0` days means no automatic clearing of the download history. lowest value that will > `YTP_AUTO_CLEAR_HISTORY_DAYS` `0` days means no automatic clearing of the download history. lowest value that will
> trigger the clearing is `1` day. This setting will **NOT** delete the downloaded files, it will only clear the > trigger the clearing is `1` day. This setting will **NOT** delete the downloaded files, it will only clear the
> history from the database. > history from the database.
</details>
# Browser extensions & bookmarklets # Browser extensions & bookmarklets

View file

@ -7,69 +7,5 @@ export default defineAppConfig({
success: 'emerald', success: 'emerald',
neutral: 'stone', neutral: 'stone',
}, },
formField: {
slots: {
label: 'block font-bold text-default',
},
},
tooltip: {
slots: {
content: 'pointer-events-auto',
},
},
dropdownMenu: {
slots: {
content: 'ytp-floating-surface',
},
},
popover: {
slots: {
content: 'ytp-floating-surface',
},
},
select: {
slots: {
content: 'ytp-floating-surface',
},
variants: {
variant: {
outline: 'bg-elevated/40 hover:bg-elevated/55 disabled:bg-elevated/20',
},
},
},
selectMenu: {
slots: {
content: 'ytp-floating-surface',
},
variants: {
variant: {
outline: 'bg-elevated/40 hover:bg-elevated/55 disabled:bg-elevated/20',
},
},
},
button: {
compoundVariants: [
{
color: 'neutral',
variant: 'outline',
class:
'bg-transparent hover:bg-elevated/30 active:bg-elevated/40 disabled:bg-transparent aria-disabled:bg-transparent',
},
{
color: 'neutral',
variant: 'soft',
class:
'bg-elevated/30 hover:bg-elevated/45 active:bg-elevated/55 disabled:bg-elevated/20 aria-disabled:bg-elevated/20',
},
{
color: 'neutral',
variant: 'ghost',
class: 'hover:bg-elevated/30 active:bg-elevated/40 focus-visible:bg-elevated/30',
},
],
defaultVariants: {
size: 'sm',
},
},
}, },
}); });

View file

@ -1,5 +1,3 @@
@layer theme, base, legacy, components, utilities;
@import 'tailwindcss'; @import 'tailwindcss';
@import '@nuxt/ui'; @import '@nuxt/ui';
@ -32,11 +30,6 @@
html.simple-mode.bg-fanart #__nuxt { html.simple-mode.bg-fanart #__nuxt {
background-image: none !important; background-image: none !important;
} }
html.dark.simple-mode.bg-fanart body,
html.dark.simple-mode.bg-fanart #__nuxt {
background-color: var(--ui-bg) !important;
}
} }
@layer components { @layer components {
@ -58,9 +51,9 @@
.shell-surface { .shell-surface {
background: background:
radial-gradient(circle at top left, rgb(99 102 241 / 0.14), transparent 28%), radial-gradient(circle at top left, rgb(99 102 241 / 0.1), transparent 28%),
radial-gradient(circle at top right, rgb(245 158 11 / 0.12), transparent 22%), radial-gradient(circle at top right, rgb(245 158 11 / 0.08), transparent 22%),
linear-gradient(180deg, rgb(255 255 255 / 0.6), rgb(248 250 252 / 0.72)); linear-gradient(180deg, rgb(255 255 255 / 0.84), rgb(248 250 252 / 0.9));
backdrop-filter: blur(16px); backdrop-filter: blur(16px);
} }
@ -72,115 +65,6 @@
backdrop-filter: blur(16px); backdrop-filter: blur(16px);
} }
.ytp-page-header {
@apply flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between;
}
.ytp-page-heading {
@apply flex min-w-0 items-center gap-3;
}
.ytp-page-kicker {
@apply flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned;
}
.ytp-page-icon {
@apply inline-flex size-11 shrink-0 items-center justify-center rounded-md border bg-elevated/70 text-primary;
border-color: var(--ytp-surface-border-solid);
}
.ytp-section-icon {
@apply inline-flex size-10 shrink-0 items-center justify-center rounded-md border bg-elevated/70 text-primary;
border-color: var(--ytp-surface-border-solid);
}
.ytp-detail-icon {
@apply inline-flex size-9 shrink-0 items-center justify-center rounded-md border bg-elevated/70 text-primary;
border-color: var(--ytp-surface-border-solid);
}
.ytp-card {
@apply min-w-0 max-w-full rounded-lg border bg-elevated/20;
border-color: var(--ytp-surface-border-soft);
}
.ytp-card-padded {
@apply min-w-0 max-w-full rounded-lg border bg-elevated/20 p-4;
border-color: var(--ytp-surface-border-soft);
}
.ytp-card-padded-lg {
@apply min-w-0 max-w-full rounded-lg border bg-elevated/20 p-4 sm:p-5;
border-color: var(--ytp-surface-border-soft);
}
.ytp-panel {
@apply min-w-0 max-w-full rounded-lg border;
border-color: var(--ytp-surface-border-soft);
}
.ytp-panel-padded {
@apply min-w-0 max-w-full rounded-lg border p-4;
border-color: var(--ytp-surface-border-soft);
}
.ytp-panel-padded-lg {
@apply min-w-0 max-w-full rounded-lg border p-4 sm:p-5;
border-color: var(--ytp-surface-border-soft);
}
.ytp-frame {
@apply min-w-0 max-w-full rounded-lg border;
border-color: var(--ytp-surface-border-soft);
}
.ytp-table-surface {
@apply min-w-0 max-w-full rounded-sm border bg-elevated/20;
border-color: var(--ytp-surface-border-solid);
}
.ytp-floating-surface {
@apply border bg-default/95 shadow-xl backdrop-blur-md;
border-color: var(--ytp-surface-border-solid);
box-shadow: 0 1rem 2rem rgb(15 23 42 / 0.1);
}
.ytp-floating-surface [data-slot='item'][data-highlighted]::before,
.ytp-floating-surface [data-slot='item'][data-state='open']::before,
.ytp-floating-surface [data-slot='item']:hover::before {
background-color: color-mix(in oklab, var(--ui-primary) 11%, transparent) !important;
}
.ytp-floating-surface [data-slot='item'][data-disabled]::before {
background-color: transparent !important;
}
.dark .ytp-floating-surface {
background: color-mix(in oklab, var(--ui-bg) 92%, var(--ui-bg-elevated) 8%);
box-shadow: 0 1rem 2rem rgb(0 0 0 / 0.3);
}
.dark .ytp-floating-surface [data-slot='item'][data-highlighted]::before,
.dark .ytp-floating-surface [data-slot='item'][data-state='open']::before,
.dark .ytp-floating-surface [data-slot='item']:hover::before {
background-color: color-mix(in oklab, var(--ui-primary) 16%, transparent) !important;
}
.ytp-border-top-soft {
@apply border-t;
border-color: var(--ytp-surface-border-soft);
}
.ytp-border-bottom-soft {
@apply border-b;
border-color: var(--ytp-surface-border-soft);
}
.ytp-border-left-soft {
@apply border-l;
border-color: var(--ytp-surface-border-soft);
}
.ytp-terminal { .ytp-terminal {
display: block; display: block;
width: 100%; width: 100%;
@ -283,15 +167,6 @@
--ui-radius: 0.5rem; --ui-radius: 0.5rem;
--ui-container: 96rem; --ui-container: 96rem;
--ui-header-height: 4.25rem; --ui-header-height: 4.25rem;
--ytp-border-strong: var(--ui-border-accented);
--ytp-surface-border-soft: var(--ui-border-accented);
--ytp-surface-border-solid: var(--ui-border-accented);
}
.dark {
--ytp-border-strong: var(--ui-border);
--ytp-surface-border-soft: color-mix(in oklab, var(--ui-border) 70%, transparent);
--ytp-surface-border-solid: var(--ui-border);
} }
html:not(.no-page-anim) .page-enter-active { html:not(.no-page-anim) .page-enter-active {

View file

@ -261,7 +261,9 @@
</div> </div>
</div> </div>
<div class="grid gap-3 ytp-card-padded md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]"> <div
class="grid gap-3 rounded-lg border border-default bg-default p-4 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)_auto]"
>
<UFormField :ui="fieldUi"> <UFormField :ui="fieldUi">
<template #label> <template #label>
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">

View file

@ -1,7 +1,7 @@
<template> <template>
<div v-if="'bool' === type && compact" class="w-full space-y-1.5"> <div v-if="'bool' === type && compact" class="w-full space-y-1.5">
<div <div
class="flex min-h-11 items-start justify-between gap-3 rounded-md border border-default bg-elevated/20 px-3 py-2" class="flex min-h-11 items-start justify-between gap-3 rounded-md border border-default bg-default/80 px-3 py-2"
> >
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="inline-flex min-w-0 items-center gap-2 text-sm font-semibold text-default"> <div class="inline-flex min-w-0 items-center gap-2 text-sm font-semibold text-default">
@ -27,7 +27,7 @@
v-model="boolModel" v-model="boolModel"
:disabled="disabled" :disabled="disabled"
color="success" color="success"
label="" :label="boolModel ? 'Yes' : 'No'"
size="lg" size="lg"
class="shrink-0" class="shrink-0"
:ui="{ root: 'items-center gap-2', wrapper: 'ms-0 text-sm' }" :ui="{ root: 'items-center gap-2', wrapper: 'ms-0 text-sm' }"
@ -70,7 +70,7 @@
:disabled="disabled" :disabled="disabled"
size="lg" size="lg"
class="w-full" class="w-full"
:ui="{ root: 'w-full', base: 'w-full bg-elevated/60' }" :ui="{ root: 'w-full', base: 'w-full bg-default/90' }"
/> />
<UTextarea <UTextarea

View file

@ -20,7 +20,7 @@
<div <div
v-if="open && suggestions.length" v-if="open && suggestions.length"
ref="dropdownRef" ref="dropdownRef"
class="absolute inset-x-0 top-full z-20 mt-1 max-h-40 overflow-y-auto rounded-md ytp-floating-surface" class="absolute inset-x-0 top-full z-20 mt-1 max-h-40 overflow-y-auto rounded-md border border-default bg-default shadow-lg"
role="listbox" role="listbox"
> >
<button <button

View file

@ -12,7 +12,7 @@
variant="outline" variant="outline"
color="neutral" color="neutral"
class="w-full" class="w-full"
:ui="{ root: 'w-full', base: 'w-full bg-elevated/60', leadingIcon: iconClass }" :ui="{ root: 'w-full', base: 'w-full bg-default/90', leadingIcon: iconClass }"
@focus="onFocus" @focus="onFocus"
@blur="hideList" @blur="hideList"
@input="onInput" @input="onInput"
@ -25,7 +25,7 @@
<div <div
v-if="showList && filteredOptions.length" v-if="showList && filteredOptions.length"
ref="dropdownRef" ref="dropdownRef"
class="absolute inset-x-0 top-full z-20 mt-1 max-h-40 overflow-y-auto rounded-md ytp-floating-surface" class="absolute inset-x-0 top-full z-20 mt-1 max-h-40 overflow-y-auto rounded-md border border-default bg-default shadow-lg"
role="menu" role="menu"
> >
<button <button

View file

@ -25,7 +25,10 @@
</UButton> </UButton>
</div> </div>
<div v-if="!limits && limitsLoading" class="ytp-card flex min-h-72 items-center justify-center"> <div
v-if="!limits && limitsLoading"
class="flex min-h-72 items-center justify-center rounded-md border border-default bg-default/90"
>
<div class="flex flex-col items-center gap-3 text-center text-toned"> <div class="flex flex-col items-center gap-3 text-center text-toned">
<UIcon name="i-lucide-loader-circle" class="size-10 animate-spin text-info" /> <UIcon name="i-lucide-loader-circle" class="size-10 animate-spin text-info" />
@ -63,7 +66,7 @@
title="Download queue is paused" title="Download queue is paused"
/> />
<div class="ytp-card shadow-sm"> <div class="rounded-md border border-default bg-default shadow-sm">
<div class="grid gap-0 lg:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]"> <div class="grid gap-0 lg:grid-cols-[minmax(0,1.05fr)_minmax(0,0.95fr)]">
<section <section
class="space-y-4 border-b border-default px-4 py-4 sm:px-5 lg:border-r lg:border-b-0" class="space-y-4 border-b border-default px-4 py-4 sm:px-5 lg:border-r lg:border-b-0"
@ -194,10 +197,13 @@
description="Overrides and extractor usage appear here once activity is detected." description="Overrides and extractor usage appear here once activity is detected."
/> />
<div v-else class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface"> <div
v-else
class="w-full min-w-0 max-w-full overflow-hidden rounded-md border border-default bg-default"
>
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-180 w-full text-sm"> <table class="min-w-180 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >

View file

@ -119,7 +119,9 @@
@click="sourceOpen = !sourceOpen" @click="sourceOpen = !sourceOpen"
> >
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="ytp-detail-icon"> <span
class="inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon name="i-lucide-file-code" class="size-4" /> <UIcon name="i-lucide-file-code" class="size-4" />
</span> </span>
<p class="text-base font-semibold text-highlighted">Source</p> <p class="text-base font-semibold text-highlighted">Source</p>
@ -165,7 +167,9 @@
@click="fieldsOpen = !fieldsOpen" @click="fieldsOpen = !fieldsOpen"
> >
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="ytp-detail-icon"> <span
class="inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon name="i-lucide-tags" class="size-4" /> <UIcon name="i-lucide-tags" class="size-4" />
</span> </span>
<p class="text-base font-semibold text-highlighted">Fields</p> <p class="text-base font-semibold text-highlighted">Fields</p>
@ -221,16 +225,14 @@
> >
<button <button
type="button" type="button"
class="grid w-full grid-cols-[minmax(7rem,0.45fr)_minmax(0,1fr)] items-center gap-3 px-3 py-2 text-left sm:grid-cols-[minmax(0,12rem)_minmax(0,1fr)]" class="flex w-full items-center justify-between gap-3 px-3 py-2 text-left"
@click="toggleField(field.key)" @click="toggleField(field.key)"
> >
<span <span class="text-[11px] font-semibold uppercase tracking-wide text-toned">
class="min-w-0 truncate text-[11px] font-semibold uppercase tracking-wide text-toned"
>
{{ field.label }} {{ field.label }}
</span> </span>
<div class="flex min-w-0 items-center justify-end gap-2"> <div class="flex items-center gap-2">
<span v-if="field.preview" class="min-w-0 truncate text-xs text-toned"> <span v-if="field.preview" class="max-w-md truncate text-xs text-toned">
{{ field.preview }} {{ field.preview }}
</span> </span>
<UIcon <UIcon
@ -304,7 +306,9 @@
@click="rawJsonOpen = !rawJsonOpen" @click="rawJsonOpen = !rawJsonOpen"
> >
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<span class="ytp-detail-icon"> <span
class="inline-flex size-9 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon name="i-lucide-braces" class="size-4" /> <UIcon name="i-lucide-braces" class="size-4" />
</span> </span>
<p class="text-base font-semibold text-highlighted">Raw Data</p> <p class="text-base font-semibold text-highlighted">Raw Data</p>

View file

@ -1,7 +1,8 @@
<template> <template>
<main class="space-y-4"> <main class="space-y-4">
<form autocomplete="off" class="space-y-4" @submit.prevent="addDownload"> <form autocomplete="off" class="space-y-4" @submit.prevent="addDownload">
<div class="ytp-card p-4 sm:p-6 space-y-4"> <UPageCard variant="outline" :ui="downloadCardUi">
<template #body>
<div class="space-y-4"> <div class="space-y-4">
<UFormField class="w-full" :ui="downloadFieldUi"> <UFormField class="w-full" :ui="downloadFieldUi">
<template #label> <template #label>
@ -25,7 +26,7 @@
v-model="form.url" v-model="form.url"
:disabled="addInProgress" :disabled="addInProgress"
size="lg" size="lg"
:variant="show_description ? 'soft' : 'outline'" variant="outline"
color="neutral" color="neutral"
class="w-full" class="w-full"
:rows="3" :rows="3"
@ -46,7 +47,7 @@
placeholder="URLs to download" placeholder="URLs to download"
:disabled="addInProgress" :disabled="addInProgress"
size="lg" size="lg"
:variant="show_description ? 'soft' : 'outline'" variant="outline"
color="neutral" color="neutral"
class="w-full" class="w-full"
:ui="{ :ui="{
@ -96,7 +97,7 @@
<div class="flex w-full gap-2"> <div class="flex w-full gap-2">
<UButton <UButton
color="neutral" color="neutral"
:variant="show_description ? 'soft' : 'outline'" variant="outline"
icon="i-lucide-info" icon="i-lucide-info"
square square
class="shrink-0" class="shrink-0"
@ -157,7 +158,7 @@
<UButton <UButton
type="button" type="button"
color="neutral" color="neutral"
:variant="showAdvanced ? 'soft' : 'outline'" variant="outline"
icon="i-lucide-settings-2" icon="i-lucide-settings-2"
size="lg" size="lg"
class="w-full justify-center" class="w-full justify-center"
@ -184,9 +185,11 @@
</span> </span>
</button> </button>
</div> </div>
</div> </template>
</UPageCard>
<div v-if="showAdvanced" class="ytp-card p-4 sm:p-6 space-y-4"> <UPageCard v-if="showAdvanced" variant="outline" :ui="downloadCardUi">
<template #body>
<div class="space-y-4"> <div class="space-y-4">
<div class="grid gap-3 md:grid-cols-2 xl:grid-cols-12"> <div class="grid gap-3 md:grid-cols-2 xl:grid-cols-12">
<div class="xl:col-span-2"> <div class="xl:col-span-2">
@ -399,7 +402,10 @@
</UFormField> </UFormField>
</div> </div>
<div v-if="config.dl_fields.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-2"> <div
v-if="config.dl_fields.length > 0"
class="grid gap-4 md:grid-cols-2 xl:grid-cols-2"
>
<DLInput <DLInput
v-for="(fi, index) in sortedDLFields" v-for="(fi, index) in sortedDLFields"
:id="fi?.id || `dlf-${index}`" :id="fi?.id || `dlf-${index}`"
@ -415,7 +421,9 @@
</div> </div>
</div> </div>
<div class="flex flex-wrap items-center justify-between gap-2 border-t border-default pt-4"> <div
class="flex flex-wrap items-center justify-between gap-2 border-t border-default pt-4"
>
<UDropdownMenu class="sm:hidden" :items="mobileActionGroups" :modal="false"> <UDropdownMenu class="sm:hidden" :items="mobileActionGroups" :modal="false">
<UButton <UButton
color="neutral" color="neutral"
@ -430,11 +438,13 @@
<div class="hidden flex-wrap items-center gap-2 sm:flex"> <div class="hidden flex-wrap items-center gap-2 sm:flex">
<UButton <UButton
type="button" type="button"
color="neutral" color="info"
variant="outline" variant="outline"
icon="i-lucide-info" icon="i-lucide-info"
:disabled="addInProgress || !hasValidUrl" :disabled="addInProgress || !hasValidUrl"
@click="emitter('getInfo', splitUrls(form.url || '')[0] || '', form.preset, form.cli)" @click="
emitter('getInfo', splitUrls(form.url || '')[0] || '', form.preset, form.cli)
"
> >
yt-dlp Information yt-dlp Information
</UButton> </UButton>
@ -442,7 +452,7 @@
<UButton <UButton
v-if="config.app.console_enabled" v-if="config.app.console_enabled"
type="button" type="button"
color="neutral" color="warning"
variant="outline" variant="outline"
icon="i-lucide-terminal" icon="i-lucide-terminal"
:disabled="!hasValidUrl" :disabled="!hasValidUrl"
@ -454,7 +464,7 @@
<UButton <UButton
v-if="config.app.console_enabled" v-if="config.app.console_enabled"
type="button" type="button"
color="neutral" color="success"
variant="outline" variant="outline"
icon="i-lucide-flask-conical" icon="i-lucide-flask-conical"
:disabled="!hasValidUrl" :disabled="!hasValidUrl"
@ -466,7 +476,7 @@
<UButton <UButton
type="button" type="button"
color="neutral" color="error"
variant="outline" variant="outline"
icon="i-lucide-rotate-ccw" icon="i-lucide-rotate-ccw"
:disabled="!!form?.id" :disabled="!!form?.id"
@ -475,7 +485,8 @@
Reset local settings Reset local settings
</UButton> </UButton>
</div> </div>
</div> </template>
</UPageCard>
</form> </form>
<UModal <UModal
@ -696,6 +707,13 @@ const testResultsPreClasses = computed(() => [
testResultsClasses.value, testResultsClasses.value,
]); ]);
const downloadCardUi = {
root: 'w-full',
container: 'w-full p-4 sm:p-6',
wrapper: 'w-full items-stretch',
body: 'w-full space-y-4',
};
const downloadFieldUi = { const downloadFieldUi = {
label: 'font-semibold text-default', label: 'font-semibold text-default',
container: 'space-y-2', container: 'space-y-2',
@ -775,6 +793,7 @@ const mobileActionGroups = computed(() => {
{ {
label: 'Reset local settings', label: 'Reset local settings',
icon: 'i-lucide-rotate-ccw', icon: 'i-lucide-rotate-ccw',
color: 'error',
disabled: Boolean(form.value?.id), disabled: Boolean(form.value?.id),
onSelect: () => void resetConfig(), onSelect: () => void resetConfig(),
}, },

View file

@ -86,7 +86,7 @@
<UIcon name="i-lucide-check" class="size-3.5" /> <UIcon name="i-lucide-check" class="size-3.5" />
</UButton> </UButton>
<UButton <UButton
color="neutral" color="error"
variant="ghost" variant="ghost"
size="xs" size="xs"
square square
@ -121,7 +121,7 @@
</UButton> </UButton>
<UButton <UButton
color="neutral" color="error"
variant="ghost" variant="ghost"
size="sm" size="sm"
icon="i-lucide-trash" icon="i-lucide-trash"

View file

@ -1,36 +0,0 @@
<template>
<div class="ytp-page-header">
<div class="ytp-page-heading">
<span class="ytp-page-icon">
<slot name="icon">
<UIcon :name="icon" class="size-5" />
</slot>
</span>
<div class="min-w-0" :class="contentClass">
<div class="ytp-page-kicker">
<slot name="kicker">
<span>{{ sectionLabel }}</span>
<span>/</span>
<span>{{ pageLabel }}</span>
</slot>
</div>
</div>
</div>
<div
v-if="$slots.actions"
class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"
>
<slot name="actions" />
</div>
</div>
</template>
<script setup lang="ts">
import type { YtpPageHeaderProps } from '~/types';
withDefaults(defineProps<YtpPageHeaderProps>(), {
contentClass: 'space-y-1',
});
</script>

View file

@ -30,15 +30,15 @@
<template #body> <template #body>
<div class="w-full space-y-6"> <div class="w-full space-y-6">
<div class="ytp-card w-full"> <UPageCard variant="subtle" class="w-full" :ui="settingsCardUi">
<div class="p-4 sm:p-5 ytp-border-bottom-soft"> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UIcon name="i-lucide-layout-dashboard" class="size-4 text-toned" /> <UIcon name="i-lucide-layout-dashboard" class="size-4 text-toned" />
<span class="text-sm font-semibold text-highlighted">Page View</span> <span class="text-sm font-semibold text-highlighted">Page View</span>
</div> </div>
</div> </template>
<div class="p-4 sm:p-5 space-y-4"> <template #body>
<UFormField label="" class="w-full" :ui="settingsFieldUi"> <UFormField label="" class="w-full" :ui="settingsFieldUi">
<USelect <USelect
v-model="draftMode" v-model="draftMode"
@ -73,18 +73,18 @@
:label="page_anims ? 'Animations On' : 'Animations Off'" :label="page_anims ? 'Animations On' : 'Animations Off'"
description="Enable page transition animations." description="Enable page transition animations."
/> />
</div> </template>
</div> </UPageCard>
<div class="ytp-card w-full"> <UPageCard variant="subtle" class="w-full" :ui="settingsCardUi">
<div class="p-4 sm:p-5 ytp-border-bottom-soft"> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UIcon name="i-lucide-image" class="size-4 text-toned" /> <UIcon name="i-lucide-image" class="size-4 text-toned" />
<span class="text-sm font-semibold text-highlighted">Background</span> <span class="text-sm font-semibold text-highlighted">Background</span>
</div> </div>
</div> </template>
<div class="p-4 sm:p-5 space-y-4"> <template #body>
<USwitch <USwitch
v-model="bg_enable" v-model="bg_enable"
class="w-full" class="w-full"
@ -95,7 +95,7 @@
<UButton <UButton
v-if="bg_enable" v-if="bg_enable"
color="neutral" color="info"
variant="outline" variant="outline"
icon="i-lucide-image-up" icon="i-lucide-image-up"
class="w-full justify-center" class="w-full justify-center"
@ -121,18 +121,18 @@
class="w-full" class="w-full"
/> />
</UFormField> </UFormField>
</div> </template>
</div> </UPageCard>
<div class="ytp-card w-full"> <UPageCard variant="subtle" class="w-full" :ui="settingsCardUi">
<div class="p-4 sm:p-5 ytp-border-bottom-soft"> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UIcon name="i-lucide-monitor" class="size-4 text-toned" /> <UIcon name="i-lucide-monitor" class="size-4 text-toned" />
<span class="text-sm font-semibold text-highlighted">Downloads</span> <span class="text-sm font-semibold text-highlighted">Downloads</span>
</div> </div>
</div> </template>
<div class="p-4 sm:p-5 space-y-4"> <template #body>
<UFormField v-if="!modeOn" label="URL Separator" class="w-full" :ui="settingsFieldUi"> <UFormField v-if="!modeOn" label="URL Separator" class="w-full" :ui="settingsFieldUi">
<USelect <USelect
v-model="separator" v-model="separator"
@ -179,18 +179,18 @@
:label="show_popover ? 'Popover On' : 'Popover Off'" :label="show_popover ? 'Popover On' : 'Popover Off'"
description="Show additional information over certain elements." description="Show additional information over certain elements."
/> />
</div> </template>
</div> </UPageCard>
<div class="ytp-card w-full"> <UPageCard variant="subtle" class="w-full" :ui="settingsCardUi">
<div class="p-4 sm:p-5 ytp-border-bottom-soft"> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UIcon name="i-lucide-download" class="size-4 text-toned" /> <UIcon name="i-lucide-download" class="size-4 text-toned" />
<span class="text-sm font-semibold text-highlighted">Queue</span> <span class="text-sm font-semibold text-highlighted">Queue</span>
</div> </div>
</div> </template>
<div class="p-4 sm:p-5 space-y-4"> <template #body>
<USwitch <USwitch
v-model="queue_auto_refresh" v-model="queue_auto_refresh"
class="w-full" class="w-full"
@ -219,18 +219,18 @@
How often to refresh the queue (5-60 seconds). Lower values increase server load. How often to refresh the queue (5-60 seconds). Lower values increase server load.
</p> </p>
</UFormField> </UFormField>
</div> </template>
</div> </UPageCard>
<div class="ytp-card w-full"> <UPageCard variant="subtle" class="w-full" :ui="settingsCardUi">
<div class="p-4 sm:p-5 ytp-border-bottom-soft"> <template #header>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UIcon name="i-lucide-bell" class="size-4 text-toned" /> <UIcon name="i-lucide-bell" class="size-4 text-toned" />
<span class="text-sm font-semibold text-highlighted">Notifications</span> <span class="text-sm font-semibold text-highlighted">Notifications</span>
</div> </div>
</div> </template>
<div class="p-4 sm:p-5 space-y-4"> <template #body>
<USwitch <USwitch
v-model="allow_toasts" v-model="allow_toasts"
class="w-full" class="w-full"
@ -288,8 +288,8 @@
:ui="settingsSwitchUi" :ui="settingsSwitchUi"
:label="toast_dismiss_on_click ? 'Dismiss on click' : 'Keep on click'" :label="toast_dismiss_on_click ? 'Dismiss on click' : 'Keep on click'"
/> />
</div> </template>
</div> </UPageCard>
</div> </div>
</template> </template>
</USlideover> </USlideover>
@ -337,6 +337,13 @@ const queue_auto_refresh = useStorage<boolean>('queue_auto_refresh', true);
const queue_auto_refresh_delay = useStorage<number>('queue_auto_refresh_delay', 10000); const queue_auto_refresh_delay = useStorage<number>('queue_auto_refresh_delay', 10000);
const isSecureContext = ref<boolean>(false); const isSecureContext = ref<boolean>(false);
const settingsCardUi = {
root: 'w-full',
container: 'w-full p-4 sm:p-5',
wrapper: 'w-full items-stretch',
body: 'w-full space-y-4',
};
const settingsFieldUi = { const settingsFieldUi = {
root: 'w-full', root: 'w-full',
container: 'mt-2 w-full', container: 'mt-2 w-full',
@ -408,10 +415,6 @@ const toastPositionItems: Array<{ label: string; value: toastPosition }> = [
{ label: 'bottom-right', value: 'bottom-right' }, { label: 'bottom-right', value: 'bottom-right' },
]; ];
const closeScrollLock = (): void => {
document.body.classList.remove('settings-panel-open');
};
const handleKeydown = (e: KeyboardEvent) => { const handleKeydown = (e: KeyboardEvent) => {
if ('Escape' === e.key && props.isOpen) { if ('Escape' === e.key && props.isOpen) {
e.preventDefault(); e.preventDefault();
@ -431,10 +434,7 @@ onMounted(async () => {
document.addEventListener('keydown', handleKeydown); document.addEventListener('keydown', handleKeydown);
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => document.removeEventListener('keydown', handleKeydown));
document.removeEventListener('keydown', handleKeydown);
closeScrollLock();
});
const onNotificationTargetChange = async (): Promise<void> => { const onNotificationTargetChange = async (): Promise<void> => {
if ('browser' === toast_target.value) { if ('browser' === toast_target.value) {
@ -455,7 +455,7 @@ watch(
draftMode.value = mode.value; draftMode.value = mode.value;
document.body.classList.add('settings-panel-open'); document.body.classList.add('settings-panel-open');
} else { } else {
closeScrollLock(); document.body.classList.remove('settings-panel-open');
} }
}, },
); );

View file

@ -1,22 +1,16 @@
<template> <template>
<div class="ytp-card bg-elevated/40 p-3"> <div class="rounded-lg border border-default/70 bg-elevated/40 p-3">
<div class="flex items-center justify-between gap-3"> <div class="flex items-center justify-between gap-3">
<div class="min-w-0 space-y-1"> <div class="min-w-0 space-y-1">
<p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-toned">{{ label }}</p> <p class="text-[11px] font-semibold uppercase tracking-[0.18em] text-toned">{{ label }}</p>
<UTooltip v-if="tooltip" :text="tooltip" :content="{ side: 'left' }"> <UTooltip v-if="tooltip" :text="tooltip" :content="{ side: 'left' }">
<div :class="valueWrap ? 'space-y-1' : 'flex items-baseline gap-1.5'"> <div class="flex items-baseline gap-1.5">
<span class="text-sm font-semibold text-highlighted">{{ value }}</span> <span class="text-sm font-semibold text-highlighted">{{ value }}</span>
<span v-if="hint" class="truncate text-xs text-toned">{{ hint }}</span> <span v-if="hint" class="truncate text-xs text-toned">{{ hint }}</span>
</div> </div>
</UTooltip> </UTooltip>
<div v-else :class="valueWrap ? 'space-y-1' : 'flex items-baseline gap-1.5'"> <div v-else class="flex items-baseline gap-1.5">
<span <span class="text-sm font-semibold text-highlighted">{{ value }}</span>
:class="[
'text-sm font-semibold text-highlighted',
valueWrap ? 'block wrap-break-word' : '',
]"
>{{ value }}</span
>
<span v-if="hint" class="truncate text-xs text-toned">{{ hint }}</span> <span v-if="hint" class="truncate text-xs text-toned">{{ hint }}</span>
</div> </div>
</div> </div>
@ -43,9 +37,8 @@ const props = withDefaults(
hint?: string; hint?: string;
tooltip?: string; tooltip?: string;
color?: Color; color?: Color;
valueWrap?: boolean;
}>(), }>(),
{ color: 'primary', hint: '', tooltip: '', valueWrap: false }, { color: 'primary', hint: '', tooltip: '' },
); );
const TILE_BG: Record<Color, string> = { const TILE_BG: Record<Color, string> = {

View file

@ -363,10 +363,12 @@
</UButton> </UButton>
</div> </div>
<div class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface"> <div
class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
>
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-215 table-fixed w-full text-sm"> <table class="min-w-215 table-fixed w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >

View file

@ -116,7 +116,7 @@
<span>Result:</span> <span>Result:</span>
</div> </div>
<div class="overflow-hidden ytp-frame"> <div class="overflow-hidden rounded-lg border border-default bg-default">
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<pre <pre
class="min-w-0 max-w-full overflow-x-auto p-4 text-xs leading-6 text-default" class="min-w-0 max-w-full overflow-x-auto p-4 text-xs leading-6 text-default"

View file

@ -34,7 +34,7 @@
<div <div
v-if="showList && filteredOptions.length" v-if="showList && filteredOptions.length"
class="absolute inset-x-0 top-full z-20 mt-1 overflow-hidden rounded-md ytp-floating-surface" class="absolute inset-x-0 top-full z-20 mt-1 overflow-hidden rounded-md border border-default bg-default shadow-lg"
role="menu" role="menu"
> >
<button <button

View file

@ -94,7 +94,6 @@
:label="nativeSubtitleTrack.name || 'Subtitles'" :label="nativeSubtitleTrack.name || 'Subtitles'"
default default
:src="uri(nativeSubtitleTrack.url)" :src="uri(nativeSubtitleTrack.url)"
@load="handleNativeTrackLoad"
/> />
Your browser does not support the video tag. Your browser does not support the video tag.
</video> </video>
@ -171,30 +170,16 @@
@click="forceSwitchToHls" @click="forceSwitchToHls"
/> />
</UTooltip> </UTooltip>
<USelect <UButton
v-if="hasSubtitles" v-if="hasSubtitles"
v-model="subtitleSelectValue"
:items="subtitleSelectItems"
value-key="value"
label-key="label"
color="neutral" color="neutral"
variant="soft" variant="soft"
size="sm" size="sm"
trailing-icon=""
:content="subtitleSelectContent"
:portal="helpPortal"
:ui="subtitleSelectUi"
class="opacity-65 transition-opacity hover:opacity-100 focus-visible:opacity-100" class="opacity-65 transition-opacity hover:opacity-100 focus-visible:opacity-100"
:aria-label="subtitleButtonLabel" :icon="subtitleEnabled ? 'i-lucide-captions' : 'i-lucide-captions-off'"
> :aria-label="subtitleEnabled ? 'Disable subtitles' : 'Enable subtitles'"
<template #default> @click="subtitleEnabled = !subtitleEnabled"
<span class="sr-only">{{ subtitleButtonLabel }}</span>
<UIcon
:name="subtitleEnabled ? 'i-lucide-captions' : 'i-lucide-captions-off'"
class="size-4 shrink-0"
/> />
</template>
</USelect>
<UButton <UButton
color="neutral" color="neutral"
variant="soft" variant="soft"
@ -444,12 +429,9 @@ const timeLabel = computed(() => {
return `${currentLabel} / ${durationLabel}`; return `${currentLabel} / ${durationLabel}`;
}); });
const { const {
subtitleTracks,
subtitleLoading, subtitleLoading,
subtitleLoadError, subtitleLoadError,
subtitleEnabled, subtitleEnabled,
selectedSubtitleTrack,
selectedSubtitleTrackId,
nativeSubtitleTrack, nativeSubtitleTrack,
usesAssSubtitleTrack, usesAssSubtitleTrack,
hasSubtitles, hasSubtitles,
@ -463,40 +445,6 @@ const {
overlay: assOverlayElement, overlay: assOverlayElement,
}); });
const SUBTITLE_OFF_VALUE = '__off__';
const subtitleSelectContent = { align: 'end' as const } as const;
const subtitleSelectUi = {
base: 'size-8 min-h-8 min-w-8 justify-center rounded-md px-0',
value: 'flex items-center justify-center px-0',
trailing: 'hidden',
leading: 'hidden',
content: 'z-40 min-w-56 w-auto max-w-[min(24rem,calc(100vw-2rem))]',
} as const;
const subtitleSelectItems = computed(() => [
{ label: 'Off', value: SUBTITLE_OFF_VALUE },
...subtitleTracks.value.map((track) => ({ label: track.name, value: track.url })),
]);
const subtitleButtonLabel = computed(() => {
if (!subtitleEnabled.value || !selectedSubtitleTrack.value) {
return 'Subtitles off';
}
return selectedSubtitleTrack.value.name || 'Subtitles';
});
const subtitleSelectValue = computed<string>({
get: () =>
subtitleEnabled.value
? (selectedSubtitleTrackId.value ?? SUBTITLE_OFF_VALUE)
: SUBTITLE_OFF_VALUE,
set: (value: string) => {
if (SUBTITLE_OFF_VALUE === value) {
subtitleEnabled.value = false;
return;
}
selectedSubtitleTrackId.value = value;
subtitleEnabled.value = true;
},
});
useHead(() => (title.value ? { title: formatPageTitle(`Playing: ${title.value}`) } : {})); useHead(() => (title.value ? { title: formatPageTitle(`Playing: ${title.value}`) } : {}));
watch( watch(
@ -1012,10 +960,6 @@ function updateMediaSessionPosition(target: EventTarget | null) {
} }
async function restoreDefaultTextTrack() { async function restoreDefaultTextTrack() {
if (true === destroyed.value) {
return;
}
const el = videoElement.value; const el = videoElement.value;
if (!el) { if (!el) {
return; return;
@ -1027,6 +971,36 @@ async function restoreDefaultTextTrack() {
return; return;
} }
const firstTrack = tracksList[0] as TextTrack | undefined;
const needsReload = firstTrack && (!firstTrack.cues || firstTrack.cues.length === 0);
if (needsReload) {
const trackElements = el.querySelectorAll('track');
trackElements.forEach((trackEl, idx) => {
const parent = trackEl.parentNode;
const clone = trackEl.cloneNode(true) as HTMLTrackElement;
trackEl.remove();
setTimeout(() => {
if (parent) {
parent.appendChild(clone);
clone.addEventListener(
'load',
() => {
const trackObj = clone.track;
if (trackObj) {
trackObj.mode = idx === 0 && subtitleEnabled.value ? 'showing' : 'disabled';
}
},
{ once: true },
);
}
}, idx * 10);
});
return;
}
for (let i = 0; i < tracksList.length; i += 1) { for (let i = 0; i < tracksList.length; i += 1) {
const track = tracksList[i] as TextTrack | undefined; const track = tracksList[i] as TextTrack | undefined;
if (track) { if (track) {
@ -1036,34 +1010,18 @@ async function restoreDefaultTextTrack() {
await new Promise((resolve) => setTimeout(resolve, 50)); await new Promise((resolve) => setTimeout(resolve, 50));
if (el !== videoElement.value) { for (let i = 0; i < tracksList.length; i += 1) {
return; const track = tracksList[i] as TextTrack | undefined;
}
if (false === subtitleEnabled.value || null === nativeSubtitleTrack.value) {
return;
}
const activeTracksList = el.textTracks;
for (let i = 0; i < activeTracksList.length; i += 1) {
const track = activeTracksList[i] as TextTrack | undefined;
if (!track) { if (!track) {
continue; continue;
} }
track.mode = i === 0 ? 'showing' : 'disabled'; track.mode = i === 0 && subtitleEnabled.value ? 'showing' : 'disabled';
} }
} catch (error) { } catch (error) {
console.warn('Failed to restore subtitle track state', error); console.warn('Failed to restore subtitle track state', error);
} }
} }
function handleNativeTrackLoad() {
if (true === destroyed.value) {
return;
}
void restoreDefaultTextTrack();
}
function applyMediaSessionMetadata() { function applyMediaSessionMetadata() {
if (false === 'mediaSession' in navigator) { if (false === 'mediaSession' in navigator) {
return; return;
@ -1284,10 +1242,6 @@ watch(subtitleEnabled, () => {
void nextTick(() => restoreDefaultTextTrack()); void nextTick(() => restoreDefaultTextTrack());
}); });
watch(selectedSubtitleTrack, () => {
void nextTick(() => restoreDefaultTextTrack());
});
onMounted(async () => { onMounted(async () => {
disableOpacity(); disableOpacity();
isTouchDevice.value = window.matchMedia('(pointer: coarse)').matches; isTouchDevice.value = window.matchMedia('(pointer: coarse)').matches;

View file

@ -123,10 +123,12 @@
<UBadge color="neutral" variant="soft" size="sm">{{ group.items.length }}</UBadge> <UBadge color="neutral" variant="soft" size="sm">{{ group.items.length }}</UBadge>
</div> </div>
<div class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface"> <div
class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
>
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-180 w-full table-auto text-sm"> <table class="min-w-180 w-full table-auto text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-left [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -186,7 +188,10 @@
</section> </section>
</template> </template>
<div v-else class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface"> <div
v-else
class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
>
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-215 w-full table-auto text-sm"> <table class="min-w-215 w-full table-auto text-sm">
<thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">

View file

@ -11,7 +11,12 @@
/> />
</div> </div>
<div class="ytp-panel p-0 relative w-full max-w-xl overflow-hidden bg-default/95"> <UPageCard
variant="outline"
:ui="pageCardUi"
class="relative w-full max-w-xl overflow-hidden bg-default/95"
>
<template #body>
<div class="space-y-6 px-5 py-6 sm:px-7 sm:py-8" role="status" aria-live="polite"> <div class="space-y-6 px-5 py-6 sm:px-7 sm:py-8" role="status" aria-live="polite">
<div <div
class="inline-flex items-center gap-2 rounded-full border border-default bg-elevated/60 px-3 py-1.5 text-xs font-semibold tracking-[0.22em] text-toned uppercase" class="inline-flex items-center gap-2 rounded-full border border-default bg-elevated/60 px-3 py-1.5 text-xs font-semibold tracking-[0.22em] text-toned uppercase"
@ -44,8 +49,16 @@
description="The native app is closing background services and should exit shortly." description="The native app is closing background services and should exit shortly."
/> />
</div> </div>
</div> </template>
</UPageCard>
</div> </div>
</template> </template>
<script setup lang="ts"></script> <script setup lang="ts">
const pageCardUi = {
root: 'w-full bg-transparent shadow-2xl shadow-primary/5',
container: 'w-full p-0',
wrapper: 'w-full items-stretch',
body: 'w-full p-0',
};
</script>

View file

@ -54,10 +54,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
const subtitleLoading = ref(false); const subtitleLoading = ref(false);
const subtitleLoadError = ref(''); const subtitleLoadError = ref('');
const subtitleEnabled = ref(true); const subtitleEnabled = ref(true);
const selectedTrackId = ref<string | null>(null); const selectedTrack = computed(() => tracks.value[0] || null);
const selectedTrack = computed(
() => tracks.value.find((track) => track.url === selectedTrackId.value) || null,
);
const nativeSubtitleTrack = computed(() => { const nativeSubtitleTrack = computed(() => {
const track = selectedTrack.value; const track = selectedTrack.value;
return subtitleEnabled.value && track?.renderer === 'native' ? track : null; return subtitleEnabled.value && track?.renderer === 'native' ? track : null;
@ -85,7 +82,6 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
assRequestId += 1; assRequestId += 1;
destroyAssRenderer(); destroyAssRenderer();
tracks.value = []; tracks.value = [];
selectedTrackId.value = null;
subtitleLoadError.value = ''; subtitleLoadError.value = '';
if (!manifestUrl || !isVideo || !canPlay) { if (!manifestUrl || !isVideo || !canPlay) {
@ -108,7 +104,6 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
tracks.value = (payload as SubtitleManifestResponse).subtitles || []; tracks.value = (payload as SubtitleManifestResponse).subtitles || [];
if (tracks.value.length > 0) { if (tracks.value.length > 0) {
selectedTrackId.value = tracks.value[0]?.url || null;
subtitleEnabled.value = true; subtitleEnabled.value = true;
} }
} catch { } catch {
@ -217,7 +212,6 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
subtitleLoadError, subtitleLoadError,
subtitleEnabled, subtitleEnabled,
selectedSubtitleTrack: selectedTrack, selectedSubtitleTrack: selectedTrack,
selectedSubtitleTrackId: selectedTrackId,
nativeSubtitleTrack, nativeSubtitleTrack,
usesAssSubtitleTrack: usesAssTrack, usesAssSubtitleTrack: usesAssTrack,
hasSubtitles, hasSubtitles,

View file

@ -1,7 +1,8 @@
<template> <template>
<NuxtLayout name="error-layout"> <NuxtLayout name="error-layout">
<div class="flex min-h-full flex-1 items-start justify-center py-4 sm:py-8"> <div class="flex min-h-full flex-1 items-start justify-center py-4 sm:py-8">
<div class="ytp-card p-0 w-full"> <UPageCard variant="outline" :ui="pageCardUi" class="w-full">
<template #body>
<div class="space-y-6 px-4 py-5 sm:px-6 sm:py-6 lg:px-7"> <div class="space-y-6 px-4 py-5 sm:px-6 sm:py-6 lg:px-7">
<div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between"> <div class="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
@ -16,8 +17,8 @@
</h1> </h1>
<p class="max-w-3xl text-sm leading-6 text-toned"> <p class="max-w-3xl text-sm leading-6 text-toned">
An unexpected error interrupted this view. You can go back home or retry the current An unexpected error interrupted this view. You can go back home or retry the
route. current route.
</p> </p>
</div> </div>
@ -64,7 +65,8 @@
</div> </div>
</section> </section>
</div> </div>
</div> </template>
</UPageCard>
</div> </div>
</NuxtLayout> </NuxtLayout>
</template> </template>
@ -78,6 +80,13 @@ const props = defineProps<{
const showStacks = ref(false); const showStacks = ref(false);
const pageCardUi = {
root: 'w-full bg-default',
container: 'w-full p-0',
wrapper: 'w-full items-stretch',
body: 'w-full p-0',
};
const handleRetry = async (): Promise<void> => { const handleRetry = async (): Promise<void> => {
await clearError({ redirect: useRoute().fullPath }); await clearError({ redirect: useRoute().fullPath });
}; };

View file

@ -183,7 +183,7 @@
<UButton <UButton
v-if="true === config.app.is_native" v-if="true === config.app.is_native"
color="neutral" color="error"
variant="ghost" variant="ghost"
size="sm" size="sm"
icon="i-lucide-power" icon="i-lucide-power"

View file

@ -6,14 +6,19 @@
aria-hidden="true" aria-hidden="true"
/> />
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-start gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 flex-1 space-y-3"> <div class="min-w-0 flex-1 space-y-3">
<nav aria-label="Breadcrumb" class="min-w-0 ytp-page-kicker"> <nav
aria-label="Breadcrumb"
class="flex min-w-0 flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -45,7 +50,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
color="neutral" color="neutral"
:variant="show_filter ? 'soft' : 'outline'" :variant="show_filter ? 'soft' : 'outline'"
@ -118,7 +123,7 @@
<div <div
v-if="controlEnabled && hasItems" v-if="controlEnabled && hasItems"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -164,11 +169,11 @@
<div <div
v-if="contentStyle === 'list' && hasItems" v-if="contentStyle === 'list' && hasItems"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-360 w-full text-sm"> <table class="min-w-360 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -315,12 +320,18 @@
</div> </div>
<div v-else-if="hasItems" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else-if="hasItems" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div <UCard
v-for="item in filteredItems" v-for="item in filteredItems"
:key="item.path" :key="item.path"
class="ytp-card flex h-full flex-col overflow-hidden" class="flex h-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
> >
<div class="p-4 pb-3 ytp-border-bottom-soft"> <template #header>
<div class="flex items-start justify-between gap-3"> <div class="flex items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -353,9 +364,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="flex flex-wrap gap-2 text-sm *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-sm *:min-w-32 *:flex-1">
<div <div
class="min-w-0 rounded-md border border-default bg-muted/20 px-3 py-2 text-center text-default" class="min-w-0 rounded-md border border-default bg-muted/20 px-3 py-2 text-center text-default"
@ -377,9 +387,8 @@
</UTooltip> </UTooltip>
</div> </div>
</div> </div>
</div>
<div v-if="controlEnabled" class="ytp-border-top-soft px-4 py-4"> <template v-if="controlEnabled" #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
v-if="item.type === 'file'" v-if="item.type === 'file'"
@ -428,8 +437,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
<div v-if="localSearch && !hasItems && !isLoading" class="space-y-3"> <div v-if="localSearch && !hasItems && !isLoading" class="space-y-3">
@ -601,6 +610,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Delete Selected', label: 'Delete Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || isLoading.value, disabled: !hasSelected.value || isLoading.value,
onSelect: () => void handleDeleteSelected(), onSelect: () => void handleDeleteSelected(),
}, },

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="logs.length > 0" v-if="logs.length > 0"
color="neutral" color="neutral"
@ -60,108 +64,89 @@
/> />
<template v-else> <template v-else>
<div v-if="filteredLogs.length > 0" class="space-y-5"> <div v-if="filteredLogs.length > 0" class="space-y-4">
<section v-for="log in filteredLogs" :key="log.tag" class="space-y-3"> <UPageCard v-for="log in filteredLogs" :key="log.tag" variant="outline" :ui="pageCardUi">
<section class="space-y-3"> <template #body>
<button <div class="space-y-4">
type="button" <div class="flex flex-wrap items-start justify-between gap-3">
class="flex w-full flex-wrap items-center justify-between gap-3 text-left" <div class="min-w-0 space-y-2">
@click="toggleRelease(log.tag)" <div class="flex flex-wrap items-center gap-2">
<div
class="inline-flex items-center gap-2 text-base font-semibold text-highlighted"
> >
<div class="flex min-w-0 items-center gap-3"> <UIcon name="i-lucide-git-branch" class="size-4 text-toned" />
<span class="ytp-section-icon"> <span>{{ log.tag }}</span>
<UIcon </div>
:name="isInstalled(log) ? 'i-lucide-badge-check' : 'i-lucide-git-branch'"
class="size-5" <UBadge v-if="isInstalled(log)" color="success" variant="soft" size="sm">
/> Installed
</UBadge>
</div>
</div>
<div class="flex flex-wrap items-center justify-end gap-2 text-xs text-toned">
<span
class="inline-flex items-center gap-1 rounded-md border border-default px-2 py-1"
>
<UIcon name="i-lucide-list" class="size-3.5" />
<span>{{ log.commits?.length || 0 }} commits</span>
</span> </span>
<div class="min-w-0 space-y-1">
<h2 class="truncate text-base font-semibold text-highlighted">
{{ log.tag }}
</h2>
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-toned">
<UTooltip v-if="log.date" :text="`Release Date: ${log.date}`"> <UTooltip v-if="log.date" :text="`Release Date: ${log.date}`">
<span class="inline-flex cursor-help items-center gap-1.5"> <span
<UIcon name="i-lucide-calendar-days" class="size-3.5 text-muted" /> class="inline-flex cursor-help items-center gap-1 rounded-md border border-default px-2 py-1"
>
<UIcon name="i-lucide-calendar-days" class="size-3.5" />
<span>{{ moment(log.date).fromNow() }}</span> <span>{{ moment(log.date).fromNow() }}</span>
</span> </span>
</UTooltip> </UTooltip>
</div> </div>
</div> </div>
</div>
<div class="flex shrink-0 items-center gap-2"> <div class="space-y-3 border-t border-default pt-4">
<UBadge
v-if="isInstalled(log)"
color="success"
variant="soft"
size="sm"
icon="i-lucide-check"
>
Installed
</UBadge>
<UBadge color="neutral" variant="outline" size="sm" icon="i-lucide-list">
{{ log.commits?.length || 0 }} commits
</UBadge>
<UIcon
name="i-lucide-chevron-right"
:class="[
'size-4 text-toned transition-transform',
isReleaseOpen(log.tag) ? 'rotate-90' : '',
]"
/>
</div>
</button>
<div v-if="isReleaseOpen(log.tag)" class="space-y-2">
<article <article
v-for="commit in log.commits" v-for="commit in log.commits"
:key="commit.sha" :key="commit.sha"
class="rounded-md border border-default bg-elevated/20 px-3 py-3 transition-colors hover:bg-elevated/35" class="flex flex-col gap-2 rounded-md border border-default bg-muted/20 px-3 py-3"
> >
<div class="min-w-0">
<NuxtLink <NuxtLink
:to="`${REPO}/commit/${commit.full_sha}`" :to="`${REPO}/commit/${commit.full_sha}`"
target="_blank" target="_blank"
class="block min-w-0 text-sm font-medium leading-5 text-highlighted transition hover:text-primary" class="block min-w-0 text-sm text-default hover:underline"
> >
{{ formatCommitMessage(commit.message) }} <span class="font-semibold text-highlighted">
</NuxtLink> {{ ucFirst(commit.message).replace(/\.$/, '') }}.
<div class="mt-2 flex flex-wrap items-center gap-2 text-xs text-toned">
<span
class="inline-flex items-center gap-1 rounded-sm border border-default px-2 py-1"
>
<UIcon name="i-lucide-user" class="size-3.5 text-muted" />
<span>{{ commit.author }}</span>
</span> </span>
<UTooltip :text="`Date: ${commit.date}`">
<time
class="inline-flex cursor-help items-center gap-1 rounded-sm border border-default px-2 py-1"
>
<UIcon name="i-lucide-clock-3" class="size-3.5 text-muted" />
<span>{{ moment(commit.date).fromNow() }}</span>
</time>
</UTooltip>
<UTooltip :text="`SHA: ${commit.full_sha}`">
<NuxtLink
:to="`${REPO}/commit/${commit.full_sha}`"
target="_blank"
class="inline-flex items-center gap-1 rounded-sm border border-default px-2 py-1 font-mono transition hover:border-primary hover:text-primary"
>
<UIcon name="i-lucide-git-commit-horizontal" class="size-3.5 text-muted" />
<span>{{ commit.sha }}</span>
</NuxtLink> </NuxtLink>
</UTooltip> </div>
<div class="flex flex-wrap items-center gap-2 text-xs text-toned">
<span
class="inline-flex items-center gap-1 rounded-md border border-default px-2 py-1"
>
<UIcon name="i-lucide-user" class="size-3.5" />
{{ commit.author }}
</span>
<UTooltip :text="`Date: ${commit.date}`">
<span
class="inline-flex cursor-help items-center gap-1 rounded-md border border-default px-2 py-1"
>
<UIcon name="i-lucide-clock-3" class="size-3.5" />
{{ moment(commit.date).fromNow() }}
</span>
</UTooltip>
<UTooltip :text="`SHA: ${commit.full_sha}`">
<span
class="inline-flex cursor-help items-center gap-1 rounded-md border border-default px-2 py-1 font-medium"
>
<UIcon name="i-lucide-git-commit-horizontal" class="size-3.5" />
{{ commit.sha }}
</span>
</UTooltip>
<span <span
v-if="commit.full_sha === app_sha" v-if="commit.full_sha === app_sha"
class="inline-flex items-center gap-1 rounded-sm border border-default px-2 py-1 font-medium" class="inline-flex items-center gap-1 rounded-md border border-default px-2 py-1 font-medium"
> >
<UIcon name="i-lucide-check" class="size-3.5 text-success" /> <UIcon name="i-lucide-check" class="size-3.5 text-success" />
<span>Installed</span> <span>Installed</span>
@ -169,8 +154,9 @@
</div> </div>
</article> </article>
</div> </div>
</section> </div>
</section> </template>
</UPageCard>
</div> </div>
<div v-else class="space-y-3"> <div v-else class="space-y-3">
@ -220,7 +206,13 @@ const isLoading = ref(true);
const query = ref(''); const query = ref('');
const toggleFilter = ref(false); const toggleFilter = ref(false);
const latestOnly = useStorage<boolean>('changelog_latest_only', true); const latestOnly = useStorage<boolean>('changelog_latest_only', true);
const openReleases = useStorage<string[]>('changelog_open_releases', []);
const pageCardUi = {
root: 'w-full bg-default',
container: 'w-full p-4 sm:p-5',
wrapper: 'w-full items-stretch',
body: 'w-full',
};
watch(toggleFilter, () => { watch(toggleFilter, () => {
if (!toggleFilter.value) { if (!toggleFilter.value) {
@ -258,27 +250,6 @@ const filteredLogs = computed<changelogs>(() => {
.filter((log): log is changeset => log !== null); .filter((log): log is changeset => log !== null);
}); });
watch(filteredLogs, (items) => {
if (openReleases.value.length > 0 || items.length < 1) {
return;
}
openReleases.value = items.slice(0, 3).map((log) => log.tag);
});
const isReleaseOpen = (tag: string): boolean => openReleases.value.includes(tag);
const toggleRelease = (tag: string): void => {
if (isReleaseOpen(tag)) {
openReleases.value = openReleases.value.filter((entry) => entry !== tag);
return;
}
openReleases.value = [...openReleases.value, tag];
};
const formatCommitMessage = (message: string): string => `${ucFirst(message).replace(/\.$/, '')}.`;
const loadContent = async (): Promise<void> => { const loadContent = async (): Promise<void> => {
if (app_version.value === '' || logs.value.length > 0) { if (app_version.value === '' || logs.value.length > 0) {
return; return;

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="items.length > 0" v-if="items.length > 0"
color="neutral" color="neutral"
@ -80,7 +84,7 @@
<div <div
v-if="!isLoading && filteredItems.length > 0" v-if="!isLoading && filteredItems.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -125,11 +129,11 @@
<div <div
v-if="contentStyle === 'list' && filteredItems.length > 0" v-if="contentStyle === 'list' && filteredItems.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-235 w-full text-sm"> <table class="min-w-235 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -234,8 +238,16 @@
<div v-else-if="filteredItems.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else-if="filteredItems.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div v-for="cond in filteredItems" :key="cond.id" class="min-w-0 w-full max-w-full"> <div v-for="cond in filteredItems" :key="cond.id" class="min-w-0 w-full max-w-full">
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -271,9 +283,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1">
<button <button
@ -308,9 +319,7 @@
<UIcon name="i-lucide-filter" class="mt-0.5 size-4 shrink-0 text-toned" /> <UIcon name="i-lucide-filter" class="mt-0.5 size-4 shrink-0 text-toned" />
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="text-xs font-medium text-toned">Filter</div> <div class="text-xs font-medium text-toned">Filter</div>
<span :class="['block', expandClass(cond.id, 'filter')]">{{ <span :class="['block', expandClass(cond.id, 'filter')]">{{ cond.filter }}</span>
cond.filter
}}</span>
</div> </div>
</button> </button>
@ -366,9 +375,8 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -390,8 +398,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -558,6 +566,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="flex min-h-0 w-full min-w-0 max-w-full flex-1 flex-col gap-6"> <main class="flex min-h-0 w-full min-w-0 max-w-full flex-1 flex-col gap-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading items-start"> <div class="flex min-w-0 items-start gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -41,15 +45,19 @@
</div> </div>
</div> </div>
<div class="ytp-card flex min-h-0 flex-1 p-0 sm:p-0 flex-col"> <UPageCard variant="naked" :ui="pageCardUi" class="flex min-h-0 flex-1">
<template #body>
<div class="flex min-h-0 flex-1 flex-col gap-4"> <div class="flex min-h-0 flex-1 flex-col gap-4">
<div <div
class="flex min-h-72 min-w-0 flex-1 overflow-hidden rounded-sm border border-default bg-neutral-950/95 shadow-sm" class="flex min-h-72 min-w-0 flex-1 overflow-hidden rounded-sm border border-default bg-neutral-950/95 shadow-sm"
> >
<div ref="terminal_window" class="terminal-host h-full min-h-0 w-full overflow-hidden" /> <div
ref="terminal_window"
class="terminal-host h-full min-h-0 w-full overflow-hidden"
/>
</div> </div>
<div class="ytp-card shadow-sm"> <div class="rounded-xl border border-default bg-default shadow-sm">
<div <div
class="flex flex-col gap-3 border-b border-default bg-muted/10 px-4 py-3 lg:flex-row lg:items-start lg:justify-between" class="flex flex-col gap-3 border-b border-default bg-muted/10 px-4 py-3 lg:flex-row lg:items-start lg:justify-between"
> >
@ -164,7 +172,9 @@
:ui="historyCardUi" :ui="historyCardUi"
> >
<div class="flex flex-wrap items-center justify-between gap-3"> <div class="flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-2 text-sm font-semibold text-highlighted"> <div
class="flex items-center gap-2 text-sm font-semibold text-highlighted"
>
<UIcon name="i-lucide-history" class="size-4 text-toned" /> <UIcon name="i-lucide-history" class="size-4 text-toned" />
<span>Recent runs</span> <span>Recent runs</span>
</div> </div>
@ -191,7 +201,7 @@
<div <div
v-else v-else
class="max-h-96 w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="max-h-96 w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-auto overscroll-contain"> <div class="w-full max-w-full overflow-auto overscroll-contain">
<table class="w-full text-sm"> <table class="w-full text-sm">
@ -251,7 +261,9 @@
.format('YYYY-M-DD H:mm Z') .format('YYYY-M-DD H:mm Z')
" "
> >
<span class="inline-flex items-center gap-1.5 cursor-help"> <span
class="inline-flex items-center gap-1.5 cursor-help"
>
<UIcon name="i-lucide-clock-3" class="size-3.5" /> <UIcon name="i-lucide-clock-3" class="size-3.5" />
<time <time
:datetime=" :datetime="
@ -358,7 +370,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </template>
</UPageCard>
</main> </main>
</template> </template>
@ -423,6 +436,13 @@ const commandInput = ref<InstanceType<typeof InputAutocomplete> | null>(null);
const commandTextarea = ref<InstanceType<typeof TextareaAutocomplete> | null>(null); const commandTextarea = ref<InstanceType<typeof TextareaAutocomplete> | null>(null);
const storedCommand = useStorage<string>('console_command', ''); const storedCommand = useStorage<string>('console_command', '');
const pageCardUi = {
root: 'flex min-h-0 flex-1 w-full bg-transparent',
container: 'flex min-h-0 flex-1 w-full p-0 sm:p-0',
wrapper: 'flex min-h-0 flex-1 w-full items-stretch',
body: 'flex min-h-0 flex-1 w-full flex-col',
};
const historyCardUi = { const historyCardUi = {
body: 'space-y-3 p-4', body: 'space-y-3 p-4',
}; };

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading items-start"> <div class="flex min-w-0 items-start gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
color="neutral" color="neutral"
variant="outline" variant="outline"
@ -43,7 +47,10 @@
</div> </div>
</div> </div>
<div v-if="!report && isLoading" class="ytp-card flex min-h-72 items-center justify-center"> <div
v-if="!report && isLoading"
class="flex min-h-72 items-center justify-center rounded-md border border-default bg-default/90"
>
<div class="flex flex-col items-center gap-3 text-center text-toned"> <div class="flex flex-col items-center gap-3 text-center text-toned">
<UIcon name="i-lucide-loader-circle" class="size-10 animate-spin text-info" /> <UIcon name="i-lucide-loader-circle" class="size-10 animate-spin text-info" />
<div class="space-y-1"> <div class="space-y-1">
@ -79,15 +86,28 @@
</div> </div>
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4"> <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
<StatCard <article
v-for="item in summaryCards" v-for="item in summaryCards"
:key="item.label" :key="item.label"
:label="item.label" class="rounded-md border border-default bg-default px-3 py-3 shadow-sm"
:value="item.value" >
:hint="item.description" <div class="flex items-start justify-between gap-3">
:icon="item.icon" <div class="min-w-0">
:color="item.color" <p class="text-xs font-medium uppercase tracking-wide text-toned">
/> {{ item.label }}
</p>
<p class="mt-1 text-xs text-toned">{{ item.description }}</p>
</div>
<span
class="inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-default bg-default"
>
<UIcon :name="item.icon" class="size-4 text-toned" />
</span>
</div>
<p :class="['mt-4 text-2xl font-semibold', item.valueClass]">{{ item.value }}</p>
</article>
</div> </div>
</section> </section>
@ -98,16 +118,28 @@
</div> </div>
<div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3"> <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
<StatCard <article
v-for="row in runtimeRows" v-for="row in runtimeRows"
:key="row.label" :key="row.label"
:label="row.label" class="rounded-md border border-default bg-default px-3 py-3 shadow-sm"
:value="row.value" >
:hint="row.description" <div class="flex items-start justify-between gap-3">
:icon="row.icon" <div class="min-w-0">
color="neutral" <p class="text-xs font-medium uppercase tracking-wide text-toned">
value-wrap {{ row.label }}
/> </p>
<p class="mt-1 text-xs text-toned">{{ row.description }}</p>
</div>
<span
class="inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-default bg-default"
>
<UIcon :name="row.icon" class="size-4 text-toned" />
</span>
</div>
<p class="mt-4 wrap-break-word text-sm font-semibold text-default">{{ row.value }}</p>
</article>
</div> </div>
</section> </section>
@ -123,7 +155,11 @@
</div> </div>
<div class="grid gap-4 lg:grid-cols-2 2xl:grid-cols-3"> <div class="grid gap-4 lg:grid-cols-2 2xl:grid-cols-3">
<article v-for="item in section.items" :key="item.id" class="ytp-card-padded shadow-sm"> <article
v-for="item in section.items"
:key="item.id"
class="rounded-md border border-default bg-default px-4 py-4 shadow-sm"
>
<div class="min-w-0 space-y-3"> <div class="min-w-0 space-y-3">
<div class="space-y-2"> <div class="space-y-2">
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
@ -162,7 +198,6 @@
<script setup lang="ts"> <script setup lang="ts">
import moment from 'moment'; import moment from 'moment';
import StatCard from '~/components/StatCard.vue';
import type { DiagnosticCheck, DiagnosticStatus } from '~/types/diagnostics'; import type { DiagnosticCheck, DiagnosticStatus } from '~/types/diagnostics';
import { requirePageShell } from '~/utils/topLevelNavigation'; import { requirePageShell } from '~/utils/topLevelNavigation';
import { copyText } from '~/utils'; import { copyText } from '~/utils';
@ -172,7 +207,7 @@ type SummaryCard = {
description: string; description: string;
value: number; value: number;
icon: string; icon: string;
color: 'success' | 'error' | 'warning' | 'neutral'; valueClass: string;
}; };
type DetailRow = { type DetailRow = {
@ -260,28 +295,28 @@ const summaryCards = computed<Array<SummaryCard>>(() => {
description: 'Checks that passed.', description: 'Checks that passed.',
value: current.summary.pass, value: current.summary.pass,
icon: 'i-lucide-badge-check', icon: 'i-lucide-badge-check',
color: current.summary.pass > 0 ? 'success' : 'neutral', valueClass: current.summary.pass > 0 ? 'text-success' : 'text-default',
}, },
{ {
label: 'Required fails', label: 'Required fails',
description: 'Items that block core use.', description: 'Items that block core use.',
value: current.summary.required_failed, value: current.summary.required_failed,
icon: 'i-lucide-octagon-alert', icon: 'i-lucide-octagon-alert',
color: current.summary.required_failed > 0 ? 'error' : 'neutral', valueClass: current.summary.required_failed > 0 ? 'text-error' : 'text-default',
}, },
{ {
label: 'Warnings', label: 'Warnings',
description: 'Optional or incomplete items.', description: 'Optional or incomplete items.',
value: current.summary.warn, value: current.summary.warn,
icon: 'i-lucide-triangle-alert', icon: 'i-lucide-triangle-alert',
color: current.summary.warn > 0 ? 'warning' : 'neutral', valueClass: current.summary.warn > 0 ? 'text-warning' : 'text-default',
}, },
{ {
label: 'Skipped', label: 'Skipped',
description: 'Not configured or not needed.', description: 'Not configured or not needed.',
value: current.summary.skip, value: current.summary.skip,
icon: 'i-lucide-minus', icon: 'i-lucide-minus',
color: 'neutral', valueClass: current.summary.skip > 0 ? 'text-toned' : 'text-default',
}, },
]; ];
}); });

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="items.length > 0" v-if="items.length > 0"
color="neutral" color="neutral"
@ -80,7 +84,7 @@
<div <div
v-if="!isLoading && filteredItems.length > 0" v-if="!isLoading && filteredItems.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -125,11 +129,11 @@
<div <div
v-if="contentStyle === 'list' && filteredItems.length > 0" v-if="contentStyle === 'list' && filteredItems.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-235 w-full text-sm"> <table class="min-w-235 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -233,8 +237,16 @@
<div v-else-if="filteredItems.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else-if="filteredItems.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div v-for="field in filteredItems" :key="field.id" class="min-w-0 w-full max-w-full"> <div v-for="field in filteredItems" :key="field.id" class="min-w-0 w-full max-w-full">
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -270,9 +282,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1">
<span <span
@ -299,9 +310,7 @@
<UIcon name="i-lucide-terminal" class="mt-0.5 size-4 shrink-0 text-toned" /> <UIcon name="i-lucide-terminal" class="mt-0.5 size-4 shrink-0 text-toned" />
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="text-xs font-medium text-toned">Associated option</div> <div class="text-xs font-medium text-toned">Associated option</div>
<span :class="['block', expandClass(field.id, 'field')]">{{ <span :class="['block', expandClass(field.id, 'field')]">{{ field.field }}</span>
field.field
}}</span>
</div> </div>
</button> </button>
@ -324,9 +333,8 @@
</button> </button>
</div> </div>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -348,8 +356,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -483,6 +491,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -16,24 +20,42 @@
<p class="max-w-3xl text-sm text-toned">{{ pageShell.description }}</p> <p class="max-w-3xl text-sm text-toned">{{ pageShell.description }}</p>
</div> </div>
</div> </div>
<div class="flex flex-wrap justify-end gap-2 xl:justify-end">
<UButton
v-for="entry in docsEntries"
:key="entry.id"
:to="entry.route"
:color="entry.file === docEntry.file ? 'primary' : 'neutral'"
:variant="entry.file === docEntry.file ? 'solid' : 'outline'"
size="sm"
:icon="entry.icon"
>
{{ entry.navLabel }}
</UButton>
</div>
</div> </div>
<div class="ytp-card p-0 overflow-hidden"> <UPageCard variant="outline" :ui="pageCardUi">
<div class="min-w-0 max-w-full px-4 py-5 sm:px-6 sm:py-6 lg:px-7"> <template #body>
<div class="px-4 py-5 sm:px-6 sm:py-6 lg:px-7">
<Markdown :file="`/api/docs/${docEntry.file}`" /> <Markdown :file="`/api/docs/${docEntry.file}`" />
</div> </div>
</div> </template>
</UPageCard>
</main> </main>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Markdown from '~/components/Markdown.vue'; import Markdown from '~/components/Markdown.vue';
import { getDocsEntryBySlug } from '~/composables/useDocs'; import { DOCS_ENTRIES, getDocsEntryBySlug } from '~/composables/useDocs';
import { formatPageTitle } from '~/utils'; import { formatPageTitle } from '~/utils';
import { requirePageShell } from '~/utils/topLevelNavigation'; import { requirePageShell } from '~/utils/topLevelNavigation';
const route = useRoute(); const route = useRoute();
const docsEntries = DOCS_ENTRIES;
const docEntry = computed(() => { const docEntry = computed(() => {
const entry = getDocsEntryBySlug(route.params.slug as string | string[] | undefined); const entry = getDocsEntryBySlug(route.params.slug as string | string[] | undefined);
@ -52,4 +74,11 @@ const pageShell = computed(() => requirePageShell(docEntry.value.id));
useHead(() => ({ useHead(() => ({
title: formatPageTitle(docEntry.value.title), title: formatPageTitle(docEntry.value.title),
})); }));
const pageCardUi = {
root: 'w-full bg-default',
container: 'w-full p-0',
wrapper: 'w-full items-stretch',
body: 'w-full p-0',
};
</script> </script>

View file

@ -6,14 +6,18 @@
aria-hidden="true" aria-hidden="true"
/> />
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -23,7 +27,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
color="neutral" color="neutral"
variant="outline" variant="outline"
@ -98,7 +102,7 @@
<div class="w-full min-w-0 max-w-full space-y-4"> <div class="w-full min-w-0 max-w-full space-y-4">
<div <div
v-if="hasItems" v-if="hasItems"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -139,11 +143,11 @@
<div <div
v-if="'list' === contentStyle && hasItems" v-if="'list' === contentStyle && hasItems"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-210 table-fixed w-full text-sm"> <table class="min-w-210 table-fixed w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -391,8 +395,16 @@
:min-height="showThumbnails ? 410 : 210" :min-height="showThumbnails ? 410 : 210"
class="min-h-0 min-w-0 w-full max-w-full" class="min-h-0 min-w-0 w-full max-w-full"
> >
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="ytp-border-bottom-soft p-4 pb-3"> class="flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"
:ui="{
body: 'flex flex-1 flex-col gap-4 p-4',
footer: 'border-t border-default px-4 py-4',
header: 'p-4 pb-3',
root: 'bg-default border border-default',
}"
>
<template #header>
<div class="flex min-w-0 flex-wrap items-start justify-between gap-3"> <div class="flex min-w-0 flex-wrap items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<UTooltip :text="item.title"> <UTooltip :text="item.title">
@ -462,9 +474,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4">
<div <div
v-if="showThumbnails" v-if="showThumbnails"
class="-mx-4 -mt-4 overflow-hidden border-b border-default bg-muted/20" class="-mx-4 -mt-4 overflow-hidden border-b border-default bg-muted/20"
@ -615,7 +626,7 @@
</p> </p>
</div> </div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
v-if="showRetryAction(item)" v-if="showRetryAction(item)"
@ -674,9 +685,8 @@
</UButton> </UButton>
</UDropdownMenu> </UDropdownMenu>
</div> </div>
</div> </template>
</div> </UCard>
</div>
</LateLoader> </LateLoader>
</div> </div>

View file

@ -1,13 +1,17 @@
<template> <template>
<div class="space-y-6"> <div class="space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
color="neutral" color="neutral"
:variant="toggleFilter ? 'soft' : 'outline'" :variant="toggleFilter ? 'soft' : 'outline'"
@ -52,7 +56,7 @@
<UButton <UButton
color="neutral" color="neutral"
:variant="config.showForm ? 'soft' : 'outline'" variant="outline"
size="sm" size="sm"
icon="i-lucide-plus" icon="i-lucide-plus"
@click="config.showForm = !config.showForm" @click="config.showForm = !config.showForm"
@ -105,7 +109,7 @@
<div class="w-full min-w-0 max-w-full space-y-4"> <div class="w-full min-w-0 max-w-full space-y-4">
<div v-if="!socket.isConnected" class="flex justify-end"> <div v-if="!socket.isConnected" class="flex justify-end">
<UButton <UButton
color="neutral" color="info"
variant="outline" variant="outline"
size="sm" size="sm"
icon="i-lucide-refresh-cw" icon="i-lucide-refresh-cw"
@ -118,7 +122,7 @@
<div <div
v-if="hasItems" v-if="hasItems"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -171,11 +175,11 @@
<div <div
v-if="'list' === contentStyle && hasItems" v-if="'list' === contentStyle && hasItems"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-210 table-fixed w-full text-sm"> <table class="min-w-210 table-fixed w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -405,8 +409,16 @@
:min-height="showThumbnails ? 475 : 265" :min-height="showThumbnails ? 475 : 265"
class="min-h-0 min-w-0 w-full max-w-full" class="min-h-0 min-w-0 w-full max-w-full"
> >
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"
:ui="{
body: 'flex flex-1 flex-col gap-4 p-4',
footer: 'border-t border-default px-4 py-4',
header: 'p-4 pb-3',
root: 'bg-default border border-default',
}"
>
<template #header>
<div class="flex min-w-0 flex-wrap items-start justify-between gap-3"> <div class="flex min-w-0 flex-wrap items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<UTooltip :text="item.title"> <UTooltip :text="item.title">
@ -482,9 +494,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4">
<div <div
v-if="showThumbnails" v-if="showThumbnails"
class="-mx-4 -mt-4 overflow-hidden border-b border-default bg-muted/20" class="-mx-4 -mt-4 overflow-hidden border-b border-default bg-muted/20"
@ -561,10 +572,7 @@
@click="toggleExpand(item._id, 'preset')" @click="toggleExpand(item._id, 'preset')"
> >
<span class="inline-flex w-full items-center justify-center gap-2"> <span class="inline-flex w-full items-center justify-center gap-2">
<UIcon <UIcon name="i-lucide-sliders-horizontal" class="size-4 shrink-0 text-toned" />
name="i-lucide-sliders-horizontal"
class="size-4 shrink-0 text-toned"
/>
<span :class="['min-w-0 text-center', expandClass(item._id, 'preset')]"> <span :class="['min-w-0 text-center', expandClass(item._id, 'preset')]">
{{ item.preset }} {{ item.preset }}
</span> </span>
@ -602,9 +610,8 @@
</span> </span>
</button> </button>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -650,8 +657,8 @@
</UButton> </UButton>
</UDropdownMenu> </UDropdownMenu>
</div> </div>
</div> </template>
</div> </UCard>
</LateLoader> </LateLoader>
</div> </div>

View file

@ -17,9 +17,11 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading items-start"> <div class="flex min-w-0 items-start gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon <UIcon
name="i-lucide-file-text" name="i-lucide-file-text"
:class="[ :class="[
@ -32,7 +34,9 @@
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -42,7 +46,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="!autoScroll" v-if="!autoScroll"
color="neutral" color="neutral"
@ -119,8 +123,9 @@
</div> </div>
</div> </div>
<div class="ytp-card min-w-0 max-w-full p-4 sm:p-5 overflow-hidden"> <UPageCard variant="naked" :ui="pageCardUi">
<div class="ytp-frame overflow-hidden shadow-sm"> <template #body>
<div class="overflow-hidden rounded-sm border border-default bg-default shadow-sm">
<div <div
ref="logContainer" ref="logContainer"
class="w-full min-w-0 max-w-full min-h-[55vh] max-h-[60vh] overflow-y-auto overflow-x-hidden bg-transparent font-mono text-sm text-default overscroll-x-contain" class="w-full min-w-0 max-w-full min-h-[55vh] max-h-[60vh] overflow-y-auto overflow-x-hidden bg-transparent font-mono text-sm text-default overscroll-x-contain"
@ -244,7 +249,8 @@
</div> </div>
</div> </div>
</div> </div>
</div> </template>
</UPageCard>
<LogDetailModal v-model="detailsOpen" :log="selectedLog" /> <LogDetailModal v-model="detailsOpen" :log="selectedLog" />
</main> </main>
@ -310,6 +316,13 @@ const reachedEnd = ref(false);
const detailsOpen = ref(false); const detailsOpen = ref(false);
const expandedRows = ref<Set<string>>(new Set()); const expandedRows = ref<Set<string>>(new Set());
const pageCardUi = {
root: 'w-full min-w-0 max-w-full bg-transparent',
container: 'w-full min-w-0 max-w-full p-4 sm:p-5',
wrapper: 'w-full min-w-0 items-stretch',
body: 'w-full min-w-0 max-w-full overflow-hidden',
};
const query = ref<string>( const query = ref<string>(
(() => { (() => {
const filter = route.query.filter ?? ''; const filter = route.query.filter ?? '';

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="notifications.length > 0" v-if="notifications.length > 0"
color="neutral" color="neutral"
@ -93,7 +97,7 @@
<div <div
v-if="!isLoading && filteredTargets.length > 0" v-if="!isLoading && filteredTargets.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -138,11 +142,11 @@
<div <div
v-if="contentStyle === 'list' && filteredTargets.length > 0" v-if="contentStyle === 'list' && filteredTargets.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-235 w-full text-sm"> <table class="min-w-235 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -271,8 +275,16 @@
<div v-else-if="filteredTargets.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else-if="filteredTargets.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div v-for="item in filteredTargets" :key="item.id" class="min-w-0 w-full max-w-full"> <div v-for="item in filteredTargets" :key="item.id" class="min-w-0 w-full max-w-full">
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -311,9 +323,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1">
<button <button
@ -423,9 +434,8 @@
</button> </button>
</div> </div>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -447,8 +457,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -647,6 +657,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="presets.length > 0" v-if="presets.length > 0"
color="neutral" color="neutral"
@ -79,7 +83,7 @@
<div <div
v-if="!isLoading && filteredPresets.length > 0" v-if="!isLoading && filteredPresets.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -124,11 +128,11 @@
<div <div
v-if="contentStyle === 'list' && filteredPresets.length > 0" v-if="contentStyle === 'list' && filteredPresets.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-200 w-full text-sm"> <table class="min-w-200 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -232,8 +236,16 @@
<div v-else-if="filteredPresets.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3"> <div v-else-if="filteredPresets.length > 0" class="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
<div v-for="item in filteredPresets" :key="item.id" class="min-w-0 w-full max-w-full"> <div v-for="item in filteredPresets" :key="item.id" class="min-w-0 w-full max-w-full">
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -271,9 +283,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1">
<span <span
@ -356,9 +367,8 @@
</div> </div>
</button> </button>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -380,8 +390,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -530,6 +540,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -1,7 +1,6 @@
<template> <template>
<div>
<AppRoot mode="simple" @ready="init" v-slot="{ openSettings }"> <AppRoot mode="simple" @ready="init" v-slot="{ openSettings }">
<div class="shell-stage shell-surface flex min-h-screen flex-col"> <div class="shell-stage flex min-h-screen flex-col bg-default/95 backdrop-blur-sm">
<ConnectionBanner /> <ConnectionBanner />
<div <div
@ -15,7 +14,8 @@
<div class="transition-transform duration-300"> <div class="transition-transform duration-300">
<div class="mx-auto w-full transition-all duration-300" :class="formContainerClass"> <div class="mx-auto w-full transition-all duration-300" :class="formContainerClass">
<div class="ytp-card p-4 sm:p-5"> <UPageCard variant="outline" :ui="formCardUi">
<template #body>
<form autocomplete="off" class="space-y-4" @submit.prevent="addDownload"> <form autocomplete="off" class="space-y-4" @submit.prevent="addDownload">
<div class="flex items-start justify-between gap-3"> <div class="flex items-start justify-between gap-3">
<div class="min-w-0 space-y-1"> <div class="min-w-0 space-y-1">
@ -30,7 +30,7 @@
<div class="flex shrink-0 items-center gap-1 sm:gap-2"> <div class="flex shrink-0 items-center gap-1 sm:gap-2">
<UTooltip v-if="!socketStore.isConnected" text="Reload queue"> <UTooltip v-if="!socketStore.isConnected" text="Reload queue">
<UButton <UButton
color="neutral" color="info"
variant="ghost" variant="ghost"
size="sm" size="sm"
icon="i-lucide-refresh-cw" icon="i-lucide-refresh-cw"
@ -64,8 +64,8 @@
<UTooltip :text="showExtras ? 'Hide extra options' : 'Show extra options'"> <UTooltip :text="showExtras ? 'Hide extra options' : 'Show extra options'">
<UButton <UButton
type="button" type="button"
color="neutral" color="info"
:variant="showExtras ? 'soft' : 'outline'" variant="outline"
size="lg" size="lg"
:icon="showExtras ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'" :icon="showExtras ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
class="shrink-0 justify-center w-12" class="shrink-0 justify-center w-12"
@ -99,7 +99,7 @@
</UButton> </UButton>
</div> </div>
<div v-if="showExtras" class="space-y-3 ytp-border-top-soft pt-4"> <div v-if="showExtras" class="space-y-3 border-t border-default pt-4">
<UFormField label="Preset" :ui="fieldUi" class="w-full"> <UFormField label="Preset" :ui="fieldUi" class="w-full">
<template #label> <template #label>
<span class="inline-flex items-center gap-2 font-semibold"> <span class="inline-flex items-center gap-2 font-semibold">
@ -155,7 +155,8 @@
</div> </div>
</div> </div>
</form> </form>
</div> </template>
</UPageCard>
</div> </div>
</div> </div>
@ -202,12 +203,13 @@
tag="div" tag="div"
class="grid grid-cols-1 gap-3 lg:grid-cols-2" class="grid grid-cols-1 gap-3 lg:grid-cols-2"
> >
<div <UCard
v-for="item in queueItems" v-for="item in queueItems"
:key="`queue-${item._id}`" :key="`queue-${item._id}`"
class="ytp-card w-full min-w-0 max-w-full overflow-hidden" class="w-full min-w-0 max-w-full overflow-hidden"
:ui="queueCardUi"
> >
<div class="p-4 pb-0 ytp-border-bottom-soft"> <template #header>
<div <div
v-if="downloadingStatuses.has(item.status) || item.status === null" v-if="downloadingStatuses.has(item.status) || item.status === null"
class="queue-progress rounded-md border border-default bg-muted/20" class="queue-progress rounded-md border border-default bg-muted/20"
@ -233,9 +235,8 @@
<span>{{ updateProgress(item) }}</span> <span>{{ updateProgress(item) }}</span>
</div> </div>
</div> </div>
</div> </template>
<div class="p-4">
<div class="flex min-w-0 flex-col gap-4 sm:flex-row"> <div class="flex min-w-0 flex-col gap-4 sm:flex-row">
<figure <figure
class="relative w-full shrink-0 overflow-hidden rounded-lg border border-default bg-muted/20 sm:w-52" class="relative w-full shrink-0 overflow-hidden rounded-lg border border-default bg-muted/20 sm:w-52"
@ -298,33 +299,15 @@
<div class="flex flex-wrap items-center gap-2 text-xs"> <div class="flex flex-wrap items-center gap-2 text-xs">
<UBadge <UBadge
:color=" :color="downloadingStatuses.has(item.status) ? 'info' : 'warning'"
downloadingStatuses.has(item.status) ? 'info' : 'warning'
"
variant="soft" variant="soft"
size="sm" size="sm"
class="gap-1"
> >
<UIcon {{ downloadingStatuses.has(item.status) ? 'Active' : 'Queued' }}
:name="getQueueIcon(item)"
:class="['size-3.5', getStatusIconAnimation(item)]"
/>
<span>{{
downloadingStatuses.has(item.status) ? 'Active' : 'Queued'
}}</span>
</UBadge> </UBadge>
<UBadge <UBadge :color="getStatusColor(item)" variant="soft" size="sm">
:color="getStatusColor(item)" {{ getStatusLabel(item) }}
variant="soft"
size="sm"
class="gap-1"
>
<UIcon
:name="getStatusIcon(item)"
:class="['size-3.5', getStatusIconAnimation(item)]"
/>
<span>{{ getStatusLabel(item) }}</span>
</UBadge> </UBadge>
<span <span
@ -349,12 +332,10 @@
</template> </template>
</p> </p>
<div <div class="mt-auto flex flex-wrap items-center justify-end gap-2 pt-1">
class="mt-auto flex flex-wrap items-center justify-end gap-2 pt-1"
>
<UButton <UButton
v-if="!item.status && item.auto_start === false" v-if="!item.status && item.auto_start === false"
color="neutral" color="success"
variant="soft" variant="soft"
size="xs" size="xs"
icon="i-lucide-play-circle" icon="i-lucide-play-circle"
@ -365,7 +346,7 @@
<UButton <UButton
v-if="!item.status && item.auto_start === true" v-if="!item.status && item.auto_start === true"
color="neutral" color="warning"
variant="soft" variant="soft"
size="xs" size="xs"
icon="i-lucide-pause" icon="i-lucide-pause"
@ -375,7 +356,7 @@
</UButton> </UButton>
<UButton <UButton
color="neutral" color="error"
variant="outline" variant="outline"
size="xs" size="xs"
icon="i-lucide-x" icon="i-lucide-x"
@ -386,8 +367,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </UCard>
</div>
</TransitionGroup> </TransitionGroup>
<UAlert <UAlert
@ -463,12 +443,12 @@
v-if="historyEntries.length > 0" v-if="historyEntries.length > 0"
class="grid grid-cols-1 gap-3 lg:grid-cols-2" class="grid grid-cols-1 gap-3 lg:grid-cols-2"
> >
<div <UCard
v-for="item in historyEntries" v-for="item in historyEntries"
:key="`history-${historyPagination.page}-${item._id}`" :key="`history-${historyPagination.page}-${item._id}`"
class="ytp-card w-full min-w-0 max-w-full overflow-hidden" class="w-full min-w-0 max-w-full overflow-hidden"
:ui="queueCardUi"
> >
<div class="p-4">
<div class="flex min-w-0 flex-col gap-4 sm:flex-row"> <div class="flex min-w-0 flex-col gap-4 sm:flex-row">
<figure <figure
class="relative w-full shrink-0 overflow-hidden rounded-lg border border-default bg-muted/20 sm:w-52" class="relative w-full shrink-0 overflow-hidden rounded-lg border border-default bg-muted/20 sm:w-52"
@ -532,17 +512,8 @@
<div class="flex flex-wrap items-center gap-2 text-xs"> <div class="flex flex-wrap items-center gap-2 text-xs">
<UBadge color="neutral" variant="soft" size="sm">History</UBadge> <UBadge color="neutral" variant="soft" size="sm">History</UBadge>
<UBadge <UBadge :color="getStatusColor(item)" variant="soft" size="sm">
:color="getStatusColor(item)" {{ getStatusLabel(item) }}
variant="soft"
size="sm"
class="gap-1"
>
<UIcon
:name="getStatusIcon(item)"
:class="['size-3.5', getStatusIconAnimation(item)]"
/>
<span>{{ getStatusLabel(item) }}</span>
</UBadge> </UBadge>
<span <span
@ -567,9 +538,7 @@
</template> </template>
</p> </p>
<div <div class="mt-auto flex flex-wrap items-center justify-end gap-2 pt-1">
class="mt-auto flex flex-wrap items-center justify-end gap-2 pt-1"
>
<UButton <UButton
v-if="getDownloadLink(item)" v-if="getDownloadLink(item)"
color="primary" color="primary"
@ -585,7 +554,7 @@
<UButton <UButton
v-if="!item.filename" v-if="!item.filename"
color="neutral" color="info"
variant="soft" variant="soft"
size="xs" size="xs"
icon="i-lucide-rotate-cw" icon="i-lucide-rotate-cw"
@ -595,7 +564,7 @@
</UButton> </UButton>
<UButton <UButton
color="neutral" color="error"
variant="outline" variant="outline"
size="xs" size="xs"
icon="i-lucide-trash" icon="i-lucide-trash"
@ -606,8 +575,7 @@
</div> </div>
</div> </div>
</div> </div>
</div> </UCard>
</div>
</div> </div>
<UAlert <UAlert
@ -695,7 +663,6 @@
</div> </div>
</div> </div>
</AppRoot> </AppRoot>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -789,6 +756,19 @@ const fieldUi = {
container: 'space-y-2', container: 'space-y-2',
}; };
const formCardUi = {
root: 'w-full border border-default bg-default',
container: 'w-full p-4 sm:p-5',
wrapper: 'w-full items-stretch',
body: 'w-full',
};
const queueCardUi = {
root: 'w-full border border-default bg-default',
header: 'p-4 pb-0',
body: 'p-4',
};
const urlInputUi = { const urlInputUi = {
root: 'w-full', root: 'w-full',
base: 'bg-elevated/60 ring-default focus-visible:ring-primary', base: 'bg-elevated/60 ring-default focus-visible:ring-primary',
@ -1110,57 +1090,6 @@ const getStatusLabel = (item: StoreItem): string => {
return statusOverrides[item.status] ?? ucFirst(item.status.replace(/_/g, ' ')); return statusOverrides[item.status] ?? ucFirst(item.status.replace(/_/g, ' '));
}; };
const getQueueIcon = (item: StoreItem): string => {
if (downloadingStatuses.has(item.status)) {
return item.is_live ? 'i-lucide-globe' : 'i-lucide-download';
}
return 'i-lucide-clock-3';
};
const getStatusIcon = (item: StoreItem): string => {
if (!item.auto_start) {
return 'i-lucide-clock-3';
}
if (item.status === null && paused.value === true) {
return 'i-lucide-circle-pause';
}
if (item.status === null) {
return 'i-lucide-circle-question-mark';
}
if (isDownloadSkipped(item)) {
return 'i-lucide-circle-slash';
}
if (item.status === 'downloading' && item.is_live) {
return 'i-lucide-globe';
}
const map: Record<string, string> = {
downloading: 'i-lucide-download',
postprocessing: 'i-lucide-settings-2',
preparing: 'i-lucide-loader-circle',
finished: 'i-lucide-circle-check',
error: 'i-lucide-triangle-alert',
cancelled: 'i-lucide-circle-x',
not_live: 'i-lucide-clock-3',
skip: 'i-lucide-circle-slash',
};
return map[item.status] ?? 'i-lucide-circle-question-mark';
};
const getStatusIconAnimation = (item: StoreItem): string => {
const icon = getStatusIcon(item);
return ['i-lucide-globe', 'i-lucide-settings-2', 'i-lucide-loader-circle'].includes(icon)
? 'animate-spin'
: '';
};
const getStatusColor = (item: StoreItem): 'neutral' | 'info' | 'success' | 'error' | 'warning' => { const getStatusColor = (item: StoreItem): 'neutral' | 'info' | 'success' | 'error' | 'warning' => {
if (item.status === null) { if (item.status === null) {
return 'neutral'; return 'neutral';

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="definitions.length > 0" v-if="definitions.length > 0"
color="neutral" color="neutral"
@ -97,7 +101,7 @@
<div <div
v-if="!isLoading && filteredDefinitions.length > 0" v-if="!isLoading && filteredDefinitions.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -130,11 +134,11 @@
<div <div
v-if="contentStyle === 'list' && filteredDefinitions.length > 0" v-if="contentStyle === 'list' && filteredDefinitions.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-255 w-full text-sm"> <table class="min-w-255 w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -262,8 +266,16 @@
:key="definition.id" :key="definition.id"
class="min-w-0 w-full max-w-full" class="min-w-0 w-full max-w-full"
> >
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -301,9 +313,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 text-xs text-toned *:min-w-32 *:flex-1">
<button <button
@ -341,9 +352,8 @@
</div> </div>
</button> </button>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -365,8 +375,8 @@
Delete Delete
</UButton> </UButton>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -562,6 +572,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -1,13 +1,17 @@
<template> <template>
<main class="w-full min-w-0 max-w-full space-y-6"> <main class="w-full min-w-0 max-w-full space-y-6">
<div class="ytp-page-header"> <div class="flex flex-col gap-4 xl:flex-row xl:items-start xl:justify-between">
<div class="ytp-page-heading"> <div class="flex min-w-0 items-center gap-3">
<span class="ytp-page-icon"> <span
class="inline-flex size-11 shrink-0 items-center justify-center rounded-md border border-default bg-elevated/70 text-primary"
>
<UIcon :name="pageShell.icon" class="size-5" /> <UIcon :name="pageShell.icon" class="size-5" />
</span> </span>
<div class="min-w-0 space-y-2"> <div class="min-w-0 space-y-2">
<div class="ytp-page-kicker"> <div
class="flex flex-wrap items-center gap-2 text-xs font-medium uppercase tracking-[0.2em] text-toned"
>
<span>{{ pageShell.sectionLabel }}</span> <span>{{ pageShell.sectionLabel }}</span>
<span>/</span> <span>/</span>
<span>{{ pageShell.pageLabel }}</span> <span>{{ pageShell.pageLabel }}</span>
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="flex w-full flex-wrap items-center gap-2 xl:w-auto xl:justify-end"> <div class="flex min-w-0 flex-wrap items-center justify-end gap-2 xl:justify-end">
<UButton <UButton
v-if="tasks.length > 0" v-if="tasks.length > 0"
color="neutral" color="neutral"
@ -79,7 +83,7 @@
<div <div
v-if="!isLoading && filteredTasks.length > 0" v-if="!isLoading && filteredTasks.length > 0"
class="flex flex-wrap items-center justify-between gap-3 ytp-card px-3 py-3" class="flex flex-wrap items-center justify-between gap-3 rounded-lg border border-default bg-default px-3 py-3"
> >
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<UButton <UButton
@ -124,11 +128,11 @@
<div <div
v-if="contentStyle === 'list' && filteredTasks.length > 0" v-if="contentStyle === 'list' && filteredTasks.length > 0"
class="w-full min-w-0 max-w-full overflow-hidden ytp-table-surface" class="w-full min-w-0 max-w-full overflow-hidden rounded-lg border border-default bg-default"
> >
<div class="w-full max-w-full overflow-x-auto overscroll-x-contain"> <div class="w-full max-w-full overflow-x-auto overscroll-x-contain">
<table class="min-w-210 table-fixed w-full text-sm"> <table class="min-w-210 table-fixed w-full text-sm">
<thead class="bg-elevated/60 text-xs uppercase tracking-wide text-toned"> <thead class="bg-muted/40 text-xs uppercase tracking-wide text-toned">
<tr <tr
class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0" class="text-center [&>th]:border-r [&>th]:border-default/60 [&>th]:px-3 [&>th]:py-3 [&>th]:font-semibold [&>th:last-child]:border-r-0"
> >
@ -335,8 +339,16 @@
class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3" class="grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3"
> >
<div v-for="item in filteredTasks" :key="item.id" class="min-w-0 w-full max-w-full"> <div v-for="item in filteredTasks" :key="item.id" class="min-w-0 w-full max-w-full">
<div class="ytp-card flex h-full min-w-0 w-full max-w-full flex-col overflow-hidden"> <UCard
<div class="p-4 pb-3 ytp-border-bottom-soft"> class="flex h-full min-w-0 w-full max-w-full flex-col"
:ui="{
root: 'bg-default border border-default',
header: 'p-4 pb-3',
body: 'flex flex-1 flex-col gap-4 p-4 pt-0',
footer: 'border-t border-default px-4 py-4',
}"
>
<template #header>
<div class="flex min-w-0 items-start justify-between gap-3"> <div class="flex min-w-0 items-start justify-between gap-3">
<div class="min-w-0 flex-1 space-y-2"> <div class="min-w-0 flex-1 space-y-2">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
@ -402,9 +414,8 @@
</label> </label>
</div> </div>
</div> </div>
</div> </template>
<div class="flex flex-1 flex-col gap-4 p-4 pt-0">
<div class="space-y-2 text-sm text-default"> <div class="space-y-2 text-sm text-default">
<div class="grid grid-cols-2 gap-2 text-xs text-toned sm:flex sm:flex-wrap"> <div class="grid grid-cols-2 gap-2 text-xs text-toned sm:flex sm:flex-wrap">
<button <button
@ -462,11 +473,7 @@
<div <div
v-if=" v-if="
item.timer || item.timer || item.folder || item.template || item.cli || willTaskBeProcessed(item)
item.folder ||
item.template ||
item.cli ||
willTaskBeProcessed(item)
" "
class="feature-meta-grid" class="feature-meta-grid"
> >
@ -558,9 +565,8 @@
</button> </button>
</div> </div>
</div> </div>
</div>
<div class="ytp-border-top-soft px-4 py-4"> <template #footer>
<div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1"> <div class="flex flex-wrap gap-2 *:min-w-32 *:flex-1">
<UButton <UButton
color="neutral" color="neutral"
@ -594,8 +600,8 @@
</UButton> </UButton>
</UDropdownMenu> </UDropdownMenu>
</div> </div>
</div> </template>
</div> </UCard>
</div> </div>
</div> </div>
@ -847,6 +853,7 @@ const bulkActionGroups = computed<DropdownMenuItem[][]>(() => [
{ {
label: 'Remove Selected', label: 'Remove Selected',
icon: 'i-lucide-trash', icon: 'i-lucide-trash',
color: 'error',
disabled: !hasSelected.value || massDelete.value, disabled: !hasSelected.value || massDelete.value,
onSelect: () => void deleteSelected(), onSelect: () => void deleteSelected(),
}, },

View file

@ -35,18 +35,10 @@ type TerminalSessionsResponse = {
items: Array<TerminalSessionItem>; items: Array<TerminalSessionItem>;
}; };
type YtpPageHeaderProps = {
icon?: string;
sectionLabel?: string;
pageLabel?: string;
contentClass?: string;
};
export { export {
ImportedItem, ImportedItem,
TerminalSessionItem, TerminalSessionItem,
TerminalSessionStatus, TerminalSessionStatus,
TerminalSessionsResponse, TerminalSessionsResponse,
YtpPageHeaderProps,
version_check, version_check,
}; };

View file

@ -214,7 +214,8 @@ const NavItems: Array<NavDefinition> = [
group: 'docs', group: 'docs',
label: 'Changelog', label: 'Changelog',
pageLabel: 'Changelog', pageLabel: 'Changelog',
description: 'Latest project changes', description:
'Latest project changes, loaded remotely when available and falling back to the bundled changelog file.',
icon: 'i-lucide-git-commit-horizontal', icon: 'i-lucide-git-commit-horizontal',
to: '/changelog', to: '/changelog',
matchPath: '/changelog', matchPath: '/changelog',

View file

@ -11,9 +11,9 @@
"typecheck": "nuxt typecheck", "typecheck": "nuxt typecheck",
"format": "oxfmt --write app/", "format": "oxfmt --write app/",
"format:check": "oxfmt --check app/", "format:check": "oxfmt --check app/",
"lint": "eslint . --no-warn-ignored", "lint": "eslint .",
"lint:ci": "eslint . --quiet --no-warn-ignored", "lint:ci": "eslint . --quiet",
"lint:fix": "eslint . --fix --no-warn-ignored", "lint:fix": "eslint . --fix",
"test": "bun test", "test": "bun test",
"test:watch": "bun test --watch", "test:watch": "bun test --watch",
"test:ci": "bun test --ci --dots", "test:ci": "bun test --ci --dots",

224
uv.lock
View file

@ -147,14 +147,14 @@ wheels = [
[[package]] [[package]]
name = "anyio" name = "anyio"
version = "4.14.0" version = "4.13.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "idna" }, { name = "idna" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/1c/b5/001890774a9552aff22502b8da382593109ce0c95314abaebbb116567545/anyio-4.14.0.tar.gz", hash = "sha256:b47c1f9ccf73e67021df785332508f99379c68fa7d0684e8e3492cb1d4b23f89", size = 253586, upload-time = "2026-06-15T22:00:49.021Z" } sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ba/16/9826f089383c593cdfc4a6e5aca94d9e91ae1692c57af82c3b2aa5e810f7/anyio-4.14.0-py3-none-any.whl", hash = "sha256:dd9b7a2a9799ed6552fde617b2c5df02b7fdd7d88392fc48101e51bae46164d9", size = 123506, upload-time = "2026-06-15T22:00:47.595Z" }, { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
] ]
[[package]] [[package]]
@ -253,11 +253,11 @@ wheels = [
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2026.6.17" version = "2026.5.20"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" },
] ]
[[package]] [[package]]
@ -437,7 +437,7 @@ wheels = [
[[package]] [[package]]
name = "dateparser" name = "dateparser"
version = "1.4.1" version = "1.4.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "python-dateutil" }, { name = "python-dateutil" },
@ -445,9 +445,9 @@ dependencies = [
{ name = "regex" }, { name = "regex" },
{ name = "tzlocal" }, { name = "tzlocal" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/d3/f4/561c49bca97af561d34eed27e3e831135eb5cb88e754c1150be41820f5c6/dateparser-1.4.1.tar.gz", hash = "sha256:f265df13c0380e2e07543ba74b67c0681aaa1096981ffcd35227e1aa0cb81c7c", size = 314734, upload-time = "2026-06-15T08:45:47.659Z" } sdist = { url = "https://files.pythonhosted.org/packages/46/2d/a0ccdb78788064fa0dc901b8524e50615c42be1d78b78d646d0b28d09180/dateparser-1.4.0.tar.gz", hash = "sha256:97a21840d5ecdf7630c584f673338a5afac5dfe84f647baf4d7e8df98f9354a4", size = 321512, upload-time = "2026-03-26T09:56:10.292Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/7c/2e5dcf53909deddd0bf38cbe277ad9806be038276b1c6c436561b4d9b2e2/dateparser-1.4.1-py3-none-any.whl", hash = "sha256:f25d4e051a84be27a35bd297e3e1dc59ff78373701b89be352ba80372d22d0d0", size = 300503, upload-time = "2026-06-15T08:45:45.951Z" }, { url = "https://files.pythonhosted.org/packages/b4/0b/3c3bb7cbe757279e693a0be6049048012f794d01f81099609ecd53b899f0/dateparser-1.4.0-py3-none-any.whl", hash = "sha256:7902b8e85d603494bf70a5a0b1decdddb2270b9c6e6b2bc8a57b93476c0df378", size = 300379, upload-time = "2026-03-26T09:56:08.409Z" },
] ]
[[package]] [[package]]
@ -551,59 +551,59 @@ wheels = [
[[package]] [[package]]
name = "greenlet" name = "greenlet"
version = "3.5.2" version = "3.5.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/dd/8b/befc3cb36965f397d87e86fb3b00e3ec0dc67c1ecb0986d7f54ee528f018/greenlet-3.5.2.tar.gz", hash = "sha256:c1b906220d83c140361cdd12eef970fb5881a168b98ee58a43786426173da14c", size = 199243, upload-time = "2026-06-17T20:19:01.317Z" } sdist = { url = "https://files.pythonhosted.org/packages/6d/6e/802acd792aebb2256fbbee8cacf2727faaeb6f240ac11008f09eae4414bc/greenlet-3.5.1.tar.gz", hash = "sha256:5a56aeb7d5d9cc4b3a735efb5095bd4b4f6f0e4f93e5ca876d0e2315137b7829", size = 197356, upload-time = "2026-05-20T15:05:03.917Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/d0/3c/bb37b9d40d65b0741a8b040ca5c307034d0a9822994dff5f825c88dd7a6b/greenlet-3.5.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:0629377725977252159de1ebd3c6e49c170a63856e585446797bb3d66d4d9c34", size = 287178, upload-time = "2026-06-17T17:35:25.132Z" }, { url = "https://files.pythonhosted.org/packages/27/69/7f7e5372d998b81001899b1c0823c957aa413ba0f2662e65821611cc31e4/greenlet-3.5.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:51518ff74664078fc51bffcc6fc529b0df5ae58da192691cee765d45ce944a2b", size = 285060, upload-time = "2026-05-20T13:08:51.899Z" },
{ url = "https://files.pythonhosted.org/packages/f0/a6/0c5902393f492f8ceb19d0b5cf139284e3a11b333a049739643b1036b6f8/greenlet-3.5.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2ddf9eddc617681108dd071b3feabf3f4a4cd64846254aec4d4ceda098b639a", size = 606900, upload-time = "2026-06-17T18:07:21.692Z" }, { url = "https://files.pythonhosted.org/packages/b1/bf/387f9b6b865fd2ae0d0be09e0004827295a01b71be76ed350dd1e28a91a4/greenlet-3.5.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ffdb3c0bb002c99cd8f298957e046c3dbf6006b5b7cdf11a4e19194624a0a0a", size = 604370, upload-time = "2026-05-20T14:00:07.492Z" },
{ url = "https://files.pythonhosted.org/packages/d8/7c/42899c31d4b87148ae4e3f87f63e13398824be6241f4dde42ded95768a34/greenlet-3.5.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f41feb9f2b59e2e61ac9bea4e344ddd9396bf3cacb2583f73a3595ed7df6f8e7", size = 619265, upload-time = "2026-06-17T18:29:44.837Z" }, { url = "https://files.pythonhosted.org/packages/32/f5/169ce3d4e4c67291bd18f8cbe0299c9f3e45102c7f1fb3c14780c93e4532/greenlet-3.5.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7715a5a2c3378ba602c3a440558261e13a820bb53a82693aacd7b7f6d964e283", size = 616987, upload-time = "2026-05-20T14:05:44.237Z" },
{ url = "https://files.pythonhosted.org/packages/6a/7e/28f991affb413b232b1e7d768db24c37b3f4d5daecc3f19b455d40bd2dea/greenlet-3.5.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9dc23f0e5ad76415457212a4b947d22ebe4dc80baf02adf7dd5647a90f38bb4e", size = 625044, upload-time = "2026-06-17T18:39:29.046Z" }, { url = "https://files.pythonhosted.org/packages/19/ba/c24110c55dffa55aa6e1d98b45310da33801aeba7686ff0190fe5d46fd32/greenlet-3.5.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d40a890035c0058cadbdc4af7569800fd28a0e527a0fdbb7b5f9418f176846ce", size = 622911, upload-time = "2026-05-20T14:09:10.598Z" },
{ url = "https://files.pythonhosted.org/packages/d3/52/4ff8c98d3cfe62b4515f8584ae14510a58f35c549cc5292b78d9b7a40b70/greenlet-3.5.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09201fa698768db245920b00fdc86ee3e73540f01ca6db162be9632642e1a473", size = 616187, upload-time = "2026-06-17T17:39:29.473Z" }, { url = "https://files.pythonhosted.org/packages/ee/e5/7f2e41d5273be07e77560d61ea4e56485b4d6c316d2a84518c62d1364061/greenlet-3.5.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc71ff466927a201b08305acac451ebe1aedfcea002f62f1f2f2ac2ac1e6a135", size = 613911, upload-time = "2026-05-20T13:14:27.539Z" },
{ url = "https://files.pythonhosted.org/packages/29/05/0cc9ec660e7acff85f93b0a048b6654371c822c884add44c02a465cf70e0/greenlet-3.5.2-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:423167363c510a75b649f5cd58d873c29498ea03598b9e4b1c3b73e0f899f3d5", size = 427322, upload-time = "2026-06-17T18:41:20.892Z" }, { url = "https://files.pythonhosted.org/packages/ec/7b/d20db2e8a5ad6c038702f3179b136f93f0a3d1a21a0c0777f3e470cdf4b2/greenlet-3.5.1-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:67821bb03e4e98664490edb787ff6af501194c29bbee0f5c1dfdcf1dc3d9d436", size = 425228, upload-time = "2026-05-20T14:01:40.837Z" },
{ url = "https://files.pythonhosted.org/packages/c9/a6/269c8bf9aefc13361ce1088f0e392b154cb21005de7862e42b5d782b81fd/greenlet-3.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1759fa4f14c398508cf20dc8037de55cc23ae8bd14c185c2718257837195ca5", size = 1573778, upload-time = "2026-06-17T18:22:13.497Z" }, { url = "https://files.pythonhosted.org/packages/c5/a4/fbdc67579b73615a1f91615e814303cc71e06128f7baaba87be79b8fb90c/greenlet-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cd443683db272ebaaca03af98c0b063ab30db70ea8a31a1559f35e3f7b744ccd", size = 1570689, upload-time = "2026-05-20T14:02:27.225Z" },
{ url = "https://files.pythonhosted.org/packages/1f/9b/391d015cbc6323e81b14c02cf825fdca7e0049c9bb489bf4ac72883118ba/greenlet-3.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b9318cdeb9abdbfdd8bc8464ee4a06dffde2c7846e1def138365a6240ab2c9a5", size = 1638092, upload-time = "2026-06-17T17:40:08.163Z" }, { url = "https://files.pythonhosted.org/packages/e6/b4/77abbe35078be39718a46cd49caf16bceb35662f97a34101dca28aa98e47/greenlet-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:089fff7a6ce8d9316d1f65ebc00273a56be258c1725b32b94de90a3a979557e1", size = 1635602, upload-time = "2026-05-20T13:14:36.344Z" },
{ url = "https://files.pythonhosted.org/packages/49/53/5b4df711f4356c62e85d9f819d87966d526d1cfb32bae49a8f7d6fc36ea4/greenlet-3.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:2c3b3311af72b3d3b03cc0f1ffd11f072e834be5d0444105cf715fc44434e39c", size = 239352, upload-time = "2026-06-17T17:38:51.593Z" }, { url = "https://files.pythonhosted.org/packages/37/f7/129f27ca700845b8ee8ca88ce7f43435a1239c2eddb7677fc938822762cf/greenlet-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:110a1ca7b49b014b097f6078272c3f4ed31af45b254de5228b79adba879f6af9", size = 238683, upload-time = "2026-05-20T13:11:50.57Z" },
{ url = "https://files.pythonhosted.org/packages/bb/b6/18efc3a329ec035c3f344b8f2b60356451950ddf9b7b64ff00023778a1dd/greenlet-3.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:f9bbd6216c45a563c2a61e478e038b439d9f248bde44f775ea37d339da643af4", size = 237635, upload-time = "2026-06-17T17:35:36.632Z" }, { url = "https://files.pythonhosted.org/packages/6d/5c/a485a36e87df8d8fd0632ee01511244f5156a20ed3746cc6599340326395/greenlet-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f16ba1efc0715b680a18b8123d90dad887c6112ae3555b4b5c32c149540c6b4e", size = 235499, upload-time = "2026-05-20T13:12:42.028Z" },
{ url = "https://files.pythonhosted.org/packages/c7/89/aaafc8e14de4ac882e02ccb963225329b0e8578aba4365e71eb678e45722/greenlet-3.5.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1c31219badba285858ba8ed117f403dea7fafee6bade9a1991875aae530c3ceb", size = 287676, upload-time = "2026-06-17T17:33:31.514Z" }, { url = "https://files.pythonhosted.org/packages/8a/cb/c62454606daf5640369c94d8a9dd540599b1bfc090e2d2180cb77f4038d2/greenlet-3.5.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8ab31c9de8651a2facdd5c5bb0011f2380dd1a7af78ce2adf4b56095294fc07", size = 285579, upload-time = "2026-05-20T13:08:56.396Z" },
{ url = "https://files.pythonhosted.org/packages/b8/fc/2308249206c12ac70de7b9a00970f84f07d10b3cd60e05d2fbcaa84124e8/greenlet-3.5.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f96ed6f4adc1066954ae95f45717657cb67468ef3b89e9a3632e14a625a8f39", size = 653552, upload-time = "2026-06-17T18:07:23.493Z" }, { url = "https://files.pythonhosted.org/packages/ec/71/c4270398c2eba968a6071af1dfbdcaeee6ec1c24bc8b435b8cc452700da6/greenlet-3.5.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e300185139abc337ade480c327183adf42a875ac7181bfe66d7d4efea31fbea", size = 651106, upload-time = "2026-05-20T14:00:09.448Z" },
{ url = "https://files.pythonhosted.org/packages/7c/24/47730d1f8f1336b9b089237521ed7a26eee997065dcb4cab81cdca333abc/greenlet-3.5.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5795e883e915333c0d5648faaa691857fbc7180136883edc377f50f0d509c2a8", size = 665756, upload-time = "2026-06-17T18:29:46.616Z" }, { url = "https://files.pythonhosted.org/packages/1a/ab/71e34b78a44ec271fb5f550c17bc46d301ddc5953890d935f270b0dcdb5a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7ffdb990dcaa0234cf9845aead5df2e3c3a8b6507d409274dd87e0d5ab05ffc2", size = 663478, upload-time = "2026-05-20T14:05:45.88Z" },
{ url = "https://files.pythonhosted.org/packages/23/5c/2664d290cbd1fef9eb3f69b5d3bc5aa91b6fa907519298ca6af93a90c6cb/greenlet-3.5.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6e9e49d732ee92a189bb7035e293029244aeba648297a9b856dc733d17ca7f0d", size = 669989, upload-time = "2026-06-17T18:39:30.79Z" }, { url = "https://files.pythonhosted.org/packages/c6/2d/2d80842910da44f78c286532d084b8a5c3717c844ae80ceb3858738ae89a/greenlet-3.5.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c09df69dc1712d131332054a858a3e5cca400967fa3a672e2324fbb0971448c", size = 667767, upload-time = "2026-05-20T14:09:12.15Z" },
{ url = "https://files.pythonhosted.org/packages/99/69/d6c99db15dc0b5e892ac3cc7b942c8b21f4a9cc3bd9ea0bc3b0f339ffbd4/greenlet-3.5.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26aed8d9503ca78889141a9739d71b383efea5f472a7c522b5410f7eb2a1b163", size = 663228, upload-time = "2026-06-17T17:39:31.073Z" }, { url = "https://files.pythonhosted.org/packages/77/96/4efd6fa5c62c85426a0c19077a586258ebc3a2a146ff2493e4312a697a22/greenlet-3.5.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f82b3597e9d83b63408affed0b48fd0f54935edac4302237b9a837be0dae33c", size = 660800, upload-time = "2026-05-20T13:14:29.129Z" },
{ url = "https://files.pythonhosted.org/packages/42/d4/fcb53fa9847d7fbd4723fbed9469c3869b9e3544c4e001d9d5aa2f66162d/greenlet-3.5.2-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:537c5c4f30395020bb9f48f53146070e3b997c3c75da14011ab732aaa19ce3ef", size = 472888, upload-time = "2026-06-17T18:41:22.511Z" }, { url = "https://files.pythonhosted.org/packages/e9/d3/dad2eecedfbb1ed7050a20dcfae40c1442b74bc7423608be2c7e03ee7133/greenlet-3.5.1-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:a4764e0bfc6a4d114c865b32520805c16a990ef5f286a514413b05d5ecd6a23d", size = 470786, upload-time = "2026-05-20T14:01:42.064Z" },
{ url = "https://files.pythonhosted.org/packages/4f/88/9e603f448e2bc107c883e95817b980fb9b45ba6aea0299b2e9978124bea2/greenlet-3.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dbebc038fcdda8f8f21cce985fd04e34e0f42007e7fc7ab7ad285caf77974b95", size = 1620723, upload-time = "2026-06-17T18:22:14.817Z" }, { url = "https://files.pythonhosted.org/packages/7a/e0/6c71401a25cac7000261304e866a2f2cc04dc74810d40e2f118aa4799495/greenlet-3.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c0141e37414c10164e702b8fb1473304221ad98f71600850c6ef7ff4880feba0", size = 1617518, upload-time = "2026-05-20T14:02:28.662Z" },
{ url = "https://files.pythonhosted.org/packages/11/91/26da17e3777858c16fdb8d020a4c68f3a03cb92f238de8f5351d5d5186e9/greenlet-3.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a207023f1cf8695fd82580b8099c09c5809be18bc2282362cdfb965dd884a317", size = 1684227, upload-time = "2026-06-17T17:40:09.536Z" }, { url = "https://files.pythonhosted.org/packages/41/26/c5c06643e8c0af9e7bf18e16cb51d0ab7625155f0392e1c9015d66d556cd/greenlet-3.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:50ae25a67bea74ea41fb14b960bc532df73eb713417b2d61892dced82fe8d3bc", size = 1681593, upload-time = "2026-05-20T13:14:39.417Z" },
{ url = "https://files.pythonhosted.org/packages/2d/44/b3a11f7aa34cb38f1b7f3df8bcd9fcd09bac9d342c2a2c9b8686c804bcd2/greenlet-3.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:c674a1dd4fe41f6a93febe7ab366ceabf15080ea31a9307811c56dac5f435f73", size = 240257, upload-time = "2026-06-17T17:35:23.359Z" }, { url = "https://files.pythonhosted.org/packages/8a/bd/e11a108317485075e68af9d23039619b86b28130c3b50d227d42edece64b/greenlet-3.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:8a17c42330e261299766b75ac1ea32caa437a9453c8f65d16a13140db378ecd3", size = 239800, upload-time = "2026-05-20T13:09:30.128Z" },
{ url = "https://files.pythonhosted.org/packages/de/e3/3b62145fe917311732041a258adb218248add00542e3131c48bd047fbed5/greenlet-3.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:3c417cd6c593bbbef6f7aa31a79f37d3db7d18832fc56b694a2150130bde784e", size = 239038, upload-time = "2026-06-17T17:37:56.792Z" }, { url = "https://files.pythonhosted.org/packages/47/f8/8e8e8417b7bf28639a5a56356ef934d0375e1d0c70a57e04d7701e870ffe/greenlet-3.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:7b5f5fae05b8ac6d176a61b60c394a8cbdc2b5b91b81793066e68745cf165e54", size = 236862, upload-time = "2026-05-20T13:09:10.498Z" },
{ url = "https://files.pythonhosted.org/packages/47/ac/d3bad483e9f6cd1848604fdffa32cac25846dd6dfcec0e6f81c790185518/greenlet-3.5.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:a96457a30384de52d9c5d2fd33abf6c1daae3db392cd556738f408b1a79a1cf0", size = 295668, upload-time = "2026-06-17T17:36:02.293Z" }, { url = "https://files.pythonhosted.org/packages/90/12/41bf27fde4d3605d3773ae57751eda182b8be2f5398011c041173b1d9534/greenlet-3.5.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:ea8da1e900d758d078810d4255d8c6aa572181896a31ec79d779eb79c3adc9ad", size = 293637, upload-time = "2026-05-20T13:12:35.529Z" },
{ url = "https://files.pythonhosted.org/packages/00/e9/3a7e557b895fd0469b00cd0b2bd498ba950e8bfdf6d7adeecf2c5e4130a6/greenlet-3.5.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4af5d4961818ab651d09c1448a03b1ba2a1726a076266ebb62330bab9f3238c", size = 652820, upload-time = "2026-06-17T18:07:24.95Z" }, { url = "https://files.pythonhosted.org/packages/44/44/ba14b23e9757707050c2f397d305bbcae62e5d7cad122f8b6baec5ae4a1f/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a19570c52a21420dcbc94e661994bc325c0b5b11304540fed514586da5dc8f2e", size = 650840, upload-time = "2026-05-20T14:00:11.079Z" },
{ url = "https://files.pythonhosted.org/packages/78/67/6225d5c5e4afc04be0fd161eec82e4b72017e8a100d222f25d7b42b0140d/greenlet-3.5.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a1789a6244ea1ba61fd4386c9a6a31873e9b0234762103364be98ef87dcb19f3", size = 658697, upload-time = "2026-06-17T18:29:48.365Z" }, { url = "https://files.pythonhosted.org/packages/a8/37/5ddc2b686a6844f91abecef43411842426da2e1573f60b49ecf2547f4ae1/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d955c89b75eeca4723d7cc14135f393cd47c32e2a6cb4a8e4c6e760a26b0986", size = 656416, upload-time = "2026-05-20T14:05:47.118Z" },
{ url = "https://files.pythonhosted.org/packages/35/ad/9b3058f999b81750a9c6d9ec424f509462d232b58002086fe2ba63b66407/greenlet-3.5.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ee6288f1933d698b4f098127ed17bda2910a75d2807915bd16294a972055d6c", size = 658945, upload-time = "2026-06-17T18:39:32.509Z" }, { url = "https://files.pythonhosted.org/packages/8c/46/5987dcd1a2570ba84f3b187536b2ca3ae97613387e57f5cfa99df068fe5e/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea37d5a157eb9493820d3792ac4ece28619a394391d2b9f2f78057d396ff0f0f", size = 656607, upload-time = "2026-05-20T14:09:13.949Z" },
{ url = "https://files.pythonhosted.org/packages/fa/99/6324b8ef916dcaddccb340b304c992ca3f947614ce0f2685d438187300b8/greenlet-3.5.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3be00501fb4a8c37f6b4b3c4773808ceb26ea65c7ea64fd5735d0f330b3786de", size = 656436, upload-time = "2026-06-17T17:39:32.509Z" }, { url = "https://files.pythonhosted.org/packages/e1/f0/d17510297c35a2992712f0bf84de3779749999f7d3d63aa1f09db7c62dbe/greenlet-3.5.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2daaaebd1a5aa88c49045b6baf9310b3263796bd88db713edf37cf53e7bb4e", size = 654397, upload-time = "2026-05-20T13:14:30.696Z" },
{ url = "https://files.pythonhosted.org/packages/92/75/1b6ecd8c027b69ab1b6798a84094df79aab5e69ac7e249c78b9d361dd1fa/greenlet-3.5.2-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:b4cad42662c796334c2d24607c411e3ed82481c1fb4e1e8ec3a5a8416060092e", size = 490529, upload-time = "2026-06-17T18:41:23.954Z" }, { url = "https://files.pythonhosted.org/packages/2c/c1/6da0a9ddcc29d7e51ef14883fa3dc1e53b3f4ffba00582106c7bf55da1d8/greenlet-3.5.1-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:8d8a23250ea3ec7b36de8fa4b541e9e2db3ee82915cc060ab0631609ad8b28de", size = 488287, upload-time = "2026-05-20T14:01:43.143Z" },
{ url = "https://files.pythonhosted.org/packages/a9/ee/f5bf9daac27c5e1b011965f64b5630a32b415daf7381b312943629e12c2a/greenlet-3.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1d554cd96841a68d464d75a3736f8e87408a7b02b1930a75fa32feb408ad62f8", size = 1617193, upload-time = "2026-06-17T18:22:16.252Z" }, { url = "https://files.pythonhosted.org/packages/37/eb/147387705bb89092645b012586e7273cb5ed3c90ef7eaf3a69173eaf0209/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bfbd69cc349e43bf3a8ae1c85548ff0718efc887615c2db16c3833d7b0b072d", size = 1614469, upload-time = "2026-05-20T14:02:30.192Z" },
{ url = "https://files.pythonhosted.org/packages/8a/21/b05d5b12715bda92ce27c118d64971d21e9b8f3563ed959a7d271e2d4223/greenlet-3.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3dff6cd3aac35f6cd3fc23460105acf576f5faf6c378de0bc088bf37c913864a", size = 1677512, upload-time = "2026-06-17T17:40:10.771Z" }, { url = "https://files.pythonhosted.org/packages/a6/4e/37ee0da7732b7aa9896f17e15579a9df34b9fcb9dd494f0adfa749af6623/greenlet-3.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4378720dd888136c27215a0214d32a4d37c3852765d45bc37aad0623423cfd78", size = 1675115, upload-time = "2026-05-20T13:14:40.972Z" },
{ url = "https://files.pythonhosted.org/packages/b8/97/1b8f1314b868041b327dc1051603e8142b826480cb0ecb8a7b7632aee9c4/greenlet-3.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:36cfea2aa075d544617176b2e84450480f0797070ad8799a8c41ada2fe449d32", size = 243145, upload-time = "2026-06-17T17:34:37.502Z" }, { url = "https://files.pythonhosted.org/packages/57/f3/97dfcf4a6eb5077f8a672234216fb5923eb89f2cab7081cb10b2cf75b605/greenlet-3.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:45718441607f9325d948db98cbc691276059316d0358c188c246da4e1d4d23d2", size = 245246, upload-time = "2026-05-20T13:12:22.646Z" },
{ url = "https://files.pythonhosted.org/packages/36/07/1b5311775e04c718a118c504d7a3a312430e2a1bd1347226aff4774e4549/greenlet-3.5.2-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:a0314aa832c94633355dc6f3ee54f195159533355a323f26926fc63b98b2ccbb", size = 288315, upload-time = "2026-06-17T17:34:34.04Z" }, { url = "https://files.pythonhosted.org/packages/5d/73/d7f72e34b582f694f4a9b248162db7b09cc458a259ba8f0c0bfa1a34ea7d/greenlet-3.5.1-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:2baee5ca02031757ffe8cc3d69f0cc0aec7065ce362622da74f32d3bcab1c541", size = 285575, upload-time = "2026-05-20T13:12:07.043Z" },
{ url = "https://files.pythonhosted.org/packages/ed/cc/6abcd2a486b58b9f77b7a93b690d59cb2c11a5906ed2ad4c63c7b9c1113d/greenlet-3.5.2-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24c59cb7db9d5c694cb8fd0c76eef8e456b2123afdfa7e4b8f2a67a0860d7682", size = 659130, upload-time = "2026-06-17T18:07:26.354Z" }, { url = "https://files.pythonhosted.org/packages/df/59/fa9c6e87dc8ad27a95dabe2f29f372b733d05a8a67470f6c901ed9975655/greenlet-3.5.1-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1ec3274918a81d3ea778b9e75b56b72b33f300edb6cf7f3a7fe1dae56683de", size = 656428, upload-time = "2026-05-20T14:00:12.556Z" },
{ url = "https://files.pythonhosted.org/packages/f2/12/f4aaad6d3d383233f700ab322568a4f29f2c701a4861d85f4811d99689b2/greenlet-3.5.2-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7bb811753703739ad318112f16eccfaabdac050037b6d092debaa8b23566b4ce", size = 669724, upload-time = "2026-06-17T18:29:50.13Z" }, { url = "https://files.pythonhosted.org/packages/f6/f9/e753408871eaa61dfe35e619cfc67512b036fde99893685d50eea9e07146/greenlet-3.5.1-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:111e2390ffffc47d5840b01711dd7fac07d4c09283d0283e7f3264b14e284c64", size = 667064, upload-time = "2026-05-20T14:05:48.662Z" },
{ url = "https://files.pythonhosted.org/packages/53/e0/4ce3a046b51e53934eae93d7f9c13975a97285741e9e1fcadf8751314c37/greenlet-3.5.2-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2debcd0ef9455b7d4879589903efc8e497d4b8fb8c0ae772309e44d1ca5e957f", size = 673494, upload-time = "2026-06-17T18:39:34.196Z" }, { url = "https://files.pythonhosted.org/packages/dc/74/807a047255bf1e09303627c46dc043dca596b6958a354d904f32ab382005/greenlet-3.5.1-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:10a9a1c0bfbc93d41156ffcb90c75fbc05544054faf15dcc1fdf9765f8b607f0", size = 672962, upload-time = "2026-05-20T14:09:15.532Z" },
{ url = "https://files.pythonhosted.org/packages/91/2a/a089811fc31c6bf8742f40a4e73470d6d401cef18e4314eb20dc399b377c/greenlet-3.5.2-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6d78b5c1c178dad90447f1b8452262709d3eef4c98f825569e74c9d0b2260ac9", size = 668089, upload-time = "2026-06-17T17:39:33.808Z" }, { url = "https://files.pythonhosted.org/packages/96/27/5565b5b40389f1c7753003a07e21892fda8660926787036d5bc0308b8113/greenlet-3.5.1-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e630136e905fe5ff43e86945ae41220b6d1470956a39220e708110ac48d01ea5", size = 665697, upload-time = "2026-05-20T13:14:32.943Z" },
{ url = "https://files.pythonhosted.org/packages/52/e0/9c18721e63445dce02ee67e4c81c0f281626604ff55ae6f7b7f4354d7129/greenlet-3.5.2-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:9558cae989faeab6fbb425cd98a0cfa4190a47fba6443973fbee0a1eb0b0b6c3", size = 479721, upload-time = "2026-06-17T18:41:25.726Z" }, { url = "https://files.pythonhosted.org/packages/76/32/19d4e13225193c29b13e308015223f7d75fd3d8623d49dd19040d2ce8ec1/greenlet-3.5.1-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:ef08c1567c78074b22d1a200183d52d04a14df447bf70bcbb6a3507a48e776fc", size = 476047, upload-time = "2026-05-20T14:01:44.39Z" },
{ url = "https://files.pythonhosted.org/packages/0f/1c/2f47c7d5fcfa98a62b705bf9a0505d86f4563c0d81cab1f7159ff1e743b7/greenlet-3.5.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:0977af2df83136f81c1f76e76d4e2fe7d0dc56ea9c101a86af26a95190b9ca32", size = 1625684, upload-time = "2026-06-17T18:22:17.664Z" }, { url = "https://files.pythonhosted.org/packages/cf/82/e7de4178c0c2d1c9a5a3be3cc0b33e46a85b3ee4a77c071bf7ad8600e079/greenlet-3.5.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:975eac34b44a7077ca4d421348455b94f0f518246a7f14bc6d2fdcfe5b584368", size = 1621256, upload-time = "2026-05-20T14:02:31.91Z" },
{ url = "https://files.pythonhosted.org/packages/b9/bf/661dd24624f70b7b32972d7693d0344ecde10278f647d7b828baf739899c/greenlet-3.5.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f9ed777c6891d8253e54468576f55e27f8fc1a662a664f946a191003574c0a74", size = 1688043, upload-time = "2026-06-17T17:40:12.403Z" }, { url = "https://files.pythonhosted.org/packages/00/10/f2dddcf7dacac17dfc68691809589adad06135eb28930429cf58a6467a2f/greenlet-3.5.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:9ab3c3a0b2ae6198e67c898dad5215a49f9ae0d0081b3c3ec59f333e39eeca26", size = 1685956, upload-time = "2026-05-20T13:14:42.55Z" },
{ url = "https://files.pythonhosted.org/packages/60/49/d9bde1d15a21296b3b521fe083eb8aabd54ac05d15de9832918f3d639543/greenlet-3.5.2-cp315-cp315-win_amd64.whl", hash = "sha256:c0ea4eb3de23f0bac1d75205e10ccfa9b418b17b01a2d7bf19e3b69dda08900a", size = 240531, upload-time = "2026-06-17T17:35:47.448Z" }, { url = "https://files.pythonhosted.org/packages/22/17/4a232b32133230ada52f70e9d7f5b65b0caef8772f01849bd8d149e7e4ca/greenlet-3.5.1-cp315-cp315-win_amd64.whl", hash = "sha256:cbfc69be86e10dcfef5b1e6269d1d6926552aa89ee39e1de3353360c1b6989ab", size = 239802, upload-time = "2026-05-20T13:13:15.481Z" },
{ url = "https://files.pythonhosted.org/packages/7f/4d/86d7768bd53e9907de0333df215c2018cd01a593b3715cbd79aa82dd94b7/greenlet-3.5.2-cp315-cp315-win_arm64.whl", hash = "sha256:7a7bfc200be40d04961d7e80e8337d726c0c1a50777e588123c3ed8ba731dcb9", size = 239579, upload-time = "2026-06-17T17:39:39.954Z" }, { url = "https://files.pythonhosted.org/packages/c2/ae/4e623a7e6d4d2a5f4cb8e4c82de4169fc637942caae68d6e676b8a128ac5/greenlet-3.5.1-cp315-cp315-win_arm64.whl", hash = "sha256:92fd6d44ac5e5a887c8a5dc4a8ba0ba908527c31c12f78c6bc7dcfe8aab279f6", size = 236853, upload-time = "2026-05-20T13:15:37.301Z" },
{ url = "https://files.pythonhosted.org/packages/92/15/907be5e8900901039bae752fa9a31c03a3c1e064833f35a4e49449184581/greenlet-3.5.2-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:98a52d6a50d4deaba304331d83ee3e10ebbdc1517fcca40b2715d1de4534065c", size = 296697, upload-time = "2026-06-17T17:37:15.887Z" }, { url = "https://files.pythonhosted.org/packages/7a/57/816d9cff29119da3505b3d6a5e14a8af89006ac36f47f891ff293ee05af1/greenlet-3.5.1-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:a6fdf2433a5441ef9a95464f7c3e674775da1c8c1177fff311cee1acad4626ed", size = 293877, upload-time = "2026-05-20T13:10:19.078Z" },
{ url = "https://files.pythonhosted.org/packages/95/5c/08c57be575c3d6a3c023bbf22144a1c7dc6ed4d134527bb36ded4dbf04a8/greenlet-3.5.2-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1587ff8b58fdf806993ed1490a06ac19c22d47b219c68b30954380029045d8d4", size = 656710, upload-time = "2026-06-17T18:07:28.046Z" }, { url = "https://files.pythonhosted.org/packages/23/a1/59b0a7c7d140ff1a75626680b9a9899b79a9176cab298b394968fb023295/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7546556f0d649f99f6a361098a55f761181bb2ea12ff150bb16d26092ad88244", size = 655333, upload-time = "2026-05-20T14:00:14.758Z" },
{ url = "https://files.pythonhosted.org/packages/8c/d0/749f917bdc9fc90fceea4aa65fbf6556e617a50714d1496bdc8ad190bb36/greenlet-3.5.2-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:feb721811d2754bfd16b48de151dd6b1f222c048e625151f2ca44cfdfd69f59c", size = 662629, upload-time = "2026-06-17T18:29:51.728Z" }, { url = "https://files.pythonhosted.org/packages/72/1b/5efe127597625042218939d01855109f352779050768b670b52edcc16a6c/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5ee3ea898009fa898f85f9982255d35278c477bebe185beca249cab42d4526c", size = 659443, upload-time = "2026-05-20T14:05:50.159Z" },
{ url = "https://files.pythonhosted.org/packages/55/87/10776cd88df54d0f563e9e21e98363f2d6af94bedc553b1da0972fa87f80/greenlet-3.5.2-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a9476cbead736dc48ce89e3cd97acff95ecc48cbf21273603a438f9870c4a014", size = 663191, upload-time = "2026-06-17T18:39:35.639Z" }, { url = "https://files.pythonhosted.org/packages/c9/9d/1dcdf7b95ab3cf8c7b6d7277c18a5e167312f2b362ddfcc5d5e6d8d84b43/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a57b0d05a0448eed231d59c0ceb287dde984551e54cbc51ac2d4865712838e9c", size = 659998, upload-time = "2026-05-20T14:09:16.912Z" },
{ url = "https://files.pythonhosted.org/packages/5a/a5/68cefae3a07f6d0093a490cf28ab604f14578f3e60205a2a2b2d5cd70af2/greenlet-3.5.2-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fe6062b1f35534e1e8fb28dfed406cf4eeff3e0bca3a0d9f8ff69f20a4abb00", size = 660147, upload-time = "2026-06-17T17:39:35.068Z" }, { url = "https://files.pythonhosted.org/packages/6c/6d/c404246ea4d22d097a7426d0efb5b781bd7eb67715f09e79001bd552ab18/greenlet-3.5.1-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5c81f74d204d3edd136ebfd50dce53acbb776995d721a0fe801626cfc93b8cd", size = 658356, upload-time = "2026-05-20T13:14:35.091Z" },
{ url = "https://files.pythonhosted.org/packages/02/aa/26ddf92826a99d87bfb8fdb8f3a262a6f16495a5d8e579737baa92fb4543/greenlet-3.5.2-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:5930d3946ecae99fa7fc0e3f3ae515426ad85058ebd9bfc6c00cca8016e6206b", size = 498199, upload-time = "2026-06-17T18:41:27.464Z" }, { url = "https://files.pythonhosted.org/packages/05/7e/c4959664fc231d587d66d8e81f2095e98056ba1954beafdcbe635e251052/greenlet-3.5.1-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:b0703c2cef53e01baec47f7a3868009913ad71ec678bbecb42a6f40895e4ce62", size = 494470, upload-time = "2026-05-20T14:01:45.611Z" },
{ url = "https://files.pythonhosted.org/packages/d2/6b/b9156d8397e4750220f54c7c5c34650f1e740a8d2f66eab9cfd1b7b53b69/greenlet-3.5.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b4ac902af825cbac8e9b2fccab8122236fd2ba6c8b71a080116d2c2ec72671b1", size = 1621675, upload-time = "2026-06-17T18:22:18.873Z" }, { url = "https://files.pythonhosted.org/packages/51/02/f8ee37fb6d2219329f350af241c27fcf12df57e723d11f6fc6d3bacdadaa/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:2c18ef16bf6d4dd410e4dd52996888ea1497be26892fe5bbc73580aba4287b8e", size = 1619216, upload-time = "2026-05-20T14:02:33.403Z" },
{ url = "https://files.pythonhosted.org/packages/b0/e3/d3250f4fa01c211a93d04e34fded63187e648dbec17b9b1a14d388040593/greenlet-3.5.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:6f1e473c06ae8be00c9034c2bb10fa277b08a93287e3111c395b839f01d27e1f", size = 1680577, upload-time = "2026-06-17T17:40:14.055Z" }, { url = "https://files.pythonhosted.org/packages/93/c5/3dc9475ace2c7a3680da12372cddd7f1ac874eb410a1ac48d3e9dab83782/greenlet-3.5.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:17d86354f0ae6b61bf9be5148d0dd34e06c3cb7c602c671f79f29ac3b150e659", size = 1678427, upload-time = "2026-05-20T13:14:43.71Z" },
{ url = "https://files.pythonhosted.org/packages/55/ba/eaee8bda4419770d7096b5a009ebff0ab20a2a28cdd83c4b591bfdf36fa9/greenlet-3.5.2-cp315-cp315t-win_amd64.whl", hash = "sha256:3c2315045f9983e2e50d7e89d95405c21bddb8745f2da4487bc080ab3525f904", size = 243482, upload-time = "2026-06-17T17:37:34.741Z" }, { url = "https://files.pythonhosted.org/packages/df/4e/750c15c317a41ffb36f0bf40b933e3d744a7dede61889f74443ea69690cf/greenlet-3.5.1-cp315-cp315t-win_amd64.whl", hash = "sha256:e7516cf6ae6b8a582c2770a0caed47b8a48373ed732c33d69a72913ae6ac923e", size = 245225, upload-time = "2026-05-20T13:13:59.366Z" },
{ url = "https://files.pythonhosted.org/packages/37/45/f794a81c91e9942c61f9110bd1f9a38a0ea565eab57f8b08cd53d3131e48/greenlet-3.5.2-cp315-cp315t-win_arm64.whl", hash = "sha256:db548d5ab6c2a8ead82c013f875090d79b5d7d2b67fc513934ce6cf66492ad7f", size = 242062, upload-time = "2026-06-17T17:35:39.814Z" }, { url = "https://files.pythonhosted.org/packages/4f/fd/d3baea2eeb7b617efd47e87ca06e2ec2c6118d303aa9e918e0ce16eadc10/greenlet-3.5.1-cp315-cp315t-win_arm64.whl", hash = "sha256:5028648bf2253ec4745add746129d3904121fa7fe871a76bed23c5720573ce0a", size = 239590, upload-time = "2026-05-20T13:13:37.382Z" },
] ]
[[package]] [[package]]
@ -1398,7 +1398,7 @@ wheels = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "9.1.1" version = "9.1.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "sys_platform == 'win32'" },
@ -1407,9 +1407,9 @@ dependencies = [
{ name = "pluggy" }, { name = "pluggy" },
{ name = "pygments" }, { name = "pygments" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } sdist = { url = "https://files.pythonhosted.org/packages/84/0e/b5858858d74958632c49b72cb25a3976ff9f632397626715be71c89d3971/pytest-9.1.0.tar.gz", hash = "sha256:41dd9148c08072446394cefd3d79701701335a9f4cae69ba92e39f6c7f5c061c", size = 1634181, upload-time = "2026-06-13T18:52:45.983Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, { url = "https://files.pythonhosted.org/packages/8b/5a/ba30a81239b909821b3153e303e7def45178bf353da4f72380e6c5e8793b/pytest-9.1.0-py3-none-any.whl", hash = "sha256:8ebb0e7888bdf2bdfc602ec51f8f62d50200af37356c74e503c79a94f5c81f32", size = 386453, upload-time = "2026-06-13T18:52:44.045Z" },
] ]
[[package]] [[package]]
@ -1727,32 +1727,32 @@ wheels = [
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.15.18" version = "0.15.17"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/74/98/1295ad5a5aa9bc85bdcdfa5d82fe7b49c61af5657df4f227637ff9de0da6/ruff-0.15.18.tar.gz", hash = "sha256:2698a964c70e8bf402dcb99c8810472d270d141e7aa8c4e13599fd52033a2f33", size = 4761437, upload-time = "2026-06-18T18:25:39.224Z" } sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b9/d0/686e984941269621e2be72612d5c1e461f8f7b38415a2a7d7a81c8ae6715/ruff-0.15.18-py3-none-linux_armv6l.whl", hash = "sha256:8b6850172348c8381b8b3084c5915a4393c2373b9b54cd5b5e1ea15812bc10df", size = 10887308, upload-time = "2026-06-18T18:25:03.062Z" }, { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" },
{ url = "https://files.pythonhosted.org/packages/ed/21/bc4123e3f5515ee99f8ce1eb93a14a0628fe4d1678663cd08f933ac16931/ruff-0.15.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3fccc153a85417dcd976883160cacce486997b0a0058dd18f54b8aaaac7d1ce2", size = 11281305, upload-time = "2026-06-18T18:25:30.026Z" }, { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" },
{ url = "https://files.pythonhosted.org/packages/51/93/4769464c25cf7ab2acb3c7dda9cad3d867eb41c59565b3e2a9d17249c90c/ruff-0.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:08d4c86a68f2c3ec2c9d56380a71fb4a4f65373055cbb8caabd645e9102f38d4", size = 10641215, upload-time = "2026-06-18T18:25:15.802Z" }, { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" },
{ url = "https://files.pythonhosted.org/packages/6c/42/56926d17120db2c208d76bf60a1a019644dd9e91dc27f0f95c9caddb1366/ruff-0.15.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37e5108745c2c0705da916d7d4de533ddf547051ef45f62888c31bae73f66318", size = 10957224, upload-time = "2026-06-18T18:25:36.955Z" }, { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" },
{ url = "https://files.pythonhosted.org/packages/22/4f/d43fab8d8189afde803103022d000a8ef9f230616d436d52a8b2b8d63b50/ruff-0.15.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56949a6ce8b3abde54c0bcb22cebfe57e8771cadc84b407ae8b8eaf67ebdcd43", size = 10699024, upload-time = "2026-06-18T18:25:05.707Z" }, { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" },
{ url = "https://files.pythonhosted.org/packages/63/42/1e3e4c68bd408b9768cf3e439acbe2c78245225faef253f7028a0cdb63e0/ruff-0.15.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01a754cd6a1b630d3f97e33eb452cf7a98040482318e870f8bc52a5a30e62657", size = 11491458, upload-time = "2026-06-18T18:25:20.275Z" }, { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" },
{ url = "https://files.pythonhosted.org/packages/20/77/47a3484bea8521e14a203d98c389c5c97846675e4f02734672da4a69b52a/ruff-0.15.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba7a07e03a44dbf10bb086ee06705b173625014ec99f73a7e6836a5e5590a0c", size = 12383752, upload-time = "2026-06-18T18:25:22.535Z" }, { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" },
{ url = "https://files.pythonhosted.org/packages/0a/ca/054159590787023d83b658a1a1819c4c8910114e7015069340b71c0961cb/ruff-0.15.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a2c40a41a4cadbcf5897b548ab29dfe248b20c540961c0247d98a3973c70403", size = 11577923, upload-time = "2026-06-18T18:25:10.702Z" }, { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" },
{ url = "https://files.pythonhosted.org/packages/6d/ff/d353d6b7bbd73cc0ec37f4463d7540e45e894338abdd9964eee0de332708/ruff-0.15.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f0480ce690cbb6c4db6e5d08f19fce98e10ba131a8b60c1bcdac42771e3ae2d", size = 11583925, upload-time = "2026-06-18T18:25:32.391Z" }, { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" },
{ url = "https://files.pythonhosted.org/packages/c1/4a/891f89b9c296ed3e5f3ece1a5629badc989d9a8fdaa30431aaf4774bc1c2/ruff-0.15.18-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2330215f1f393fa8733f55edce04fcf94c36a2c460fcde31f78cc84e4951e9b1", size = 11582834, upload-time = "2026-06-18T18:25:27.309Z" }, { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" },
{ url = "https://files.pythonhosted.org/packages/32/a3/ed9e370154bf85de360b93c03026157f02d4943b2d01ff4945f4429f8e8a/ruff-0.15.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a6aa6a3d979e48ae617578183674bf264fbe7d0114a796a26bd678d67963c7ff", size = 10927328, upload-time = "2026-06-18T18:25:34.676Z" }, { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" },
{ url = "https://files.pythonhosted.org/packages/f5/d1/5cf5909329fedb5d39d555ee818ba5cf4638e1a301b89785d34f2905bfcb/ruff-0.15.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a81beadbbff2c9c245561ae3f77b16709d87f35eec650d0501679239d3449b22", size = 10693187, upload-time = "2026-06-18T18:25:08.245Z" }, { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" },
{ url = "https://files.pythonhosted.org/packages/fd/44/ff6c635cf2c4f4e7b618b6640da057376baa36014695487d88aed4794268/ruff-0.15.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2186d9e940ae332ab293623a75b5f4fe49565f449954d50a72a046683aa6b809", size = 11208721, upload-time = "2026-06-18T18:25:41.327Z" }, { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" },
{ url = "https://files.pythonhosted.org/packages/88/d9/5baa2a30861adfb7022cf33c1e35b2fc18085b08c16f83eff4c7b99a5f48/ruff-0.15.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c2abf140438032bc77b2284a6c9944ecd8a19e5f1c7b52b1b8e4a0a80d19a7a", size = 11678599, upload-time = "2026-06-18T18:25:13.607Z" }, { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" },
{ url = "https://files.pythonhosted.org/packages/c3/1a/0725a7cfdc32ff769efb96ee782bec882e16448c5d9e3be947ec4c04ce27/ruff-0.15.18-py3-none-win32.whl", hash = "sha256:02299e6e9fa5b297a3f6d5d10d7bcd655c925b028bb8b9d4588214549c6b9ec4", size = 10901903, upload-time = "2026-06-18T18:25:24.755Z" }, { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" },
{ url = "https://files.pythonhosted.org/packages/f3/51/805d9f6fb7970505c3504794a5ec350f605361b807fef4dcf214ebd35e72/ruff-0.15.18-py3-none-win_amd64.whl", hash = "sha256:dac80dc8d26b2257dbefabed62f5d255c3937b4ccb122da1fc634794fa3578b3", size = 12041189, upload-time = "2026-06-18T18:25:17.915Z" }, { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" },
{ url = "https://files.pythonhosted.org/packages/29/4c/67bb45e41609eb4726f1bfeb59e083cf91d14c696d4bd14c234a980be93d/ruff-0.15.18-py3-none-win_arm64.whl", hash = "sha256:b2c9257fcbd4a3e5b977a1904e6facca016bafe2edc17df24db67cfaee03b4e4", size = 11329958, upload-time = "2026-06-18T18:25:43.686Z" }, { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" },
] ]
[[package]] [[package]]
name = "selenium" name = "selenium"
version = "4.45.0" version = "4.44.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "certifi" }, { name = "certifi" },
@ -1762,9 +1762,9 @@ dependencies = [
{ name = "urllib3", extra = ["socks"] }, { name = "urllib3", extra = ["socks"] },
{ name = "websocket-client" }, { name = "websocket-client" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/86/48/486aa67320f27452e9f551b8608f1a59ce7091c8fe7ebc9f4eba274775d4/selenium-4.45.0.tar.gz", hash = "sha256:563f0c4102f112df1cda30d46ce6d177b2e4a7a3d4b0756902d5dc84d3a8a365", size = 1005503, upload-time = "2026-06-16T04:43:57.915Z" } sdist = { url = "https://files.pythonhosted.org/packages/2d/4a/6d0a4f4a07e2a91511a51398203ee82bf6ce644a448aaa35c59b44aa9531/selenium-4.44.0.tar.gz", hash = "sha256:b03a831fcfcab9d912b4682f60718c48a04560d6c62f7496c16b7498c9a4427e", size = 993133, upload-time = "2026-05-12T22:48:19.246Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/e4/8a/6ff6beb9c7c6cc642f628df9328a8b6637f86602eff8d28e70b5d4e8bca7/selenium-4.45.0-py3-none-any.whl", hash = "sha256:1fd9d0dc08192b2f8100e264ed720f83b05d2dd3a7feff673df04e0c7580df4b", size = 9536616, upload-time = "2026-06-16T04:43:55.968Z" }, { url = "https://files.pythonhosted.org/packages/1f/bc/885047e975e996cb317db31c4551caa915aafc6befea990f082c7233adc2/selenium-4.44.0-py3-none-any.whl", hash = "sha256:d01ea3e5ecad8149460a765f7cf5177194c21dcc0173093fc05427c289b1bf24", size = 9654291, upload-time = "2026-05-12T22:48:16.836Z" },
] ]
[[package]] [[package]]
@ -1814,36 +1814,36 @@ wheels = [
[[package]] [[package]]
name = "sqlalchemy" name = "sqlalchemy"
version = "2.0.51" version = "2.0.50"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/02/f1/a7a892f18d4d224e6b26f706531eafccc41e37594d37d304786969ee13cb/sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9", size = 9912201, upload-time = "2026-06-15T15:41:20.012Z" } sdist = { url = "https://files.pythonhosted.org/packages/57/da/6fbf010c8ebb347679d0d100b22fe9ba5e13fd04046c5df7280d2f0bf706/sqlalchemy-2.0.50.tar.gz", hash = "sha256:af5607d11ef90fd6a5c0549fe0045dce1663d427426bcfb506dcb5346a85a3b9", size = 9907424, upload-time = "2026-05-24T19:20:04.018Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/54/fe/a210d52fd1a90ecfae8a78e9d8b27e18d733d60818a8bf250ff690b75120/sqlalchemy-2.0.51-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c2056838b6685b72fdb36c99996cf862753461a62f2e84f4196371d3b2d6a07", size = 2157184, upload-time = "2026-06-15T16:08:50.374Z" }, { url = "https://files.pythonhosted.org/packages/0b/c4/c42356b527296e9862f67990efce31ef78b4cf69cd3f80873a528a060320/sqlalchemy-2.0.50-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:06a9210bdc5f4298cff0781087e2ff45683922252dacc452846373a58761f093", size = 2156697, upload-time = "2026-05-24T19:27:54.764Z" },
{ url = "https://files.pythonhosted.org/packages/17/6b/2dce8369b199cb855110e056032f94a9f66dacc2237d3d39c115a86eac56/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483b11bd46bf35fc14c52faf338b04300c9e6ce554bce9b11be85bfec3bc3195", size = 3284735, upload-time = "2026-06-15T16:19:46.934Z" }, { url = "https://files.pythonhosted.org/packages/60/a1/b1a70e3c4365ac7fe9e347f3710f19b562c866fb96d45e3c891588789a7b/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b53784972ade4f8174b9aa661f31a06f8a936d2cfdd602913ff3c6dd40ae873", size = 3284260, upload-time = "2026-05-24T20:09:34.195Z" },
{ url = "https://files.pythonhosted.org/packages/53/ff/dbc495b8a14da840faffb353857a72d4190113cac33727906fb997047f0f/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bed1ee8b01da6088210aa9412023326fb98a599ba502e6118308601dcbef77f", size = 3302756, upload-time = "2026-06-15T16:26:41.336Z" }, { url = "https://files.pythonhosted.org/packages/3f/4a/f3ac3caa19f263d57b0a47f8c91bbf56583dc2d3fc63acfbf644abb24fe0/sqlalchemy-2.0.50-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31648fa14460537e768a7303b078e4344d208e0d23e06867c1f376a227ed82db", size = 3302280, upload-time = "2026-05-24T20:17:17.825Z" },
{ url = "https://files.pythonhosted.org/packages/cf/d5/fde8f4dddcf518ee15ab35a7c6a28acc32c8ba548d1d2aa451f96e6dbb0b/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72ca54c952107ba5cd58854b67a5a6268631289d21651a1235396f3b98b47400", size = 3232055, upload-time = "2026-06-15T16:19:49.286Z" }, { url = "https://files.pythonhosted.org/packages/66/55/ccada3e3d62254587819749a0bc69f41173eb48a6e385d10e66d32a9c88e/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:03f4323c980ad0e918cc9e5369b015f759f4e534db5bbaf4dc36832c10d05064", size = 3231580, upload-time = "2026-05-24T20:09:36.406Z" },
{ url = "https://files.pythonhosted.org/packages/67/d1/43d3a0ac955a58601c24fa23038b1c55ee3a1ec02c0f96ebb1eae2bcf614/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e693d15533a45cd5906f0589f9c35090bef6ef45bf1e8195c424aa0ae06a8d", size = 3269850, upload-time = "2026-06-15T16:26:43.017Z" }, { url = "https://files.pythonhosted.org/packages/05/f6/6809349130a2de0e109e7f00fd7d431da9565b9b2868b32ee684754f672b/sqlalchemy-2.0.50-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2b9dcc43afef8ac157cd92fce96985d6b8b0cfbd3df4d666f66b4d55a75d202f", size = 3269375, upload-time = "2026-05-24T20:17:20.34Z" },
{ url = "https://files.pythonhosted.org/packages/94/df/de669c7054cd47c4439ac34b1b2ee8b804a794791fbb10720e997a2c87c7/sqlalchemy-2.0.51-cp313-cp313-win32.whl", hash = "sha256:b93ab07b5292dbe7e6b8da89475275e7042744283921344b56105f3eeb0f828b", size = 2117721, upload-time = "2026-06-15T16:23:12.36Z" }, { url = "https://files.pythonhosted.org/packages/48/84/278a811ef4e07be9c89dc5cdd7be833268509a66a68c4897cf585e67428f/sqlalchemy-2.0.50-cp313-cp313-win32.whl", hash = "sha256:60922d6599065ddca2c6f376b9aa2f41a6b85a271725e0909490bbc50b1998a5", size = 2117229, upload-time = "2026-05-24T19:50:08.215Z" },
{ url = "https://files.pythonhosted.org/packages/d0/8a/403c51d064196bae20a0bc2476577f83a3f8dd299719a97417086b7f2ec5/sqlalchemy-2.0.51-cp313-cp313-win_amd64.whl", hash = "sha256:0f053118c30e53161857a953e4de667d90e274980dccbe5dd3829bbbeece72a5", size = 2143615, upload-time = "2026-06-15T16:23:13.906Z" }, { url = "https://files.pythonhosted.org/packages/f6/1c/067cc6187ed32d2ec222fe6d2643acc1659a6d0659f8a7cbc5ad3ae83280/sqlalchemy-2.0.50-cp313-cp313-win_amd64.whl", hash = "sha256:287086e67275a212c4582d166a6fb03a65ccc5551d80866270ce0dd9f34eccd3", size = 2143126, upload-time = "2026-05-24T19:50:09.691Z" },
{ url = "https://files.pythonhosted.org/packages/b1/49/a739be2e1d02a96a658eb71ab45d921c874249252358ad24a5bffdd02525/sqlalchemy-2.0.51-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6ea306caaae6bd5afd0a46050003c88f6bf33227377a49298c498c3cb88ff491", size = 2158999, upload-time = "2026-06-15T16:08:51.759Z" }, { url = "https://files.pythonhosted.org/packages/df/32/10ac51b4be7cdecd7e93d069251c86dfbf70b7adbd7c67b48ccea6c49e1c/sqlalchemy-2.0.50-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c966932507a4d7d0a37314927dbfcd89720e3f37d2a1e3352e7ae7939fa8e8a0", size = 2158519, upload-time = "2026-05-24T19:27:56.472Z" },
{ url = "https://files.pythonhosted.org/packages/23/6b/2e0e38cf75c8780eca78d9b2e78164f8bcfd70125e5caa588ff5cbb9c9f4/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c45a496d6bc05dec41dcd4c3a2b183723f47473255c159cd80b503c8f246424d", size = 3282539, upload-time = "2026-06-15T16:19:51.065Z" }, { url = "https://files.pythonhosted.org/packages/5a/76/e703d2f7681d7d66c4c891af3f07c7ccf4c76ad7f18351de035b5eda007a/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:faffef4bcc20a1892e65e155293d99d60855bbbc79250ab712819cfd56a8e6bb", size = 3282063, upload-time = "2026-05-24T20:09:38.57Z" },
{ url = "https://files.pythonhosted.org/packages/dd/a1/e77854cb5336fd37dc3c6ae3b71de242c98caac5725120be0b526b31cbd0/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4004ada0aafe8ae1991b2cd1d99c6d9146126e123bd6f883c260d974aa012e54", size = 3287545, upload-time = "2026-06-15T16:26:44.735Z" }, { url = "https://files.pythonhosted.org/packages/31/26/ef168b184a25701f9995e8fb7e503fafd7a99c1c77cda1bc1a26ea2ed486/sqlalchemy-2.0.50-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c206aec519a2e7bd08abbfb33436e325fd22c632d9c21a9047e376ce241646e", size = 3287069, upload-time = "2026-05-24T20:17:21.942Z" },
{ url = "https://files.pythonhosted.org/packages/f6/ab/9e17272fd4dac8df3b83c4fbe52b998a1c9d89a843c8c35ff29b74ff7364/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f6bcad487aee1c638d707235682fc96f741de00663619881ab235400d03289e", size = 3230929, upload-time = "2026-06-15T16:19:52.625Z" }, { url = "https://files.pythonhosted.org/packages/c2/15/765acc2bc693bccc43ca4a95d5b69750da8aaf6db1b5c616536e087f8920/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:bef4ac756363227ef6402a75fee025a4bc690f92328e825868939b3b3a446a6d", size = 3230453, upload-time = "2026-05-24T20:09:40.398Z" },
{ url = "https://files.pythonhosted.org/packages/02/3c/52f408ea701781caee975606beccc48845f2aee8711ac29843d612c0306c/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:39a76529db6305693d8d4affa58ad5b5e2e18edd62daea628b29b97930b3513d", size = 3252888, upload-time = "2026-06-15T16:26:46.454Z" }, { url = "https://files.pythonhosted.org/packages/63/61/08e03c3adbf5db0087a0b6816746fec8f3032fb2f7fc899a9bb9b2a48ce4/sqlalchemy-2.0.50-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:96fbee6b19c19cd1556c8bf9419447cf2ec149ffcab7ab64348c23e54ef8547f", size = 3252413, upload-time = "2026-05-24T20:17:24.067Z" },
{ url = "https://files.pythonhosted.org/packages/24/16/3efd2ee6bc4ca4693a30a1dd17a91b606cae15d517d2a4746611d9b73ce8/sqlalchemy-2.0.51-cp314-cp314-win32.whl", hash = "sha256:08a204d8b5638717c26a24df18fcf40af45a6b22e35b70b1d62f0113c2e278e8", size = 2120551, upload-time = "2026-06-15T16:23:15.629Z" }, { url = "https://files.pythonhosted.org/packages/03/0c/370a1f2db38436c615e10134c8a37de3688e74084792380695f3f5083860/sqlalchemy-2.0.50-cp314-cp314-win32.whl", hash = "sha256:8f00e3eb43ba30eb1b238ee03a8a62309486d1321eda3328bb611e0340033ad8", size = 2120063, upload-time = "2026-05-24T19:50:11.08Z" },
{ url = "https://files.pythonhosted.org/packages/7b/78/55b12e70f45bccc40d9e483925c065027b3b98ea4cbbdf6f8c2546feaf6c/sqlalchemy-2.0.51-cp314-cp314-win_amd64.whl", hash = "sha256:96747bfbadb055466e5b46d572618170046b45ce5a4879167f50d70a5319a499", size = 2146318, upload-time = "2026-06-15T16:23:17.108Z" }, { url = "https://files.pythonhosted.org/packages/7f/a0/fe92bb9817863bc13ba093bda931979a26cc2ca69f8e8f26d07add3d7c6f/sqlalchemy-2.0.50-cp314-cp314-win_amd64.whl", hash = "sha256:15708c613cd5005b7dffe1f66ee6a63ee8f5e46799f71c70ebad74178c676a39", size = 2145830, upload-time = "2026-05-24T19:50:12.452Z" },
{ url = "https://files.pythonhosted.org/packages/21/db/a9574ed40fed418924b1b1a3e54f47ee3963053b3d3d325a0d36b41f2c08/sqlalchemy-2.0.51-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1a213be1fcd5e49d9904c3b9939211ded90bc2a64e93f4c01963474285de", size = 2178920, upload-time = "2026-06-15T15:59:56.285Z" }, { url = "https://files.pythonhosted.org/packages/cc/ff/e5640a98a0b2f491eb8fde10fb6c773621a2e44340de231fafcc9370f4a9/sqlalchemy-2.0.50-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3699dac4be410e97049a1658e9480da9cde956594aa0f3aebc60b88f21c5ba70", size = 2178435, upload-time = "2026-05-24T19:42:58.889Z" },
{ url = "https://files.pythonhosted.org/packages/bf/90/a1bb5c7cbba76b7bc1fbd586d0a5479a7bc9c27b4a8298f22ec9423b2bb3/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c6b36ed71f41942bdcd2ad2522be46bfce09d5705be5640ecf19bbc7660e4b7", size = 3566534, upload-time = "2026-06-15T15:58:35.024Z" }, { url = "https://files.pythonhosted.org/packages/b7/85/337116e186f1236375b5fb70c21cfac98e8e8ab0d3a47be838dc47a59e08/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f96233858e3df43932ac11589e22520da6e8aeb624b03fedfeebb0e8ea213086", size = 3566059, upload-time = "2026-05-24T20:01:20.848Z" },
{ url = "https://files.pythonhosted.org/packages/15/4b/481f1fed30e0e9e8dd24aecbb49f29eb57fe7657ece5cf06ee9b84bb97d8/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c2c62877097e1a0db401fba5cb4debee33265e5b2a55c4ccb489c02c53b4f72", size = 3535844, upload-time = "2026-06-15T16:02:43.973Z" }, { url = "https://files.pythonhosted.org/packages/96/34/bb0e190e161c3c2c24314a65add57218be14a4a9486886b7f5047c1ff7c8/sqlalchemy-2.0.50-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c4e70c46fad30c3bcc6a4708bc0130a3173e11a5b25f0ea4a9d8911b450f1f52", size = 3535366, upload-time = "2026-05-24T20:03:56.768Z" },
{ url = "https://files.pythonhosted.org/packages/02/71/0aa64aeda645510af0a43f7d9ee70932f0d1dc4263aed34c50ee891d9df3/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0378d055e9e8cd6ce4d8dff683bdd3d7d413533c4ee51d67a2b1e0f9eacc0f23", size = 3475355, upload-time = "2026-06-15T15:58:36.592Z" }, { url = "https://files.pythonhosted.org/packages/df/5a/a7f759f97e4fd499c5d4e4488c760d5a7fbecf3028b465a04274fcd52384/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1918a3cf564d16d95bca7301005f41ab2ad50b07cd3b9da50d3ed986db148d6a", size = 3474879, upload-time = "2026-05-24T20:01:23.058Z" },
{ url = "https://files.pythonhosted.org/packages/05/db/6061db32316446135a3abae5f308d144ab988a34234726042da3e58b1c63/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e46fc36029eff666391e0531e5387b62ce6c4f1d8e50b3fb3099eaca1b42522", size = 3486591, upload-time = "2026-06-15T16:02:45.346Z" }, { url = "https://files.pythonhosted.org/packages/9d/d9/2907ea38eb60687d297bf9c39e5ee58053c87b57fe8a9cae97090cecbf10/sqlalchemy-2.0.50-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b00098cdbdbd38c7be3d568b0c9c3122b8c0ec62b911b57cd5e6e0254d60a76d", size = 3486117, upload-time = "2026-05-24T20:03:59.052Z" },
{ url = "https://files.pythonhosted.org/packages/0d/c9/f14fdf71bb8957e0c7e39db69bbdf12b5c80f4ef775fdfa127bf4e0d6760/sqlalchemy-2.0.51-cp314-cp314t-win32.whl", hash = "sha256:9161cfc9efce70d1715f47d6ff40f79c6778c00d53be4fbc09d70301e4b83ba7", size = 2151313, upload-time = "2026-06-15T16:03:39.127Z" }, { url = "https://files.pythonhosted.org/packages/f2/e3/5aa06f167559f8c0bdae487e297d23ba548150ab016a3418265d617a4985/sqlalchemy-2.0.50-cp314-cp314t-win32.whl", hash = "sha256:1fbd55a969d7ac44a98e3dec75016074f809fa08f871585ace58dde110d1bf3e", size = 2150823, upload-time = "2026-05-24T20:08:58.644Z" },
{ url = "https://files.pythonhosted.org/packages/6a/c6/673e618e6f4f297e126d9b56ea2f6478708f6c1af4e3223835c22e2c3697/sqlalchemy-2.0.51-cp314-cp314t-win_amd64.whl", hash = "sha256:159bb6ba32059f57ad7375a8f50d844dd2f19d14954ecf820cd33e20debd46b2", size = 2186280, upload-time = "2026-06-15T16:03:40.569Z" }, { url = "https://files.pythonhosted.org/packages/65/9b/112fb8f977582d7489d036e409e3723948bcf5320b3ac465f3c481bbe8f9/sqlalchemy-2.0.50-cp314-cp314t-win_amd64.whl", hash = "sha256:c5c3cdb753a9004183e1ccb634b41611654c989e61bc68617ce878e46d6f1e51", size = 2185794, upload-time = "2026-05-24T20:09:00.319Z" },
{ url = "https://files.pythonhosted.org/packages/e2/22/dbf013a12ec759e54a34a119e9e217435b3f71b2dd5c61a7ade0a25dae87/sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5", size = 1944334, upload-time = "2026-06-15T16:09:22.418Z" }, { url = "https://files.pythonhosted.org/packages/d0/10/f7220e9b784d295d241c86ed99aeb537f92afcd469a64861f2717e9bb077/sqlalchemy-2.0.50-py3-none-any.whl", hash = "sha256:92064363517a3ff8212b5a93b8c62876579d8dfd1ca5b561335f30152d884fa9", size = 1943861, upload-time = "2026-05-24T19:59:01.119Z" },
] ]
[[package]] [[package]]
@ -1909,14 +1909,14 @@ wheels = [
[[package]] [[package]]
name = "tzlocal" name = "tzlocal"
version = "5.4.3" version = "5.3.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "tzdata", marker = "sys_platform == 'win32'" }, { name = "tzdata", marker = "sys_platform == 'win32'" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/48/55/15e2340963d2bfedcc6042da3911438fd336f8ae96b65bdbe3a29766da0c/tzlocal-5.4.3.tar.gz", hash = "sha256:3a8c9bc18cf47e1dcde252ea0e6a72a6cde320a400b6ac6db1f1f8cccd553c00", size = 30873, upload-time = "2026-06-17T04:17:41.764Z" } sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/42/28/fc144409c71569e928585f8f3c629d80d1ca3ef40175e9222f01588f98c9/tzlocal-5.4.3-py3-none-any.whl", hash = "sha256:24ce97bb58e2a973f7640ec2553ab4e6f6d5a0d0d1aa9dc43bca21d89e1feb82", size = 18039, upload-time = "2026-06-17T04:17:40.027Z" }, { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" },
] ]
[[package]] [[package]]