Add auto-thumbnails, library-wide remaining time, backup restore
Auto-generated course thumbnails: find_course_thumbnail() falls back to grabbing a frame from a course's first video via ffmpeg when there's no manual cover image, cached to .offlineu_thumbnail.jpg so it only ever runs once. Folded into the "Precompute" prewarm button, now "Precompute Lengths & Cover Art". Library-wide "Remaining" stat: sums every course's already-cached duration (no ffprobe, just a JSON read) into the dashboard's Library Stats card, alongside the existing "Watched" figure. Backup restore: new /api/backup/restore endpoint and a "Choose Backup File..." control in Settings, with zip-slip and missing-course guards. Also fixed a gap in the export itself - next_up.json and outline_config.json weren't being backed up before, so restore wouldn't have been a true round trip. Move Surprise Me from a full-width button above the course list to a dice-icon button in the dashboard header, swapping with the course-name badge depending on whether a course is loaded. Update README to cover all of the above. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -85,17 +85,21 @@ silently stay blank instead of erroring.
|
||||
opt-in transcript search across subtitle files
|
||||
- Course cards show media file count, total video/audio runtime, and
|
||||
completion % at a glance
|
||||
- Cover art: uses a manually-placed `cover`/`folder`/`thumbnail`/`thumb`/
|
||||
`poster` image if a course has one, otherwise auto-generates one via
|
||||
`ffmpeg` from a frame of the course's first video
|
||||
- Hide courses/folders from the browser without touching anything on disk;
|
||||
bulk-select to hide or queue several at once
|
||||
- Bulk rename across course/folder names (find & replace)
|
||||
|
||||
**Dashboard**
|
||||
- Library-wide stats (courses, lessons completed, time watched, day streak)
|
||||
and a 90-day activity heatmap
|
||||
- Library-wide stats (courses, lessons completed, time watched, time
|
||||
remaining, day streak) and a 90-day activity heatmap
|
||||
- Next Up queue (manually curated, reorderable)
|
||||
- Pick Back Up (courses with progress that have gone stale)
|
||||
- Recently Added / Recently Viewed
|
||||
- Surprise Me — random pick, weighted toward incomplete courses
|
||||
- Surprise Me — dice icon in the header, random pick weighted toward
|
||||
incomplete courses
|
||||
|
||||
**Playback & progress**
|
||||
- Video/audio player with resize, playback-speed presets, and resume-from-
|
||||
@@ -103,9 +107,11 @@ silently stay blank instead of erroring.
|
||||
- Auto-tracks watch progress and completion per lesson
|
||||
- Video/audio durations read via `ffprobe` and cached persistently per
|
||||
course (`.offlineu_duration_cache.json`), so total runtime and per-lesson
|
||||
length show up before you've ever pressed play — not just after
|
||||
- Settings → "Precompute Video Lengths" walks the whole library in the
|
||||
background to populate that cache up front, with live progress
|
||||
length show up before you've ever pressed play — not just after; the
|
||||
same cache backs the library-wide "time remaining" stat
|
||||
- Settings → "Precompute Lengths & Cover Art" walks the whole library in
|
||||
the background to populate durations and thumbnails up front, with live
|
||||
progress
|
||||
|
||||
**Notes**
|
||||
- Timestamped notes per lesson, capturable via a keyboard shortcut without
|
||||
@@ -120,9 +126,12 @@ silently stay blank instead of erroring.
|
||||
5-minute filesystem-scan cache)
|
||||
|
||||
**Backup & integrations**
|
||||
- One-click backup export: settings, hidden-path choices, recent-view
|
||||
history, and every course's progress/notes as a zip (not the course files
|
||||
themselves)
|
||||
- One-click backup export and restore: settings, hidden-path choices, the
|
||||
Next Up queue, recent-view history, Outline config, and every course's
|
||||
progress/notes as a zip (not the course files themselves). Restore
|
||||
overwrites current data and needs a matching course folder to already
|
||||
exist for each course's progress to land - it's a "put my data back"
|
||||
action, not a merge
|
||||
- Optional [Outline](https://www.getoutline.com/) integration — push a
|
||||
lesson's notes to an Outline document/collection
|
||||
|
||||
@@ -142,10 +151,11 @@ Everything under `OFFLINEU_DATA_DIR` (app-wide, not tied to a course):
|
||||
|
||||
Per-course, written inside the course's own folder on the library volume:
|
||||
|
||||
| File | Contents |
|
||||
| ----------------------------------- | ---------------------------------------------------- |
|
||||
| `.offlineu_progress.json` | Per-lesson completed/progress/duration/notes |
|
||||
| `.offlineu_duration_cache.json` | ffprobe duration cache, keyed by (path, size, mtime) |
|
||||
| File | Contents |
|
||||
| ----------------------------------- | -------------------------------------------------------- |
|
||||
| `.offlineu_progress.json` | Per-lesson completed/progress/duration/notes |
|
||||
| `.offlineu_duration_cache.json` | ffprobe duration cache, keyed by (path, size, mtime) |
|
||||
| `.offlineu_thumbnail.jpg` | Auto-generated cover art (only if no manual cover exists) |
|
||||
|
||||
---
|
||||
|
||||
@@ -162,7 +172,8 @@ MyCourse/
|
||||
│ └── resources/
|
||||
│ └── extras.md
|
||||
├── .offlineu_progress.json ← created automatically
|
||||
└── .offlineu_duration_cache.json ← created automatically
|
||||
├── .offlineu_duration_cache.json ← created automatically
|
||||
└── .offlineu_thumbnail.jpg ← created automatically, only if no manual cover exists
|
||||
```
|
||||
|
||||
No metadata files needed — course/section/lesson names come straight from
|
||||
|
||||
Reference in New Issue
Block a user