Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Support multi-value TXXX/WXXX frames in ID3v2 - #11

Merged
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master
Jun 5, 2026
Merged

Support multi-value TXXX/WXXX frames in ID3v2#11
ralph-irving merged 3 commits into
LMS-Community:masterfrom
Rouzax:master

Conversation

@Rouzax

Copy link
Copy Markdown

Summary

  • Add null-separated multi-value support to the TXXX/WXXX handler in id3.c
  • Returns arrayref when multiple values present, scalar when single (no behavior change for existing files)
  • Mirrors the existing STRINGLIST handler pattern for standard text frames (TPE1, TALB, etc.)
  • Enables plural tags like TXXX:ALBUMARTISTS (written by Picard) to reach LMS as arrays

Context

Part of LMS-Community/slimserver#1555 (display_artist support). Vorbis/FLAC already deliver multi-value tags correctly; this closes the MP3 gap.

Forum discussion (post #133 in the thread): https://forums.lyrion.org/forum/user-forums/ripping-encoding-transcoding-tagging/1816764-lms-metadata-scaan-overrides-local-tags

Test plan

  • Four new MP3 test fixtures covering: 2 values, 3 values, empty slot, single value
  • 12 new test cases added to mp3.t
  • All 413 tests pass (401 existing + 12 new)
  • Single-value TXXX regression: existing tests at lines 329, 525, 933 still pass as scalars

Rouzax added 3 commits May 12, 2026 14:26
Four fixtures covering null-separated multi-value TXXX fields
(2-value, 3-value, empty-slot, and single-value regression guard)
plus the Python script that generates them.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
ID3v2.4 allows null-separated multiple strings in TXXX value fields.
Audio::Scan previously read only the first value. Add a loop mirroring
the existing STRINGLIST handler for standard text frames: returns an
arrayref when multiple values are present, scalar when single.
This enables plural tags like TXXX:ALBUMARTISTS written by Picard
to reach consumers as arrays instead of being truncated.
Signed-off-by: Rouzax <GitHub@mgdn.nl>
Tests cover: two values, three values, empty slot skipping,
and existing single-value regression (covered by pre-existing tests).
Signed-off-by: Rouzax <GitHub@mgdn.nl>
@michaelherger

Copy link
Copy Markdown
Member

Please note that we won't have new binaries for all possible platforms "automatically". I tend to only update recent, popular platforms by default. But I understand the change doesn't break existing installations, but rather adds a missing "feature" (support for multiple values). Therefore for users of outdated versions of this library nothing will change - neither good or bad.

@Rouzax

Copy link
Copy Markdown
Author

Thanks for the note on platform coverage. That's completely fine.

The change is indeed additive only. Installations running an older Audio-Scan will keep getting a single scalar for TXXX frames, exactly as today. Nothing breaks for them.

On the slimserver side, the code that consumes these tags already needs to handle both scalars and arrayrefs anyway (some tag types already return arrays). So the scanner will work correctly regardless of which Audio-Scan version is installed: arrayref means multi-value support is available, scalar means it falls back to current behavior.

@ralph-irving
ralph-irving merged commit bcfd472 into LMS-Community:masterJun 5, 2026
2 checks passed
@ralph-irving

Copy link
Copy Markdown

I plan to review another PR from Andy's Audio::Scan repository and include it here before making another release. andygrundman#16

@Rouzax

Copy link
Copy Markdown
Author

Any update on this one? You mentioned wanting to include andygrundman#16 before making another release.

Asking because the Audio::Scan bundled with slimserver is still 1.10, in both public/9.2 (be3d0ef82) and the display_artist branch, so multi-value TXXX frames still come back as the first value only. On an MP3 library that means ALBUMARTISTS and MUSICBRAINZ_ALBUMARTISTID both truncate, which leaves the plural artist tag work in LMS-Community/slimserver#1576 unavailable to MP3 users.

No rush intended, I mostly want to know whether to plan around it.

@michaelherger

Copy link
Copy Markdown
Member

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

@Rouzax

Rouzax commented Aug 17, 2026

Copy link
Copy Markdown
Author

What Perl version on what platform are you using? We are at Audio::Scan v1.13 for the most popular platforms.

I see that I'm at Audio::Scan: 1.11 on my prodcution server

Lyrion Music Server Status
Lyrion Music Server Version: 9.1.1 - 1779815526 @ Wed Jun 17 12:31:55 CUT 2026
Hostname: LMS
Server IP Address: 192.168.2.12
Server HTTP Port Number: 9000
Operating system: Windows 2022 Server (64-bit) - EN - cp1252
Platform Architecture: 8664
Database Version: SQLite
Total Players Recognized: 2
Perl and Module Versions
Perl Version: 5.32.1 - MSWin32-x64-multi-thread
Audio::Scan: 1.11
DBD::SQLite: 1.66 (sqlite 3.32.3)
IO::Socket::SSL: 2.069
Mozilla::CA: 20200520
Net::SSLeay: 1.90 - OpenSSL 1.1.1i 8 Dec 2020

@michaelherger

Copy link
Copy Markdown
Member

Windows is at v1.13 on 9.2. See:

https://github.com/LMS-Community/slimserver/blob/public/9.2/CPAN/arch/5.32/MSWin32-x64-multi-thread/Audio/Scan.pm#L5

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Rouzax@michaelherger@ralph-irving