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>
This commit is contained in:
@@ -782,6 +782,7 @@
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.grid-card-thumb-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
border-radius: var(--radius);
|
||||
@@ -822,15 +823,32 @@
|
||||
font-size: 0.75em;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.grid-card-progress-track {
|
||||
height: 3px;
|
||||
border-radius: 2px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
overflow: hidden;
|
||||
.grid-card-progress-ring {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 6px;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 50%;
|
||||
background: conic-gradient(var(--accent) calc(var(--pct) * 1%), rgba(0, 0, 0, 0.4) 0);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.grid-card-progress-fill {
|
||||
height: 100%;
|
||||
background: var(--accent);
|
||||
.grid-card-progress-ring::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 3px;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-secondary);
|
||||
}
|
||||
.grid-card-progress-ring-check {
|
||||
position: relative;
|
||||
color: var(--accent);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.transcript-search-toggle {
|
||||
@@ -1704,19 +1722,17 @@
|
||||
: courseInitialHtml(item.name);
|
||||
const clickHandler = selectionMode ? `toggleSelection('${safePath}')` : `loadCoursePath('${safePath}')`;
|
||||
const pct = item.completion_percentage;
|
||||
const progressBar = pct
|
||||
? `<div class="grid-card-progress-track"><div class="grid-card-progress-fill" style="width: ${pct}%;"></div></div>`
|
||||
const ringHtml = pct
|
||||
? `<div class="grid-card-progress-ring" style="--pct: ${pct};" title="${pct}% complete">${pct >= 100 ? '<span class="grid-card-progress-ring-check">✓</span>' : ''}</div>`
|
||||
: '';
|
||||
const metaBits = [`${item.media_files} media file${item.media_files === 1 ? '' : 's'}`];
|
||||
if (item.duration_display) metaBits.push(item.duration_display);
|
||||
if (pct) metaBits.push(`${pct}% done`);
|
||||
return `
|
||||
<div class="library-grid-card" onclick="${clickHandler}">
|
||||
${selectableAttrs(item)}
|
||||
<div class="grid-card-thumb-wrap">${iconHtml}</div>
|
||||
<div class="grid-card-thumb-wrap">${iconHtml}${ringHtml}</div>
|
||||
<div class="grid-card-name" title="${escapeAttr(item.name)}">${item.name}</div>
|
||||
<div class="grid-card-meta">${metaBits.join(' · ')}</div>
|
||||
${progressBar}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user