diff --git a/docs/en/updates/changelog.md b/docs/en/updates/changelog.md index f7d4ae5..5fe314d 100644 --- a/docs/en/updates/changelog.md +++ b/docs/en/updates/changelog.md @@ -1,5 +1,12 @@ # Update Log +## v5.0.1 + +- Fixed bug where courses were not auto-tracked on first install/update +- Auto-track newly added courses, auto-remove courses no longer in the list +- Fixed incorrect current week highlight on past semester courses +- Extension icon click now opens docs page based on user language setting + ## v5.0.0 - Multi-language support (Korean/English/Japanese/Chinese) diff --git a/docs/ja/updates/changelog.md b/docs/ja/updates/changelog.md index 133dfbd..562b5db 100644 --- a/docs/ja/updates/changelog.md +++ b/docs/ja/updates/changelog.md @@ -1,5 +1,12 @@ # アップデートログ +## v5.0.1 + +- 初回インストール/アップデート時に科目が自動トラッキングされないバグを修正 +- 新しく追加された科目の自動トラッキング、削除された科目の自動除去 +- 過去学期の講義で現在の週として誤って表示されるバグを修正 +- 拡張機能アイコンクリック時にユーザー言語設定に基づくドキュメントページへ移動 + ## v5.0.0 - 多言語対応(韓国語/英語/日本語/中国語) diff --git a/docs/updates/changelog.md b/docs/updates/changelog.md index 78c53a5..592a519 100644 --- a/docs/updates/changelog.md +++ b/docs/updates/changelog.md @@ -1,5 +1,12 @@ # 업데이트 로그 +## v5.0.1 + +- 첫 설치/업데이트 시 과목 자동 트래킹이 안 되던 버그 수정 +- 새로 추가된 과목 자동 트래킹, 사라진 과목 자동 제거 +- 이전 학기 강의에서 현재 주차로 잘못 표시되는 버그 수정 +- 확장 프로그램 아이콘 클릭 시 사용자 언어 설정 기반 문서 페이지 이동 + ## v5.0.0 - 다국어 지원 (한국어/영어/일본어/중국어) diff --git a/docs/zh/updates/changelog.md b/docs/zh/updates/changelog.md index 4237d8d..7b55311 100644 --- a/docs/zh/updates/changelog.md +++ b/docs/zh/updates/changelog.md @@ -1,5 +1,12 @@ # 更新日志 +## v5.0.1 + +- 修复首次安装/更新时科目未自动跟踪的问题 +- 自动跟踪新增科目,自动移除已不存在的科目 +- 修复过去学期课程错误显示为当前周次的问题 +- 点击扩展图标时根据用户语言设置跳转到对应文档页面 + ## v5.0.0 - 多语言支持(韩语/英语/日语/中文) diff --git a/src/background.ts b/src/background.ts index f2a7192..8e02ea5 100644 --- a/src/background.ts +++ b/src/background.ts @@ -25,5 +25,11 @@ chrome.runtime.onInstalled.addListener((details) => { }); chrome.action.onClicked.addListener(() => { - chrome.runtime.openOptionsPage(); + const BASE_URL = 'https://hs-shell.github.io/dotbugi/'; + const LANG_PATHS: Record = { en: 'en/', ja: 'ja/', zh: 'zh/' }; + + chrome.storage.local.get('language', (result) => { + const langPath = LANG_PATHS[result.language] ?? ''; + chrome.tabs.create({ url: BASE_URL + langPath }); + }); }); diff --git a/src/hooks/useGetCourses.ts b/src/hooks/useGetCourses.ts index 695280a..fec2477 100644 --- a/src/hooks/useGetCourses.ts +++ b/src/hooks/useGetCourses.ts @@ -30,17 +30,39 @@ export const useGetCourses = () => { saveDataToStorage('courses', JSON.stringify(courses)); loadDataFromStorage('trackedCourseIds', (savedIds) => { - if (savedIds) { - // 빈 배열([])도 유효한 저장 상태로 취급 (사용자가 의도적으로 모두 해제한 경우) - setTrackedCourseIdsState(savedIds); - } else { - // 최초 사용: 비교과(커뮤니티)와 이전 학기 과목 제외하고 전부 트래킹 - const defaultIds = courses - .filter((c) => !c.isCommunity && c.isCurrentSemester !== false) - .map((c) => c.courseId); - setTrackedCourseIdsState(defaultIds); - saveDataToStorage('trackedCourseIds', defaultIds); - } + if (!savedIds && courses.length === 0) return; + + loadDataFromStorage('knownCourseIds', (knownIds) => { + const knownSet = new Set(knownIds ?? []); + + if (savedIds) { + const currentCourseIds = new Set(courses.map((c) => c.courseId)); + // 현재 강의 목록에 없는 과목은 추적에서 제거 + const filtered = savedIds.filter((id) => currentCourseIds.has(id)); + // 새로 추가된 과목 자동 추가 + const newTrackableIds = courses + .filter((c) => !knownSet.has(c.courseId) && !c.isCommunity) + .map((c) => c.courseId); + const mergedIds = [...filtered, ...newTrackableIds]; + setTrackedCourseIdsState(mergedIds); + if (filtered.length !== savedIds.length || newTrackableIds.length > 0) { + saveDataToStorage('trackedCourseIds', mergedIds); + } + } else if (courses.length > 0) { + // 최초 사용: 비교과(커뮤니티)와 이전 학기 과목 제외하고 전부 트래킹 + const defaultIds = courses + .filter((c) => !c.isCommunity) + .map((c) => c.courseId); + setTrackedCourseIdsState(defaultIds); + saveDataToStorage('trackedCourseIds', defaultIds); + } + + // 현재 과목 목록을 knownCourseIds로 저장 + if (courses.length > 0) { + const updatedKnown = [...new Set([...knownSet, ...courses.map((c) => c.courseId)])]; + saveDataToStorage('knownCourseIds', updatedKnown); + } + }); }); }; diff --git a/src/lib/courseStatus/currentWeek.ts b/src/lib/courseStatus/currentWeek.ts index 2129039..095c73b 100644 --- a/src/lib/courseStatus/currentWeek.ts +++ b/src/lib/courseStatus/currentWeek.ts @@ -63,6 +63,9 @@ function parseSectionDateRange(text: string, year: number): { start: Date; end: // ── Highlight & scroll button ─────────────────────────────────────── export function highlightCurrentWeek() { + // .course_box_current는 현재 학기 강의에서만 존재 + if (!document.querySelector('.course_box_current')) return; + const now = new Date(); const sections = document.querySelectorAll('li[id^="section-"]'); const fallbackYear = inferYear(sections); diff --git a/src/lib/injectCourseToggles.ts b/src/lib/injectCourseToggles.ts index a093c3b..ae19239 100644 --- a/src/lib/injectCourseToggles.ts +++ b/src/lib/injectCourseToggles.ts @@ -12,14 +12,37 @@ export function injectCourseToggles() { saveDataToStorage('communityIds', communityIds); loadDataFromStorage('trackedCourseIds', (savedIds) => { - const trackedIds = savedIds ?? allCourses - .filter((c) => !c.isCommunity && c.isCurrentSemester !== false) - .map((c) => c.courseId); + loadDataFromStorage('knownCourseIds', (knownIds) => { + const knownSet = new Set(knownIds ?? []); + + const currentCourseIds = new Set(allCourses.map((c) => c.courseId)); + + let trackedIds: string[]; + let changed = false; + if (savedIds) { + // 현재 강의 목록에 없는 과목은 추적에서 제거 + const filtered = savedIds.filter((id) => currentCourseIds.has(id)); + // 새로 추가된 과목 자동 추가 + const newTrackableIds = allCourses + .filter((c) => !knownSet.has(c.courseId) && !c.isCommunity) + .map((c) => c.courseId); + trackedIds = [...filtered, ...newTrackableIds]; + changed = filtered.length !== savedIds.length || newTrackableIds.length > 0; + } else { + trackedIds = allCourses + .filter((c) => !c.isCommunity) + .map((c) => c.courseId); + changed = true; + } - if (!savedIds) { + if (changed) { saveDataToStorage('trackedCourseIds', trackedIds); } + // knownCourseIds 업데이트 + const updatedKnown = [...new Set([...knownSet, ...currentCourseIds])]; + saveDataToStorage('knownCourseIds', updatedKnown); + const trackedSet = new Set(trackedIds); const listItems = document.querySelectorAll('.my-course-lists > li'); @@ -48,6 +71,7 @@ export function injectCourseToggles() { courseBox.appendChild(toggle); } }); + }); }); } diff --git a/src/lib/parseCourses.ts b/src/lib/parseCourses.ts index badf2cd..8f2ced0 100644 --- a/src/lib/parseCourses.ts +++ b/src/lib/parseCourses.ts @@ -17,8 +17,7 @@ function parseCourseFromElement(li: Element): CourseBase | null { if (!courseId || !courseTitle || !prof) return null; const isCommunity = li.classList.contains(COMMUNITY_CLASS); - const isCurrentSemester = isCommunity || !!li.querySelector('.course_box_current'); - return { courseId, courseTitle, prof, isCommunity, isCurrentSemester }; + return { courseId, courseTitle, prof, isCommunity }; } export function parseCoursesFromDOM(): CourseBase[] { diff --git a/src/types.ts b/src/types.ts index 0158fa6..ab6dd7a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,7 +3,6 @@ export type CourseBase = { courseTitle: string; prof: string; isCommunity?: boolean; - isCurrentSemester?: boolean; }; export type Vod = CourseBase & {