Spaces:
Paused
Paused
File size: 3,057 Bytes
02f8344 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | const STORAGE_KEY = 'shadowing-progress'
const META_KEY = 'shadowing-video-meta'
/**
* @typedef {Object} ShadowingProgress
* @property {string} video_id
* @property {number} currentSegment
* @property {number[]} dictationScores
* @property {number[]} pronunciationScores
* @property {number[]} flaggedSegments
*/
export function loadProgress(videoId) {
try {
const raw = localStorage.getItem(STORAGE_KEY)
const all = raw ? JSON.parse(raw) : {}
return all[videoId] || {
video_id: videoId,
currentSegment: 0,
dictationScores: [],
pronunciationScores: [],
flaggedSegments: [],
}
} catch {
return {
video_id: videoId,
currentSegment: 0,
dictationScores: [],
pronunciationScores: [],
flaggedSegments: [],
}
}
}
export function saveProgress(videoId, patch) {
try {
const raw = localStorage.getItem(STORAGE_KEY)
const all = raw ? JSON.parse(raw) : {}
all[videoId] = { ...loadProgress(videoId), ...patch, video_id: videoId }
localStorage.setItem(STORAGE_KEY, JSON.stringify(all))
} catch { /* ignore */ }
}
export function saveVideoMeta(videoId, { title, level, sourceUrl } = {}) {
try {
const raw = localStorage.getItem(META_KEY)
const all = raw ? JSON.parse(raw) : {}
all[videoId] = {
...all[videoId],
title: title ?? all[videoId]?.title,
level: level ?? all[videoId]?.level,
sourceUrl: sourceUrl ?? all[videoId]?.sourceUrl,
lastVisitedAt: new Date().toISOString(),
}
localStorage.setItem(META_KEY, JSON.stringify(all))
} catch { /* ignore */ }
}
/** Local fallback history from progress/meta keys. */
export function listLocalHistory() {
try {
const progRaw = localStorage.getItem(STORAGE_KEY)
const metaRaw = localStorage.getItem(META_KEY)
const prog = progRaw ? JSON.parse(progRaw) : {}
const meta = metaRaw ? JSON.parse(metaRaw) : {}
return Object.keys(prog)
.map((videoId) => ({
video_id: videoId,
title: meta[videoId]?.title || videoId,
level: meta[videoId]?.level || 'Intermediate',
segment_count: 0,
last_viewed_at: meta[videoId]?.lastVisitedAt || null,
_local: true,
}))
.sort((a, b) => {
const ta = a.last_viewed_at ? new Date(a.last_viewed_at).getTime() : 0
const tb = b.last_viewed_at ? new Date(b.last_viewed_at).getTime() : 0
return tb - ta
})
} catch {
return []
}
}
export function updateLocalHistoryMeta(videoId, { title, level } = {}) {
saveVideoMeta(videoId, { title, level })
}
export function removeLocalHistory(videoId) {
try {
const progRaw = localStorage.getItem(STORAGE_KEY)
const metaRaw = localStorage.getItem(META_KEY)
const prog = progRaw ? JSON.parse(progRaw) : {}
const meta = metaRaw ? JSON.parse(metaRaw) : {}
delete prog[videoId]
delete meta[videoId]
localStorage.setItem(STORAGE_KEY, JSON.stringify(prog))
localStorage.setItem(META_KEY, JSON.stringify(meta))
} catch { /* ignore */ }
}
|