@karaplay/file-coder 1.2.0 → 1.3.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/README.md +36 -0
- package/RELEASE_v1.2.0.md +161 -0
- package/dist/ncntokar.browser.js +8 -1
- package/dist/ncntokar.js +8 -1
- package/package.json +1 -1
- package/temp/Z2510001.cur +0 -0
- package/temp/Z2510001.lyr +0 -37
- package/temp/Z2510001.mid +0 -0
- package/test-emk-output.kar +0 -0
- package/test-emk-to-kar.js +0 -79
- package/test-extract-simple.js +0 -22
- package/test-readkar.js +0 -24
package/README.md
CHANGED
|
@@ -216,3 +216,39 @@ MIT
|
|
|
216
216
|
|
|
217
217
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
218
218
|
|
|
219
|
+
|
|
220
|
+
## Changelog
|
|
221
|
+
|
|
222
|
+
### v1.3.0 (Latest)
|
|
223
|
+
**🔧 Critical Fix: Beginning Lyrics Preservation**
|
|
224
|
+
|
|
225
|
+
- **Fixed**: Beginning lyrics were being cut off during EMK to KAR and NCN to KAR conversion
|
|
226
|
+
- **Improved**: Smart detection and skipping of instrumental intro markers (e.g., "....ดนตรี....")
|
|
227
|
+
- **Added**: 6 comprehensive tests to verify beginning lyrics preservation
|
|
228
|
+
- **Verified**: All 119 tests passing, ensuring complete lyric integrity from EMK decode to KAR output
|
|
229
|
+
|
|
230
|
+
**What was fixed:**
|
|
231
|
+
Previously, the conversion process was double-skipping the first 4 lines of lyrics, causing the actual beginning of songs to be missing from KAR files. This version correctly preserves all lyrics from the beginning while intelligently filtering out non-lyrical markers.
|
|
232
|
+
|
|
233
|
+
**Comparison test:**
|
|
234
|
+
```typescript
|
|
235
|
+
// EMK decoded lyrics vs KAR output: 100% match
|
|
236
|
+
// First lyric: "ท่องเที่ยวมาแล้วแทบทั่วเมืองไทย" ✅
|
|
237
|
+
// Last lyric: "กับยุพิน ที่เมืองพระรถ..." ✅
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### v1.2.0
|
|
241
|
+
- Added Thai encoding tests (6 new tests)
|
|
242
|
+
- Verified TIS-620 encoding preservation
|
|
243
|
+
- Updated README with encoding clarification
|
|
244
|
+
|
|
245
|
+
### v1.1.1
|
|
246
|
+
- Documentation update for Thai encoding in KAR files
|
|
247
|
+
- No code changes
|
|
248
|
+
|
|
249
|
+
### v1.0.0
|
|
250
|
+
- Initial release
|
|
251
|
+
- Full browser and server support
|
|
252
|
+
- EMK decoding and NCN to KAR conversion
|
|
253
|
+
- Thai language support (TIS-620)
|
|
254
|
+
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Release v1.2.0 - Thai Encoding Fix 🎉
|
|
2
|
+
|
|
3
|
+
## 🐛 Bug Fix Release
|
|
4
|
+
|
|
5
|
+
**Package**: `@karaplay/file-coder`
|
|
6
|
+
**Version**: 1.2.0
|
|
7
|
+
**Published**: December 17, 2025
|
|
8
|
+
|
|
9
|
+
## ✅ What Was Fixed
|
|
10
|
+
|
|
11
|
+
### Thai Lyrics Now Fully Readable!
|
|
12
|
+
|
|
13
|
+
Fixed a critical bug where Thai lyrics in KAR files generated from EMK files were not readable when extracted programmatically.
|
|
14
|
+
|
|
15
|
+
#### The Problem
|
|
16
|
+
- EMK to KAR conversion was writing Thai text correctly (TIS-620 encoding)
|
|
17
|
+
- BUT when reading KAR files back, Thai characters appeared garbled
|
|
18
|
+
- The `extractLyricsFromKar()` function was not properly decoding Thai text
|
|
19
|
+
|
|
20
|
+
#### The Solution
|
|
21
|
+
- Fixed `readKarFile()` to properly decode TIS-620 bytes as Thai characters
|
|
22
|
+
- Fixed `extractLyricsFromKar()` to return properly decoded Thai text
|
|
23
|
+
- Applied same fix to browser versions (`readKarBuffer`, `extractLyricsFromKarBuffer`)
|
|
24
|
+
|
|
25
|
+
## 🧪 New Tests
|
|
26
|
+
|
|
27
|
+
Added **6 comprehensive Thai encoding tests**:
|
|
28
|
+
|
|
29
|
+
1. ✅ Preserve Thai characters in title and artist
|
|
30
|
+
2. ✅ Preserve Thai characters when reading KAR file back
|
|
31
|
+
3. ✅ Extract readable Thai lyrics from KAR file
|
|
32
|
+
4. ✅ Handle Thai characters in karaoke track
|
|
33
|
+
5. ✅ Preserve Thai encoding in KAR file bytes
|
|
34
|
+
6. ✅ Match Thai content between EMK and KAR
|
|
35
|
+
|
|
36
|
+
**Total Tests**: 113 passing (107 original + 6 new)
|
|
37
|
+
|
|
38
|
+
## 📊 Test Results
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
Test Suites: 8 passed, 8 total
|
|
42
|
+
Tests: 113 passed, 113 total
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
All tests pass including:
|
|
46
|
+
- Unit tests for all functions
|
|
47
|
+
- Integration tests with real EMK files
|
|
48
|
+
- Thai encoding verification tests
|
|
49
|
+
- Browser API tests
|
|
50
|
+
|
|
51
|
+
## 🔧 Technical Details
|
|
52
|
+
|
|
53
|
+
### Files Modified
|
|
54
|
+
|
|
55
|
+
1. **`src/kar-reader.ts`**
|
|
56
|
+
- Fixed `readKarFile()` to decode TIS-620 text events
|
|
57
|
+
- Simplified `extractLyricsFromKar()` to use decoded text
|
|
58
|
+
|
|
59
|
+
2. **`src/kar-reader.browser.ts`**
|
|
60
|
+
- Applied same fixes for browser environment
|
|
61
|
+
|
|
62
|
+
3. **`src/emk-to-kar.ts`**
|
|
63
|
+
- Added comment clarifying TIS-620 encoding preservation
|
|
64
|
+
|
|
65
|
+
### How It Works
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Before (garbled):
|
|
69
|
+
// midi-file decodes as Latin-1 → "àʹèËìàÁ×ͧ¾ÃÐö"
|
|
70
|
+
|
|
71
|
+
// After (correct):
|
|
72
|
+
// Re-encode as Latin-1 bytes → Decode as TIS-620 → "เสน่ห์เมืองพระรถ"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The fix converts the garbled Latin-1 strings back to their original bytes, then properly decodes them as TIS-620 (Thai encoding).
|
|
76
|
+
|
|
77
|
+
## 📦 Installation
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install @karaplay/file-coder@1.2.0
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Or update:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm update @karaplay/file-coder
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 🎯 Usage Example
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { convertEmkToKar, extractLyricsFromKar } from '@karaplay/file-coder';
|
|
93
|
+
|
|
94
|
+
// Convert EMK to KAR
|
|
95
|
+
const result = convertEmkToKar({
|
|
96
|
+
inputEmk: 'song.emk',
|
|
97
|
+
outputKar: 'song.kar'
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log(result.metadata.title); // ✅ Thai text readable!
|
|
101
|
+
console.log(result.metadata.artist); // ✅ Thai text readable!
|
|
102
|
+
|
|
103
|
+
// Extract lyrics
|
|
104
|
+
const lyrics = extractLyricsFromKar('song.kar');
|
|
105
|
+
lyrics.forEach(lyric => {
|
|
106
|
+
console.log(lyric); // ✅ Thai lyrics readable!
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 🔍 Verification
|
|
111
|
+
|
|
112
|
+
Test with your own EMK files:
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
const { convertEmkToKar, extractLyricsFromKar } = require('@karaplay/file-coder');
|
|
116
|
+
|
|
117
|
+
// Convert
|
|
118
|
+
convertEmkToKar({
|
|
119
|
+
inputEmk: 'your-thai-song.emk',
|
|
120
|
+
outputKar: 'output.kar'
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Extract and verify
|
|
124
|
+
const lyrics = extractLyricsFromKar('output.kar');
|
|
125
|
+
const thaiRegex = /[\u0E00-\u0E7F]/;
|
|
126
|
+
const hasThaiChars = lyrics.some(l => thaiRegex.test(l));
|
|
127
|
+
|
|
128
|
+
console.log('Thai characters preserved:', hasThaiChars); // Should be true!
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 📝 Breaking Changes
|
|
132
|
+
|
|
133
|
+
**None** - This is a bug fix release. All existing code will continue to work, but Thai text will now be properly readable.
|
|
134
|
+
|
|
135
|
+
## 🎊 Summary
|
|
136
|
+
|
|
137
|
+
| Metric | Value |
|
|
138
|
+
|--------|-------|
|
|
139
|
+
| Version | 1.2.0 |
|
|
140
|
+
| Tests | 113 passing |
|
|
141
|
+
| Bug Fixes | Thai encoding |
|
|
142
|
+
| New Tests | 6 |
|
|
143
|
+
| Breaking Changes | None |
|
|
144
|
+
|
|
145
|
+
## 🔗 Links
|
|
146
|
+
|
|
147
|
+
- **npm**: https://www.npmjs.com/package/@karaplay/file-coder
|
|
148
|
+
- **Version**: 1.2.0
|
|
149
|
+
|
|
150
|
+
## 🙏 Thank You
|
|
151
|
+
|
|
152
|
+
Thank you for reporting this issue! Thai lyrics are now fully supported and readable throughout the entire EMK→KAR conversion process.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
**Upgrade now to get proper Thai encoding support!** 🚀
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm install @karaplay/file-coder@1.2.0
|
|
160
|
+
```
|
|
161
|
+
|
package/dist/ncntokar.browser.js
CHANGED
|
@@ -170,11 +170,18 @@ function buildKaraokeTrackBrowser(metadata, cursorBuffer, ticksPerBeat) {
|
|
|
170
170
|
const cursor = new BrowserCursorReader(cursorBuffer);
|
|
171
171
|
const splitter = new grapheme_splitter_1.default();
|
|
172
172
|
let previousAbsoluteTimestamp = 0;
|
|
173
|
+
// Note: metadata.fullLyric already has title/artist removed (starts from line 4 of original file)
|
|
174
|
+
// We should process ALL lines in fullLyric to avoid cutting off the beginning
|
|
173
175
|
const lyricsWithEndings = splitLinesKeepEndings(metadata.fullLyric);
|
|
174
|
-
for (let i =
|
|
176
|
+
for (let i = 0; i < lyricsWithEndings.length; i++) {
|
|
175
177
|
const trimmed = trimLineEndings(lyricsWithEndings[i]);
|
|
176
178
|
if (!trimmed || trimmed.length === 0)
|
|
177
179
|
continue;
|
|
180
|
+
// Skip instrumental intro markers (e.g., "....ดนตรี...." or similar patterns)
|
|
181
|
+
// These are common in EMK files but don't have timing data
|
|
182
|
+
if (trimmed.match(/^\.{2,}[^.]+\.{2,}$/)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
178
185
|
const lineForTiming = "/" + trimmed;
|
|
179
186
|
const graphemes = splitter.splitGraphemes(lineForTiming);
|
|
180
187
|
for (const g of graphemes) {
|
package/dist/ncntokar.js
CHANGED
|
@@ -209,11 +209,18 @@ function buildKaraokeTrack(metadata, cursorBuffer, ticksPerBeat) {
|
|
|
209
209
|
const splitter = new grapheme_splitter_1.default();
|
|
210
210
|
let previousAbsoluteTimestamp = 0;
|
|
211
211
|
// Process each lyric line
|
|
212
|
+
// Note: metadata.fullLyric already has title/artist removed (starts from line 4 of original file)
|
|
213
|
+
// We should process ALL lines in fullLyric to avoid cutting off the beginning
|
|
212
214
|
const lyricsWithEndings = splitLinesKeepEndings(metadata.fullLyric);
|
|
213
|
-
for (let i =
|
|
215
|
+
for (let i = 0; i < lyricsWithEndings.length; i++) {
|
|
214
216
|
const trimmed = trimLineEndings(lyricsWithEndings[i]);
|
|
215
217
|
if (!trimmed || trimmed.length === 0)
|
|
216
218
|
continue;
|
|
219
|
+
// Skip instrumental intro markers (e.g., "....ดนตรี...." or similar patterns)
|
|
220
|
+
// These are common in EMK files but don't have timing data
|
|
221
|
+
if (trimmed.match(/^\.{2,}[^.]+\.{2,}$/)) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
217
224
|
const lineForTiming = "/" + trimmed;
|
|
218
225
|
const graphemes = splitter.splitGraphemes(lineForTiming);
|
|
219
226
|
for (const g of graphemes) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@karaplay/file-coder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A comprehensive library for encoding/decoding karaoke files (.emk, .kar, MIDI) with Next.js support. Convert EMK to KAR, read/write karaoke files, full browser and server support.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/temp/Z2510001.cur
DELETED
|
Binary file
|
package/temp/Z2510001.lyr
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
�ʹ������ͧ���ö(Ab)
|
|
2
|
-
ǧ�����ǧ
|
|
3
|
-
Ab
|
|
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
|
-
|
package/temp/Z2510001.mid
DELETED
|
Binary file
|
package/test-emk-output.kar
DELETED
|
Binary file
|
package/test-emk-to-kar.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const { convertEmkToKar } = require('./dist/emk-to-kar');
|
|
2
|
-
const { readKarFile, extractLyricsFromKar } = require('./dist/kar-reader');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const iconv = require('iconv-lite');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
|
|
7
|
-
console.log('=== Testing EMK to KAR conversion with Thai lyrics ===\n');
|
|
8
|
-
|
|
9
|
-
// Clean up old output
|
|
10
|
-
const outputPath = path.join(__dirname, 'test-emk-output.kar');
|
|
11
|
-
if (fs.existsSync(outputPath)) {
|
|
12
|
-
fs.unlinkSync(outputPath);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Convert EMK to KAR
|
|
16
|
-
const result = convertEmkToKar({
|
|
17
|
-
inputEmk: path.join(__dirname, 'songs/emk/Z2510001.emk'),
|
|
18
|
-
outputKar: outputPath,
|
|
19
|
-
keepIntermediateFiles: true,
|
|
20
|
-
intermediateDir: __dirname
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
console.log('Conversion result:', result.success);
|
|
24
|
-
console.log('Title:', result.metadata.title);
|
|
25
|
-
console.log('Artist:', result.metadata.artist);
|
|
26
|
-
|
|
27
|
-
// Read the intermediate lyric file
|
|
28
|
-
const lyricPath = path.join(__dirname, 'Z2510001.lyr');
|
|
29
|
-
if (fs.existsSync(lyricPath)) {
|
|
30
|
-
const lyricBuffer = fs.readFileSync(lyricPath);
|
|
31
|
-
const lyricText = iconv.decode(lyricBuffer, 'tis-620');
|
|
32
|
-
console.log('\nIntermediate lyric file (first 200 chars):');
|
|
33
|
-
console.log(lyricText.substring(0, 200));
|
|
34
|
-
|
|
35
|
-
const thaiRegex = /[\u0E00-\u0E7F]/;
|
|
36
|
-
console.log('Has Thai in intermediate lyric:', thaiRegex.test(lyricText));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Read back the KAR file
|
|
40
|
-
console.log('\n=== Reading back the KAR file ===');
|
|
41
|
-
const karInfo = readKarFile(outputPath);
|
|
42
|
-
console.log('KAR Title:', karInfo.metadata.title);
|
|
43
|
-
console.log('KAR Artist:', karInfo.metadata.artist);
|
|
44
|
-
|
|
45
|
-
// Extract lyrics
|
|
46
|
-
const lyrics = extractLyricsFromKar(outputPath);
|
|
47
|
-
console.log('\nExtracted lyrics (first 10):');
|
|
48
|
-
lyrics.slice(0, 10).forEach((lyric, i) => {
|
|
49
|
-
console.log(`${i + 1}. "${lyric}"`);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Check for Thai characters
|
|
53
|
-
const thaiRegex = /[\u0E00-\u0E7F]/;
|
|
54
|
-
const hasThaiInLyrics = lyrics.some(l => thaiRegex.test(l));
|
|
55
|
-
console.log('\n❌ ERROR: Has Thai characters in extracted lyrics:', hasThaiInLyrics);
|
|
56
|
-
console.log('Expected: true');
|
|
57
|
-
console.log('Actual:', hasThaiInLyrics);
|
|
58
|
-
|
|
59
|
-
// Check the actual bytes in the KAR file
|
|
60
|
-
console.log('\n=== Checking KAR file bytes ===');
|
|
61
|
-
const karBuffer = fs.readFileSync(outputPath);
|
|
62
|
-
let foundThai = false;
|
|
63
|
-
for (let i = 0; i < karBuffer.length - 20; i++) {
|
|
64
|
-
if (karBuffer[i] === 0x40 && karBuffer[i+1] === 0x54) { // @T
|
|
65
|
-
const slice = karBuffer.slice(i, Math.min(i + 30, karBuffer.length));
|
|
66
|
-
const text = iconv.decode(slice, 'tis-620');
|
|
67
|
-
if (thaiRegex.test(text)) {
|
|
68
|
-
console.log('✓ Found Thai in KAR bytes:', text.substring(0, 25));
|
|
69
|
-
foundThai = true;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!foundThai) {
|
|
76
|
-
console.log('❌ ERROR: No Thai characters found in KAR file bytes!');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
process.exit(hasThaiInLyrics ? 0 : 1);
|
package/test-extract-simple.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
const { extractLyricsFromKar } = require('./dist/kar-reader');
|
|
2
|
-
|
|
3
|
-
const lyrics = extractLyricsFromKar('test-emk-output.kar');
|
|
4
|
-
|
|
5
|
-
console.log('Total lyrics:', lyrics.length);
|
|
6
|
-
console.log('\nFirst 20 lyrics:');
|
|
7
|
-
lyrics.slice(0, 20).forEach((lyric, i) => {
|
|
8
|
-
const bytes = Buffer.from(lyric, 'utf8');
|
|
9
|
-
console.log(`${i + 1}. "${lyric}" [${bytes.length} bytes] [${Array.from(bytes.slice(0, 10)).map(b => '0x'+b.toString(16)).join(', ')}]`);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
// Check for Thai
|
|
13
|
-
const thaiRegex = /[\u0E00-\u0E7F]/;
|
|
14
|
-
const hasThaiInLyrics = lyrics.some(l => thaiRegex.test(l));
|
|
15
|
-
console.log('\nHas Thai characters:', hasThaiInLyrics);
|
|
16
|
-
|
|
17
|
-
// Show some that have Thai
|
|
18
|
-
const thaiLyrics = lyrics.filter(l => thaiRegex.test(l));
|
|
19
|
-
console.log('\nLyrics with Thai (first 10):');
|
|
20
|
-
thaiLyrics.slice(0, 10).forEach((lyric, i) => {
|
|
21
|
-
console.log(`${i + 1}. "${lyric}"`);
|
|
22
|
-
});
|
package/test-readkar.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const { readKarFile } = require('./dist/kar-reader');
|
|
2
|
-
|
|
3
|
-
const info = readKarFile('test-emk-output.kar');
|
|
4
|
-
|
|
5
|
-
console.log('=== KAR File Info ===');
|
|
6
|
-
console.log('Title:', info.metadata.title);
|
|
7
|
-
console.log('Artist:', info.metadata.artist);
|
|
8
|
-
console.log('Has Karaoke Track:', info.metadata.hasKaraokeTrack);
|
|
9
|
-
console.log('\nTracks:');
|
|
10
|
-
|
|
11
|
-
info.tracks.forEach((track, i) => {
|
|
12
|
-
console.log(`\nTrack ${i}: ${track.name || 'unnamed'}`);
|
|
13
|
-
console.log(` Events: ${track.events}`);
|
|
14
|
-
console.log(` Has Text: ${track.hasText}`);
|
|
15
|
-
console.log(` Text Events: ${track.textEvents.length}`);
|
|
16
|
-
|
|
17
|
-
if (track.name === 'Words' && track.textEvents.length > 0) {
|
|
18
|
-
console.log(' First 15 text events:');
|
|
19
|
-
track.textEvents.slice(0, 15).forEach((text, j) => {
|
|
20
|
-
const bytes = Buffer.from(text, 'utf8');
|
|
21
|
-
console.log(` ${j}. "${text}" [${bytes.length} bytes]`);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
});
|