@ihabdevteam/core 0.347.0 → 0.349.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/dist/components.cjs.js +185 -185
- package/dist/hooks.cjs.js +5 -5
- package/dist/i18n.cjs.js +3 -3
- package/dist/ihabdevteam-core.cjs.js +183 -183
- package/dist/ihabdevteam-core.d.ts +1 -1
- package/dist/packages/core/src/components/Training/TrainingStepAudioPlayer.js +13 -1
- package/dist/packages/core/src/components/Training/audioPlaybackRules.d.ts +17 -0
- package/dist/packages/core/src/components/Training/audioPlaybackRules.js +42 -0
- package/dist/packages/core/src/i18n/locales/en.json +10 -481
- package/dist/packages/core/src/i18n/locales/ko.json +10 -479
- package/dist/packages/core/src/version.d.ts +1 -1
- package/dist/packages/core/src/version.js +1 -1
- package/dist/utils.cjs.js +4 -4
- package/package.json +1 -1
|
@@ -1754,7 +1754,7 @@ export declare function copyText(text: string): Promise<boolean>;
|
|
|
1754
1754
|
*
|
|
1755
1755
|
* 값은 손으로 적고 `test/coreVersion.test.ts` 가 package.json 과 어긋나면 운다.
|
|
1756
1756
|
*/
|
|
1757
|
-
export declare const CORE_VERSION = "0.
|
|
1757
|
+
export declare const CORE_VERSION = "0.349.0";
|
|
1758
1758
|
|
|
1759
1759
|
/** @public */
|
|
1760
1760
|
declare const coreDefault: Record<string, unknown>;
|
|
@@ -27,7 +27,7 @@ import { useWaveReady } from './useWaveReady';
|
|
|
27
27
|
import { useObjectUrls } from './useObjectUrls';
|
|
28
28
|
import { useAnchorRect } from './useAnchorRect';
|
|
29
29
|
import { useProgressTicker } from './useProgressTicker';
|
|
30
|
-
import { nextTrackIndex, shouldIgnorePause, buildSegments, totalDurationOf, normalizeSources } from './audioPlaybackRules';
|
|
30
|
+
import { nextTrackIndex, shouldIgnorePause, buildSegments, totalDurationOf, normalizeSources, needsReload } from './audioPlaybackRules';
|
|
31
31
|
/** @public */
|
|
32
32
|
export default function TrainingStepAudioPlayer({ btnLabel, soundSrc, bucketPath, onDone, disabled = false, ttsText = null, className, showSoundWaveForm = true, showNoiseWaveForm = true, leadInMs = 0, tailMs = 0 }) {
|
|
33
33
|
const { t } = useTranslation();
|
|
@@ -312,6 +312,18 @@ export default function TrainingStepAudioPlayer({ btnLabel, soundSrc, bucketPath
|
|
|
312
312
|
* (`test/audioPlaybackRateSurvivesLoad.test.tsx` 가 `load()` 자리 수를 센다).
|
|
313
313
|
*/
|
|
314
314
|
const loadSound = useCallback((a, src) => {
|
|
315
|
+
/* **이미 들고 있는 소리는 다시 받지 않는다**(말귀 청 (311), 2026-10-19).
|
|
316
|
+
`src` 를 걸고 `load()` 를 부르면 새 요청이다. 폰에서 그것이 침묵이 되고, 하나만
|
|
317
|
+
실패해도 *"소스를 가져오지 못했다"* 가 떴다 — 한 낱말에 `load()` 가 넷이었고
|
|
318
|
+
되풀이마다 하나씩 더 붙었다. 까닭은 다시 듣기가 **같은 주소**를 또 걸었던 것이다. */
|
|
319
|
+
if (!needsReload(a, src)) {
|
|
320
|
+
try {
|
|
321
|
+
a.currentTime = 0;
|
|
322
|
+
}
|
|
323
|
+
catch (e) { }
|
|
324
|
+
applyPlaybackRate(a);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
315
327
|
a.src = src;
|
|
316
328
|
applyPlaybackRate(a); // defaultPlaybackRate 를 먼저 세워 둔다 — load() 가 그것으로 되돌린다
|
|
317
329
|
a.load();
|
|
@@ -138,3 +138,20 @@ export interface NormalizedSource {
|
|
|
138
138
|
* 이 판단에 닿으려면 네트워크와 오디오 요소가 먼저 필요했다.
|
|
139
139
|
*/
|
|
140
140
|
export declare function normalizeSources(soundSrc: unknown, bucketPath: string | null | undefined, resolvePath: (code: string, bucketHint?: string | null) => string | null): NormalizedSource[];
|
|
141
|
+
/**
|
|
142
|
+
* **같은 소리를 다시 받아야 하나** — 말귀 청 (311), 2026-10-19.
|
|
143
|
+
*
|
|
144
|
+
* `src` 를 걸고 `load()` 를 부르면 **새 요청**이다. 로컬에서는 안 보이지만 느린 망(폰)에서는
|
|
145
|
+
* 그만큼 **침묵**이 되고, 그중 하나만 실패해도 *"소스를 가져오지 못했다"* 가 뜬다.
|
|
146
|
+
* 말귀가 폰 폭에서 `HTMLMediaElement` 의 `src`·`load()`·`play()` 를 가로채 재니 **한
|
|
147
|
+
* 낱말(0.77초)을 한 번 듣는 동안 같은 파일에 `load()` 가 넷**이었고, **되풀이마다 하나씩 더**
|
|
148
|
+
* 붙었다(다시 듣기가 같은 주소를 또 걸었다).
|
|
149
|
+
*
|
|
150
|
+
* 이미 그 주소를 들고 있고 **길이까지 알고 있으면**(`readyState >= HAVE_METADATA`) 다시 받을
|
|
151
|
+
* 까닭이 없다 — `currentTime = 0` 뒤 `play()` 면 된다.
|
|
152
|
+
*
|
|
153
|
+
* **주소는 풀어서 견준다.** 부르는 쪽은 상대 주소를 줄 수 있고 `currentSrc` 는 늘 절대
|
|
154
|
+
* 주소라, 글자로 견주면 **같은 파일을 늘 다르다고 본다**(그러면 이 셈이 아무것도 안 아낀다).
|
|
155
|
+
* 서명 주소는 받을 때마다 조각이 달라지는데, 그때는 **참으로 다른 주소**라 다시 받는 것이 맞다.
|
|
156
|
+
*/
|
|
157
|
+
export declare function needsReload(el: Pick<HTMLMediaElement, 'currentSrc' | 'src' | 'readyState'>, src: string): boolean;
|
|
@@ -161,3 +161,45 @@ export function normalizeSources(soundSrc, bucketPath, resolvePath) {
|
|
|
161
161
|
}
|
|
162
162
|
return out;
|
|
163
163
|
}
|
|
164
|
+
/* ── 아래는 **왜 `audioWaits` 가 아니라 여기인가** ──
|
|
165
|
+
처음에 `audioWaits.ts` 에 넣었다가 **시험 95개가 빨개졌다.** 그 모듈은 **열두 시험이
|
|
166
|
+
공장 꼴로 흉내** 낸다(`vi.mock(... , () => ({ measureAudioDuration, waitForCanPlay }))`) —
|
|
167
|
+
공장은 자기가 쓰는 이름만 내보내므로, 이름을 하나 더하면 그 열둘에서 `undefined` 가 되어
|
|
168
|
+
던진다. **코드는 맞았고 흉내가 빈약해서 난 거짓 빨강**이다.
|
|
169
|
+
이 파일은 흉내 내는 시험이 **0 곳**이고 순수 규칙이 사는 자리다. 받아 오는 몫이 없는
|
|
170
|
+
판단은 여기 둔다 — 그러면 다음에 규칙을 더해도 그 열둘이 안 깨진다. */
|
|
171
|
+
/**
|
|
172
|
+
* **같은 소리를 다시 받아야 하나** — 말귀 청 (311), 2026-10-19.
|
|
173
|
+
*
|
|
174
|
+
* `src` 를 걸고 `load()` 를 부르면 **새 요청**이다. 로컬에서는 안 보이지만 느린 망(폰)에서는
|
|
175
|
+
* 그만큼 **침묵**이 되고, 그중 하나만 실패해도 *"소스를 가져오지 못했다"* 가 뜬다.
|
|
176
|
+
* 말귀가 폰 폭에서 `HTMLMediaElement` 의 `src`·`load()`·`play()` 를 가로채 재니 **한
|
|
177
|
+
* 낱말(0.77초)을 한 번 듣는 동안 같은 파일에 `load()` 가 넷**이었고, **되풀이마다 하나씩 더**
|
|
178
|
+
* 붙었다(다시 듣기가 같은 주소를 또 걸었다).
|
|
179
|
+
*
|
|
180
|
+
* 이미 그 주소를 들고 있고 **길이까지 알고 있으면**(`readyState >= HAVE_METADATA`) 다시 받을
|
|
181
|
+
* 까닭이 없다 — `currentTime = 0` 뒤 `play()` 면 된다.
|
|
182
|
+
*
|
|
183
|
+
* **주소는 풀어서 견준다.** 부르는 쪽은 상대 주소를 줄 수 있고 `currentSrc` 는 늘 절대
|
|
184
|
+
* 주소라, 글자로 견주면 **같은 파일을 늘 다르다고 본다**(그러면 이 셈이 아무것도 안 아낀다).
|
|
185
|
+
* 서명 주소는 받을 때마다 조각이 달라지는데, 그때는 **참으로 다른 주소**라 다시 받는 것이 맞다.
|
|
186
|
+
*/
|
|
187
|
+
export function needsReload(el, src) {
|
|
188
|
+
if (!src)
|
|
189
|
+
return true;
|
|
190
|
+
if (el.readyState < 1 /* HAVE_METADATA */)
|
|
191
|
+
return true;
|
|
192
|
+
const have = el.currentSrc || el.src;
|
|
193
|
+
if (!have)
|
|
194
|
+
return true;
|
|
195
|
+
return resolveSoundUrl(have) !== resolveSoundUrl(src);
|
|
196
|
+
}
|
|
197
|
+
/** 주소를 절대 꼴로 — 못 풀면 글자 그대로(시험·서버 자리에서 `location` 이 없을 수 있다) */
|
|
198
|
+
function resolveSoundUrl(u) {
|
|
199
|
+
try {
|
|
200
|
+
return new URL(u, typeof location === 'undefined' ? 'http://localhost/' : location.href).href;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return u;
|
|
204
|
+
}
|
|
205
|
+
}
|