Commit Graph
15 Commits
Author SHA1 Message Date
rmsitzandClaude Sonnet 5 bf0a02d008 Redesign expandable lists to a leaner, flat style
Course tree (lesson-page sidebar + dashboard's loaded-course view) and
File Management's Manage Library browser both move from boxed,
bordered rows to a flat list: no per-row background/border, a small
leading chevron that doubles as the expand affordance instead of a
separate right-edge button, indentation for hierarchy. The chevron's
rotation is pure CSS (:has(+ .tree-content.expanded) / :has(+
.curate-children.expanded)) rather than JS swapping glyph text, which
also let a fair amount of now-redundant JS come out.

The course tree's new styles are scoped under .tree-container (course
dashboard) and .lesson-sidebar (lesson page) so they don't leak into
the Library folder browser and other rows that reuse the same base
.tree-header/.lesson-item/etc. class names elsewhere in
course_dashboard.html - confirmed those are visually untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 10:45:38 -04:00
rmsitzandClaude Sonnet 5 016acacdb5 Add expand all/collapse all to the course tree
An "Expand all" link above the tree (toggling to "Collapse all" once
everything's open) opens or closes every section at once - on both
the lesson page's sidebar and the dashboard's loaded-course view.
Toggles stay right-aligned per section, matching convention rather
than moving to the left. Label reflects current state on load and
persists through the same remembered-sections mechanism as manual
expand/collapse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 10:27:42 -04:00
rmsitzandClaude Sonnet 5 9fb193a07e Header/footer polish, fix dead link, add focus rings
- Dashboard header shortened to match every other page (was notably
  taller than the rest).
- Files moved before Settings in the bottom nav.
- Removed the header's course-name badge - purely redundant with the
  page's own heading directly below it.
- Fixed a dead link: "Progress" pointed to #stats, but no element
  with that id existed anywhere on the page.
- Added a visible :focus-visible ring across all pages - tabbing
  through the site previously gave no indication of what was focused.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 10:14:02 -04:00
rmsitzandClaude Sonnet 5 becbb0b419 Move sidebar left, add collapse toggle and remembered sections
- Course outline sidebar now sits on the left of the player instead
  of the right (mobile stacking order unchanged - video still first).
- Collapsible to a slim rail via a toggle button, remembered per
  device, for a full-width player when wanted.
- Which sections a user has manually expanded is now remembered
  (keyed by the section's path) and shared between the lesson-page
  sidebar and the dashboard's course view, so re-opening a course
  doesn't reset everything back to collapsed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 09:41:52 -04:00
rmsitzandClaude Sonnet 5 0ed531503e Add hover tooltips for truncated sidebar titles
Section and lesson names in the course-outline sidebar/tree get
clipped with an ellipsis when they don't fit - a title attribute now
shows the full text on hover.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 09:17:30 -04:00
rmsitzandClaude Sonnet 5 4f25d4201b Add course outline sidebar to the lesson page
Shows every section and lesson in the course - videos and standalone
documents alike - so jumping to a different section no longer means
backing out to the course page first. Current lesson is highlighted,
its section auto-expands and scrolls into view; sticky on desktop,
stacks below the player on narrow viewports. Replaces the old
"Lessons in this section" list, which only showed the current
section.

The tree-rendering markup (shared with the loaded-course dashboard
view) is now a single macro in templates/_course_tree.html instead of
being duplicated, so both views stay in sync going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 09:13:09 -04:00
rmsitzandClaude Sonnet 5 72c7f67c3d Remove unreliable duplicate-lesson-file matching
Filename-similarity matching within a folder can't distinguish a real
re-download duplicate from a course that splits one topic across
several numbered files ("...Part 1"/"...Part 2", "-1"/"-2"/"-3") -
both look like near-100% matches by name alone, and the latter is a
common, completely normal pattern. This produced hundreds of false
positives in practice. Removes Duplicate Lesson Files entirely
(detection function, its two API routes, and the File Management UI
section); whole-course-folder matching (Duplicate Courses) is
unaffected and stays the only duplicate scan in the app.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 08:25:37 -04:00
rmsitzandClaude Sonnet 5 8220bb542a Widen thumbnail sampling window past platform bumpers
Many course platforms (Pluralsight, Packt, ...) open with a generic
branded bumper animation running 10-20s before the actual course
title card. The 8s candidate window landed squarely inside that
bumper and grabbed the platform logo instead of anything
course-specific. Candidates now spread across the first ~25s.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 20:33:37 -04:00
rmsitzandClaude Sonnet 5 de9c05d0d0 Fix race condition in thumbnail candidate generation
Concurrent requests for the same course's thumbnail (e.g. the
Precompute background scan overlapping an ordinary page load) shared
fixed candidate filenames, so one request's cleanup could delete a
temp file the other was still using, crashing with ENOENT. Candidate
filenames are now unique per call.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 20:27:08 -04:00
rmsitzandClaude Sonnet 5 36d9e7f89b Add autoplay, progress rings, duplicate-lesson detection, title-card thumbnails
- Auto-play next lesson on end, with a cancelable countdown and a
  Settings toggle (default on).
- Grid-view course cards show a small progress ring (checkmark at
  100%) instead of a separate bar.
- Duplicate Lesson Files: scans within each course/folder for media
  files that look like the same lesson downloaded twice, with per-file
  delete and a shared ignore list with Duplicate Courses.
- Auto-generated cover art now samples a few early candidate frames
  and keeps the largest JPEG, favoring an intro title card over a
  blank fade-in or a plain presenter frame.
- Settings -> "Regenerate Thumbnails" re-runs that logic for every
  course with an auto-generated thumbnail (never touches manual
  covers), so already-cached thumbnails can pick up the improvement.
- Add .gitignore for __pycache__/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 20:20:36 -04:00
rmsitzandClaude Sonnet 5 fc83876abe Add Favorites, storage drill-down, keyboard shortcuts, and What's New
- Favorites: star toggle on course rows, the course page, and a new
  dashboard card; rebased on rename/move, backed up/restored, and
  caught by stale-reference cleanup (also fixed a pre-existing gap
  where favorites.json wasn't in the backup file list).
- Storage Usage: click a folder row to drill into its contents one
  level at a time, with a Back button.
- Lesson player: added ,/. (speed step), [/] (prev/next lesson), and
  F (fullscreen) keyboard shortcuts.
- Settings: a CHANGELOG.md-backed "What's New" list, since VERSION
  alone only ever shows the current build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 19:23:40 -04:00
rmsitzandClaude Sonnet 5 1fbf0c9312 Fix video resize handle drifting off-screen
The resize observer was persisting any rendered size change, including
incidental reflow from the page's own responsive max-width clamping on
window/viewport resize - not just deliberate corner-handle drags. This
let the stored size drift into a badly non-16:9 box over repeated views
on different window sizes, pushing the actual resize grip far below the
fold. Now only persists while the user has mousedown on the video, and
caps rendered height at 80vh as a backstop against already-drifted values.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 19:00:40 -04:00
rmsitzandClaude Sonnet 5 ecabc828ea Cache the category tree walk (fixes ~1s File Management page load)
_build_category_index() was the one tree-scanning function never
wrapped in the app's existing 5-minute cache - it ran fresh on every
File Management page load and Sort Unsorted scan (not a manual "this
may take a moment" action like Duplicate Courses or Storage Usage), so
the cost was invisible until it was already slow. Measured ~1.0-1.1s
consistently against the live NAS-mounted library at 161 courses,
confirmed via profiling that a single call makes dozens of iterdir()
round-trips - each one a network hop over SMB. Now shares the same
cache_get_or_compute pattern and invalidate_cache() call sites as
get_all_course_dirs(), so no new invalidation logic was needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 18:06:57 -04:00
rmsitzandClaude Sonnet 5 ba8d7e2a1b Add search, bulk actions, undo, and storage usage to File Management
- Manage Library search: find any course/folder by name anywhere in
  the tree instead of expanding levels one by one; results carry the
  same Move/Rename/Hide actions.
- Bulk select: every row gets a checkbox, so items found via search or
  expanded across different tree levels can be hidden, shown, or moved
  to the same destination together in one batch.
- Undo last action: a "Last action: ... [Undo]" bar appears after any
  move/rename (Sort Unsorted apply, Bulk Rename apply, a Manage
  Library move/rename, a bulk move) and reverses the whole batch.
  Deliberately never covers Hide/Show (already a one-click toggle) or
  Delete (permanent by design) - only ever move/rename, which are
  trivially reversible. Re-checks each item before reversing it, so a
  partial failure reports exactly what did and didn't reverse.
- Storage Usage: disk usage per top-level library folder, largest
  first, with a simple proportional bar; a manual scan since it reads
  every file's size.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 14:41:26 -04:00
rmsitzandClaude Sonnet 5 71d6158c60 Fix build version showing "unknown" in production
The previous approach baked git rev-parse --short HEAD into the image
at Docker build time, but Dockhand's build context doesn't reliably
have .git available, so it silently fell back to "unknown" in
production even though the build itself succeeded. Replace it with a
plain VERSION file committed to the repo (a timestamp + short
description, updated by hand alongside each commit) that ships via the
same COPY . . as everything else - no git access needed inside the
build at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 14:00:42 -04:00