Skip to content

Commit 8730ba0

Browse files
committed
More analysis of RegExpReplace
1 parent 073147e commit 8730ba0

File tree

3 files changed

+231
-0
lines changed

3 files changed

+231
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# RegExpReplace → MediaMonkey 5 Port (JS) — Plan & Data Structures
2+
3+
## Goals
4+
- Port the legacy VBScript/INI-based add-on to MM5 using JS/HTML/CSS.
5+
- Preserve preset-driven find/replace; modernize UI and storage; improve safety.
6+
7+
## Migration Plan (Concise)
8+
1) **Scaffold Add-on**
9+
- Create `addon.xml`, `src/` JS entry (`main.js`) plus HTML dialogs.
10+
- Bundle with ES modules or TypeScript → single JS output.
11+
12+
2) **Presets Model & Storage**
13+
- Define a JSON schema for presets; add validation/defaults.
14+
- Import legacy INI once (parser/converter); store in add-on data folder or MM5 settings.
15+
16+
3) **Field Mapping**
17+
- Map friendly names → MM5 track properties (Title, Artist, Album, Path, Custom1-5, etc.).
18+
- Getter/setter helpers; commit via `track.commitAsync()`.
19+
20+
4) **Engine (Find/Replace)**
21+
- `applyPreset(tracks, preset)` handles: resolve source/target, regex/literal, whole-word/match-case, optional JS expression evaluator (safer than VBScript Eval), path safety.
22+
- Add dry-run/preview option and error logging.
23+
24+
5) **UI (MM5)**
25+
- HTML dialogs for: preset picker, manage presets, main find/replace.
26+
- Commands registered to main menu, toolbar, and context menus; last-used preset shortcuts.
27+
28+
6) **Persistence & Safety**
29+
- JSON settings/presets; optional backup/export.
30+
- Guard filesystem moves; consider simple undo (session cache of originals).
31+
32+
7) **Testing**
33+
- Unit-test parser/engine; manual UI tests; sample presets migrated from legacy.
34+
35+
## Data Structure Sketches (JS/TS)
36+
37+
```typescript
38+
export type FieldName =
39+
| 'Title' | 'Artist' | 'Album' | 'AlbumArtist' | 'Genre' | 'Year'
40+
| 'TrackNumber' | 'DiscNumber' | 'Comment' | 'Lyrics'
41+
| 'Path' | 'Filename' | 'Folder'
42+
| 'Custom1' | 'Custom2' | 'Custom3' | 'Custom4' | 'Custom5';
43+
44+
export interface Preset {
45+
id: string; // stable id
46+
name: string;
47+
description?: string;
48+
menuGroup?: string; // optional submenu label
49+
shortcut?: string;
50+
icon?: string;
51+
toolbar?: boolean;
52+
53+
findWhat: string;
54+
findInto: FieldName;
55+
findRegExp: boolean;
56+
wholeWord: boolean;
57+
matchCase: boolean;
58+
59+
replaceWith: string;
60+
replaceFrom?: FieldName; // defaults to findInto if omitted
61+
replaceRegExp: boolean;
62+
replaceExpr?: boolean; // indicates expression evaluation
63+
}
64+
65+
export interface PresetStore {
66+
version: number;
67+
presets: Preset[];
68+
lastUsedIds?: string[];
69+
}
70+
71+
export interface ApplyOptions {
72+
dryRun?: boolean;
73+
previewLimit?: number;
74+
stopOnError?: boolean;
75+
}
76+
```
77+
78+
### Helpers (outline)
79+
- `parseLegacyIni(iniText): Preset[]` — one-time importer.
80+
- `serializeStore(store): string` — JSON persistence.
81+
- `expandPlaceholders(text, ctx)` — handles `<NUMBER/STRING>`, `<Into/From Field>`.
82+
- `getField(track, fieldName)`, `setField(track, fieldName, value)`.
83+
- `computeReplacement(input, preset, ctx)` — regex/literal/expression pathway.
84+
- `applyPreset(tracks, preset, opts)` — main engine with progress and optional dry-run.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# RegExpReplace-readable.vbs → JS Port Name Mapping
2+
3+
| Current name | Suggested JS name | Purpose |
4+
| --- | --- | --- |
5+
| OnStartUp | registerAddon | Initialize add-on, menus, options |
6+
| OptionsDialog / iz / b3 | showOptionsDialog | Render/save options |
7+
| q4 | buildBaseMenus | Add Manage/Options/last-used menu items |
8+
| nx | showManagePresetsDialog | Manage presets UI |
9+
| b8 | showFindReplaceDialog | Main find/replace UI |
10+
| mw | syncMenuStates | Sync checked/enabled states |
11+
| ln | setUiBusy | Enable/disable UI during work |
12+
| ae / cq / q8 | writePreset / deletePreset / readPreset | INI preset CRUD |
13+
| l | parsePresetField | Parse field from preset string |
14+
| pj | unquoteValue | Strip surrounding quotes |
15+
| dg | quoteValue | Escape/quote for serialization |
16+
| pc | serializePreset | Write preset to storage |
17+
| ra | loadPresetState | Load preset into memory/UI |
18+
| ih | expandFieldPlaceholders | Expand `<Into/From Field>` |
19+
| e7 | normalizePresetOrder | Sort/reindex presets |
20+
| ha | importPresets | Import/merge presets (INI) |
21+
| ql | rewritePresetSection | Rewrite INI after deletes |
22+
| pi | deletePreset | Remove preset and menus |
23+
| mr | swapPresets | Reorder presets |
24+
| kz | updatePresetRow | Edit preset in manage table |
25+
| pw / py / de / j7 / p9 | refreshPresetMenus | Keep menus/toolbar in sync |
26+
| po | countGroupPresets | Count presets in a menu group |
27+
| ho | buildToolbarButtons | Build toolbar items for presets |
28+
| et | resolvePresetIcon | Resolve icon/name and register |
29+
| kg / pl | updateLastUsed | Track last-executed presets |
30+
| dv / nw / eq / p6 / gf / fg / h4 / ko / d9 / cz / ar | handleFieldChange | Field-change handlers in dialogs |
31+
| p7 | savePresetFromDialog | Save/create/update preset |
32+
| mh | deleteSelectedPreset | Delete selected preset |
33+
| ll | bulkDeletePresets | Multi-delete in manage dialog |
34+
| bd / lh / ic / pg | togglePresetSource | Switch/load external INI |
35+
| fv / a3 / fl | renderPresetsTable | Render/manage presets table |
36+
| k7 / ig / dy / il / ge / mm / ca / h5 / qs / k5 | handleRowMove | Row selection/drag/hold move |
37+
| mb | handleTableClick | Click handling in manage list |
38+
| bf | refreshTable | Resort/refresh timer |
39+
| kx | executePresetByName | Run preset (optionally show adjust dialog) |
40+
| hg | applyCurrentPreset | Apply find/replace to tracks |
41+
| oh | applyPresetToFields | Orchestrate field replacements |
42+
| jy | applyReplacement | Apply to field/path; handle file ops |
43+
| r2 | computeReplacement | Regex/literal/expression replacement |
44+
| hv | highlightMatches | Highlight matches/replacements |
45+
| bp | hasMatch | Test pattern presence |
46+
| cm / mv | getFieldValue | Resolve current song field |
47+
| d1 / ht | setFieldValue | Composite field setters |
48+
| ep | firstMatch | First regex match for highlight |
49+
| MapChr / MapChrCase / MapArray / MapArrayCase / MapArrayEx | mapChars / mapArray | Mapping utilities |
50+
| RegExp / RegExpEx / RegSub | regexMatch / regexAll / regexSub | Regex helpers |
51+
| k6 | expandPlaceholders | Expand numbered/string/field placeholders |
52+
| mf | expandNamePlaceholders | Placeholder handling in names |
53+
| SetVar / GetVar / LetVar | setTemp / getTemp / letTemp | Temp var storage |
54+
| DateISO / DateTimeISO / Choose / IIf / IfNull / Min / Max / SQLQuery | dateIso / dateTimeIso / choose / iif / ifNull / min / max / sqlQuery | Expression helpers |
55+
| q0 | initTracklist | Build tracklist (selected/visible/NP) |
56+
| io / iv / e2 / gg / nl / qw / px / ah | navigateMatches | Find/next/prev/replace commands |
57+
| am | renderTrackPreviewRow | Build preview row |
58+
| cy | updatePreviewRow | Update preview row after replace |
59+
| bm | filterTracklist | Keep/remove/select matched/unmatched |
60+
| eu | isNowPlayingView | Determine current view |
61+
| aw / es / mq / g8 / jm | syncWithSelection | Sync with MM selection changes |
62+
| ai | togglePreviewCheckbox | Checkbox handling |
63+
| f9 / lb / it / lj / qb / c3 / o5 | updateControlsState | Enable/disable controls |
64+
| hs timers (ge/mm/qs/h5/k5/ca/d2) | handleRowMoveTimer | Smooth move timers |
65+
| kc / bf | initialRefreshTimer | Refresh timer manage dialog |
66+
| l0 / bx | safeRefreshPreview | Guarded refresh |
67+
| pf / ls | htmlEscape / renderPresetRow | Escape and render rows |
68+
| a6 | resolveSkinCss | Locate skin CSS |
69+
| be | adjustTimezone | TZ adjust datetime |
70+
| lr | updateHistory | Maintain find/replace history |
71+
| hm / no | loadSettings / saveSettings | Read/write INI settings |
72+
| le / em | onOptionsChanged | Respond to options changes |
73+
| gw / ml | fillDefaultPatterns | Default regex patterns |
74+
| dr / hp / ci | markDirty / clearDirty / isDirty | Dirty-state tracking |
75+
| fp | promptSaveIfDirty | Prompt to save edits |
76+
| n8 | closeDialog | Dialog cleanup |
77+
| nd / jl / hj / an | handleMenuCommand | Menu/toolbar entry points |
78+
| j5 | showHelp | Show regex/VBScript quick ref |
79+
| n0 | openHomepage | Open project page |
80+
| c4 | fieldMap | Friendly → field expressions |
81+
| ht | setterMap | Field setter overrides |
82+
| d7 | customFieldLabels | Custom label cache |
83+
| c8 | sqlCache | SQL query cache |
84+
| ef | regexCache | Cached regex objects |

legacy/mm5-port/presets.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
export type FieldName =
2+
| 'Title' | 'Artist' | 'Album' | 'AlbumArtist'
3+
| 'Genre' | 'Year' | 'TrackNumber' | 'DiscNumber'
4+
| 'Comment' | 'Lyrics'
5+
| 'Path' | 'Filename' | 'Folder'
6+
| 'Custom1' | 'Custom2' | 'Custom3' | 'Custom4' | 'Custom5';
7+
8+
export interface Preset {
9+
id: string; // stable identifier (uuid or slug)
10+
name: string;
11+
description?: string;
12+
menuGroup?: string; // optional submenu label
13+
shortcut?: string;
14+
icon?: string;
15+
toolbar?: boolean;
16+
17+
findWhat: string;
18+
findInto: FieldName;
19+
findRegExp: boolean;
20+
wholeWord: boolean;
21+
matchCase: boolean;
22+
23+
replaceWith: string;
24+
replaceFrom?: FieldName; // defaults to findInto if omitted
25+
replaceRegExp: boolean;
26+
replaceExpr?: boolean; // indicates expression evaluation (JS-based)
27+
}
28+
29+
export interface PresetStore {
30+
version: number;
31+
presets: Preset[];
32+
lastUsedIds?: string[];
33+
}
34+
35+
export interface ApplyOptions {
36+
dryRun?: boolean;
37+
previewLimit?: number;
38+
stopOnError?: boolean;
39+
}
40+
41+
export interface PlaceholderContext {
42+
intoField: FieldName;
43+
fromField: FieldName;
44+
numberParams: string[];
45+
stringParams: string[];
46+
}
47+
48+
export interface ReplacementContext {
49+
track: any; // MM5 track object
50+
preset: Preset;
51+
srcValue: string;
52+
dstField: FieldName;
53+
}
54+
55+
export type Getter = (track: any) => string;
56+
export type Setter = (track: any, value: string) => Promise<void>;
57+
58+
export interface FieldMapEntry {
59+
get: Getter;
60+
set: Setter;
61+
}
62+
63+
export type FieldMap = Record<FieldName, FieldMapEntry>;

0 commit comments

Comments
 (0)